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