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