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