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