r20124: clean up nested extern declaration warnings
[Samba.git] / source3 / smbd / sesssetup.c
blob4d731f9c595bdf4447b063877a9c2b697cf12450
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 extern struct auth_context *negprot_global_auth_context;
27 extern BOOL global_encrypted_passwords_negotiated;
28 extern BOOL global_spnego_negotiated;
29 extern enum protocol_types Protocol;
30 extern int max_send;
32 uint32 global_client_caps = 0;
35 on a logon error possibly map the error to success if "map to guest"
36 is set approriately
38 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39 const char *user, const char *domain)
41 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
43 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44 DEBUG(3,("No such user %s [%s] - using guest account\n",
45 user, domain));
46 status = make_server_info_guest(server_info);
50 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52 DEBUG(3,("Registered username %s for guest access\n",user));
53 status = make_server_info_guest(server_info);
57 return status;
60 /****************************************************************************
61 Add the standard 'Samba' signature to the end of the session setup.
62 ****************************************************************************/
64 static int add_signature(char *outbuf, char *p)
66 char *start = p;
67 fstring lanman;
69 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
71 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
75 return PTR_DIFF(p, start);
78 /****************************************************************************
79 Start the signing engine if needed. Don't fail signing here.
80 ****************************************************************************/
82 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
84 if (!server_info->guest && !srv_signing_started()) {
85 /* We need to start the signing engine
86 * here but a W2K client sends the old
87 * "BSRSPYL " signature instead of the
88 * correct one. Subsequent packets will
89 * be correct.
91 srv_check_sign_mac(inbuf, False);
95 /****************************************************************************
96 Send a security blob via a session setup reply.
97 ****************************************************************************/
99 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
100 DATA_BLOB blob, NTSTATUS nt_status)
102 char *p;
104 if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105 ERROR_NT(nt_status_squash(nt_status));
106 } else {
107 set_message(outbuf,4,0,True);
109 nt_status = nt_status_squash(nt_status);
110 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
111 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
112 SSVAL(outbuf, smb_vwv3, blob.length);
113 p = smb_buf(outbuf);
115 /* should we cap this? */
116 memcpy(p, blob.data, blob.length);
117 p += blob.length;
119 p += add_signature( outbuf, p );
121 set_message_end(outbuf,p);
124 show_msg(outbuf);
125 return send_smb(smbd_server_fd(),outbuf);
128 /****************************************************************************
129 Do a 'guest' logon, getting back the
130 ****************************************************************************/
132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
134 struct auth_context *auth_context;
135 auth_usersupplied_info *user_info = NULL;
137 NTSTATUS nt_status;
138 unsigned char chal[8];
140 ZERO_STRUCT(chal);
142 DEBUG(3,("Got anonymous request\n"));
144 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
145 return nt_status;
148 if (!make_user_info_guest(&user_info)) {
149 (auth_context->free)(&auth_context);
150 return NT_STATUS_NO_MEMORY;
153 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
154 (auth_context->free)(&auth_context);
155 free_user_info(&user_info);
156 return nt_status;
160 #ifdef HAVE_KRB5
161 /****************************************************************************
162 reply to a session setup spnego negotiate packet for kerberos
163 ****************************************************************************/
164 static int reply_spnego_kerberos(connection_struct *conn,
165 char *inbuf, char *outbuf,
166 int length, int bufsize,
167 DATA_BLOB *secblob)
169 TALLOC_CTX *mem_ctx;
170 DATA_BLOB ticket;
171 char *client, *p, *domain;
172 fstring netbios_domain_name;
173 struct passwd *pw;
174 fstring user;
175 int sess_vuid;
176 NTSTATUS ret;
177 PAC_DATA *pac_data;
178 DATA_BLOB ap_rep, ap_rep_wrapped, response;
179 auth_serversupplied_info *server_info = NULL;
180 DATA_BLOB session_key = data_blob(NULL, 0);
181 uint8 tok_id[2];
182 DATA_BLOB nullblob = data_blob(NULL, 0);
183 fstring real_username;
184 BOOL map_domainuser_to_guest = False;
185 BOOL username_was_mapped;
186 PAC_LOGON_INFO *logon_info = NULL;
188 ZERO_STRUCT(ticket);
189 ZERO_STRUCT(pac_data);
190 ZERO_STRUCT(ap_rep);
191 ZERO_STRUCT(ap_rep_wrapped);
192 ZERO_STRUCT(response);
194 mem_ctx = talloc_init("reply_spnego_kerberos");
195 if (mem_ctx == NULL)
196 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
198 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
199 talloc_destroy(mem_ctx);
200 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
203 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
205 data_blob_free(&ticket);
207 if (!NT_STATUS_IS_OK(ret)) {
208 DEBUG(1,("Failed to verify incoming ticket!\n"));
209 talloc_destroy(mem_ctx);
210 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
213 DEBUG(3,("Ticket name is [%s]\n", client));
215 p = strchr_m(client, '@');
216 if (!p) {
217 DEBUG(3,("Doesn't look like a valid principal\n"));
218 data_blob_free(&ap_rep);
219 data_blob_free(&session_key);
220 SAFE_FREE(client);
221 talloc_destroy(mem_ctx);
222 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
225 *p = 0;
227 /* save the PAC data if we have it */
229 if (pac_data) {
230 logon_info = get_logon_info_from_pac(pac_data);
231 if (logon_info) {
232 netsamlogon_cache_store( client, &logon_info->info3 );
236 if (!strequal(p+1, lp_realm())) {
237 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
238 if (!lp_allow_trusted_domains()) {
239 data_blob_free(&ap_rep);
240 data_blob_free(&session_key);
241 SAFE_FREE(client);
242 talloc_destroy(mem_ctx);
243 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
247 /* this gives a fully qualified user name (ie. with full realm).
248 that leads to very long usernames, but what else can we do? */
250 domain = p+1;
252 if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
254 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
255 domain = netbios_domain_name;
256 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
258 } else {
260 /* If we have winbind running, we can (and must) shorten the
261 username by using the short netbios name. Otherwise we will
262 have inconsistent user names. With Kerberos, we get the
263 fully qualified realm, with ntlmssp we get the short
264 name. And even w2k3 does use ntlmssp if you for example
265 connect to an ip address. */
267 struct winbindd_request wb_request;
268 struct winbindd_response wb_response;
269 NSS_STATUS wb_result;
271 ZERO_STRUCT(wb_request);
272 ZERO_STRUCT(wb_response);
274 DEBUG(10, ("Mapping [%s] to short name\n", domain));
276 fstrcpy(wb_request.domain_name, domain);
278 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
279 &wb_request, &wb_response);
281 if (wb_result == NSS_STATUS_SUCCESS) {
283 fstrcpy(netbios_domain_name,
284 wb_response.data.domain_info.name);
285 domain = netbios_domain_name;
287 DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
288 } else {
289 DEBUG(3, ("Could not find short name -- winbind "
290 "not running?\n"));
294 fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
296 /* lookup the passwd struct, create a new user if necessary */
298 username_was_mapped = map_username( user );
300 pw = smb_getpwnam( mem_ctx, user, real_username, True );
302 if (pw) {
303 /* if a real user check pam account restrictions */
304 /* only really perfomed if "obey pam restriction" is true */
305 /* do this before an eventual mappign to guest occurs */
306 ret = smb_pam_accountcheck(pw->pw_name);
307 if ( !NT_STATUS_IS_OK(ret)) {
308 DEBUG(1, ("PAM account restriction prevents user login\n"));
309 data_blob_free(&ap_rep);
310 data_blob_free(&session_key);
311 TALLOC_FREE(mem_ctx);
312 return ERROR_NT(nt_status_squash(ret));
316 if (!pw) {
318 /* this was originally the behavior of Samba 2.2, if a user
319 did not have a local uid but has been authenticated, then
320 map them to a guest account */
322 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
323 map_domainuser_to_guest = True;
324 fstrcpy(user,lp_guestaccount());
325 pw = smb_getpwnam( mem_ctx, user, real_username, True );
328 /* extra sanity check that the guest account is valid */
330 if ( !pw ) {
331 DEBUG(1,("Username %s is invalid on this system\n", user));
332 SAFE_FREE(client);
333 data_blob_free(&ap_rep);
334 data_blob_free(&session_key);
335 TALLOC_FREE(mem_ctx);
336 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
340 /* setup the string used by %U */
342 sub_set_smb_name( real_username );
343 reload_services(True);
345 if ( map_domainuser_to_guest ) {
346 make_server_info_guest(&server_info);
347 } else if (logon_info) {
348 /* pass the unmapped username here since map_username()
349 will be called again from inside make_server_info_info3() */
351 ret = make_server_info_info3(mem_ctx, client, domain,
352 &server_info, &logon_info->info3);
353 if ( !NT_STATUS_IS_OK(ret) ) {
354 DEBUG(1,("make_server_info_info3 failed: %s!\n",
355 nt_errstr(ret)));
356 SAFE_FREE(client);
357 data_blob_free(&ap_rep);
358 data_blob_free(&session_key);
359 TALLOC_FREE(mem_ctx);
360 return ERROR_NT(nt_status_squash(ret));
363 } else {
364 ret = make_server_info_pw(&server_info, real_username, pw);
366 if ( !NT_STATUS_IS_OK(ret) ) {
367 DEBUG(1,("make_server_info_pw failed: %s!\n",
368 nt_errstr(ret)));
369 SAFE_FREE(client);
370 data_blob_free(&ap_rep);
371 data_blob_free(&session_key);
372 TALLOC_FREE(mem_ctx);
373 return ERROR_NT(nt_status_squash(ret));
376 /* make_server_info_pw does not set the domain. Without this
377 * we end up with the local netbios name in substitutions for
378 * %D. */
380 if (server_info->sam_account != NULL) {
381 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
385 server_info->was_mapped |= username_was_mapped;
387 /* we need to build the token for the user. make_server_info_guest()
388 already does this */
390 if ( !server_info->ptok ) {
391 ret = create_local_token( server_info );
392 if ( !NT_STATUS_IS_OK(ret) ) {
393 SAFE_FREE(client);
394 data_blob_free(&ap_rep);
395 data_blob_free(&session_key);
396 TALLOC_FREE( mem_ctx );
397 TALLOC_FREE( server_info );
398 return ERROR_NT(nt_status_squash(ret));
402 /* register_vuid keeps the server info */
403 /* register_vuid takes ownership of session_key, no need to free after this.
404 A better interface would copy it.... */
405 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
407 SAFE_FREE(client);
409 if (sess_vuid == UID_FIELD_INVALID ) {
410 ret = NT_STATUS_LOGON_FAILURE;
411 } else {
412 /* current_user_info is changed on new vuid */
413 reload_services( True );
415 set_message(outbuf,4,0,True);
416 SSVAL(outbuf, smb_vwv3, 0);
418 if (server_info->guest) {
419 SSVAL(outbuf,smb_vwv2,1);
422 SSVAL(outbuf, smb_uid, sess_vuid);
424 sessionsetup_start_signing_engine(server_info, inbuf);
427 /* wrap that up in a nice GSS-API wrapping */
428 if (NT_STATUS_IS_OK(ret)) {
429 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
430 } else {
431 ap_rep_wrapped = data_blob(NULL, 0);
433 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
434 reply_sesssetup_blob(conn, outbuf, response, ret);
436 data_blob_free(&ap_rep);
437 data_blob_free(&ap_rep_wrapped);
438 data_blob_free(&response);
439 TALLOC_FREE(mem_ctx);
441 return -1; /* already replied */
443 #endif
445 /****************************************************************************
446 Send a session setup reply, wrapped in SPNEGO.
447 Get vuid and check first.
448 End the NTLMSSP exchange context if we are OK/complete fail
449 This should be split into two functions, one to handle each
450 leg of the NTLM auth steps.
451 ***************************************************************************/
453 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
454 uint16 vuid,
455 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
456 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
457 BOOL wrap)
459 BOOL ret;
460 DATA_BLOB response;
461 struct auth_serversupplied_info *server_info = NULL;
463 if (NT_STATUS_IS_OK(nt_status)) {
464 server_info = (*auth_ntlmssp_state)->server_info;
465 } else {
466 nt_status = do_map_to_guest(nt_status,
467 &server_info,
468 (*auth_ntlmssp_state)->ntlmssp_state->user,
469 (*auth_ntlmssp_state)->ntlmssp_state->domain);
472 if (NT_STATUS_IS_OK(nt_status)) {
473 int sess_vuid;
474 DATA_BLOB nullblob = data_blob(NULL, 0);
475 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
477 /* register_vuid keeps the server info */
478 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
479 (*auth_ntlmssp_state)->server_info = NULL;
481 if (sess_vuid == UID_FIELD_INVALID ) {
482 nt_status = NT_STATUS_LOGON_FAILURE;
483 } else {
485 /* current_user_info is changed on new vuid */
486 reload_services( True );
488 set_message(outbuf,4,0,True);
489 SSVAL(outbuf, smb_vwv3, 0);
491 if (server_info->guest) {
492 SSVAL(outbuf,smb_vwv2,1);
495 SSVAL(outbuf,smb_uid,sess_vuid);
497 sessionsetup_start_signing_engine(server_info, inbuf);
501 if (wrap) {
502 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
503 } else {
504 response = *ntlmssp_blob;
507 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
508 if (wrap) {
509 data_blob_free(&response);
512 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
513 and the other end, that we are not finished yet. */
515 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
516 /* NB. This is *NOT* an error case. JRA */
517 auth_ntlmssp_end(auth_ntlmssp_state);
518 /* Kill the intermediate vuid */
519 invalidate_vuid(vuid);
522 return ret;
525 /****************************************************************************
526 Reply to a session setup spnego negotiate packet.
527 ****************************************************************************/
529 static int reply_spnego_negotiate(connection_struct *conn,
530 char *inbuf,
531 char *outbuf,
532 uint16 vuid,
533 int length, int bufsize,
534 DATA_BLOB blob1,
535 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
537 char *OIDs[ASN1_MAX_OIDS];
538 DATA_BLOB secblob;
539 int i;
540 DATA_BLOB chal;
541 #ifdef HAVE_KRB5
542 BOOL got_kerberos_mechanism = False;
543 #endif
544 NTSTATUS nt_status;
546 /* parse out the OIDs and the first sec blob */
547 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
548 /* Kill the intermediate vuid */
549 invalidate_vuid(vuid);
551 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
554 /* only look at the first OID for determining the mechToken --
555 accoirding to RFC2478, we should choose the one we want
556 and renegotiate, but i smell a client bug here..
558 Problem observed when connecting to a member (samba box)
559 of an AD domain as a user in a Samba domain. Samba member
560 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
561 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
562 NTLMSSP mechtoken. --jerry */
564 #ifdef HAVE_KRB5
565 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
566 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
567 got_kerberos_mechanism = True;
569 #endif
571 for (i=0;OIDs[i];i++) {
572 DEBUG(3,("Got OID %s\n", OIDs[i]));
573 free(OIDs[i]);
575 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
577 #ifdef HAVE_KRB5
578 if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
579 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
580 length, bufsize, &secblob);
581 data_blob_free(&secblob);
582 /* Kill the intermediate vuid */
583 invalidate_vuid(vuid);
585 return ret;
587 #endif
589 if (*auth_ntlmssp_state) {
590 auth_ntlmssp_end(auth_ntlmssp_state);
593 nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
594 if (!NT_STATUS_IS_OK(nt_status)) {
595 /* Kill the intermediate vuid */
596 invalidate_vuid(vuid);
598 return ERROR_NT(nt_status_squash(nt_status));
601 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
602 secblob, &chal);
604 data_blob_free(&secblob);
606 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
607 &chal, nt_status, True);
609 data_blob_free(&chal);
611 /* already replied */
612 return -1;
615 /****************************************************************************
616 Reply to a session setup spnego auth packet.
617 ****************************************************************************/
619 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
620 uint16 vuid,
621 int length, int bufsize,
622 DATA_BLOB blob1,
623 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
625 DATA_BLOB auth, auth_reply;
626 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
628 if (!spnego_parse_auth(blob1, &auth)) {
629 #if 0
630 file_save("auth.dat", blob1.data, blob1.length);
631 #endif
632 /* Kill the intermediate vuid */
633 invalidate_vuid(vuid);
635 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
638 if (!*auth_ntlmssp_state) {
639 /* Kill the intermediate vuid */
640 invalidate_vuid(vuid);
642 /* auth before negotiatiate? */
643 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
646 nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
647 auth, &auth_reply);
649 data_blob_free(&auth);
651 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
652 auth_ntlmssp_state,
653 &auth_reply, nt_status, True);
655 data_blob_free(&auth_reply);
657 /* and tell smbd that we have already replied to this packet */
658 return -1;
661 /****************************************************************************
662 Reply to a session setup command.
663 conn POINTER CAN BE NULL HERE !
664 ****************************************************************************/
666 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
667 char *outbuf,
668 int length,int bufsize)
670 uint8 *p;
671 DATA_BLOB blob1;
672 int ret;
673 size_t bufrem;
674 fstring native_os, native_lanman, primary_domain;
675 char *p2;
676 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
677 enum remote_arch_types ra_type = get_remote_arch();
678 int vuid = SVAL(inbuf,smb_uid);
679 user_struct *vuser = NULL;
681 DEBUG(3,("Doing spnego session setup\n"));
683 if (global_client_caps == 0) {
684 global_client_caps = IVAL(inbuf,smb_vwv10);
686 if (!(global_client_caps & CAP_STATUS32)) {
687 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
692 p = (uint8 *)smb_buf(inbuf);
694 if (data_blob_len == 0) {
695 /* an invalid request */
696 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
699 bufrem = smb_bufrem(inbuf, p);
700 /* pull the spnego blob */
701 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
703 #if 0
704 file_save("negotiate.dat", blob1.data, blob1.length);
705 #endif
707 p2 = inbuf + smb_vwv13 + data_blob_len;
708 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
709 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
710 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
711 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
712 native_os, native_lanman, primary_domain));
714 if ( ra_type == RA_WIN2K ) {
715 /* Windows 2003 doesn't set the native lanman string,
716 but does set primary domain which is a bug I think */
718 if ( !strlen(native_lanman) )
719 ra_lanman_string( primary_domain );
720 else
721 ra_lanman_string( native_lanman );
724 vuser = get_partial_auth_user_struct(vuid);
725 if (!vuser) {
726 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
727 if (vuid == UID_FIELD_INVALID ) {
728 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
731 vuser = get_partial_auth_user_struct(vuid);
734 if (!vuser) {
735 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
738 SSVAL(outbuf,smb_uid,vuid);
740 if (blob1.data[0] == ASN1_APPLICATION(0)) {
741 /* its a negTokenTarg packet */
742 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
743 &vuser->auth_ntlmssp_state);
744 data_blob_free(&blob1);
745 return ret;
748 if (blob1.data[0] == ASN1_CONTEXT(1)) {
749 /* its a auth packet */
750 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
751 &vuser->auth_ntlmssp_state);
752 data_blob_free(&blob1);
753 return ret;
756 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
757 DATA_BLOB chal;
758 NTSTATUS nt_status;
759 if (!vuser->auth_ntlmssp_state) {
760 nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
761 if (!NT_STATUS_IS_OK(nt_status)) {
762 /* Kill the intermediate vuid */
763 invalidate_vuid(vuid);
765 return ERROR_NT(nt_status_squash(nt_status));
769 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
770 blob1, &chal);
772 data_blob_free(&blob1);
774 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
775 &vuser->auth_ntlmssp_state,
776 &chal, nt_status, False);
777 data_blob_free(&chal);
778 return -1;
781 /* what sort of packet is this? */
782 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
784 data_blob_free(&blob1);
786 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
789 /****************************************************************************
790 On new VC == 0, shutdown *all* old connections and users.
791 It seems that only NT4.x does this. At W2K and above (XP etc.).
792 a new session setup with VC==0 is ignored.
793 ****************************************************************************/
795 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
796 void *p)
798 struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
799 const char *ip = (const char *)p;
801 if (!process_exists(pid_to_procid(sessionid->pid))) {
802 return 0;
805 if (sessionid->pid == sys_getpid()) {
806 return 0;
809 if (strcmp(ip, sessionid->ip_addr) != 0) {
810 return 0;
813 message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
814 NULL, 0, True);
815 return 0;
818 static void setup_new_vc_session(void)
820 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
821 #if 0
822 conn_close_all();
823 invalidate_all_vuids();
824 #endif
825 if (lp_reset_on_zero_vc()) {
826 session_traverse(shutdown_other_smbds, client_addr());
830 /****************************************************************************
831 Reply to a session setup command.
832 ****************************************************************************/
834 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
835 int length,int bufsize)
837 int sess_vuid;
838 int smb_bufsize;
839 DATA_BLOB lm_resp;
840 DATA_BLOB nt_resp;
841 DATA_BLOB plaintext_password;
842 fstring user;
843 fstring sub_user; /* Sainitised username for substituion */
844 fstring domain;
845 fstring native_os;
846 fstring native_lanman;
847 fstring primary_domain;
848 static BOOL done_sesssetup = False;
849 auth_usersupplied_info *user_info = NULL;
850 auth_serversupplied_info *server_info = NULL;
852 NTSTATUS nt_status;
854 BOOL doencrypt = global_encrypted_passwords_negotiated;
856 DATA_BLOB session_key;
858 START_PROFILE(SMBsesssetupX);
860 ZERO_STRUCT(lm_resp);
861 ZERO_STRUCT(nt_resp);
862 ZERO_STRUCT(plaintext_password);
864 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
866 /* a SPNEGO session setup has 12 command words, whereas a normal
867 NT1 session setup has 13. See the cifs spec. */
868 if (CVAL(inbuf, smb_wct) == 12 &&
869 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
870 if (!global_spnego_negotiated) {
871 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
872 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
875 if (SVAL(inbuf,smb_vwv4) == 0) {
876 setup_new_vc_session();
878 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
881 smb_bufsize = SVAL(inbuf,smb_vwv2);
883 if (Protocol < PROTOCOL_NT1) {
884 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
886 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
887 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
889 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
890 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
893 if (doencrypt) {
894 lm_resp = data_blob(smb_buf(inbuf), passlen1);
895 } else {
896 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
897 /* Ensure null termination */
898 plaintext_password.data[passlen1] = 0;
901 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
902 *domain = 0;
904 } else {
905 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
906 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
907 enum remote_arch_types ra_type = get_remote_arch();
908 char *p = smb_buf(inbuf);
909 char *save_p = smb_buf(inbuf);
910 uint16 byte_count;
913 if(global_client_caps == 0) {
914 global_client_caps = IVAL(inbuf,smb_vwv11);
916 if (!(global_client_caps & CAP_STATUS32)) {
917 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
920 /* client_caps is used as final determination if client is NT or Win95.
921 This is needed to return the correct error codes in some
922 circumstances.
925 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
926 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
927 set_remote_arch( RA_WIN95);
932 if (!doencrypt) {
933 /* both Win95 and WinNT stuff up the password lengths for
934 non-encrypting systems. Uggh.
936 if passlen1==24 its a win95 system, and its setting the
937 password length incorrectly. Luckily it still works with the
938 default code because Win95 will null terminate the password
939 anyway
941 if passlen1>0 and passlen2>0 then maybe its a NT box and its
942 setting passlen2 to some random value which really stuffs
943 things up. we need to fix that one. */
945 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
946 passlen2 = 0;
949 /* check for nasty tricks */
950 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
951 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
954 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
955 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
958 /* Save the lanman2 password and the NT md4 password. */
960 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
961 doencrypt = False;
964 if (doencrypt) {
965 lm_resp = data_blob(p, passlen1);
966 nt_resp = data_blob(p+passlen1, passlen2);
967 } else {
968 pstring pass;
969 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
971 #if 0
972 /* This was the previous fix. Not sure if it's still valid. JRA. */
973 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
974 /* NT4.0 stuffs up plaintext unicode password lengths... */
975 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
976 sizeof(pass), passlen1, STR_TERMINATE);
977 #endif
979 if (unic && (passlen2 == 0) && passlen1) {
980 /* Only a ascii plaintext password was sent. */
981 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
982 passlen1, STR_TERMINATE|STR_ASCII);
983 } else {
984 srvstr_pull(inbuf, pass, smb_buf(inbuf),
985 sizeof(pass), unic ? passlen2 : passlen1,
986 STR_TERMINATE);
988 plaintext_password = data_blob(pass, strlen(pass)+1);
991 p += passlen1 + passlen2;
992 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
993 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
994 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
995 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
997 /* not documented or decoded by Ethereal but there is one more string
998 in the extra bytes which is the same as the PrimaryDomain when using
999 extended security. Windows NT 4 and 2003 use this string to store
1000 the native lanman string. Windows 9x does not include a string here
1001 at all so we have to check if we have any extra bytes left */
1003 byte_count = SVAL(inbuf, smb_vwv13);
1004 if ( PTR_DIFF(p, save_p) < byte_count)
1005 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1006 else
1007 fstrcpy( primary_domain, "null" );
1009 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1010 domain, native_os, native_lanman, primary_domain));
1012 if ( ra_type == RA_WIN2K ) {
1013 if ( strlen(native_lanman) == 0 )
1014 ra_lanman_string( primary_domain );
1015 else
1016 ra_lanman_string( native_lanman );
1021 if (SVAL(inbuf,smb_vwv4) == 0) {
1022 setup_new_vc_session();
1025 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1027 if (*user) {
1028 if (global_spnego_negotiated) {
1030 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1032 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1033 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1035 fstrcpy(sub_user, user);
1036 } else {
1037 fstrcpy(sub_user, lp_guestaccount());
1040 sub_set_smb_name(sub_user);
1042 reload_services(True);
1044 if (lp_security() == SEC_SHARE) {
1045 /* in share level we should ignore any passwords */
1047 data_blob_free(&lm_resp);
1048 data_blob_free(&nt_resp);
1049 data_blob_clear_free(&plaintext_password);
1051 map_username(sub_user);
1052 add_session_user(sub_user);
1053 /* Then force it to null for the benfit of the code below */
1054 *user = 0;
1057 if (!*user) {
1059 nt_status = check_guest_password(&server_info);
1061 } else if (doencrypt) {
1062 if (!negprot_global_auth_context) {
1063 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
1064 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1066 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1067 lm_resp, nt_resp);
1068 if (NT_STATUS_IS_OK(nt_status)) {
1069 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
1070 user_info,
1071 &server_info);
1073 } else {
1074 struct auth_context *plaintext_auth_context = NULL;
1075 const uint8 *chal;
1077 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1079 if (NT_STATUS_IS_OK(nt_status)) {
1080 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1082 if (!make_user_info_for_reply(&user_info,
1083 user, domain, chal,
1084 plaintext_password)) {
1085 nt_status = NT_STATUS_NO_MEMORY;
1088 if (NT_STATUS_IS_OK(nt_status)) {
1089 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
1090 user_info,
1091 &server_info);
1093 (plaintext_auth_context->free)(&plaintext_auth_context);
1098 free_user_info(&user_info);
1100 if (!NT_STATUS_IS_OK(nt_status)) {
1101 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1104 if (!NT_STATUS_IS_OK(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 /* Ensure we can't possible take a code path leading to a null defref. */
1112 if (!server_info) {
1113 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1116 nt_status = create_local_token(server_info);
1117 if (!NT_STATUS_IS_OK(nt_status)) {
1118 DEBUG(10, ("create_local_token failed: %s\n",
1119 nt_errstr(nt_status)));
1120 data_blob_free(&nt_resp);
1121 data_blob_free(&lm_resp);
1122 data_blob_clear_free(&plaintext_password);
1123 return ERROR_NT(nt_status_squash(nt_status));
1126 if (server_info->user_session_key.data) {
1127 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1128 } else {
1129 session_key = data_blob(NULL, 0);
1132 data_blob_clear_free(&plaintext_password);
1134 /* it's ok - setup a reply */
1135 set_message(outbuf,3,0,True);
1136 if (Protocol >= PROTOCOL_NT1) {
1137 char *p = smb_buf( outbuf );
1138 p += add_signature( outbuf, p );
1139 set_message_end( outbuf, p );
1140 /* perhaps grab OS version here?? */
1143 if (server_info->guest) {
1144 SSVAL(outbuf,smb_vwv2,1);
1147 /* register the name and uid as being validated, so further connections
1148 to a uid can get through without a password, on the same VC */
1150 if (lp_security() == SEC_SHARE) {
1151 sess_vuid = UID_FIELD_INVALID;
1152 data_blob_free(&session_key);
1153 TALLOC_FREE(server_info);
1154 } else {
1155 /* register_vuid keeps the server info */
1156 sess_vuid = register_vuid(server_info, session_key,
1157 nt_resp.data ? nt_resp : lm_resp,
1158 sub_user);
1159 if (sess_vuid == UID_FIELD_INVALID) {
1160 data_blob_free(&nt_resp);
1161 data_blob_free(&lm_resp);
1162 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1165 /* current_user_info is changed on new vuid */
1166 reload_services( True );
1168 sessionsetup_start_signing_engine(server_info, inbuf);
1171 data_blob_free(&nt_resp);
1172 data_blob_free(&lm_resp);
1174 SSVAL(outbuf,smb_uid,sess_vuid);
1175 SSVAL(inbuf,smb_uid,sess_vuid);
1177 if (!done_sesssetup)
1178 max_send = MIN(max_send,smb_bufsize);
1180 done_sesssetup = True;
1182 END_PROFILE(SMBsesssetupX);
1183 return chain_reply(inbuf,outbuf,length,bufsize);