Fix the %m security bug again - and try to make it harder to reintroduce in
[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         if (!ads) {
126                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
127         }
128
129         ads->auth.realm = strdup(lp_realm());
130
131         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
132         if (!NT_STATUS_IS_OK(ret)) {
133                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
134                 ads_destroy(&ads);
135                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
136         }
137
138         DEBUG(3,("Ticket name is [%s]\n", client));
139
140         p = strchr_m(client, '@');
141         if (!p) {
142                 DEBUG(3,("Doesn't look like a valid principal\n"));
143                 ads_destroy(&ads);
144                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
145         }
146
147         *p = 0;
148         if (strcasecmp(p+1, ads->auth.realm) != 0) {
149                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
150                 if (!lp_allow_trusted_domains()) {
151                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
152                 }
153                 /* this gives a fully qualified user name (ie. with full realm).
154                    that leads to very long usernames, but what else can we do? */
155                 asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
156         } else {
157                 user = strdup(client);
158         }
159         ads_destroy(&ads);
160
161         /* the password is good - let them in */
162         pw = smb_getpwnam(user,False);
163         if (!pw && !strstr(user, lp_winbind_separator())) {
164                 char *user2;
165                 /* try it with a winbind domain prefix */
166                 asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
167                 pw = smb_getpwnam(user2,False);
168                 if (pw) {
169                         free(user);
170                         user = user2;
171                 }
172         }
173
174         if (!pw) {
175                 DEBUG(1,("Username %s is invalid on this system\n",user));
176                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
177         }
178
179         if (!make_server_info_pw(&server_info,pw)) {
180                 DEBUG(1,("make_server_info_from_pw failed!\n"));
181                 return ERROR_NT(NT_STATUS_NO_MEMORY);
182         }
183         
184         sess_vuid = register_vuid(server_info, user);
185
186         free(user);
187         free_server_info(&server_info);
188
189         if (sess_vuid == -1) {
190                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
191         }
192
193         set_message(outbuf,4,0,True);
194         SSVAL(outbuf, smb_vwv3, 0);
195         add_signature(outbuf);
196  
197         SSVAL(outbuf,smb_uid,sess_vuid);
198         SSVAL(inbuf,smb_uid,sess_vuid);
199         
200         return chain_reply(inbuf,outbuf,length,bufsize);
201 }
202 #endif
203
204
205 /****************************************************************************
206 send a security blob via a session setup reply
207 ****************************************************************************/
208 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
209                                  DATA_BLOB blob)
210 {
211         char *p;
212
213         set_message(outbuf,4,0,True);
214
215         /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
216            that we aren't finished yet */
217
218         SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
219         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
220         SSVAL(outbuf, smb_vwv3, blob.length);
221         p = smb_buf(outbuf);
222         memcpy(p, blob.data, blob.length);
223         p += blob.length;
224         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
225         p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
226         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
227         set_message_end(outbuf,p);
228         
229         return send_smb(smbd_server_fd(),outbuf);
230 }
231
232 /****************************************************************************
233 reply to a session setup spnego negotiate packet
234 ****************************************************************************/
235 static int reply_spnego_negotiate(connection_struct *conn, 
236                                   char *inbuf,
237                                   char *outbuf,
238                                   int length, int bufsize,
239                                   DATA_BLOB blob1)
240 {
241         char *OIDs[ASN1_MAX_OIDS];
242         DATA_BLOB secblob;
243         int i;
244         uint32 ntlmssp_command, neg_flags, chal_flags;
245         DATA_BLOB chal, spnego_chal, extra_data;
246         const uint8 *cryptkey;
247         BOOL got_kerberos = False;
248         NTSTATUS nt_status;
249         extern pstring global_myname;
250
251         /* parse out the OIDs and the first sec blob */
252         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
253                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
254         }
255         
256         for (i=0;OIDs[i];i++) {
257                 DEBUG(3,("Got OID %s\n", OIDs[i]));
258                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
259                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
260                         got_kerberos = True;
261                 }
262                 free(OIDs[i]);
263         }
264         DEBUG(3,("Got secblob of size %d\n", secblob.length));
265
266 #ifdef HAVE_KRB5
267         if (got_kerberos) {
268                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
269                                                 length, bufsize, &secblob);
270                 data_blob_free(&secblob);
271                 return ret;
272         }
273 #endif
274
275         /* parse the NTLMSSP packet */
276 #if 0
277         file_save("secblob.dat", secblob.data, secblob.length);
278 #endif
279
280         if (!msrpc_parse(&secblob, "CddB",
281                          "NTLMSSP",
282                          &ntlmssp_command,
283                          &neg_flags,
284                          &extra_data)) {
285                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
286         }
287        
288         DEBUG(5, ("Extra data: \n"));
289         dump_data(5, extra_data.data, extra_data.length);
290
291         data_blob_free(&secblob);
292         data_blob_free(&extra_data);
293
294         if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
295                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
296         }
297
298         DEBUG(3,("Got neg_flags=0x%08x\n", neg_flags));
299
300         debug_ntlmssp_flags(neg_flags);
301
302         if (ntlmssp_auth_context) {
303                 (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
304         }
305
306         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
307                 return ERROR_NT(nt_status);
308         }
309
310         cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
311
312         /* Give them the challenge. For now, ignore neg_flags and just
313            return the flags we want. Obviously this is not correct */
314         
315         chal_flags = NTLMSSP_NEGOTIATE_UNICODE | 
316                 NTLMSSP_NEGOTIATE_LM_KEY | 
317                 NTLMSSP_NEGOTIATE_NTLM |
318                 NTLMSSP_CHAL_TARGET_INFO;
319         
320         {
321                 DATA_BLOB domain_blob, netbios_blob, realm_blob;
322                 
323                 msrpc_gen(&domain_blob, 
324                           "U",
325                           lp_workgroup());
326
327                 msrpc_gen(&netbios_blob, 
328                           "U",
329                           global_myname);
330                 
331                 msrpc_gen(&realm_blob, 
332                           "U",
333                           lp_realm());
334                 
335
336                 msrpc_gen(&chal, "CddddbBBBB",
337                           "NTLMSSP", 
338                           NTLMSSP_CHALLENGE,
339                           0,
340                           0x30, /* ?? */
341                           chal_flags,
342                           cryptkey, 8,
343                           domain_blob.data, domain_blob.length,
344                           domain_blob.data, domain_blob.length,
345                           netbios_blob.data, netbios_blob.length,
346                           realm_blob.data, realm_blob.length);
347
348                 data_blob_free(&domain_blob);
349                 data_blob_free(&netbios_blob);
350                 data_blob_free(&realm_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);
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;
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         return chain_reply(inbuf,outbuf,length,bufsize);
499 }
500
501
502 /****************************************************************************
503 reply to a session setup spnego anonymous packet
504 ****************************************************************************/
505 static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
506                                   int length, int bufsize)
507 {
508         int sess_vuid;
509         auth_serversupplied_info *server_info = NULL;
510         NTSTATUS nt_status;
511
512         nt_status = check_guest_password(&server_info);
513
514         if (!NT_STATUS_IS_OK(nt_status)) {
515                 return ERROR_NT(nt_status_squash(nt_status));
516         }
517
518         sess_vuid = register_vuid(server_info, lp_guestaccount());
519
520         free_server_info(&server_info);
521   
522         if (sess_vuid == -1) {
523                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
524         }
525
526         set_message(outbuf,4,0,True);
527         SSVAL(outbuf, smb_vwv3, 0);
528         add_signature(outbuf);
529  
530         SSVAL(outbuf,smb_uid,sess_vuid);
531         SSVAL(inbuf,smb_uid,sess_vuid);
532         
533         return chain_reply(inbuf,outbuf,length,bufsize);
534 }
535
536
537 /****************************************************************************
538 reply to a session setup command
539 ****************************************************************************/
540 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf,
541                                         int length,int bufsize)
542 {
543         uint8 *p;
544         DATA_BLOB blob1;
545         int ret;
546
547         DEBUG(3,("Doing spnego session setup\n"));
548
549         if (global_client_caps == 0) {
550                 global_client_caps = IVAL(inbuf,smb_vwv10);
551         }
552                 
553         p = (uint8 *)smb_buf(inbuf);
554
555         if (SVAL(inbuf, smb_vwv7) == 0) {
556                 /* an anonymous request */
557                 return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize);
558         }
559
560         /* pull the spnego blob */
561         blob1 = data_blob(p, SVAL(inbuf, smb_vwv7));
562
563 #if 0
564         file_save("negotiate.dat", blob1.data, blob1.length);
565 #endif
566
567         if (blob1.data[0] == ASN1_APPLICATION(0)) {
568                 /* its a negTokenTarg packet */
569                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
570                 data_blob_free(&blob1);
571                 return ret;
572         }
573
574         if (blob1.data[0] == ASN1_CONTEXT(1)) {
575                 /* its a auth packet */
576                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
577                 data_blob_free(&blob1);
578                 return ret;
579         }
580
581         /* what sort of packet is this? */
582         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
583
584         data_blob_free(&blob1);
585
586         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
587 }
588
589
590 /****************************************************************************
591 reply to a session setup command
592 ****************************************************************************/
593 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
594                           int length,int bufsize)
595 {
596         int sess_vuid;
597         int   smb_bufsize;    
598         DATA_BLOB lm_resp;
599         DATA_BLOB nt_resp;
600         DATA_BLOB plaintext_password;
601         pstring user;
602         pstring sub_user; /* Sainitised username for substituion */
603         fstring domain;
604         fstring native_os;
605         fstring native_lanman;
606         static BOOL done_sesssetup = False;
607         extern BOOL global_encrypted_passwords_negotiated;
608         extern BOOL global_spnego_negotiated;
609         extern int Protocol;
610         extern fstring remote_machine;
611         extern userdom_struct current_user_info;
612         extern int max_send;
613
614         auth_usersupplied_info *user_info = NULL;
615         extern struct auth_context *negprot_global_auth_context;
616         auth_serversupplied_info *server_info = NULL;
617
618         NTSTATUS nt_status;
619
620         BOOL doencrypt = global_encrypted_passwords_negotiated;
621
622         START_PROFILE(SMBsesssetupX);
623
624         ZERO_STRUCT(lm_resp);
625         ZERO_STRUCT(nt_resp);
626         ZERO_STRUCT(plaintext_password);
627
628         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
629
630         /* a SPNEGO session setup has 12 command words, whereas a normal
631            NT1 session setup has 13. See the cifs spec. */
632         if (CVAL(inbuf, smb_wct) == 12 &&
633             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
634                 if (!global_spnego_negotiated) {
635                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
636                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
637                 }
638
639                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
640         }
641
642         smb_bufsize = SVAL(inbuf,smb_vwv2);
643
644         if (Protocol < PROTOCOL_NT1) {
645                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
646                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
647                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
648                 }
649
650                 if (doencrypt) {
651                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
652                 } else {
653                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
654                         /* Ensure null termination */
655                         plaintext_password.data[passlen1] = 0;
656                 }
657
658                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
659                 *domain = 0;
660   
661         } else {
662                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
663                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
664                 enum remote_arch_types ra_type = get_remote_arch();
665                 char *p = smb_buf(inbuf);    
666
667                 if(global_client_caps == 0)
668                         global_client_caps = IVAL(inbuf,smb_vwv11);
669                 
670                 /* client_caps is used as final determination if client is NT or Win95. 
671                    This is needed to return the correct error codes in some
672                    circumstances.
673                 */
674                 
675                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
676                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
677                                 set_remote_arch( RA_WIN95);
678                         }
679                 }
680                 
681                 if (!doencrypt) {
682                         /* both Win95 and WinNT stuff up the password lengths for
683                            non-encrypting systems. Uggh. 
684                            
685                            if passlen1==24 its a win95 system, and its setting the
686                            password length incorrectly. Luckily it still works with the
687                            default code because Win95 will null terminate the password
688                            anyway 
689                            
690                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
691                            setting passlen2 to some random value which really stuffs
692                            things up. we need to fix that one.  */
693                         
694                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
695                                 passlen2 = 0;
696                 }
697                 
698                 /* check for nasty tricks */
699                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
700                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
701                 }
702
703                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
704                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
705                 }
706
707                 /* Save the lanman2 password and the NT md4 password. */
708                 
709                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
710                         doencrypt = False;
711                 }
712
713                 if (doencrypt) {
714                         lm_resp = data_blob(p, passlen1);
715                         nt_resp = data_blob(p+passlen1, passlen2);
716                 } else {
717                         pstring pass;
718                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
719                                     sizeof(pass),  passlen1, STR_TERMINATE);
720                         plaintext_password = data_blob(pass, strlen(pass)+1);
721                 }
722                 
723                 p += passlen1 + passlen2;
724                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
725                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
726                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
727                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
728                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
729                          domain,native_os,native_lanman));
730         }
731         
732         /* don't allow for weird usernames or domains */
733         alpha_strcpy(user, user, ". _-$", sizeof(user));
734         alpha_strcpy(domain, domain, ". _-", sizeof(domain));
735         if (strstr(user, "..") || strstr(domain,"..")) {
736                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
737         }
738
739         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
740
741         if (*user) {
742                 if (global_spnego_negotiated) {
743                         
744                         /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
745                         
746                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
747                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
748                 }
749                 pstrcpy(sub_user, user);
750         } else {
751                 pstrcpy(sub_user, lp_guestaccount());
752         }
753
754         pstrcpy(current_user_info.smb_name,sub_user);
755
756         reload_services(True);
757         
758         if (lp_security() == SEC_SHARE) {
759                 /* in share level we should ignore any passwords */
760
761                 data_blob_free(&lm_resp);
762                 data_blob_free(&nt_resp);
763                 data_blob_clear_free(&plaintext_password);
764
765                 map_username(sub_user);
766                 add_session_user(sub_user);
767                 /* Then force it to null for the benfit of the code below */
768                 *user = 0;
769         }
770         
771         if (!*user) {
772
773                 nt_status = check_guest_password(&server_info);
774
775         } else if (doencrypt) {
776                 if (!make_user_info_for_reply_enc(&user_info, 
777                                                   user, domain, 
778                                                   lm_resp, nt_resp)) {
779                         nt_status = NT_STATUS_NO_MEMORY;
780                 } else {
781                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
782                                                                                      user_info, 
783                                                                                      &server_info);
784                 }
785         } else {
786                 struct auth_context *plaintext_auth_context = NULL;
787                 const uint8 *chal;
788                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
789                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
790                         
791                         if (!make_user_info_for_reply(&user_info, 
792                                                       user, domain, chal,
793                                                       plaintext_password)) {
794                                 nt_status = NT_STATUS_NO_MEMORY;
795                         }
796                 
797                         if (NT_STATUS_IS_OK(nt_status)) {
798                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
799                                                                                         user_info, 
800                                                                                         &server_info); 
801                                 
802                                 (plaintext_auth_context->free)(&plaintext_auth_context);
803                         }
804                 }
805         }
806
807         free_user_info(&user_info);
808         
809         data_blob_free(&lm_resp);
810         data_blob_free(&nt_resp);
811         data_blob_clear_free(&plaintext_password);
812         
813         if (!NT_STATUS_IS_OK(nt_status)) {
814                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
815         }
816         
817         if (!NT_STATUS_IS_OK(nt_status)) {
818                 return ERROR_NT(nt_status_squash(nt_status));
819         }
820         
821         /* it's ok - setup a reply */
822         if (Protocol < PROTOCOL_NT1) {
823                 set_message(outbuf,3,0,True);
824         } else {
825                 set_message(outbuf,3,0,True);
826                 add_signature(outbuf);
827                 /* perhaps grab OS version here?? */
828         }
829         
830         if (server_info->guest) {
831                 SSVAL(outbuf,smb_vwv2,1);
832         }
833
834         /* register the name and uid as being validated, so further connections
835            to a uid can get through without a password, on the same VC */
836
837         sess_vuid = register_vuid(server_info, sub_user);
838
839         free_server_info(&server_info);
840   
841         if (sess_vuid == -1) {
842                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
843         }
844
845  
846         SSVAL(outbuf,smb_uid,sess_vuid);
847         SSVAL(inbuf,smb_uid,sess_vuid);
848         
849         if (!done_sesssetup)
850                 max_send = MIN(max_send,smb_bufsize);
851         
852         done_sesssetup = True;
853         
854         END_PROFILE(SMBsesssetupX);
855         return chain_reply(inbuf,outbuf,length,bufsize);
856 }