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