c37c655fd1630d33936b23f7599d847ea910936b
[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        2002
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 uint32 global_client_caps = 0;
26 static struct auth_context *ntlmssp_auth_context = NULL;
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                         make_server_info_guest(server_info);
41                         status = NT_STATUS_OK;
42                 }
43         }
44
45         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
46                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
47                         DEBUG(3,("Registered username %s for guest access\n",user));
48                         make_server_info_guest(server_info);
49                         status = NT_STATUS_OK;
50                 }
51         }
52
53         return status;
54 }
55
56
57 /****************************************************************************
58  Add the standard 'Samba' signature to the end of the session setup.
59 ****************************************************************************/
60 static void add_signature(char *outbuf) 
61 {
62         char *p;
63         p = smb_buf(outbuf);
64         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
65         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
66         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
67         set_message_end(outbuf,p);
68 }
69
70 /****************************************************************************
71  Do a 'guest' logon, getting back the 
72 ****************************************************************************/
73 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
74 {
75         struct auth_context *auth_context;
76         auth_usersupplied_info *user_info = NULL;
77         
78         NTSTATUS nt_status;
79         unsigned char chal[8];
80
81         ZERO_STRUCT(chal);
82
83         DEBUG(3,("Got anonymous request\n"));
84
85         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
86                 return nt_status;
87         }
88
89         if (!make_user_info_guest(&user_info)) {
90                 (auth_context->free)(&auth_context);
91                 return NT_STATUS_NO_MEMORY;
92         }
93         
94         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
95         (auth_context->free)(&auth_context);
96         free_user_info(&user_info);
97         return nt_status;
98 }
99
100
101 #ifdef HAVE_KRB5
102 /****************************************************************************
103 reply to a session setup spnego negotiate packet for kerberos
104 ****************************************************************************/
105 static int reply_spnego_kerberos(connection_struct *conn, 
106                                  char *inbuf, char *outbuf,
107                                  int length, int bufsize,
108                                  DATA_BLOB *secblob)
109 {
110         DATA_BLOB ticket;
111         char *client, *p;
112         const struct passwd *pw;
113         char *user;
114         int sess_vuid;
115         NTSTATUS ret;
116         DATA_BLOB auth_data;
117         auth_serversupplied_info *server_info = NULL;
118         ADS_STRUCT *ads;
119
120         if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
121                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
122         }
123
124         ads = ads_init_simple();
125
126         if (!ads) {
127                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
128         }
129
130         ads->auth.realm = strdup(lp_realm());
131
132         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
133         if (!NT_STATUS_IS_OK(ret)) {
134                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
135                 ads_destroy(&ads);
136                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
137         }
138
139         DEBUG(3,("Ticket name is [%s]\n", client));
140
141         p = strchr_m(client, '@');
142         if (!p) {
143                 DEBUG(3,("Doesn't look like a valid principal\n"));
144                 ads_destroy(&ads);
145                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
146         }
147
148         *p = 0;
149         if (strcasecmp(p+1, ads->auth.realm) != 0) {
150                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
151                 if (!lp_allow_trusted_domains()) {
152                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
153                 }
154                 /* this gives a fully qualified user name (ie. with full realm).
155                    that leads to very long usernames, but what else can we do? */
156                 asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
157         } else {
158                 user = strdup(client);
159         }
160         ads_destroy(&ads);
161
162         /* the password is good - let them in */
163         pw = smb_getpwnam(user,False);
164         if (!pw && !strstr(user, lp_winbind_separator())) {
165                 char *user2;
166                 /* try it with a winbind domain prefix */
167                 asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
168                 pw = smb_getpwnam(user2,False);
169                 if (pw) {
170                         free(user);
171                         user = user2;
172                 }
173         }
174
175         if (!pw) {
176                 DEBUG(1,("Username %s is invalid on this system\n",user));
177                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
178         }
179
180         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
181                 DEBUG(1,("make_server_info_from_pw failed!\n"));
182                 return ERROR_NT(ret);
183         }
184         
185         sess_vuid = register_vuid(server_info, user);
186
187         free(user);
188         free_server_info(&server_info);
189
190         if (sess_vuid == -1) {
191                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
192         }
193
194         set_message(outbuf,4,0,True);
195         SSVAL(outbuf, smb_vwv3, 0);
196         add_signature(outbuf);
197  
198         SSVAL(outbuf,smb_uid,sess_vuid);
199         SSVAL(inbuf,smb_uid,sess_vuid);
200         
201         return chain_reply(inbuf,outbuf,length,bufsize);
202 }
203 #endif
204
205
206 /****************************************************************************
207 send a security blob via a session setup reply
208 ****************************************************************************/
209 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
210                                  DATA_BLOB blob, uint32 errcode)
211 {
212         char *p;
213
214         set_message(outbuf,4,0,True);
215
216         /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
217            that we aren't finished yet */
218
219         SIVAL(outbuf, smb_rcls, errcode);
220         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
221         SSVAL(outbuf, smb_vwv3, blob.length);
222         p = smb_buf(outbuf);
223         memcpy(p, blob.data, blob.length);
224         p += blob.length;
225         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
226         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
227         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
228         set_message_end(outbuf,p);
229         
230         return send_smb(smbd_server_fd(),outbuf);
231 }
232
233 /****************************************************************************
234 reply to a session setup spnego negotiate packet
235 ****************************************************************************/
236 static int reply_spnego_negotiate(connection_struct *conn, 
237                                   char *inbuf,
238                                   char *outbuf,
239                                   int length, int bufsize,
240                                   DATA_BLOB blob1)
241 {
242         char *OIDs[ASN1_MAX_OIDS];
243         DATA_BLOB secblob;
244         int i;
245         uint32 ntlmssp_command, neg_flags, chal_flags;
246         DATA_BLOB chal, spnego_chal;
247         const uint8 *cryptkey;
248         BOOL got_kerberos = False;
249         NTSTATUS nt_status;
250         extern pstring global_myname;
251         char *cliname=NULL, *domname=NULL;
252
253         /* parse out the OIDs and the first sec blob */
254         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
255                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
256         }
257         
258         for (i=0;OIDs[i];i++) {
259                 DEBUG(3,("Got OID %s\n", OIDs[i]));
260                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
261                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
262                         got_kerberos = True;
263                 }
264                 free(OIDs[i]);
265         }
266         DEBUG(3,("Got secblob of size %d\n", secblob.length));
267
268 #ifdef HAVE_KRB5
269         if (got_kerberos && (SEC_ADS == lp_security())) {
270                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
271                                                 length, bufsize, &secblob);
272                 data_blob_free(&secblob);
273                 return ret;
274         }
275 #endif
276
277         /* parse the NTLMSSP packet */
278 #if 0
279         file_save("secblob.dat", secblob.data, secblob.length);
280 #endif
281
282         if (!msrpc_parse(&secblob, "CddAA",
283                          "NTLMSSP",
284                          &ntlmssp_command,
285                          &neg_flags,
286                          &cliname,
287                          &domname)) {
288                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
289         }
290        
291         data_blob_free(&secblob);
292
293         if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
294                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
295         }
296
297         debug_ntlmssp_flags(neg_flags);
298
299         if (ntlmssp_auth_context) {
300                 (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
301         }
302
303         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
304                 return ERROR_NT(nt_status);
305         }
306
307         cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
308
309         /* Give them the challenge. For now, ignore neg_flags and just
310            return the flags we want. Obviously this is not correct */
311         
312         chal_flags = NTLMSSP_NEGOTIATE_UNICODE | 
313                 NTLMSSP_NEGOTIATE_128 | 
314                 NTLMSSP_NEGOTIATE_NTLM |
315                 NTLMSSP_CHAL_TARGET_INFO;
316         
317         {
318                 DATA_BLOB domain_blob, struct_blob;
319                 fstring dnsname, dnsdomname;
320                 
321                 msrpc_gen(&domain_blob, 
322                           "U",
323                           lp_workgroup());
324
325                 fstrcpy(dnsdomname, lp_realm());
326                 strlower(dnsdomname);
327
328                 fstrcpy(dnsname, global_myname);
329                 fstrcat(dnsname, ".");
330                 fstrcat(dnsname, lp_realm());
331                 strlower(dnsname);
332
333                 msrpc_gen(&struct_blob, "aaaaa",
334                           2, lp_workgroup(),
335                           1, global_myname,
336                           4, dnsdomname,
337                           3, dnsname,
338                           0, "");
339
340                 msrpc_gen(&chal, "CdUdbddB",
341                           "NTLMSSP", 
342                           NTLMSSP_CHALLENGE,
343                           lp_workgroup(),
344                           chal_flags,
345                           cryptkey, 8,
346                           0, 0,
347                           struct_blob.data, struct_blob.length);
348
349                 data_blob_free(&domain_blob);
350                 data_blob_free(&struct_blob);
351         }
352
353         if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
354                 DEBUG(3,("Failed to generate challenge\n"));
355                 data_blob_free(&chal);
356                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
357         }
358
359         /* now tell the client to send the auth packet */
360         reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
361
362         data_blob_free(&chal);
363         data_blob_free(&spnego_chal);
364
365         /* and tell smbd that we have already replied to this packet */
366         return -1;
367 }
368
369         
370 /****************************************************************************
371 reply to a session setup spnego auth packet
372 ****************************************************************************/
373 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
374                              int length, int bufsize,
375                              DATA_BLOB blob1)
376 {
377         DATA_BLOB auth, response;
378         char *workgroup = NULL, *user = NULL, *machine = NULL;
379         DATA_BLOB lmhash, nthash, sess_key;
380         DATA_BLOB plaintext_password = data_blob(NULL, 0);
381         uint32 ntlmssp_command, neg_flags;
382         NTSTATUS nt_status;
383         int sess_vuid;
384         BOOL as_guest;
385         uint32 auth_flags = AUTH_FLAG_NONE;
386         auth_usersupplied_info *user_info = NULL;
387         auth_serversupplied_info *server_info = NULL;
388
389         /* we must have setup the auth context by now */
390         if (!ntlmssp_auth_context) {
391                 DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n"));
392                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
393         }
394
395         if (!spnego_parse_auth(blob1, &auth)) {
396 #if 0
397                 file_save("auth.dat", blob1.data, blob1.length);
398 #endif
399                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
400         }
401
402         /* now the NTLMSSP encoded auth hashes */
403         if (!msrpc_parse(&auth, "CdBBUUUBd", 
404                          "NTLMSSP", 
405                          &ntlmssp_command, 
406                          &lmhash,
407                          &nthash,
408                          &workgroup, 
409                          &user, 
410                          &machine,
411                          &sess_key,
412                          &neg_flags)) {
413                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
414         }
415
416         data_blob_free(&auth);
417         data_blob_free(&sess_key);
418         
419         DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
420                  user, workgroup, machine, lmhash.length, nthash.length));
421
422         /* the client has given us its machine name (which we otherwise would not get on port 445).
423            we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
424
425         set_remote_machine_name(machine);
426
427         reload_services(True);
428
429 #if 0
430         file_save("nthash1.dat", nthash.data, nthash.length);
431         file_save("lmhash1.dat", lmhash.data, lmhash.length);
432 #endif
433
434         if (lmhash.length) {
435                 auth_flags |= AUTH_FLAG_LM_RESP;
436         }
437
438         if (nthash.length == 24) {
439                 auth_flags |= AUTH_FLAG_NTLM_RESP;
440         } else if (nthash.length > 24) {
441                 auth_flags |= AUTH_FLAG_NTLMv2_RESP;
442         }
443
444         if (!make_user_info_map(&user_info, 
445                                 user, workgroup, 
446                                 machine, 
447                                 lmhash, nthash,
448                                 plaintext_password, 
449                                 auth_flags, True)) {
450                 return ERROR_NT(NT_STATUS_NO_MEMORY);
451         }
452
453         nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); 
454
455         if (!NT_STATUS_IS_OK(nt_status)) {
456                 nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
457         }
458
459         SAFE_FREE(workgroup);
460         SAFE_FREE(machine);
461                         
462         (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
463
464         free_user_info(&user_info);
465         
466         data_blob_free(&lmhash);
467         
468         data_blob_free(&nthash);
469
470         if (!NT_STATUS_IS_OK(nt_status)) {
471                 SAFE_FREE(user);
472                 return ERROR_NT(nt_status_squash(nt_status));
473         }
474
475         as_guest = server_info->guest;
476
477         sess_vuid = register_vuid(server_info, user);
478         free_server_info(&server_info);
479
480         SAFE_FREE(user);
481   
482         if (sess_vuid == -1) {
483                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
484         }
485
486         set_message(outbuf,4,0,True);
487         SSVAL(outbuf, smb_vwv3, 0);
488
489         if (as_guest) {
490                 SSVAL(outbuf,smb_vwv2,1);
491         }
492
493         add_signature(outbuf);
494  
495         SSVAL(outbuf,smb_uid,sess_vuid);
496         SSVAL(inbuf,smb_uid,sess_vuid);
497
498         response = spnego_gen_auth_response();
499         reply_sesssetup_blob(conn, outbuf, response, 0);
500
501         /* and tell smbd that we have already replied to this packet */
502         return -1;
503 }
504
505
506 /****************************************************************************
507 reply to a session setup spnego anonymous packet
508 ****************************************************************************/
509 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
510                                   int length, int bufsize)
511 {
512         int sess_vuid;
513         auth_serversupplied_info *server_info = NULL;
514         NTSTATUS nt_status;
515
516         nt_status = check_guest_password(&server_info);
517
518         if (!NT_STATUS_IS_OK(nt_status)) {
519                 return ERROR_NT(nt_status_squash(nt_status));
520         }
521
522         sess_vuid = register_vuid(server_info, lp_guestaccount());
523
524         free_server_info(&server_info);
525   
526         if (sess_vuid == -1) {
527                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
528         }
529
530         set_message(outbuf,4,0,True);
531         SSVAL(outbuf, smb_vwv3, 0);
532         add_signature(outbuf);
533  
534         SSVAL(outbuf,smb_uid,sess_vuid);
535         SSVAL(inbuf,smb_uid,sess_vuid);
536         
537         return chain_reply(inbuf,outbuf,length,bufsize);
538 }
539
540
541 /****************************************************************************
542 reply to a session setup command
543 ****************************************************************************/
544 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
545                                         int length,int bufsize)
546 {
547         uint8 *p;
548         DATA_BLOB blob1;
549         int ret;
550
551         DEBUG(3,("Doing spnego session setup\n"));
552
553         if (global_client_caps == 0) {
554                 global_client_caps = IVAL(inbuf,smb_vwv10);
555         }
556                 
557         p = (uint8 *)smb_buf(inbuf);
558
559         if (SVAL(inbuf, smb_vwv7) == 0) {
560                 /* an anonymous request */
561                 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
562         }
563
564         /* pull the spnego blob */
565         blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
566
567 #if 0
568         file_save("negotiate.dat", blob1.data, blob1.length);
569 #endif
570
571         if (blob1.data[0] == ASN1_APPLICATION(0)) {
572                 /* its a negTokenTarg packet */
573                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
574                 data_blob_free(&blob1);
575                 return ret;
576         }
577
578         if (blob1.data[0] == ASN1_CONTEXT(1)) {
579                 /* its a auth packet */
580                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
581                 data_blob_free(&blob1);
582                 return ret;
583         }
584
585         /* what sort of packet is this? */
586         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
587
588         data_blob_free(&blob1);
589
590         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
591 }
592
593
594 /****************************************************************************
595 reply to a session setup command
596 ****************************************************************************/
597 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
598                           int length,int bufsize)
599 {
600         int sess_vuid;
601         int   smb_bufsize;    
602         DATA_BLOB lm_resp;
603         DATA_BLOB nt_resp;
604         DATA_BLOB plaintext_password;
605         pstring user;
606         pstring sub_user; /* Sainitised username for substituion */
607         fstring domain;
608         fstring native_os;
609         fstring native_lanman;
610         static BOOL done_sesssetup = False;
611         extern BOOL global_encrypted_passwords_negotiated;
612         extern BOOL global_spnego_negotiated;
613         extern int Protocol;
614         extern userdom_struct current_user_info;
615         extern int max_send;
616
617         auth_usersupplied_info *user_info = NULL;
618         extern struct auth_context *negprot_global_auth_context;
619         auth_serversupplied_info *server_info = NULL;
620
621         NTSTATUS nt_status;
622
623         BOOL doencrypt = global_encrypted_passwords_negotiated;
624
625         START_PROFILE(SMBsesssetupX);
626
627         ZERO_STRUCT(lm_resp);
628         ZERO_STRUCT(nt_resp);
629         ZERO_STRUCT(plaintext_password);
630
631         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
632
633         /* a SPNEGO session setup has 12 command words, whereas a normal
634            NT1 session setup has 13. See the cifs spec. */
635         if (CVAL(inbuf, smb_wct) == 12 &&
636             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
637                 if (!global_spnego_negotiated) {
638                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
639                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
640                 }
641
642                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
643         }
644
645         smb_bufsize = SVAL(inbuf,smb_vwv2);
646
647         if (Protocol < PROTOCOL_NT1) {
648                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
649                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
650                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
651                 }
652
653                 if (doencrypt) {
654                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
655                 } else {
656                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
657                         /* Ensure null termination */
658                         plaintext_password.data[passlen1] = 0;
659                 }
660
661                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
662                 *domain = 0;
663   
664         } else {
665                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
666                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
667                 enum remote_arch_types ra_type = get_remote_arch();
668                 char *p = smb_buf(inbuf);    
669
670                 if(global_client_caps == 0)
671                         global_client_caps = IVAL(inbuf,smb_vwv11);
672                 
673                 /* client_caps is used as final determination if client is NT or Win95. 
674                    This is needed to return the correct error codes in some
675                    circumstances.
676                 */
677                 
678                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
679                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
680                                 set_remote_arch( RA_WIN95);
681                         }
682                 }
683                 
684                 if (!doencrypt) {
685                         /* both Win95 and WinNT stuff up the password lengths for
686                            non-encrypting systems. Uggh. 
687                            
688                            if passlen1==24 its a win95 system, and its setting the
689                            password length incorrectly. Luckily it still works with the
690                            default code because Win95 will null terminate the password
691                            anyway 
692                            
693                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
694                            setting passlen2 to some random value which really stuffs
695                            things up. we need to fix that one.  */
696                         
697                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
698                                 passlen2 = 0;
699                 }
700                 
701                 /* check for nasty tricks */
702                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
703                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
704                 }
705
706                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
707                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
708                 }
709
710                 /* Save the lanman2 password and the NT md4 password. */
711                 
712                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
713                         doencrypt = False;
714                 }
715
716                 if (doencrypt) {
717                         lm_resp = data_blob(p, passlen1);
718                         nt_resp = data_blob(p+passlen1, passlen2);
719                 } else {
720                         pstring pass;
721                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
722                                     sizeof(pass),  passlen1, STR_TERMINATE);
723                         plaintext_password = data_blob(pass, strlen(pass)+1);
724                 }
725                 
726                 p += passlen1 + passlen2;
727                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
728                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
729                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
730                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
731                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
732                          domain,native_os,native_lanman));
733         }
734         
735         /* don't allow for weird usernames or domains */
736         alpha_strcpy(user, user, ". _-$", sizeof(user));
737         alpha_strcpy(domain, domain, ". _-", sizeof(domain));
738         if (strstr(user, "..") || strstr(domain,"..")) {
739                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
740         }
741
742         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
743
744         if (*user) {
745                 if (global_spnego_negotiated) {
746                         
747                         /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
748                         
749                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
750                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
751                 }
752                 pstrcpy(sub_user, user);
753         } else {
754                 pstrcpy(sub_user, lp_guestaccount());
755         }
756
757         pstrcpy(current_user_info.smb_name,sub_user);
758
759         reload_services(True);
760         
761         if (lp_security() == SEC_SHARE) {
762                 /* in share level we should ignore any passwords */
763
764                 data_blob_free(&lm_resp);
765                 data_blob_free(&nt_resp);
766                 data_blob_clear_free(&plaintext_password);
767
768                 map_username(sub_user);
769                 add_session_user(sub_user);
770                 /* Then force it to null for the benfit of the code below */
771                 *user = 0;
772         }
773         
774         if (!*user) {
775
776                 nt_status = check_guest_password(&server_info);
777
778         } else if (doencrypt) {
779                 if (!make_user_info_for_reply_enc(&user_info, 
780                                                   user, domain, 
781                                                   lm_resp, nt_resp)) {
782                         nt_status = NT_STATUS_NO_MEMORY;
783                 } else {
784                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
785                                                                                      user_info, 
786                                                                                      &server_info);
787                 }
788         } else {
789                 struct auth_context *plaintext_auth_context = NULL;
790                 const uint8 *chal;
791                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
792                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
793                         
794                         if (!make_user_info_for_reply(&user_info, 
795                                                       user, domain, chal,
796                                                       plaintext_password)) {
797                                 nt_status = NT_STATUS_NO_MEMORY;
798                         }
799                 
800                         if (NT_STATUS_IS_OK(nt_status)) {
801                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
802                                                                                         user_info, 
803                                                                                         &server_info); 
804                                 
805                                 (plaintext_auth_context->free)(&plaintext_auth_context);
806                         }
807                 }
808         }
809
810         free_user_info(&user_info);
811         
812         data_blob_free(&lm_resp);
813         data_blob_free(&nt_resp);
814         data_blob_clear_free(&plaintext_password);
815         
816         if (!NT_STATUS_IS_OK(nt_status)) {
817                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
818         }
819         
820         if (!NT_STATUS_IS_OK(nt_status)) {
821                 return ERROR_NT(nt_status_squash(nt_status));
822         }
823         
824         /* it's ok - setup a reply */
825         if (Protocol < PROTOCOL_NT1) {
826                 set_message(outbuf,3,0,True);
827         } else {
828                 set_message(outbuf,3,0,True);
829                 add_signature(outbuf);
830                 /* perhaps grab OS version here?? */
831         }
832         
833         if (server_info->guest) {
834                 SSVAL(outbuf,smb_vwv2,1);
835         }
836
837         /* register the name and uid as being validated, so further connections
838            to a uid can get through without a password, on the same VC */
839
840         sess_vuid = register_vuid(server_info, sub_user);
841
842         free_server_info(&server_info);
843   
844         if (sess_vuid == -1) {
845                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
846         }
847
848  
849         SSVAL(outbuf,smb_uid,sess_vuid);
850         SSVAL(inbuf,smb_uid,sess_vuid);
851         
852         if (!done_sesssetup)
853                 max_send = MIN(max_send,smb_bufsize);
854         
855         done_sesssetup = True;
856         
857         END_PROFILE(SMBsesssetupX);
858         return chain_reply(inbuf,outbuf,length,bufsize);
859 }