r17915: Saturn fixes
[Samba/gbeck.git] / source / smbd / sesssetup.c
blobdd8d9fc8525e5d74be3656cf4a5deecff2fffb04
1 /*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
26 uint32 global_client_caps = 0;
29 on a logon error possibly map the error to success if "map to guest"
30 is set approriately
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33 const char *user, const char *domain)
35 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
36 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
37 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
38 DEBUG(3,("No such user %s [%s] - using guest account\n",
39 user, domain));
40 status = make_server_info_guest(server_info);
44 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
45 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
46 DEBUG(3,("Registered username %s for guest access\n",user));
47 status = make_server_info_guest(server_info);
51 return status;
54 /****************************************************************************
55 Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
58 static int add_signature(char *outbuf, char *p)
60 char *start = p;
61 fstring lanman;
63 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
65 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
66 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
67 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
69 return PTR_DIFF(p, start);
72 /****************************************************************************
73 Start the signing engine if needed. Don't fail signing here.
74 ****************************************************************************/
76 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
78 if (!server_info->guest && !srv_signing_started()) {
79 /* We need to start the signing engine
80 * here but a W2K client sends the old
81 * "BSRSPYL " signature instead of the
82 * correct one. Subsequent packets will
83 * be correct.
85 srv_check_sign_mac(inbuf, False);
89 /****************************************************************************
90 Send a security blob via a session setup reply.
91 ****************************************************************************/
93 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
94 DATA_BLOB blob, NTSTATUS nt_status)
96 char *p;
98 if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
99 ERROR_NT(nt_status_squash(nt_status));
100 } else {
101 set_message(outbuf,4,0,True);
103 nt_status = nt_status_squash(nt_status);
104 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
105 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
106 SSVAL(outbuf, smb_vwv3, blob.length);
107 p = smb_buf(outbuf);
109 /* should we cap this? */
110 memcpy(p, blob.data, blob.length);
111 p += blob.length;
113 p += add_signature( outbuf, p );
115 set_message_end(outbuf,p);
118 show_msg(outbuf);
119 return send_smb(smbd_server_fd(),outbuf);
122 /****************************************************************************
123 Do a 'guest' logon, getting back the
124 ****************************************************************************/
126 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
128 struct auth_context *auth_context;
129 auth_usersupplied_info *user_info = NULL;
131 NTSTATUS nt_status;
132 unsigned char chal[8];
134 ZERO_STRUCT(chal);
136 DEBUG(3,("Got anonymous request\n"));
138 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
139 return nt_status;
142 if (!make_user_info_guest(&user_info)) {
143 (auth_context->free)(&auth_context);
144 return NT_STATUS_NO_MEMORY;
147 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
148 (auth_context->free)(&auth_context);
149 free_user_info(&user_info);
150 return nt_status;
154 #ifdef HAVE_KRB5
155 /****************************************************************************
156 reply to a session setup spnego negotiate packet for kerberos
157 ****************************************************************************/
158 static int reply_spnego_kerberos(connection_struct *conn,
159 char *inbuf, char *outbuf,
160 int length, int bufsize,
161 DATA_BLOB *secblob)
163 TALLOC_CTX *mem_ctx;
164 DATA_BLOB ticket;
165 char *client, *p, *domain;
166 fstring netbios_domain_name;
167 struct passwd *pw;
168 fstring user;
169 int sess_vuid;
170 NTSTATUS ret;
171 PAC_DATA *pac_data;
172 DATA_BLOB ap_rep, ap_rep_wrapped, response;
173 auth_serversupplied_info *server_info = NULL;
174 DATA_BLOB session_key = data_blob(NULL, 0);
175 uint8 tok_id[2];
176 DATA_BLOB nullblob = data_blob(NULL, 0);
177 fstring real_username;
178 BOOL map_domainuser_to_guest = False;
179 BOOL username_was_mapped;
180 PAC_LOGON_INFO *logon_info = NULL;
182 ZERO_STRUCT(ticket);
183 ZERO_STRUCT(pac_data);
184 ZERO_STRUCT(ap_rep);
185 ZERO_STRUCT(ap_rep_wrapped);
186 ZERO_STRUCT(response);
188 mem_ctx = talloc_init("reply_spnego_kerberos");
189 if (mem_ctx == NULL)
190 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
192 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
193 talloc_destroy(mem_ctx);
194 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
197 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
199 data_blob_free(&ticket);
201 if (!NT_STATUS_IS_OK(ret)) {
202 DEBUG(1,("Failed to verify incoming ticket!\n"));
203 talloc_destroy(mem_ctx);
204 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
207 DEBUG(3,("Ticket name is [%s]\n", client));
209 p = strchr_m(client, '@');
210 if (!p) {
211 DEBUG(3,("Doesn't look like a valid principal\n"));
212 data_blob_free(&ap_rep);
213 data_blob_free(&session_key);
214 SAFE_FREE(client);
215 talloc_destroy(mem_ctx);
216 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
219 *p = 0;
221 /* save the PAC data if we have it */
223 if (pac_data) {
224 logon_info = get_logon_info_from_pac(pac_data);
225 if (logon_info) {
226 netsamlogon_cache_store( client, &logon_info->info3 );
230 if (!strequal(p+1, lp_realm())) {
231 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
232 if (!lp_allow_trusted_domains()) {
233 data_blob_free(&ap_rep);
234 data_blob_free(&session_key);
235 SAFE_FREE(client);
236 talloc_destroy(mem_ctx);
237 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
241 /* this gives a fully qualified user name (ie. with full realm).
242 that leads to very long usernames, but what else can we do? */
244 domain = p+1;
246 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
248 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
249 domain = netbios_domain_name;
250 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
252 } else {
254 /* If we have winbind running, we can (and must) shorten the
255 username by using the short netbios name. Otherwise we will
256 have inconsistent user names. With Kerberos, we get the
257 fully qualified realm, with ntlmssp we get the short
258 name. And even w2k3 does use ntlmssp if you for example
259 connect to an ip address. */
261 struct winbindd_request wb_request;
262 struct winbindd_response wb_response;
263 NSS_STATUS wb_result;
265 ZERO_STRUCT(wb_request);
266 ZERO_STRUCT(wb_response);
268 DEBUG(10, ("Mapping [%s] to short name\n", domain));
270 fstrcpy(wb_request.domain_name, domain);
272 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
273 &wb_request, &wb_response);
275 if (wb_result == NSS_STATUS_SUCCESS) {
277 fstrcpy(netbios_domain_name,
278 wb_response.data.domain_info.name);
279 domain = netbios_domain_name;
281 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
282 } else {
283 DEBUG(3, ("Could not find short name -- winbind "
284 "not running?\n"));
288 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
290 /* lookup the passwd struct, create a new user if necessary */
292 username_was_mapped = map_username( user );
294 pw = smb_getpwnam( mem_ctx, user, real_username, True );
295 if (!pw) {
297 /* this was originally the behavior of Samba 2.2, if a user
298 did not have a local uid but has been authenticated, then
299 map them to a guest account */
301 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
302 map_domainuser_to_guest = True;
303 fstrcpy(user,lp_guestaccount());
304 pw = smb_getpwnam( mem_ctx, user, real_username, True );
307 /* extra sanity check that the guest account is valid */
309 if ( !pw ) {
310 DEBUG(1,("Username %s is invalid on this system\n", user));
311 SAFE_FREE(client);
312 data_blob_free(&ap_rep);
313 data_blob_free(&session_key);
314 talloc_destroy(mem_ctx);
315 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
319 /* setup the string used by %U */
321 sub_set_smb_name( real_username );
322 reload_services(True);
324 if ( map_domainuser_to_guest ) {
325 make_server_info_guest(&server_info);
326 } else if (logon_info) {
327 /* pass the unmapped username here since map_username()
328 will be called again from inside make_server_info_info3() */
330 ret = make_server_info_info3(mem_ctx, user, domain,
331 &server_info, &logon_info->info3);
332 if ( !NT_STATUS_IS_OK(ret) ) {
333 DEBUG(1,("make_server_info_info3 failed: %s!\n",
334 nt_errstr(ret)));
335 SAFE_FREE(client);
336 data_blob_free(&ap_rep);
337 data_blob_free(&session_key);
338 talloc_destroy(mem_ctx);
339 return ERROR_NT(nt_status_squash(ret));
342 } else {
343 ret = make_server_info_pw(&server_info, real_username, pw);
345 if ( !NT_STATUS_IS_OK(ret) ) {
346 DEBUG(1,("make_server_info_pw failed: %s!\n",
347 nt_errstr(ret)));
348 SAFE_FREE(client);
349 data_blob_free(&ap_rep);
350 data_blob_free(&session_key);
351 talloc_destroy(mem_ctx);
352 return ERROR_NT(nt_status_squash(ret));
355 /* make_server_info_pw does not set the domain. Without this
356 * we end up with the local netbios name in substitutions for
357 * %D. */
359 if (server_info->sam_account != NULL) {
360 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
364 server_info->was_mapped |= username_was_mapped;
366 /* we need to build the token for the user. make_server_info_guest()
367 already does this */
369 if ( !server_info->ptok ) {
370 ret = create_local_token( server_info );
371 if ( !NT_STATUS_IS_OK(ret) ) {
372 SAFE_FREE(client);
373 data_blob_free(&ap_rep);
374 data_blob_free(&session_key);
375 TALLOC_FREE( mem_ctx );
376 TALLOC_FREE( server_info );
377 return ERROR_NT(nt_status_squash(ret));
381 /* register_vuid keeps the server info */
382 /* register_vuid takes ownership of session_key, no need to free after this.
383 A better interface would copy it.... */
384 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
386 SAFE_FREE(client);
388 if (sess_vuid == UID_FIELD_INVALID ) {
389 ret = NT_STATUS_LOGON_FAILURE;
390 } else {
391 /* current_user_info is changed on new vuid */
392 reload_services( True );
394 set_message(outbuf,4,0,True);
395 SSVAL(outbuf, smb_vwv3, 0);
397 if (server_info->guest) {
398 SSVAL(outbuf,smb_vwv2,1);
401 SSVAL(outbuf, smb_uid, sess_vuid);
403 sessionsetup_start_signing_engine(server_info, inbuf);
406 /* wrap that up in a nice GSS-API wrapping */
407 if (NT_STATUS_IS_OK(ret)) {
408 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
409 } else {
410 ap_rep_wrapped = data_blob(NULL, 0);
412 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
413 reply_sesssetup_blob(conn, outbuf, response, ret);
415 data_blob_free(&ap_rep);
416 data_blob_free(&ap_rep_wrapped);
417 data_blob_free(&response);
418 talloc_destroy(mem_ctx);
420 return -1; /* already replied */
422 #endif
424 /****************************************************************************
425 Send a session setup reply, wrapped in SPNEGO.
426 Get vuid and check first.
427 End the NTLMSSP exchange context if we are OK/complete fail
428 This should be split into two functions, one to handle each
429 leg of the NTLM auth steps.
430 ***************************************************************************/
432 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
433 uint16 vuid,
434 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
435 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
436 BOOL wrap)
438 BOOL ret;
439 DATA_BLOB response;
440 struct auth_serversupplied_info *server_info = NULL;
442 if (NT_STATUS_IS_OK(nt_status)) {
443 server_info = (*auth_ntlmssp_state)->server_info;
444 } else {
445 nt_status = do_map_to_guest(nt_status,
446 &server_info,
447 (*auth_ntlmssp_state)->ntlmssp_state->user,
448 (*auth_ntlmssp_state)->ntlmssp_state->domain);
451 if (NT_STATUS_IS_OK(nt_status)) {
452 int sess_vuid;
453 DATA_BLOB nullblob = data_blob(NULL, 0);
454 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
456 /* register_vuid keeps the server info */
457 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
458 (*auth_ntlmssp_state)->server_info = NULL;
460 if (sess_vuid == UID_FIELD_INVALID ) {
461 nt_status = NT_STATUS_LOGON_FAILURE;
462 } else {
464 /* current_user_info is changed on new vuid */
465 reload_services( True );
467 set_message(outbuf,4,0,True);
468 SSVAL(outbuf, smb_vwv3, 0);
470 if (server_info->guest) {
471 SSVAL(outbuf,smb_vwv2,1);
474 SSVAL(outbuf,smb_uid,sess_vuid);
476 sessionsetup_start_signing_engine(server_info, inbuf);
480 if (wrap) {
481 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
482 } else {
483 response = *ntlmssp_blob;
486 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
487 if (wrap) {
488 data_blob_free(&response);
491 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
492 and the other end, that we are not finished yet. */
494 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
495 /* NB. This is *NOT* an error case. JRA */
496 auth_ntlmssp_end(auth_ntlmssp_state);
497 /* Kill the intermediate vuid */
498 invalidate_vuid(vuid);
501 return ret;
504 /****************************************************************************
505 Reply to a session setup spnego negotiate packet.
506 ****************************************************************************/
508 static int reply_spnego_negotiate(connection_struct *conn,
509 char *inbuf,
510 char *outbuf,
511 uint16 vuid,
512 int length, int bufsize,
513 DATA_BLOB blob1,
514 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
516 char *OIDs[ASN1_MAX_OIDS];
517 DATA_BLOB secblob;
518 int i;
519 DATA_BLOB chal;
520 #ifdef HAVE_KRB5
521 BOOL got_kerberos_mechanism = False;
522 #endif
523 NTSTATUS nt_status;
525 /* parse out the OIDs and the first sec blob */
526 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
527 /* Kill the intermediate vuid */
528 invalidate_vuid(vuid);
530 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
533 /* only look at the first OID for determining the mechToken --
534 accoirding to RFC2478, we should choose the one we want
535 and renegotiate, but i smell a client bug here..
537 Problem observed when connecting to a member (samba box)
538 of an AD domain as a user in a Samba domain. Samba member
539 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
540 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
541 NTLMSSP mechtoken. --jerry */
543 #ifdef HAVE_KRB5
544 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
545 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
546 got_kerberos_mechanism = True;
548 #endif
550 for (i=0;OIDs[i];i++) {
551 DEBUG(3,("Got OID %s\n", OIDs[i]));
552 free(OIDs[i]);
554 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
556 #ifdef HAVE_KRB5
557 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
558 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
559 length, bufsize, &secblob);
560 data_blob_free(&secblob);
561 /* Kill the intermediate vuid */
562 invalidate_vuid(vuid);
564 return ret;
566 #endif
568 if (*auth_ntlmssp_state) {
569 auth_ntlmssp_end(auth_ntlmssp_state);
572 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
573 if (!NT_STATUS_IS_OK(nt_status)) {
574 /* Kill the intermediate vuid */
575 invalidate_vuid(vuid);
577 return ERROR_NT(nt_status_squash(nt_status));
580 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
581 secblob, &chal);
583 data_blob_free(&secblob);
585 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
586 &chal, nt_status, True);
588 data_blob_free(&chal);
590 /* already replied */
591 return -1;
594 /****************************************************************************
595 Reply to a session setup spnego auth packet.
596 ****************************************************************************/
598 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
599 uint16 vuid,
600 int length, int bufsize,
601 DATA_BLOB blob1,
602 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
604 DATA_BLOB auth, auth_reply;
605 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
607 if (!spnego_parse_auth(blob1, &auth)) {
608 #if 0
609 file_save("auth.dat", blob1.data, blob1.length);
610 #endif
611 /* Kill the intermediate vuid */
612 invalidate_vuid(vuid);
614 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
617 if (!*auth_ntlmssp_state) {
618 /* Kill the intermediate vuid */
619 invalidate_vuid(vuid);
621 /* auth before negotiatiate? */
622 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
625 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
626 auth, &auth_reply);
628 data_blob_free(&auth);
630 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
631 auth_ntlmssp_state,
632 &auth_reply, nt_status, True);
634 data_blob_free(&auth_reply);
636 /* and tell smbd that we have already replied to this packet */
637 return -1;
640 /****************************************************************************
641 Reply to a session setup command.
642 conn POINTER CAN BE NULL HERE !
643 ****************************************************************************/
645 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
646 char *outbuf,
647 int length,int bufsize)
649 uint8 *p;
650 DATA_BLOB blob1;
651 int ret;
652 size_t bufrem;
653 fstring native_os, native_lanman, primary_domain;
654 char *p2;
655 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
656 enum remote_arch_types ra_type = get_remote_arch();
657 int vuid = SVAL(inbuf,smb_uid);
658 user_struct *vuser = NULL;
660 DEBUG(3,("Doing spnego session setup\n"));
662 if (global_client_caps == 0) {
663 global_client_caps = IVAL(inbuf,smb_vwv10);
665 if (!(global_client_caps & CAP_STATUS32)) {
666 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
671 p = (uint8 *)smb_buf(inbuf);
673 if (data_blob_len == 0) {
674 /* an invalid request */
675 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
678 bufrem = smb_bufrem(inbuf, p);
679 /* pull the spnego blob */
680 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
682 #if 0
683 file_save("negotiate.dat", blob1.data, blob1.length);
684 #endif
686 p2 = inbuf + smb_vwv13 + data_blob_len;
687 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
688 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
689 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
690 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
691 native_os, native_lanman, primary_domain));
693 if ( ra_type == RA_WIN2K ) {
694 /* Windows 2003 doesn't set the native lanman string,
695 but does set primary domain which is a bug I think */
697 if ( !strlen(native_lanman) )
698 ra_lanman_string( primary_domain );
699 else
700 ra_lanman_string( native_lanman );
703 vuser = get_partial_auth_user_struct(vuid);
704 if (!vuser) {
705 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
706 if (vuid == UID_FIELD_INVALID ) {
707 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
710 vuser = get_partial_auth_user_struct(vuid);
713 if (!vuser) {
714 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
717 SSVAL(outbuf,smb_uid,vuid);
719 if (blob1.data[0] == ASN1_APPLICATION(0)) {
720 /* its a negTokenTarg packet */
721 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
722 &vuser->auth_ntlmssp_state);
723 data_blob_free(&blob1);
724 return ret;
727 if (blob1.data[0] == ASN1_CONTEXT(1)) {
728 /* its a auth packet */
729 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
730 &vuser->auth_ntlmssp_state);
731 data_blob_free(&blob1);
732 return ret;
735 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
736 DATA_BLOB chal;
737 NTSTATUS nt_status;
738 if (!vuser->auth_ntlmssp_state) {
739 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
740 if (!NT_STATUS_IS_OK(nt_status)) {
741 /* Kill the intermediate vuid */
742 invalidate_vuid(vuid);
744 return ERROR_NT(nt_status_squash(nt_status));
748 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
749 blob1, &chal);
751 data_blob_free(&blob1);
753 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
754 &vuser->auth_ntlmssp_state,
755 &chal, nt_status, False);
756 data_blob_free(&chal);
757 return -1;
760 /* what sort of packet is this? */
761 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
763 data_blob_free(&blob1);
765 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
768 /****************************************************************************
769 On new VC == 0, shutdown *all* old connections and users.
770 It seems that only NT4.x does this. At W2K and above (XP etc.).
771 a new session setup with VC==0 is ignored.
772 ****************************************************************************/
774 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
775 void *p)
777 struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
778 const char *ip = (const char *)p;
780 if (!process_exists(pid_to_procid(sessionid->pid))) {
781 return 0;
784 if (sessionid->pid == sys_getpid()) {
785 return 0;
788 if (strcmp(ip, sessionid->ip_addr) != 0) {
789 return 0;
792 message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
793 NULL, 0, True);
794 return 0;
797 static void setup_new_vc_session(void)
799 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
800 #if 0
801 conn_close_all();
802 invalidate_all_vuids();
803 #endif
804 if (lp_reset_on_zero_vc()) {
805 session_traverse(shutdown_other_smbds, client_addr());
809 /****************************************************************************
810 Reply to a session setup command.
811 ****************************************************************************/
813 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
814 int length,int bufsize)
816 int sess_vuid;
817 int smb_bufsize;
818 DATA_BLOB lm_resp;
819 DATA_BLOB nt_resp;
820 DATA_BLOB plaintext_password;
821 fstring user;
822 fstring sub_user; /* Sainitised username for substituion */
823 fstring domain;
824 fstring native_os;
825 fstring native_lanman;
826 fstring primary_domain;
827 static BOOL done_sesssetup = False;
828 extern BOOL global_encrypted_passwords_negotiated;
829 extern BOOL global_spnego_negotiated;
830 extern enum protocol_types Protocol;
831 extern int max_send;
833 auth_usersupplied_info *user_info = NULL;
834 extern struct auth_context *negprot_global_auth_context;
835 auth_serversupplied_info *server_info = NULL;
837 NTSTATUS nt_status;
839 BOOL doencrypt = global_encrypted_passwords_negotiated;
841 DATA_BLOB session_key;
843 START_PROFILE(SMBsesssetupX);
845 ZERO_STRUCT(lm_resp);
846 ZERO_STRUCT(nt_resp);
847 ZERO_STRUCT(plaintext_password);
849 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
851 /* a SPNEGO session setup has 12 command words, whereas a normal
852 NT1 session setup has 13. See the cifs spec. */
853 if (CVAL(inbuf, smb_wct) == 12 &&
854 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
855 if (!global_spnego_negotiated) {
856 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
857 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
860 if (SVAL(inbuf,smb_vwv4) == 0) {
861 setup_new_vc_session();
863 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
866 smb_bufsize = SVAL(inbuf,smb_vwv2);
868 if (Protocol < PROTOCOL_NT1) {
869 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
871 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
872 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
874 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
875 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
878 if (doencrypt) {
879 lm_resp = data_blob(smb_buf(inbuf), passlen1);
880 } else {
881 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
882 /* Ensure null termination */
883 plaintext_password.data[passlen1] = 0;
886 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
887 *domain = 0;
889 } else {
890 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
891 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
892 enum remote_arch_types ra_type = get_remote_arch();
893 char *p = smb_buf(inbuf);
894 char *save_p = smb_buf(inbuf);
895 uint16 byte_count;
898 if(global_client_caps == 0) {
899 global_client_caps = IVAL(inbuf,smb_vwv11);
901 if (!(global_client_caps & CAP_STATUS32)) {
902 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
905 /* client_caps is used as final determination if client is NT or Win95.
906 This is needed to return the correct error codes in some
907 circumstances.
910 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
911 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
912 set_remote_arch( RA_WIN95);
917 if (!doencrypt) {
918 /* both Win95 and WinNT stuff up the password lengths for
919 non-encrypting systems. Uggh.
921 if passlen1==24 its a win95 system, and its setting the
922 password length incorrectly. Luckily it still works with the
923 default code because Win95 will null terminate the password
924 anyway
926 if passlen1>0 and passlen2>0 then maybe its a NT box and its
927 setting passlen2 to some random value which really stuffs
928 things up. we need to fix that one. */
930 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
931 passlen2 = 0;
934 /* check for nasty tricks */
935 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
936 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
939 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
940 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
943 /* Save the lanman2 password and the NT md4 password. */
945 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
946 doencrypt = False;
949 if (doencrypt) {
950 lm_resp = data_blob(p, passlen1);
951 nt_resp = data_blob(p+passlen1, passlen2);
952 } else {
953 pstring pass;
954 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
956 #if 0
957 /* This was the previous fix. Not sure if it's still valid. JRA. */
958 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
959 /* NT4.0 stuffs up plaintext unicode password lengths... */
960 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
961 sizeof(pass), passlen1, STR_TERMINATE);
962 #endif
964 if (unic && (passlen2 == 0) && passlen1) {
965 /* Only a ascii plaintext password was sent. */
966 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
967 passlen1, STR_TERMINATE|STR_ASCII);
968 } else {
969 srvstr_pull(inbuf, pass, smb_buf(inbuf),
970 sizeof(pass), unic ? passlen2 : passlen1,
971 STR_TERMINATE);
973 plaintext_password = data_blob(pass, strlen(pass)+1);
976 p += passlen1 + passlen2;
977 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
978 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
979 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
980 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
982 /* not documented or decoded by Ethereal but there is one more string
983 in the extra bytes which is the same as the PrimaryDomain when using
984 extended security. Windows NT 4 and 2003 use this string to store
985 the native lanman string. Windows 9x does not include a string here
986 at all so we have to check if we have any extra bytes left */
988 byte_count = SVAL(inbuf, smb_vwv13);
989 if ( PTR_DIFF(p, save_p) < byte_count)
990 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
991 else
992 fstrcpy( primary_domain, "null" );
994 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
995 domain, native_os, native_lanman, primary_domain));
997 if ( ra_type == RA_WIN2K ) {
998 if ( strlen(native_lanman) == 0 )
999 ra_lanman_string( primary_domain );
1000 else
1001 ra_lanman_string( native_lanman );
1006 if (SVAL(inbuf,smb_vwv4) == 0) {
1007 setup_new_vc_session();
1010 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1012 if (*user) {
1013 if (global_spnego_negotiated) {
1015 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1017 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1018 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1020 fstrcpy(sub_user, user);
1021 } else {
1022 fstrcpy(sub_user, lp_guestaccount());
1025 sub_set_smb_name(sub_user);
1027 reload_services(True);
1029 if (lp_security() == SEC_SHARE) {
1030 /* in share level we should ignore any passwords */
1032 data_blob_free(&lm_resp);
1033 data_blob_free(&nt_resp);
1034 data_blob_clear_free(&plaintext_password);
1036 map_username(sub_user);
1037 add_session_user(sub_user);
1038 /* Then force it to null for the benfit of the code below */
1039 *user = 0;
1042 if (!*user) {
1044 nt_status = check_guest_password(&server_info);
1046 } else if (doencrypt) {
1047 if (!negprot_global_auth_context) {
1048 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1049 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1051 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1052 lm_resp, nt_resp);
1053 if (NT_STATUS_IS_OK(nt_status)) {
1054 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
1055 user_info,
1056 &server_info);
1058 } else {
1059 struct auth_context *plaintext_auth_context = NULL;
1060 const uint8 *chal;
1062 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1064 if (NT_STATUS_IS_OK(nt_status)) {
1065 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1067 if (!make_user_info_for_reply(&user_info,
1068 user, domain, chal,
1069 plaintext_password)) {
1070 nt_status = NT_STATUS_NO_MEMORY;
1073 if (NT_STATUS_IS_OK(nt_status)) {
1074 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1075 user_info,
1076 &server_info);
1078 (plaintext_auth_context->free)(&plaintext_auth_context);
1083 free_user_info(&user_info);
1085 if (!NT_STATUS_IS_OK(nt_status)) {
1086 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1089 if (!NT_STATUS_IS_OK(nt_status)) {
1090 data_blob_free(&nt_resp);
1091 data_blob_free(&lm_resp);
1092 data_blob_clear_free(&plaintext_password);
1093 return ERROR_NT(nt_status_squash(nt_status));
1096 /* Ensure we can't possible take a code path leading to a null defref. */
1097 if (!server_info) {
1098 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1101 nt_status = create_local_token(server_info);
1102 if (!NT_STATUS_IS_OK(nt_status)) {
1103 DEBUG(10, ("create_local_token failed: %s\n",
1104 nt_errstr(nt_status)));
1105 data_blob_free(&nt_resp);
1106 data_blob_free(&lm_resp);
1107 data_blob_clear_free(&plaintext_password);
1108 return ERROR_NT(nt_status_squash(nt_status));
1111 if (server_info->user_session_key.data) {
1112 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1113 } else {
1114 session_key = data_blob(NULL, 0);
1117 data_blob_clear_free(&plaintext_password);
1119 /* it's ok - setup a reply */
1120 set_message(outbuf,3,0,True);
1121 if (Protocol >= PROTOCOL_NT1) {
1122 char *p = smb_buf( outbuf );
1123 p += add_signature( outbuf, p );
1124 set_message_end( outbuf, p );
1125 /* perhaps grab OS version here?? */
1128 if (server_info->guest) {
1129 SSVAL(outbuf,smb_vwv2,1);
1132 /* register the name and uid as being validated, so further connections
1133 to a uid can get through without a password, on the same VC */
1135 if (lp_security() == SEC_SHARE) {
1136 sess_vuid = UID_FIELD_INVALID;
1137 data_blob_free(&session_key);
1138 TALLOC_FREE(server_info);
1139 } else {
1140 /* register_vuid keeps the server info */
1141 sess_vuid = register_vuid(server_info, session_key,
1142 nt_resp.data ? nt_resp : lm_resp,
1143 sub_user);
1144 if (sess_vuid == UID_FIELD_INVALID) {
1145 data_blob_free(&nt_resp);
1146 data_blob_free(&lm_resp);
1147 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1150 /* current_user_info is changed on new vuid */
1151 reload_services( True );
1153 sessionsetup_start_signing_engine(server_info, inbuf);
1156 data_blob_free(&nt_resp);
1157 data_blob_free(&lm_resp);
1159 SSVAL(outbuf,smb_uid,sess_vuid);
1160 SSVAL(inbuf,smb_uid,sess_vuid);
1162 if (!done_sesssetup)
1163 max_send = MIN(max_send,smb_bufsize);
1165 done_sesssetup = True;
1167 END_PROFILE(SMBsesssetupX);
1168 return chain_reply(inbuf,outbuf,length,bufsize);