root/source4/smb_server/smb/sesssetup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sesssetup_common_strings
  2. smbsrv_sesssetup_backend_send
  3. sesssetup_old_send
  4. sesssetup_old
  5. sesssetup_nt1_send
  6. sesssetup_nt1
  7. sesssetup_spnego_send
  8. sesssetup_spnego
  9. smbsrv_sesssetup_backend

   1 
   2 /* 
   3    Unix SMB/CIFS implementation.
   4    handle SMBsessionsetup
   5    Copyright (C) Andrew Tridgell                      1998-2001
   6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
   7    Copyright (C) Jim McDonough                        2002
   8    Copyright (C) Luke Howard                          2003
   9    Copyright (C) Stefan Metzmacher                    2005
  10    
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15    
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20    
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "version.h"
  27 #include "auth/credentials/credentials.h"
  28 #include "auth/gensec/gensec.h"
  29 #include "auth/auth.h"
  30 #include "smb_server/smb_server.h"
  31 #include "smbd/service_stream.h"
  32 #include "librpc/gen_ndr/nbt.h"
  33 #include "param/param.h"
  34 
  35 /*
  36   setup the OS, Lanman and domain portions of a session setup reply
  37 */
  38 static void sesssetup_common_strings(struct smbsrv_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
  39                                      char **os, char **lanman, char **domain)
  40 {
  41         (*os) = talloc_asprintf(req, "Unix");
  42         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
  43         (*domain) = talloc_asprintf(req, "%s", 
  44                                     lp_workgroup(req->smb_conn->lp_ctx));
  45 }
  46 
  47 static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
  48                                           union smb_sesssetup *sess,
  49                                           NTSTATUS status)
  50 {
  51         if (NT_STATUS_IS_OK(status)) {
  52                 req->smb_conn->negotiate.done_sesssetup = true;
  53                 /* we need to keep the session long term */
  54                 req->session = talloc_steal(req->smb_conn, req->session);
  55         }
  56         smbsrv_reply_sesssetup_send(req, sess, status);
  57 }
  58 
  59 static void sesssetup_old_send(struct auth_check_password_request *areq,
     /* [<][>][^][v][top][bottom][index][help] */
  60                                void *private_data)
  61 {
  62         struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
  63         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
  64         struct auth_serversupplied_info *server_info = NULL;
  65         struct auth_session_info *session_info;
  66         struct smbsrv_session *smb_sess;
  67         NTSTATUS status;
  68 
  69         status = auth_check_password_recv(areq, req, &server_info);
  70         if (!NT_STATUS_IS_OK(status)) goto failed;
  71 
  72         /* This references server_info into session_info */
  73         status = auth_generate_session_info(req, req->smb_conn->connection->event.ctx, req->smb_conn->lp_ctx, 
  74                                             server_info, &session_info);
  75         if (!NT_STATUS_IS_OK(status)) goto failed;
  76 
  77         /* allocate a new session */
  78         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
  79         if (!smb_sess) {
  80                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
  81                 goto failed;
  82         }
  83 
  84         /* Ensure this is marked as a 'real' vuid, not one
  85          * simply valid for the session setup leg */
  86         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
  87         if (!NT_STATUS_IS_OK(status)) goto failed;
  88 
  89         /* To correctly process any AndX packet (like a tree connect)
  90          * we need to fill in the session on the request here */
  91         req->session = smb_sess;
  92         sess->old.out.vuid = smb_sess->vuid;
  93 
  94 failed:
  95         status = auth_nt_status_squash(status);
  96         smbsrv_sesssetup_backend_send(req, sess, status);
  97 }
  98 
  99 /*
 100   handler for old style session setup
 101 */
 102 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
     /* [<][>][^][v][top][bottom][index][help] */
 103 {
 104         struct auth_usersupplied_info *user_info = NULL;
 105         struct socket_address *remote_address;
 106         const char *remote_machine = NULL;
 107 
 108         sess->old.out.vuid = 0;
 109         sess->old.out.action = 0;
 110 
 111         sesssetup_common_strings(req, 
 112                                  &sess->old.out.os,
 113                                  &sess->old.out.lanman,
 114                                  &sess->old.out.domain);
 115 
 116         if (!req->smb_conn->negotiate.done_sesssetup) {
 117                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
 118         }
 119 
 120         if (req->smb_conn->negotiate.calling_name) {
 121                 remote_machine = req->smb_conn->negotiate.calling_name->name;
 122         }
 123         
 124         remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
 125         if (!remote_address) goto nomem;
 126 
 127         if (!remote_machine) {
 128                 remote_machine = remote_address->addr;
 129         }
 130 
 131         user_info = talloc(req, struct auth_usersupplied_info);
 132         if (!user_info) goto nomem;
 133         
 134         user_info->mapped_state = false;
 135         user_info->logon_parameters = 0;
 136         user_info->flags = 0;
 137         user_info->client.account_name = sess->old.in.user;
 138         user_info->client.domain_name = sess->old.in.domain;
 139         user_info->workstation_name = remote_machine;
 140         user_info->remote_host = talloc_steal(user_info, remote_address);
 141         
 142         user_info->password_state = AUTH_PASSWORD_RESPONSE;
 143         user_info->password.response.lanman = sess->old.in.password;
 144         user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
 145         user_info->password.response.nt = data_blob(NULL, 0);
 146 
 147         auth_check_password_send(req->smb_conn->negotiate.auth_context, user_info,
 148                                  sesssetup_old_send, req);
 149         return;
 150 
 151 nomem:
 152         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
 153 }
 154 
 155 static void sesssetup_nt1_send(struct auth_check_password_request *areq,
     /* [<][>][^][v][top][bottom][index][help] */
 156                                void *private_data)
 157 {
 158         struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
 159         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
 160         struct auth_serversupplied_info *server_info = NULL;
 161         struct auth_session_info *session_info;
 162         struct smbsrv_session *smb_sess;
 163         NTSTATUS status;
 164 
 165         status = auth_check_password_recv(areq, req, &server_info);
 166         if (!NT_STATUS_IS_OK(status)) goto failed;
 167 
 168         /* This references server_info into session_info */
 169         status = auth_generate_session_info(req, req->smb_conn->connection->event.ctx, 
 170                                             req->smb_conn->lp_ctx, 
 171                                             server_info, &session_info);
 172         if (!NT_STATUS_IS_OK(status)) goto failed;
 173 
 174         /* allocate a new session */
 175         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
 176         if (!smb_sess) {
 177                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
 178                 goto failed;
 179         }
 180 
 181         /* Ensure this is marked as a 'real' vuid, not one
 182          * simply valid for the session setup leg */
 183         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
 184         if (!NT_STATUS_IS_OK(status)) goto failed;
 185 
 186         /* To correctly process any AndX packet (like a tree connect)
 187          * we need to fill in the session on the request here */
 188         req->session = smb_sess;
 189         sess->nt1.out.vuid = smb_sess->vuid;
 190 
 191         if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
 192                 /* Already signing, or disabled */
 193                 goto done;
 194         }
 195 
 196 done:
 197         status = NT_STATUS_OK;
 198 failed:
 199         status = auth_nt_status_squash(status);
 200         smbsrv_sesssetup_backend_send(req, sess, status);
 201 }
 202 
 203 /*
 204   handler for NT1 style session setup
 205 */
 206 static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
     /* [<][>][^][v][top][bottom][index][help] */
 207 {
 208         NTSTATUS status;
 209         struct auth_context *auth_context;
 210         struct auth_usersupplied_info *user_info = NULL;
 211         struct socket_address *remote_address;
 212         const char *remote_machine = NULL;
 213         
 214         sess->nt1.out.vuid = 0;
 215         sess->nt1.out.action = 0;
 216 
 217         sesssetup_common_strings(req, 
 218                                  &sess->nt1.out.os,
 219                                  &sess->nt1.out.lanman,
 220                                  &sess->nt1.out.domain);
 221 
 222         if (!req->smb_conn->negotiate.done_sesssetup) {
 223                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
 224                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
 225         }
 226 
 227         if (req->smb_conn->negotiate.oid) {
 228                 if (sess->nt1.in.user && *sess->nt1.in.user) {
 229                         /* We can't accept a normal login, because we
 230                          * don't have a challenge */
 231                         status = NT_STATUS_LOGON_FAILURE;
 232                         goto failed;
 233                 }
 234 
 235                 /* TODO: should we use just "anonymous" here? */
 236                 status = auth_context_create(req, 
 237                                              req->smb_conn->connection->event.ctx,
 238                                              req->smb_conn->connection->msg_ctx,
 239                                              req->smb_conn->lp_ctx,
 240                                              &auth_context);
 241                 if (!NT_STATUS_IS_OK(status)) goto failed;
 242         } else {
 243                 auth_context = req->smb_conn->negotiate.auth_context;
 244         }
 245 
 246         if (req->smb_conn->negotiate.calling_name) {
 247                 remote_machine = req->smb_conn->negotiate.calling_name->name;
 248         }
 249 
 250         remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
 251         if (!remote_address) goto nomem;
 252 
 253         if (!remote_machine) {
 254                 remote_machine = remote_address->addr;
 255         }
 256 
 257         user_info = talloc(req, struct auth_usersupplied_info);
 258         if (!user_info) goto nomem;
 259 
 260         user_info->mapped_state = false;
 261         user_info->logon_parameters = 0;
 262         user_info->flags = 0;
 263         user_info->client.account_name = sess->nt1.in.user;
 264         user_info->client.domain_name = sess->nt1.in.domain;
 265         user_info->workstation_name = remote_machine;
 266         user_info->remote_host = talloc_steal(user_info, remote_address);
 267         
 268         user_info->password_state = AUTH_PASSWORD_RESPONSE;
 269         user_info->password.response.lanman = sess->nt1.in.password1;
 270         user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
 271         user_info->password.response.nt = sess->nt1.in.password2;
 272         user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
 273 
 274         auth_check_password_send(auth_context, user_info,
 275                                  sesssetup_nt1_send, req);
 276         return;
 277 
 278 nomem:
 279         status = NT_STATUS_NO_MEMORY;
 280 failed:
 281         status = auth_nt_status_squash(status);
 282         smbsrv_sesssetup_backend_send(req, sess, status);
 283 }
 284 
 285 struct sesssetup_spnego_state {
 286         struct smbsrv_request *req;
 287         union smb_sesssetup *sess;
 288         struct smbsrv_session *smb_sess;
 289 };
 290 
 291 static void sesssetup_spnego_send(struct gensec_update_request *greq, void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 292 {
 293         struct sesssetup_spnego_state *s = talloc_get_type(private_data,
 294                                            struct sesssetup_spnego_state);
 295         struct smbsrv_request *req = s->req;
 296         union smb_sesssetup *sess = s->sess;
 297         struct smbsrv_session *smb_sess = s->smb_sess;
 298         struct auth_session_info *session_info = NULL;
 299         NTSTATUS status;
 300         NTSTATUS skey_status;
 301         DATA_BLOB session_key;
 302 
 303         status = gensec_update_recv(greq, req, &sess->spnego.out.secblob);
 304         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 305                 goto done;
 306         } else if (!NT_STATUS_IS_OK(status)) {
 307                 goto failed;
 308         }
 309 
 310         status = gensec_session_info(smb_sess->gensec_ctx, &session_info);
 311         if (!NT_STATUS_IS_OK(status)) goto failed;
 312 
 313         skey_status = gensec_session_key(smb_sess->gensec_ctx, &session_key);
 314         if (NT_STATUS_IS_OK(skey_status)) {
 315                 smbsrv_setup_signing(req->smb_conn, &session_key, NULL);
 316         }
 317 
 318         /* Ensure this is marked as a 'real' vuid, not one
 319          * simply valid for the session setup leg */
 320         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
 321         if (!NT_STATUS_IS_OK(status)) goto failed;
 322 
 323         req->session = smb_sess;
 324 
 325 done:
 326         sess->spnego.out.vuid = smb_sess->vuid;
 327 failed:
 328         status = auth_nt_status_squash(status);
 329         smbsrv_sesssetup_backend_send(req, sess, status);
 330         if (!NT_STATUS_IS_OK(status) && 
 331             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 332                 talloc_free(smb_sess);
 333         }
 334 }
 335 
 336 /*
 337   handler for SPNEGO style session setup
 338 */
 339 static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
     /* [<][>][^][v][top][bottom][index][help] */
 340 {
 341         NTSTATUS status;
 342         struct smbsrv_session *smb_sess = NULL;
 343         struct sesssetup_spnego_state *s = NULL;
 344         uint16_t vuid;
 345 
 346         sess->spnego.out.vuid = 0;
 347         sess->spnego.out.action = 0;
 348 
 349         sesssetup_common_strings(req, 
 350                                  &sess->spnego.out.os,
 351                                  &sess->spnego.out.lanman,
 352                                  &sess->spnego.out.workgroup);
 353 
 354         if (!req->smb_conn->negotiate.done_sesssetup) {
 355                 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
 356                 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
 357         }
 358 
 359         vuid = SVAL(req->in.hdr,HDR_UID);
 360 
 361         /* lookup an existing session */
 362         smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
 363         if (!smb_sess) {
 364                 struct gensec_security *gensec_ctx;
 365 
 366                 status = samba_server_gensec_start(req,
 367                                                    req->smb_conn->connection->event.ctx,
 368                                                    req->smb_conn->connection->msg_ctx,
 369                                                    req->smb_conn->lp_ctx,
 370                                                    req->smb_conn->negotiate.server_credentials,
 371                                                    "cifs",
 372                                                    &gensec_ctx);
 373                 if (!NT_STATUS_IS_OK(status)) {
 374                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
 375                         goto failed;
 376                 }
 377 
 378                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
 379 
 380                 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
 381                 if (!NT_STATUS_IS_OK(status)) {
 382                         DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 
 383                                   gensec_get_name_by_oid(gensec_ctx, req->smb_conn->negotiate.oid), nt_errstr(status)));
 384                         goto failed;
 385                 }
 386 
 387                 /* allocate a new session */
 388                 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
 389                 if (!smb_sess) {
 390                         status = NT_STATUS_INSUFFICIENT_RESOURCES;
 391                         goto failed;
 392                 }
 393         }
 394 
 395         if (!smb_sess) {
 396                 status = NT_STATUS_ACCESS_DENIED;
 397                 goto failed;
 398         }
 399 
 400         if (!smb_sess->gensec_ctx) {
 401                 status = NT_STATUS_INTERNAL_ERROR;
 402                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
 403                 goto failed;
 404         }
 405 
 406         s = talloc(req, struct sesssetup_spnego_state);
 407         if (!s) goto nomem;
 408         s->req          = req;
 409         s->sess         = sess;
 410         s->smb_sess     = smb_sess;
 411 
 412         gensec_update_send(smb_sess->gensec_ctx, sess->spnego.in.secblob,
 413                            sesssetup_spnego_send, s);
 414         return;
 415 
 416 nomem:
 417         status = NT_STATUS_NO_MEMORY;
 418 failed:
 419         talloc_free(smb_sess);
 420         status = auth_nt_status_squash(status);
 421         smbsrv_sesssetup_backend_send(req, sess, status);
 422 }
 423 
 424 /*
 425   backend for sessionsetup call - this takes all 3 variants of the call
 426 */
 427 void smbsrv_sesssetup_backend(struct smbsrv_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 428                               union smb_sesssetup *sess)
 429 {
 430         switch (sess->old.level) {
 431                 case RAW_SESSSETUP_OLD:
 432                         sesssetup_old(req, sess);
 433                         return;
 434 
 435                 case RAW_SESSSETUP_NT1:
 436                         sesssetup_nt1(req, sess);
 437                         return;
 438 
 439                 case RAW_SESSSETUP_SPNEGO:
 440                         sesssetup_spnego(req, sess);
 441                         return;
 442 
 443                 case RAW_SESSSETUP_SMB2:
 444                         break;
 445         }
 446 
 447         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);
 448 }

/* [<][>][^][v][top][bottom][index][help] */