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