Initial import
[samba] / source / smbd / sesssetup.c
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
8
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.
13    
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.
18    
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.
22 */
23
24 #include "includes.h"
25
26 uint32 global_client_caps = 0;
27
28 /*
29   on a logon error possibly map the error to success if "map to guest"
30   is set approriately
31 */
32 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
33                                 const char *user, const char *domain)
34 {
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);
41                 }
42         }
43
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);
48                 }
49         }
50
51         return status;
52 }
53
54 /****************************************************************************
55  Add the standard 'Samba' signature to the end of the session setup.
56 ****************************************************************************/
57
58 static int add_signature(char *outbuf, char *p)
59 {
60         char *start = p;
61         fstring lanman;
62
63         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
64
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);
68
69         return PTR_DIFF(p, start);
70 }
71
72 /****************************************************************************
73  Start the signing engine if needed. Don't fail signing here.
74 ****************************************************************************/
75
76 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
77 {
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.
84                  */
85                 srv_check_sign_mac(inbuf, False);
86         }
87 }
88
89 /****************************************************************************
90  Send a security blob via a session setup reply.
91 ****************************************************************************/
92
93 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
94                                  DATA_BLOB blob, NTSTATUS nt_status)
95 {
96         char *p;
97
98         set_message(outbuf,4,0,True);
99
100         nt_status = nt_status_squash(nt_status);
101         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
102         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
103         SSVAL(outbuf, smb_vwv3, blob.length);
104         p = smb_buf(outbuf);
105
106         /* should we cap this? */
107         memcpy(p, blob.data, blob.length);
108         p += blob.length;
109
110         p += add_signature( outbuf, p );
111
112         set_message_end(outbuf,p);
113
114         show_msg(outbuf);
115         return send_smb(smbd_server_fd(),outbuf);
116 }
117
118 /****************************************************************************
119  Do a 'guest' logon, getting back the 
120 ****************************************************************************/
121
122 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
123 {
124         struct auth_context *auth_context;
125         auth_usersupplied_info *user_info = NULL;
126         
127         NTSTATUS nt_status;
128         unsigned char chal[8];
129
130         ZERO_STRUCT(chal);
131
132         DEBUG(3,("Got anonymous request\n"));
133
134         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
135                 return nt_status;
136         }
137
138         if (!make_user_info_guest(&user_info)) {
139                 (auth_context->free)(&auth_context);
140                 return NT_STATUS_NO_MEMORY;
141         }
142         
143         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
144         (auth_context->free)(&auth_context);
145         free_user_info(&user_info);
146         return nt_status;
147 }
148
149
150 #ifdef HAVE_KRB5
151 /****************************************************************************
152 reply to a session setup spnego negotiate packet for kerberos
153 ****************************************************************************/
154 static int reply_spnego_kerberos(connection_struct *conn, 
155                                  char *inbuf, char *outbuf,
156                                  int length, int bufsize,
157                                  DATA_BLOB *secblob)
158 {
159         TALLOC_CTX *mem_ctx;
160         DATA_BLOB ticket;
161         char *client, *p, *domain;
162         fstring netbios_domain_name;
163         struct passwd *pw;
164         fstring user;
165         int sess_vuid;
166         NTSTATUS ret;
167         PAC_DATA *pac_data;
168         DATA_BLOB ap_rep, ap_rep_wrapped, response;
169         auth_serversupplied_info *server_info = NULL;
170         DATA_BLOB session_key = data_blob(NULL, 0);
171         uint8 tok_id[2];
172         DATA_BLOB nullblob = data_blob(NULL, 0);
173         fstring real_username;
174         BOOL map_domainuser_to_guest = False;
175         PAC_LOGON_INFO *logon_info = NULL;
176
177         ZERO_STRUCT(ticket);
178         ZERO_STRUCT(pac_data);
179         ZERO_STRUCT(ap_rep);
180         ZERO_STRUCT(ap_rep_wrapped);
181         ZERO_STRUCT(response);
182
183         mem_ctx = talloc_init("reply_spnego_kerberos");
184         if (mem_ctx == NULL)
185                 return ERROR_NT(NT_STATUS_NO_MEMORY);
186
187         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
188                 talloc_destroy(mem_ctx);
189                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
190         }
191
192         ret = ads_verify_ticket(mem_ctx, lp_realm(), &ticket, &client, &pac_data, &ap_rep, &session_key);
193
194         data_blob_free(&ticket);
195
196         if (!NT_STATUS_IS_OK(ret)) {
197                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
198                 talloc_destroy(mem_ctx);
199                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
200         }
201
202         DEBUG(3,("Ticket name is [%s]\n", client));
203
204         p = strchr_m(client, '@');
205         if (!p) {
206                 DEBUG(3,("Doesn't look like a valid principal\n"));
207                 data_blob_free(&ap_rep);
208                 data_blob_free(&session_key);
209                 SAFE_FREE(client);
210                 talloc_destroy(mem_ctx);
211                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
212         }
213
214         *p = 0;
215
216         /* save the PAC data if we have it */
217
218         if (pac_data) {
219                 logon_info = get_logon_info_from_pac(pac_data);
220                 netsamlogon_cache_store( client, &logon_info->info3 );
221         }
222
223         if (!strequal(p+1, lp_realm())) {
224                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
225                 if (!lp_allow_trusted_domains()) {
226                         data_blob_free(&ap_rep);
227                         data_blob_free(&session_key);
228                         SAFE_FREE(client);
229                         talloc_destroy(mem_ctx);
230                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
231                 }
232         }
233
234         /* this gives a fully qualified user name (ie. with full realm).
235            that leads to very long usernames, but what else can we do? */
236
237         domain = p+1;
238
239         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
240
241                 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
242                 domain = netbios_domain_name;
243                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
244
245         } else {
246
247                 /* If we have winbind running, we can (and must) shorten the
248                    username by using the short netbios name. Otherwise we will
249                    have inconsistent user names. With Kerberos, we get the
250                    fully qualified realm, with ntlmssp we get the short
251                    name. And even w2k3 does use ntlmssp if you for example
252                    connect to an ip address. */
253
254                 struct winbindd_request wb_request;
255                 struct winbindd_response wb_response;
256                 NSS_STATUS wb_result;
257
258                 ZERO_STRUCT(wb_request);
259                 ZERO_STRUCT(wb_response);
260
261                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
262
263                 fstrcpy(wb_request.domain_name, domain);
264
265                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
266                                              &wb_request, &wb_response);
267
268                 if (wb_result == NSS_STATUS_SUCCESS) {
269
270                         fstrcpy(netbios_domain_name,
271                                 wb_response.data.domain_info.name);
272                         domain = netbios_domain_name;
273
274                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
275                 } else {
276                         DEBUG(3, ("Could not find short name -- winbind "
277                                   "not running?\n"));
278                 }
279         }
280
281         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
282         
283         /* lookup the passwd struct, create a new user if necessary */
284
285         map_username( user );
286
287         pw = smb_getpwnam( user, real_username, True );
288         if (!pw) {
289
290                 /* this was originally the behavior of Samba 2.2, if a user
291                    did not have a local uid but has been authenticated, then 
292                    map them to a guest account */
293
294                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
295                         map_domainuser_to_guest = True;
296                         fstrcpy(user,lp_guestaccount());
297                         pw = smb_getpwnam( user, real_username, True );
298                 } 
299
300                 /* extra sanity check that the guest account is valid */
301
302                 if ( !pw ) {
303                         DEBUG(1,("Username %s is invalid on this system\n", user));
304                         SAFE_FREE(client);
305                         data_blob_free(&ap_rep);
306                         data_blob_free(&session_key);
307                         talloc_destroy(mem_ctx);
308                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
309                 }
310         }
311
312         /* setup the string used by %U */
313         
314         sub_set_smb_name( real_username );
315         reload_services(True);
316         if ( map_domainuser_to_guest ) {
317                 make_server_info_guest(&server_info);
318         } else if (logon_info) {
319                 ret = make_server_info_pac(&server_info, real_username, pw, logon_info);
320
321                 if ( !NT_STATUS_IS_OK(ret) ) {
322                         DEBUG(1,("make_server_info_pac failed!\n"));
323                         SAFE_FREE(client);
324                         data_blob_free(&ap_rep);
325                         data_blob_free(&session_key);
326                         passwd_free(&pw);
327                         talloc_destroy(mem_ctx);
328                         return ERROR_NT(ret);
329                 }
330
331         } else {
332                 ret = make_server_info_pw(&server_info, real_username, pw);
333
334                 if ( !NT_STATUS_IS_OK(ret) ) {
335                         DEBUG(1,("make_server_info_from_pw failed!\n"));
336                         SAFE_FREE(client);
337                         data_blob_free(&ap_rep);
338                         data_blob_free(&session_key);
339                         passwd_free(&pw);
340                         talloc_destroy(mem_ctx);
341                         return ERROR_NT(ret);
342                 }
343
344                 /* make_server_info_pw does not set the domain. Without this we end up
345                  * with the local netbios name in substitutions for %D. */
346
347                 if (server_info->sam_account != NULL) {
348                         pdb_set_domain(server_info->sam_account, domain, PDB_SET);
349                 }
350         }
351
352
353         passwd_free(&pw);
354
355         /* register_vuid keeps the server info */
356         /* register_vuid takes ownership of session_key, no need to free after this.
357            A better interface would copy it.... */
358         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
359
360         SAFE_FREE(client);
361
362         if (sess_vuid == -1) {
363                 ret = NT_STATUS_LOGON_FAILURE;
364         } else {
365                 /* current_user_info is changed on new vuid */
366                 reload_services( True );
367
368                 set_message(outbuf,4,0,True);
369                 SSVAL(outbuf, smb_vwv3, 0);
370                         
371                 if (server_info->guest) {
372                         SSVAL(outbuf,smb_vwv2,1);
373                 }
374                 
375                 SSVAL(outbuf, smb_uid, sess_vuid);
376
377                 sessionsetup_start_signing_engine(server_info, inbuf);
378         }
379
380         /* wrap that up in a nice GSS-API wrapping */
381         if (NT_STATUS_IS_OK(ret)) {
382                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
383         } else {
384                 ap_rep_wrapped = data_blob(NULL, 0);
385         }
386         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
387         reply_sesssetup_blob(conn, outbuf, response, ret);
388
389         data_blob_free(&ap_rep);
390         data_blob_free(&ap_rep_wrapped);
391         data_blob_free(&response);
392         talloc_destroy(mem_ctx);
393
394         return -1; /* already replied */
395 }
396 #endif
397
398 /****************************************************************************
399  Send a session setup reply, wrapped in SPNEGO.
400  Get vuid and check first.
401  End the NTLMSSP exchange context if we are OK/complete fail
402  This should be split into two functions, one to handle each
403  leg of the NTLM auth steps.
404 ***************************************************************************/
405
406 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
407                                  uint16 vuid,
408                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
409                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
410                                  BOOL wrap) 
411 {
412         BOOL ret;
413         DATA_BLOB response;
414         struct auth_serversupplied_info *server_info = NULL;
415
416         if (NT_STATUS_IS_OK(nt_status)) {
417                 server_info = (*auth_ntlmssp_state)->server_info;
418         } else {
419                 nt_status = do_map_to_guest(nt_status, 
420                                             &server_info, 
421                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
422                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
423         }
424
425         if (NT_STATUS_IS_OK(nt_status)) {
426                 int sess_vuid;
427                 DATA_BLOB nullblob = data_blob(NULL, 0);
428                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
429
430                 /* register_vuid keeps the server info */
431                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
432                 (*auth_ntlmssp_state)->server_info = NULL;
433
434                 if (sess_vuid == -1) {
435                         nt_status = NT_STATUS_LOGON_FAILURE;
436                 } else {
437                         
438                         /* current_user_info is changed on new vuid */
439                         reload_services( True );
440
441                         set_message(outbuf,4,0,True);
442                         SSVAL(outbuf, smb_vwv3, 0);
443                         
444                         if (server_info->guest) {
445                                 SSVAL(outbuf,smb_vwv2,1);
446                         }
447                         
448                         SSVAL(outbuf,smb_uid,sess_vuid);
449
450                         sessionsetup_start_signing_engine(server_info, inbuf);
451                 }
452         }
453
454         if (wrap) {
455                 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
456         } else {
457                 response = *ntlmssp_blob;
458         }
459
460         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
461         if (wrap) {
462                 data_blob_free(&response);
463         }
464
465         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
466            and the other end, that we are not finished yet. */
467
468         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
469                 /* NB. This is *NOT* an error case. JRA */
470                 auth_ntlmssp_end(auth_ntlmssp_state);
471                 /* Kill the intermediate vuid */
472                 invalidate_vuid(vuid);
473         }
474
475         return ret;
476 }
477
478 /****************************************************************************
479  Reply to a session setup spnego negotiate packet.
480 ****************************************************************************/
481
482 static int reply_spnego_negotiate(connection_struct *conn, 
483                                   char *inbuf,
484                                   char *outbuf,
485                                   uint16 vuid,
486                                   int length, int bufsize,
487                                   DATA_BLOB blob1,
488                                   AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
489 {
490         char *OIDs[ASN1_MAX_OIDS];
491         DATA_BLOB secblob;
492         int i;
493         DATA_BLOB chal;
494 #ifdef HAVE_KRB5
495         BOOL got_kerberos_mechanism = False;
496 #endif
497         NTSTATUS nt_status;
498
499         /* parse out the OIDs and the first sec blob */
500         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
501                 /* Kill the intermediate vuid */
502                 invalidate_vuid(vuid);
503
504                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
505         }
506
507         /* only look at the first OID for determining the mechToken --
508            accoirding to RFC2478, we should choose the one we want 
509            and renegotiate, but i smell a client bug here..  
510            
511            Problem observed when connecting to a member (samba box) 
512            of an AD domain as a user in a Samba domain.  Samba member 
513            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
514            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
515            NTLMSSP mechtoken.                 --jerry              */
516
517 #ifdef HAVE_KRB5        
518         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
519             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
520                 got_kerberos_mechanism = True;
521         }
522 #endif
523                 
524         for (i=0;OIDs[i];i++) {
525                 DEBUG(3,("Got OID %s\n", OIDs[i]));
526                 free(OIDs[i]);
527         }
528         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
529
530 #ifdef HAVE_KRB5
531         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
532                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
533                                                 length, bufsize, &secblob);
534                 data_blob_free(&secblob);
535                 /* Kill the intermediate vuid */
536                 invalidate_vuid(vuid);
537
538                 return ret;
539         }
540 #endif
541
542         if (*auth_ntlmssp_state) {
543                 auth_ntlmssp_end(auth_ntlmssp_state);
544         }
545
546         nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
547         if (!NT_STATUS_IS_OK(nt_status)) {
548                 /* Kill the intermediate vuid */
549                 invalidate_vuid(vuid);
550
551                 return ERROR_NT(nt_status);
552         }
553
554         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
555                                         secblob, &chal);
556
557         data_blob_free(&secblob);
558
559         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
560                              &chal, nt_status, True);
561
562         data_blob_free(&chal);
563
564         /* already replied */
565         return -1;
566 }
567         
568 /****************************************************************************
569  Reply to a session setup spnego auth packet.
570 ****************************************************************************/
571
572 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
573                              uint16 vuid,
574                              int length, int bufsize,
575                              DATA_BLOB blob1,
576                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
577 {
578         DATA_BLOB auth, auth_reply;
579         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
580
581         if (!spnego_parse_auth(blob1, &auth)) {
582 #if 0
583                 file_save("auth.dat", blob1.data, blob1.length);
584 #endif
585                 /* Kill the intermediate vuid */
586                 invalidate_vuid(vuid);
587
588                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
589         }
590         
591         if (!*auth_ntlmssp_state) {
592                 /* Kill the intermediate vuid */
593                 invalidate_vuid(vuid);
594
595                 /* auth before negotiatiate? */
596                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
597         }
598         
599         nt_status = auth_ntlmssp_update(*auth_ntlmssp_state, 
600                                         auth, &auth_reply);
601
602         data_blob_free(&auth);
603
604         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
605                              auth_ntlmssp_state,
606                              &auth_reply, nt_status, True);
607                 
608         data_blob_free(&auth_reply);
609
610         /* and tell smbd that we have already replied to this packet */
611         return -1;
612 }
613
614 /****************************************************************************
615  Reply to a session setup command.
616 ****************************************************************************/
617
618 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
619                                         char *outbuf,
620                                         int length,int bufsize)
621 {
622         uint8 *p;
623         DATA_BLOB blob1;
624         int ret;
625         size_t bufrem;
626         fstring native_os, native_lanman, primary_domain;
627         char *p2;
628         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
629         enum remote_arch_types ra_type = get_remote_arch();
630         int vuid = SVAL(inbuf,smb_uid);
631         user_struct *vuser = NULL;
632
633         DEBUG(3,("Doing spnego session setup\n"));
634
635         if (global_client_caps == 0) {
636                 global_client_caps = IVAL(inbuf,smb_vwv10);
637
638                 if (!(global_client_caps & CAP_STATUS32)) {
639                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
640                 }
641
642         }
643                 
644         p = (uint8 *)smb_buf(inbuf);
645
646         if (data_blob_len == 0) {
647                 /* an invalid request */
648                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
649         }
650
651         bufrem = smb_bufrem(inbuf, p);
652         /* pull the spnego blob */
653         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
654
655 #if 0
656         file_save("negotiate.dat", blob1.data, blob1.length);
657 #endif
658
659         p2 = inbuf + smb_vwv13 + data_blob_len;
660         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
661         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
662         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
663         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
664                 native_os, native_lanman, primary_domain));
665
666         if ( ra_type == RA_WIN2K ) {
667                 /* Windows 2003 doesn't set the native lanman string, 
668                    but does set primary domain which is a bug I think */
669                            
670                 if ( !strlen(native_lanman) )
671                         ra_lanman_string( primary_domain );
672                 else
673                         ra_lanman_string( native_lanman );
674         }
675                 
676         vuser = get_partial_auth_user_struct(vuid);
677         if (!vuser) {
678                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
679                 if (vuid == -1) {
680                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
681                 }
682         
683                 vuser = get_partial_auth_user_struct(vuid);
684         }
685
686         if (!vuser) {
687                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
688         }
689         
690         SSVAL(outbuf,smb_uid,vuid);
691         
692         if (blob1.data[0] == ASN1_APPLICATION(0)) {
693                 /* its a negTokenTarg packet */
694                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
695                                              &vuser->auth_ntlmssp_state);
696                 data_blob_free(&blob1);
697                 return ret;
698         }
699
700         if (blob1.data[0] == ASN1_CONTEXT(1)) {
701                 /* its a auth packet */
702                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
703                                         &vuser->auth_ntlmssp_state);
704                 data_blob_free(&blob1);
705                 return ret;
706         }
707
708         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
709                 DATA_BLOB chal;
710                 NTSTATUS nt_status;
711                 if (!vuser->auth_ntlmssp_state) {
712                         nt_status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
713                         if (!NT_STATUS_IS_OK(nt_status)) {
714                                 /* Kill the intermediate vuid */
715                                 invalidate_vuid(vuid);
716                                 
717                                 return ERROR_NT(nt_status);
718                         }
719                 }
720
721                 nt_status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
722                                                 blob1, &chal);
723                 
724                 data_blob_free(&blob1);
725                 
726                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
727                                            &vuser->auth_ntlmssp_state,
728                                            &chal, nt_status, False);
729                 data_blob_free(&chal);
730                 return -1;
731         }
732
733         /* what sort of packet is this? */
734         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
735
736         data_blob_free(&blob1);
737
738         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
739 }
740
741 /****************************************************************************
742  On new VC == 0, shutdown *all* old connections and users.
743  It seems that only NT4.x does this. At W2K and above (XP etc.).
744  a new session setup with VC==0 is ignored.
745 ****************************************************************************/
746
747 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
748                                 void *p)
749 {
750         struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
751         const char *ip = (const char *)p;
752
753         if (!process_exists(pid_to_procid(sessionid->pid))) {
754                 return 0;
755         }
756
757         if (sessionid->pid == sys_getpid()) {
758                 return 0;
759         }
760
761         if (strcmp(ip, sessionid->ip_addr) != 0) {
762                 return 0;
763         }
764
765         message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
766                          NULL, 0, True);
767         return 0;
768 }
769
770 static void setup_new_vc_session(void)
771 {
772         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
773 #if 0
774         conn_close_all();
775         invalidate_all_vuids();
776 #endif
777         if (lp_reset_on_zero_vc()) {
778                 session_traverse(shutdown_other_smbds, client_addr());
779         }
780 }
781
782 /****************************************************************************
783  Reply to a session setup command.
784 ****************************************************************************/
785
786 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
787                           int length,int bufsize)
788 {
789         int sess_vuid;
790         int   smb_bufsize;    
791         DATA_BLOB lm_resp;
792         DATA_BLOB nt_resp;
793         DATA_BLOB plaintext_password;
794         fstring user;
795         fstring sub_user; /* Sainitised username for substituion */
796         fstring domain;
797         fstring native_os;
798         fstring native_lanman;
799         fstring primary_domain;
800         static BOOL done_sesssetup = False;
801         extern BOOL global_encrypted_passwords_negotiated;
802         extern BOOL global_spnego_negotiated;
803         extern enum protocol_types Protocol;
804         extern int max_send;
805
806         auth_usersupplied_info *user_info = NULL;
807         extern struct auth_context *negprot_global_auth_context;
808         auth_serversupplied_info *server_info = NULL;
809
810         NTSTATUS nt_status;
811
812         BOOL doencrypt = global_encrypted_passwords_negotiated;
813
814         DATA_BLOB session_key;
815         
816         START_PROFILE(SMBsesssetupX);
817
818         ZERO_STRUCT(lm_resp);
819         ZERO_STRUCT(nt_resp);
820         ZERO_STRUCT(plaintext_password);
821
822         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
823
824         /* a SPNEGO session setup has 12 command words, whereas a normal
825            NT1 session setup has 13. See the cifs spec. */
826         if (CVAL(inbuf, smb_wct) == 12 &&
827             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
828                 if (!global_spnego_negotiated) {
829                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
830                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
831                 }
832
833                 if (SVAL(inbuf,smb_vwv4) == 0) {
834                         setup_new_vc_session();
835                 }
836                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
837         }
838
839         smb_bufsize = SVAL(inbuf,smb_vwv2);
840
841         if (Protocol < PROTOCOL_NT1) {
842                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
843
844                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
845                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
846
847                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
848                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
849                 }
850
851                 if (doencrypt) {
852                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
853                 } else {
854                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
855                         /* Ensure null termination */
856                         plaintext_password.data[passlen1] = 0;
857                 }
858
859                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
860                 *domain = 0;
861
862         } else {
863                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
864                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
865                 enum remote_arch_types ra_type = get_remote_arch();
866                 char *p = smb_buf(inbuf);    
867                 char *save_p = smb_buf(inbuf);
868                 uint16 byte_count;
869                         
870
871                 if(global_client_caps == 0) {
872                         global_client_caps = IVAL(inbuf,smb_vwv11);
873                 
874                         if (!(global_client_caps & CAP_STATUS32)) {
875                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
876                         }
877
878                         /* client_caps is used as final determination if client is NT or Win95. 
879                            This is needed to return the correct error codes in some
880                            circumstances.
881                         */
882                 
883                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
884                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
885                                         set_remote_arch( RA_WIN95);
886                                 }
887                         }
888                 }
889
890                 if (!doencrypt) {
891                         /* both Win95 and WinNT stuff up the password lengths for
892                            non-encrypting systems. Uggh. 
893                            
894                            if passlen1==24 its a win95 system, and its setting the
895                            password length incorrectly. Luckily it still works with the
896                            default code because Win95 will null terminate the password
897                            anyway 
898                            
899                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
900                            setting passlen2 to some random value which really stuffs
901                            things up. we need to fix that one.  */
902                         
903                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
904                                 passlen2 = 0;
905                 }
906                 
907                 /* check for nasty tricks */
908                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
909                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
910                 }
911
912                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
913                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
914                 }
915
916                 /* Save the lanman2 password and the NT md4 password. */
917                 
918                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
919                         doencrypt = False;
920                 }
921
922                 if (doencrypt) {
923                         lm_resp = data_blob(p, passlen1);
924                         nt_resp = data_blob(p+passlen1, passlen2);
925                 } else {
926                         pstring pass;
927                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
928
929 #if 0
930                         /* This was the previous fix. Not sure if it's still valid. JRA. */
931                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
932                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
933                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
934                                         sizeof(pass), passlen1, STR_TERMINATE);
935 #endif
936
937                         if (unic && (passlen2 == 0) && passlen1) {
938                                 /* Only a ascii plaintext password was sent. */
939                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
940                                         passlen1, STR_TERMINATE|STR_ASCII);
941                         } else {
942                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
943                                         sizeof(pass),  unic ? passlen2 : passlen1, 
944                                         STR_TERMINATE);
945                         }
946                         plaintext_password = data_blob(pass, strlen(pass)+1);
947                 }
948                 
949                 p += passlen1 + passlen2;
950                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
951                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
952                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
953                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
954
955                 /* not documented or decoded by Ethereal but there is one more string 
956                    in the extra bytes which is the same as the PrimaryDomain when using 
957                    extended security.  Windows NT 4 and 2003 use this string to store 
958                    the native lanman string. Windows 9x does not include a string here 
959                    at all so we have to check if we have any extra bytes left */
960                 
961                 byte_count = SVAL(inbuf, smb_vwv13);
962                 if ( PTR_DIFF(p, save_p) < byte_count)
963                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
964                 else 
965                         fstrcpy( primary_domain, "null" );
966
967                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
968                          domain, native_os, native_lanman, primary_domain));
969
970                 if ( ra_type == RA_WIN2K ) {
971                         if ( strlen(native_lanman) == 0 )
972                                 ra_lanman_string( primary_domain );
973                         else
974                                 ra_lanman_string( native_lanman );
975                 }
976
977         }
978
979         if (SVAL(inbuf,smb_vwv4) == 0) {
980                 setup_new_vc_session();
981         }
982
983         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
984
985         if (*user) {
986                 if (global_spnego_negotiated) {
987                         
988                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
989                         
990                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
991                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
992                 }
993                 fstrcpy(sub_user, user);
994         } else {
995                 fstrcpy(sub_user, lp_guestaccount());
996         }
997
998         sub_set_smb_name(sub_user);
999
1000         reload_services(True);
1001         
1002         if (lp_security() == SEC_SHARE) {
1003                 /* in share level we should ignore any passwords */
1004
1005                 data_blob_free(&lm_resp);
1006                 data_blob_free(&nt_resp);
1007                 data_blob_clear_free(&plaintext_password);
1008
1009                 map_username(sub_user);
1010                 add_session_user(sub_user);
1011                 /* Then force it to null for the benfit of the code below */
1012                 *user = 0;
1013         }
1014         
1015         if (!*user) {
1016
1017                 nt_status = check_guest_password(&server_info);
1018
1019         } else if (doencrypt) {
1020                 if (!negprot_global_auth_context) {
1021                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1022                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1023                 }
1024                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1025                                                          lm_resp, nt_resp);
1026                 if (NT_STATUS_IS_OK(nt_status)) {
1027                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1028                                                                                      user_info, 
1029                                                                                      &server_info);
1030                 }
1031         } else {
1032                 struct auth_context *plaintext_auth_context = NULL;
1033                 const uint8 *chal;
1034                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
1035                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1036                         
1037                         if (!make_user_info_for_reply(&user_info, 
1038                                                       user, domain, chal,
1039                                                       plaintext_password)) {
1040                                 nt_status = NT_STATUS_NO_MEMORY;
1041                         }
1042                 
1043                         if (NT_STATUS_IS_OK(nt_status)) {
1044                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1045                                                                                         user_info, 
1046                                                                                         &server_info); 
1047                                 
1048                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1049                         }
1050                 }
1051         }
1052
1053         free_user_info(&user_info);
1054         
1055         if (!NT_STATUS_IS_OK(nt_status)) {
1056                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1057         }
1058         
1059         if (!NT_STATUS_IS_OK(nt_status)) {
1060                 data_blob_free(&nt_resp);
1061                 data_blob_free(&lm_resp);
1062                 data_blob_clear_free(&plaintext_password);
1063                 return ERROR_NT(nt_status_squash(nt_status));
1064         }
1065
1066         if (server_info->user_session_key.data) {
1067                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1068         } else {
1069                 session_key = data_blob(NULL, 0);
1070         }
1071
1072         data_blob_clear_free(&plaintext_password);
1073         
1074         /* it's ok - setup a reply */
1075         set_message(outbuf,3,0,True);
1076         if (Protocol >= PROTOCOL_NT1) {
1077                 char *p = smb_buf( outbuf );
1078                 p += add_signature( outbuf, p );
1079                 set_message_end( outbuf, p );
1080                 /* perhaps grab OS version here?? */
1081         }
1082         
1083         if (server_info->guest) {
1084                 SSVAL(outbuf,smb_vwv2,1);
1085         }
1086
1087         /* register the name and uid as being validated, so further connections
1088            to a uid can get through without a password, on the same VC */
1089
1090         /* register_vuid keeps the server info */
1091         sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
1092         data_blob_free(&nt_resp);
1093         data_blob_free(&lm_resp);
1094
1095         if (sess_vuid == -1) {
1096                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
1097         }
1098
1099         /* current_user_info is changed on new vuid */
1100         reload_services( True );
1101
1102         sessionsetup_start_signing_engine(server_info, inbuf);
1103
1104         SSVAL(outbuf,smb_uid,sess_vuid);
1105         SSVAL(inbuf,smb_uid,sess_vuid);
1106         
1107         if (!done_sesssetup)
1108                 max_send = MIN(max_send,smb_bufsize);
1109         
1110         done_sesssetup = True;
1111         
1112         END_PROFILE(SMBsesssetupX);
1113         return chain_reply(inbuf,outbuf,length,bufsize);
1114 }