convert snprintf() calls using pstrings & fstrings
[ira/wip.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         fstr_sprintf( 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         DATA_BLOB nullblob = data_blob(NULL, 0);
157
158         ZERO_STRUCT(ticket);
159         ZERO_STRUCT(auth_data);
160         ZERO_STRUCT(ap_rep);
161         ZERO_STRUCT(ap_rep_wrapped);
162         ZERO_STRUCT(response);
163
164         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
165                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
166         }
167
168         ads = ads_init_simple();
169
170         if (!ads) {
171                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
172         }
173
174         ads->auth.realm = strdup(lp_realm());
175
176         ret = ads_verify_ticket(ads, &ticket, &client, &auth_data, &ap_rep, session_key);
177         if (!NT_STATUS_IS_OK(ret)) {
178                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
179                 ads_destroy(&ads);
180                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
181         }
182
183         data_blob_free(&auth_data);
184
185         DEBUG(3,("Ticket name is [%s]\n", client));
186
187         p = strchr_m(client, '@');
188         if (!p) {
189                 DEBUG(3,("Doesn't look like a valid principal\n"));
190                 ads_destroy(&ads);
191                 data_blob_free(&ap_rep);
192                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
193         }
194
195         *p = 0;
196         if (strcasecmp(p+1, ads->auth.realm) != 0) {
197                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
198                 if (!lp_allow_trusted_domains()) {
199                         data_blob_free(&ap_rep);
200                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
201                 }
202                 foreign = True;
203         }
204
205         /* this gives a fully qualified user name (ie. with full realm).
206            that leads to very long usernames, but what else can we do? */
207         asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
208         
209         pw = Get_Pwnam(user);
210         if (!pw && !foreign) {
211                 pw = Get_Pwnam(client);
212                 SAFE_FREE(user);
213                 user = smb_xstrdup(client);
214         }
215
216         ads_destroy(&ads);
217
218         /* setup the string used by %U */
219         sub_set_smb_name(user);
220
221         reload_services(True);
222
223         if (!pw) {
224                 DEBUG(1,("Username %s is invalid on this system\n",user));
225                 data_blob_free(&ap_rep);
226                 return ERROR_NT(NT_STATUS_NO_SUCH_USER);
227         }
228
229         if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
230                 DEBUG(1,("make_server_info_from_pw failed!\n"));
231                 data_blob_free(&ap_rep);
232                 return ERROR_NT(ret);
233         }
234
235         /* Copy out the session key from the AP_REQ. */
236         memcpy(server_info->session_key, session_key, sizeof(session_key));
237
238         /* register_vuid keeps the server info */
239         sess_vuid = register_vuid(server_info, nullblob, user);
240
241         free(user);
242
243         if (sess_vuid == -1) {
244                 ret = NT_STATUS_LOGON_FAILURE;
245         } else {
246                 set_message(outbuf,4,0,True);
247                 SSVAL(outbuf, smb_vwv3, 0);
248                         
249                 if (server_info->guest) {
250                         SSVAL(outbuf,smb_vwv2,1);
251                 }
252                 
253                 SSVAL(outbuf, smb_uid, sess_vuid);
254
255                 if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
256                         exit_server("reply_spnego_kerberos: bad smb signature");
257                 }
258         }
259
260         /* wrap that up in a nice GSS-API wrapping */
261         if (NT_STATUS_IS_OK(ret)) {
262                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
263         } else {
264                 ap_rep_wrapped = data_blob(NULL, 0);
265         }
266         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
267         reply_sesssetup_blob(conn, outbuf, response, ret);
268
269         data_blob_free(&ap_rep);
270         data_blob_free(&ap_rep_wrapped);
271         data_blob_free(&response);
272
273         return -1; /* already replied */
274 }
275 #endif
276
277 /****************************************************************************
278  Send a session setup reply, wrapped in SPNEGO.
279  Get vuid and check first.
280  End the NTLMSSP exchange context if we are OK/complete fail
281 ***************************************************************************/
282
283 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
284                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
285                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
286 {
287         BOOL ret;
288         DATA_BLOB response;
289         struct auth_serversupplied_info *server_info = NULL;
290
291         if (NT_STATUS_IS_OK(nt_status)) {
292                 server_info = (*auth_ntlmssp_state)->server_info;
293         } else {
294                 nt_status = do_map_to_guest(nt_status, 
295                                             &server_info, 
296                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
297                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
298         }
299
300         if (NT_STATUS_IS_OK(nt_status)) {
301                 int sess_vuid;
302                 DATA_BLOB nullblob = data_blob(NULL, 0);
303
304                 /* register_vuid keeps the server info */
305                 sess_vuid = register_vuid(server_info, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
306                 (*auth_ntlmssp_state)->server_info = NULL;
307
308                 if (sess_vuid == -1) {
309                         nt_status = NT_STATUS_LOGON_FAILURE;
310                 } else {
311                         
312                         set_message(outbuf,4,0,True);
313                         SSVAL(outbuf, smb_vwv3, 0);
314                         
315                         if (server_info->guest) {
316                                 SSVAL(outbuf,smb_vwv2,1);
317                         }
318                         
319                         SSVAL(outbuf,smb_uid,sess_vuid);
320
321                         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
322                                 exit_server("reply_spnego_ntlmssp: bad smb signature");
323                         }
324
325                 }
326         }
327
328         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
329         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
330         data_blob_free(&response);
331
332         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
333            and the other end, that we are not finished yet. */
334
335         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
336                 auth_ntlmssp_end(auth_ntlmssp_state);
337         }
338
339         return ret;
340 }
341
342 /****************************************************************************
343  Reply to a session setup spnego negotiate packet.
344 ****************************************************************************/
345
346 static int reply_spnego_negotiate(connection_struct *conn, 
347                                   char *inbuf,
348                                   char *outbuf,
349                                   int length, int bufsize,
350                                   DATA_BLOB blob1)
351 {
352         char *OIDs[ASN1_MAX_OIDS];
353         DATA_BLOB secblob;
354         int i;
355         DATA_BLOB chal;
356         BOOL got_kerberos = False;
357         NTSTATUS nt_status;
358
359         /* parse out the OIDs and the first sec blob */
360         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
361                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
362         }
363         
364         for (i=0;OIDs[i];i++) {
365                 DEBUG(3,("Got OID %s\n", OIDs[i]));
366                 if (strcmp(OID_KERBEROS5, OIDs[i]) == 0 ||
367                     strcmp(OID_KERBEROS5_OLD, OIDs[i]) == 0) {
368                         got_kerberos = True;
369                 }
370                 free(OIDs[i]);
371         }
372         DEBUG(3,("Got secblob of size %d\n", secblob.length));
373
374 #ifdef HAVE_KRB5
375         if (got_kerberos && (SEC_ADS == lp_security())) {
376                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
377                                                 length, bufsize, &secblob);
378                 data_blob_free(&secblob);
379                 return ret;
380         }
381 #endif
382
383         if (global_ntlmssp_state) {
384                 auth_ntlmssp_end(&global_ntlmssp_state);
385         }
386
387         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
388         if (!NT_STATUS_IS_OK(nt_status)) {
389                 return ERROR_NT(nt_status);
390         }
391
392         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
393                                         secblob, &chal);
394
395         data_blob_free(&secblob);
396
397         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
398                              &chal, nt_status);
399                 
400         data_blob_free(&chal);
401
402         /* already replied */
403         return -1;
404 }
405         
406 /****************************************************************************
407  Reply to a session setup spnego auth packet.
408 ****************************************************************************/
409
410 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
411                              int length, int bufsize,
412                              DATA_BLOB blob1)
413 {
414         DATA_BLOB auth, auth_reply;
415         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
416
417         if (!spnego_parse_auth(blob1, &auth)) {
418 #if 0
419                 file_save("auth.dat", blob1.data, blob1.length);
420 #endif
421                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
422         }
423         
424         if (!global_ntlmssp_state) {
425                 /* auth before negotiatiate? */
426                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
427         }
428         
429         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
430                                                 auth, &auth_reply);
431
432         data_blob_free(&auth);
433
434         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
435                              &auth_reply, nt_status);
436                 
437         data_blob_free(&auth_reply);
438
439         /* and tell smbd that we have already replied to this packet */
440         return -1;
441 }
442
443 /****************************************************************************
444  Reply to a session setup command.
445 ****************************************************************************/
446
447 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
448                                         char *outbuf,
449                                         int length,int bufsize)
450 {
451         uint8 *p;
452         DATA_BLOB blob1;
453         int ret;
454         size_t bufrem;
455         fstring native_os, native_lanman;
456         char *p2;
457         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
458         enum remote_arch_types ra_type = get_remote_arch();
459
460         DEBUG(3,("Doing spnego session setup\n"));
461
462         if (global_client_caps == 0) {
463                 global_client_caps = IVAL(inbuf,smb_vwv10);
464         }
465                 
466         p = (uint8 *)smb_buf(inbuf);
467
468         if (data_blob_len == 0) {
469                 /* an invalid request */
470                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
471         }
472
473         bufrem = smb_bufrem(inbuf, p);
474         /* pull the spnego blob */
475         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
476
477 #if 0
478         file_save("negotiate.dat", blob1.data, blob1.length);
479 #endif
480
481         p2 = inbuf + smb_vwv13 + data_blob_len;
482         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
483         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
484         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s]\n", native_os, native_lanman));
485
486         if ( ra_type == RA_WIN2K )
487                 ra_lanman_string( native_lanman );
488
489         if (blob1.data[0] == ASN1_APPLICATION(0)) {
490                 /* its a negTokenTarg packet */
491                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
492                 data_blob_free(&blob1);
493                 return ret;
494         }
495
496         if (blob1.data[0] == ASN1_CONTEXT(1)) {
497                 /* its a auth packet */
498                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
499                 data_blob_free(&blob1);
500                 return ret;
501         }
502
503         /* what sort of packet is this? */
504         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
505
506         data_blob_free(&blob1);
507
508         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
509 }
510
511 /****************************************************************************
512  On new VC == 0, shutdown *all* old connections and users.
513  It seems that only NT4.x does this. At W2K and above (XP etc.).
514  a new session setup with VC==0 is ignored.
515 ****************************************************************************/
516
517 static void setup_new_vc_session(void)
518 {
519         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
520 #if 0
521         conn_close_all();
522         invalidate_all_vuids();
523 #endif
524 }
525
526 /****************************************************************************
527  Reply to a session setup command.
528 ****************************************************************************/
529
530 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
531                           int length,int bufsize)
532 {
533         int sess_vuid;
534         int   smb_bufsize;    
535         DATA_BLOB lm_resp;
536         DATA_BLOB nt_resp;
537         DATA_BLOB plaintext_password;
538         fstring user;
539         fstring sub_user; /* Sainitised username for substituion */
540         fstring domain;
541         fstring native_os;
542         fstring native_lanman;
543         static BOOL done_sesssetup = False;
544         extern BOOL global_encrypted_passwords_negotiated;
545         extern BOOL global_spnego_negotiated;
546         extern int Protocol;
547         extern int max_send;
548
549         auth_usersupplied_info *user_info = NULL;
550         extern struct auth_context *negprot_global_auth_context;
551         auth_serversupplied_info *server_info = NULL;
552
553         NTSTATUS nt_status;
554
555         BOOL doencrypt = global_encrypted_passwords_negotiated;
556         
557         START_PROFILE(SMBsesssetupX);
558
559         ZERO_STRUCT(lm_resp);
560         ZERO_STRUCT(nt_resp);
561         ZERO_STRUCT(plaintext_password);
562
563         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
564
565         /* a SPNEGO session setup has 12 command words, whereas a normal
566            NT1 session setup has 13. See the cifs spec. */
567         if (CVAL(inbuf, smb_wct) == 12 &&
568             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
569                 if (!global_spnego_negotiated) {
570                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
571                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
572                 }
573
574                 if (SVAL(inbuf,smb_vwv4) == 0) {
575                         setup_new_vc_session();
576                 }
577                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
578         }
579
580         smb_bufsize = SVAL(inbuf,smb_vwv2);
581
582         if (Protocol < PROTOCOL_NT1) {
583                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
584                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
585                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
586                 }
587
588                 if (doencrypt) {
589                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
590                 } else {
591                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
592                         /* Ensure null termination */
593                         plaintext_password.data[passlen1] = 0;
594                 }
595
596                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
597                 *domain = 0;
598
599         } else {
600                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
601                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
602                 enum remote_arch_types ra_type = get_remote_arch();
603                 char *p = smb_buf(inbuf);    
604
605                 if(global_client_caps == 0)
606                         global_client_caps = IVAL(inbuf,smb_vwv11);
607                 
608                 /* client_caps is used as final determination if client is NT or Win95. 
609                    This is needed to return the correct error codes in some
610                    circumstances.
611                 */
612                 
613                 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
614                         if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
615                                 set_remote_arch( RA_WIN95);
616                         }
617                 }
618
619                 if (!doencrypt) {
620                         /* both Win95 and WinNT stuff up the password lengths for
621                            non-encrypting systems. Uggh. 
622                            
623                            if passlen1==24 its a win95 system, and its setting the
624                            password length incorrectly. Luckily it still works with the
625                            default code because Win95 will null terminate the password
626                            anyway 
627                            
628                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
629                            setting passlen2 to some random value which really stuffs
630                            things up. we need to fix that one.  */
631                         
632                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
633                                 passlen2 = 0;
634                 }
635                 
636                 /* check for nasty tricks */
637                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
638                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
639                 }
640
641                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
642                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
643                 }
644
645                 /* Save the lanman2 password and the NT md4 password. */
646                 
647                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
648                         doencrypt = False;
649                 }
650
651                 if (doencrypt) {
652                         lm_resp = data_blob(p, passlen1);
653                         nt_resp = data_blob(p+passlen1, passlen2);
654                 } else {
655                         pstring pass;
656                         BOOL unic;
657                         unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
658                         srvstr_pull(inbuf, pass, smb_buf(inbuf), 
659                                     sizeof(pass),  unic ? passlen2 : passlen1, 
660                                     STR_TERMINATE);
661                         plaintext_password = data_blob(pass, strlen(pass)+1);
662                 }
663                 
664                 p += passlen1 + passlen2;
665                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
666                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
667                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
668                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
669                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
670                          domain,native_os,native_lanman));
671
672                 if ( ra_type == RA_WIN2K )
673                         ra_lanman_string( native_lanman );
674
675         }
676         
677         if (SVAL(inbuf,smb_vwv4) == 0) {
678                 setup_new_vc_session();
679         }
680
681         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
682
683         if (*user) {
684                 if (global_spnego_negotiated) {
685                         
686                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
687                         
688                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
689                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
690                 }
691                 fstrcpy(sub_user, user);
692
693                 /* setup the string used by %U */
694                 sub_set_smb_name(user);
695         } else {
696                 fstrcpy(sub_user, lp_guestaccount());
697         }
698
699         sub_set_smb_name(sub_user);
700
701         reload_services(True);
702         
703         if (lp_security() == SEC_SHARE) {
704                 /* in share level we should ignore any passwords */
705
706                 data_blob_free(&lm_resp);
707                 data_blob_free(&nt_resp);
708                 data_blob_clear_free(&plaintext_password);
709
710                 map_username(sub_user);
711                 add_session_user(sub_user);
712                 /* Then force it to null for the benfit of the code below */
713                 *user = 0;
714         }
715         
716         if (!*user) {
717
718                 nt_status = check_guest_password(&server_info);
719
720         } else if (doencrypt) {
721                 if (!negprot_global_auth_context) {
722                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
723                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
724                 }
725                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
726                                                          lm_resp, nt_resp);
727                 if (NT_STATUS_IS_OK(nt_status)) {
728                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
729                                                                                      user_info, 
730                                                                                      &server_info);
731                 }
732         } else {
733                 struct auth_context *plaintext_auth_context = NULL;
734                 const uint8 *chal;
735                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
736                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
737                         
738                         if (!make_user_info_for_reply(&user_info, 
739                                                       user, domain, chal,
740                                                       plaintext_password)) {
741                                 nt_status = NT_STATUS_NO_MEMORY;
742                         }
743                 
744                         if (NT_STATUS_IS_OK(nt_status)) {
745                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
746                                                                                         user_info, 
747                                                                                         &server_info); 
748                                 
749                                 (plaintext_auth_context->free)(&plaintext_auth_context);
750                         }
751                 }
752         }
753
754         free_user_info(&user_info);
755         
756         data_blob_free(&lm_resp);
757         data_blob_clear_free(&plaintext_password);
758         
759         if (!NT_STATUS_IS_OK(nt_status)) {
760                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
761         }
762         
763         if (!NT_STATUS_IS_OK(nt_status)) {
764                 data_blob_free(&nt_resp);
765                 return ERROR_NT(nt_status_squash(nt_status));
766         }
767
768         /* it's ok - setup a reply */
769         set_message(outbuf,3,0,True);
770         if (Protocol >= PROTOCOL_NT1) {
771                 char *p = smb_buf( outbuf );
772                 p += add_signature( outbuf, p );
773                 set_message_end( outbuf, p );
774                 /* perhaps grab OS version here?? */
775         }
776         
777         if (server_info->guest) {
778                 SSVAL(outbuf,smb_vwv2,1);
779         }
780
781         /* register the name and uid as being validated, so further connections
782            to a uid can get through without a password, on the same VC */
783
784         /* register_vuid keeps the server info */
785         sess_vuid = register_vuid(server_info, nt_resp, sub_user);
786         data_blob_free(&nt_resp);
787
788         if (sess_vuid == -1) {
789                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
790         }
791
792         if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
793                 exit_server("reply_sesssetup_and_X: bad smb signature");
794         }
795
796         SSVAL(outbuf,smb_uid,sess_vuid);
797         SSVAL(inbuf,smb_uid,sess_vuid);
798         
799         if (!done_sesssetup)
800                 max_send = MIN(max_send,smb_bufsize);
801         
802         done_sesssetup = True;
803         
804         END_PROFILE(SMBsesssetupX);
805         return chain_reply(inbuf,outbuf,length,bufsize);
806 }