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