r7020: fixing printer ace values and getting rid of false compiler warning about...
[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 <jmcd@us.ibm.com> 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 extern BOOL global_encrypted_passwords_negotiated;
29 extern BOOL global_spnego_negotiated;
30 extern enum protocol_types Protocol;
31 extern int max_send;
32 extern struct auth_context *negprot_global_auth_context;
33
34 static struct auth_ntlmssp_state *global_ntlmssp_state;
35
36 /*
37   on a logon error possibly map the error to success if "map to guest"
38   is set approriately
39 */
40 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
41                                 const char *user, const char *domain)
42 {
43         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
44                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
45                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
46                         DEBUG(3,("No such user %s [%s] - using guest account\n",
47                                  user, domain));
48                         status = make_server_info_guest(server_info);
49                 }
50         }
51
52         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
53                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
54                         DEBUG(3,("Registered username %s for guest access\n",user));
55                         status = make_server_info_guest(server_info);
56                 }
57         }
58
59         return status;
60 }
61
62 /****************************************************************************
63  Add the standard 'Samba' signature to the end of the session setup.
64 ****************************************************************************/
65
66 static int add_signature(char *outbuf, char *p)
67 {
68         char *start = p;
69         fstring lanman;
70
71         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
72
73         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
74         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
75         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
76
77         return PTR_DIFF(p, start);
78 }
79
80 /****************************************************************************
81  Send a security blob via a session setup reply.
82 ****************************************************************************/
83
84 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
85                                  DATA_BLOB blob, NTSTATUS nt_status)
86 {
87         char *p;
88
89         set_message(outbuf,4,0,True);
90
91         nt_status = nt_status_squash(nt_status);
92         SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
93         SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
94         SSVAL(outbuf, smb_vwv3, blob.length);
95         p = smb_buf(outbuf);
96
97         /* should we cap this? */
98         memcpy(p, blob.data, blob.length);
99         p += blob.length;
100
101         p += add_signature( outbuf, p );
102
103         set_message_end(outbuf,p);
104
105         return send_smb(smbd_server_fd(),outbuf);
106 }
107
108 /****************************************************************************
109  Do a 'guest' logon, getting back the 
110 ****************************************************************************/
111
112 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
113 {
114         struct auth_context *auth_context;
115         auth_usersupplied_info *user_info = NULL;
116         
117         NTSTATUS nt_status;
118         unsigned char chal[8];
119
120         ZERO_STRUCT(chal);
121
122         DEBUG(3,("Got anonymous request\n"));
123
124         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
125                 return nt_status;
126         }
127
128
129         if (!make_user_info_guest(&user_info)) {
130                 (auth_context->free)(&auth_context);
131                 return NT_STATUS_NO_MEMORY;
132         }
133         
134         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
135         (auth_context->free)(&auth_context);
136         free_user_info(&user_info);
137         return nt_status;
138 }
139
140
141 #ifdef HAVE_KRB5
142 /****************************************************************************
143 reply to a session setup spnego negotiate packet for kerberos
144 ****************************************************************************/
145 static int reply_spnego_kerberos(connection_struct *conn, 
146                                  char *inbuf, char *outbuf,
147                                  int length, int bufsize,
148                                  DATA_BLOB *secblob)
149 {
150         int map_domainuser_to_guest = 0;
151         DATA_BLOB ticket;
152         char *client, *p, *domain;
153         fstring netbios_domain_name;
154         struct passwd *pw;
155         char *user;
156         int sess_vuid;
157         NTSTATUS ret;
158         DATA_BLOB auth_data;
159         DATA_BLOB ap_rep, ap_rep_wrapped, response;
160         auth_serversupplied_info *server_info = NULL;
161         DATA_BLOB session_key = data_blob(NULL, 0);
162         uint8 tok_id[2];
163         DATA_BLOB nullblob = data_blob(NULL, 0);
164         fstring real_username;
165
166         ZERO_STRUCT(ticket);
167         ZERO_STRUCT(auth_data);
168         ZERO_STRUCT(ap_rep);
169         ZERO_STRUCT(ap_rep_wrapped);
170         ZERO_STRUCT(response);
171
172         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
173                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
174         }
175
176         ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
177
178         data_blob_free(&ticket);
179
180         if (!NT_STATUS_IS_OK(ret)) {
181                 DEBUG(1,("Failed to verify incoming ticket!\n"));       
182                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
183         }
184
185         data_blob_free(&auth_data);
186
187         DEBUG(3,("Ticket name is [%s]\n", client));
188
189         p = strchr_m(client, '@');
190         if (!p) {
191                 DEBUG(3,("Doesn't look like a valid principal\n"));
192                 data_blob_free(&ap_rep);
193                 data_blob_free(&session_key);
194                 SAFE_FREE(client);
195                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
196         }
197
198         *p = 0;
199         if (!strequal(p+1, lp_realm())) {
200                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
201                 if (!lp_allow_trusted_domains()) {
202                         data_blob_free(&ap_rep);
203                         data_blob_free(&session_key);
204                         SAFE_FREE(client);
205                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
206                 }
207         }
208
209         /* this gives a fully qualified user name (ie. with full realm).
210            that leads to very long usernames, but what else can we do? */
211
212         domain = p+1;
213
214         {
215                 /* If we have winbind running, we can (and must) shorten the
216                    username by using the short netbios name. Otherwise we will
217                    have inconsistent user names. With Kerberos, we get the
218                    fully qualified realm, with ntlmssp we get the short
219                    name. And even w2k3 does use ntlmssp if you for example
220                    connect to an ip address. */
221
222                 struct winbindd_request wb_request;
223                 struct winbindd_response wb_response;
224                 NSS_STATUS wb_result;
225
226                 ZERO_STRUCT(wb_request);
227                 ZERO_STRUCT(wb_response);
228
229                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
230
231                 fstrcpy(wb_request.domain_name, domain);
232
233                 wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
234                                              &wb_request, &wb_response);
235
236                 if (wb_result == NSS_STATUS_SUCCESS) {
237
238                         fstrcpy(netbios_domain_name,
239                                 wb_response.data.domain_info.name);
240                         domain = netbios_domain_name;
241
242                         DEBUG(10, ("Mapped to [%s]\n", domain));
243                 } else {
244                         DEBUG(3, ("Could not find short name -- winbind "
245                                   "not running?\n"));
246                 }
247         }
248
249         asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
250         /* lookup the passwd struct, create a new user if necessary */
251                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_VALID_DOMAIN_USER ){ 
252                         map_domainuser_to_guest == 1;
253                         fstrcpy(user,lp_guestaccount());
254                         pw = smb_getpwnam( user, real_username, True );
255                 } else {
256
257         map_username( user );
258
259         pw = smb_getpwnam( user, real_username, True );
260         
261         if (!pw) {
262                 }
263                 DEBUG(1,("Username %s is invalid on this system\n",user));
264                 SAFE_FREE(user);
265                 SAFE_FREE(client);
266                 data_blob_free(&ap_rep);
267                 data_blob_free(&session_key);
268                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
269         }
270
271         /* setup the string used by %U */
272         
273         sub_set_smb_name( real_username );
274         reload_services(True);
275         if (map_domainuser_to_guest == 1) {                     
276                         make_server_info_guest(&server_info);
277         }else{
278          if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw))) 
279         {
280                 DEBUG(1,("make_server_info_from_pw failed!\n"));
281                 SAFE_FREE(user);
282                 SAFE_FREE(client);
283                 data_blob_free(&ap_rep);
284
285                 data_blob_free(&session_key);
286                 return ERROR_NT(ret);
287         }
288         }
289
290         /* make_server_info_pw does not set the domain. Without this we end up
291          * with the local netbios name in substitutions for %D. */
292
293         if (server_info->sam_account != NULL) {
294                 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
295         }
296
297         /* register_vuid keeps the server info */
298         /* register_vuid takes ownership of session_key, no need to free after this.
299            A better interface would copy it.... */
300         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
301
302         SAFE_FREE(user);
303         SAFE_FREE(client);
304
305         if (sess_vuid == -1) {
306                 ret = NT_STATUS_LOGON_FAILURE;
307         } else {
308                 /* current_user_info is changed on new vuid */
309                 reload_services( True );
310
311                 set_message(outbuf,4,0,True);
312                 SSVAL(outbuf, smb_vwv3, 0);
313                         
314                 if (server_info->guest) {
315                         SSVAL(outbuf,smb_vwv2,1);
316                 }
317                 
318                 SSVAL(outbuf, smb_uid, sess_vuid);
319
320                 if (!server_info->guest && !srv_signing_started()) {
321                         /* We need to start the signing engine
322                          * here but a W2K client sends the old
323                          * "BSRSPYL " signature instead of the
324                          * correct one. Subsequent packets will
325                          * be correct.
326                          */
327                         srv_check_sign_mac(inbuf, False);
328                 }
329         }
330
331         /* wrap that up in a nice GSS-API wrapping */
332         if (NT_STATUS_IS_OK(ret)) {
333                 ap_rep_wrapped = spnego_gen_krb5_wrap(
334                         ap_rep,
335                         CONST_ADD(const uint8 *, TOK_ID_KRB_AP_REP));
336         } else {
337                 ap_rep_wrapped = data_blob(NULL, 0);
338         }
339         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
340         reply_sesssetup_blob(conn, outbuf, response, ret);
341
342         data_blob_free(&ap_rep);
343         data_blob_free(&ap_rep_wrapped);
344         data_blob_free(&response);
345
346         return -1; /* already replied */
347 }
348 #endif
349
350 /****************************************************************************
351  Send a session setup reply, wrapped in SPNEGO.
352  Get vuid and check first.
353  End the NTLMSSP exchange context if we are OK/complete fail
354 ***************************************************************************/
355
356 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
357                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
358                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) 
359 {
360         BOOL ret;
361         DATA_BLOB response;
362         struct auth_serversupplied_info *server_info = NULL;
363
364         if (NT_STATUS_IS_OK(nt_status)) {
365                 server_info = (*auth_ntlmssp_state)->server_info;
366         } else {
367                 nt_status = do_map_to_guest(nt_status, 
368                                             &server_info, 
369                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
370                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
371         }
372
373         if (NT_STATUS_IS_OK(nt_status)) {
374                 int sess_vuid;
375                 DATA_BLOB nullblob = data_blob(NULL, 0);
376                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
377
378                 /* register_vuid keeps the server info */
379                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
380                 (*auth_ntlmssp_state)->server_info = NULL;
381
382                 if (sess_vuid == -1) {
383                         nt_status = NT_STATUS_LOGON_FAILURE;
384                 } else {
385                         
386                         /* current_user_info is changed on new vuid */
387                         reload_services( True );
388
389                         set_message(outbuf,4,0,True);
390                         SSVAL(outbuf, smb_vwv3, 0);
391                         
392                         if (server_info->guest) {
393                                 SSVAL(outbuf,smb_vwv2,1);
394                         }
395                         
396                         SSVAL(outbuf,smb_uid,sess_vuid);
397
398                         if (!server_info->guest && !srv_signing_started()) {
399                                 /* We need to start the signing engine
400                                  * here but a W2K client sends the old
401                                  * "BSRSPYL " signature instead of the
402                                  * correct one. Subsequent packets will
403                                  * be correct.
404                                  */
405
406                                 srv_check_sign_mac(inbuf, False);
407                         }
408                 }
409         }
410
411         response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
412         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
413         data_blob_free(&response);
414
415         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
416            and the other end, that we are not finished yet. */
417
418         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
419                 auth_ntlmssp_end(auth_ntlmssp_state);
420         }
421
422         return ret;
423 }
424
425 /****************************************************************************
426  Reply to a session setup spnego negotiate packet.
427 ****************************************************************************/
428
429 static int reply_spnego_negotiate(connection_struct *conn, 
430                                   char *inbuf,
431                                   char *outbuf,
432                                   int length, int bufsize,
433                                   DATA_BLOB blob1)
434 {
435         char *OIDs[ASN1_MAX_OIDS];
436         DATA_BLOB secblob;
437         int i;
438         DATA_BLOB chal;
439 #ifdef HAVE_KRB5
440         BOOL got_kerberos_mechanism = False;
441 #endif
442         NTSTATUS nt_status;
443
444         /* parse out the OIDs and the first sec blob */
445         if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
446                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
447         }
448
449         /* only look at the first OID for determining the mechToken --
450            accoirding to RFC2478, we should choose the one we want 
451            and renegotiate, but i smell a client bug here..  
452            
453            Problem observed when connecting to a member (samba box) 
454            of an AD domain as a user in a Samba domain.  Samba member 
455            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
456            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
457            NTLMSSP mechtoken.                 --jerry              */
458
459 #ifdef HAVE_KRB5        
460         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
461             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
462                 got_kerberos_mechanism = True;
463         }
464 #endif
465                 
466         for (i=0;OIDs[i];i++) {
467                 DEBUG(3,("Got OID %s\n", OIDs[i]));
468                 free(OIDs[i]);
469         }
470         DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
471
472 #ifdef HAVE_KRB5
473         if (got_kerberos_mechanism && (SEC_ADS == lp_security())) {
474                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
475                                                 length, bufsize, &secblob);
476                 data_blob_free(&secblob);
477                 return ret;
478         }
479 #endif
480
481         if (global_ntlmssp_state) {
482                 auth_ntlmssp_end(&global_ntlmssp_state);
483         }
484
485         nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
486         if (!NT_STATUS_IS_OK(nt_status)) {
487                 return ERROR_NT(nt_status);
488         }
489
490         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
491                                         secblob, &chal);
492
493         data_blob_free(&secblob);
494
495         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
496                              &chal, nt_status);
497                 
498         data_blob_free(&chal);
499
500         /* already replied */
501         return -1;
502 }
503         
504 /****************************************************************************
505  Reply to a session setup spnego auth packet.
506 ****************************************************************************/
507
508 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
509                              int length, int bufsize,
510                              DATA_BLOB blob1)
511 {
512         DATA_BLOB auth, auth_reply;
513         NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
514
515         if (!spnego_parse_auth(blob1, &auth)) {
516 #if 0
517                 file_save("auth.dat", blob1.data, blob1.length);
518 #endif
519                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
520         }
521         
522         if (!global_ntlmssp_state) {
523                 /* auth before negotiatiate? */
524                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
525         }
526         
527         nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
528                                                 auth, &auth_reply);
529
530         data_blob_free(&auth);
531
532         reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
533                              &auth_reply, nt_status);
534                 
535         data_blob_free(&auth_reply);
536
537         /* and tell smbd that we have already replied to this packet */
538         return -1;
539 }
540
541 /****************************************************************************
542  Reply to a session setup command.
543 ****************************************************************************/
544
545 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
546                                         char *outbuf,
547                                         int length,int bufsize)
548 {
549         uint8 *p;
550         DATA_BLOB blob1;
551         int ret;
552         size_t bufrem;
553         fstring native_os, native_lanman, primary_domain;
554         char *p2;
555         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
556         enum remote_arch_types ra_type = get_remote_arch();
557
558         DEBUG(3,("Doing spnego session setup\n"));
559
560         if (global_client_caps == 0) {
561                 global_client_caps = IVAL(inbuf,smb_vwv10);
562
563                 if (!(global_client_caps & CAP_STATUS32)) {
564                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
565                 }
566
567         }
568                 
569         p = (uint8 *)smb_buf(inbuf);
570
571         if (data_blob_len == 0) {
572                 /* an invalid request */
573                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
574         }
575
576         bufrem = smb_bufrem(inbuf, p);
577         /* pull the spnego blob */
578         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
579
580 #if 0
581         file_save("negotiate.dat", blob1.data, blob1.length);
582 #endif
583
584         p2 = inbuf + smb_vwv13 + data_blob_len;
585         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
586         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
587         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
588         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
589                 native_os, native_lanman, primary_domain));
590
591         if ( ra_type == RA_WIN2K ) {
592                 /* Windows 2003 doesn't set the native lanman string, 
593                    but does set primary domain which is a bug I think */
594                            
595                 if ( !strlen(native_lanman) )
596                         ra_lanman_string( primary_domain );
597                 else
598                         ra_lanman_string( native_lanman );
599         }
600                 
601         if (blob1.data[0] == ASN1_APPLICATION(0)) {
602                 /* its a negTokenTarg packet */
603                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
604                 data_blob_free(&blob1);
605                 return ret;
606         }
607
608         if (blob1.data[0] == ASN1_CONTEXT(1)) {
609                 /* its a auth packet */
610                 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
611                 data_blob_free(&blob1);
612                 return ret;
613         }
614
615         /* what sort of packet is this? */
616         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
617
618         data_blob_free(&blob1);
619
620         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
621 }
622
623 /****************************************************************************
624  On new VC == 0, shutdown *all* old connections and users.
625  It seems that only NT4.x does this. At W2K and above (XP etc.).
626  a new session setup with VC==0 is ignored.
627 ****************************************************************************/
628
629 static void setup_new_vc_session(void)
630 {
631         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
632 #if 0
633         conn_close_all();
634         invalidate_all_vuids();
635 #endif
636 }
637
638 /****************************************************************************
639  Reply to a session setup command.
640 ****************************************************************************/
641
642 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
643                           int length,int bufsize)
644 {
645         int sess_vuid;
646         int   smb_bufsize;    
647         DATA_BLOB lm_resp;
648         DATA_BLOB nt_resp;
649         DATA_BLOB plaintext_password;
650         fstring user;
651         fstring sub_user; /* Sainitised username for substituion */
652         fstring domain;
653         fstring native_os;
654         fstring native_lanman;
655         fstring primary_domain;
656         static BOOL done_sesssetup = False;
657
658         auth_usersupplied_info *user_info = NULL;
659         auth_serversupplied_info *server_info = NULL;
660
661         NTSTATUS nt_status;
662
663         BOOL doencrypt = global_encrypted_passwords_negotiated;
664
665         DATA_BLOB session_key;
666         
667         START_PROFILE(SMBsesssetupX);
668
669         ZERO_STRUCT(lm_resp);
670         ZERO_STRUCT(nt_resp);
671         ZERO_STRUCT(plaintext_password);
672
673         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
674
675         /* a SPNEGO session setup has 12 command words, whereas a normal
676            NT1 session setup has 13. See the cifs spec. */
677         if (CVAL(inbuf, smb_wct) == 12 &&
678             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
679                 if (!global_spnego_negotiated) {
680                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
681                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
682                 }
683
684                 if (SVAL(inbuf,smb_vwv4) == 0) {
685                         setup_new_vc_session();
686                 }
687                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
688         }
689
690         smb_bufsize = SVAL(inbuf,smb_vwv2);
691
692         if (Protocol < PROTOCOL_NT1) {
693                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
694
695                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
696                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
697
698                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
699                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
700                 }
701
702                 if (doencrypt) {
703                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
704                 } else {
705                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
706                         /* Ensure null termination */
707                         plaintext_password.data[passlen1] = 0;
708                 }
709
710                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
711                 *domain = 0;
712
713         } else {
714                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
715                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
716                 enum remote_arch_types ra_type = get_remote_arch();
717                 char *p = smb_buf(inbuf);    
718                 char *save_p = smb_buf(inbuf);
719                 uint16 byte_count;
720                         
721
722                 if(global_client_caps == 0) {
723                         global_client_caps = IVAL(inbuf,smb_vwv11);
724                 
725                         if (!(global_client_caps & CAP_STATUS32)) {
726                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
727                         }
728
729                         /* client_caps is used as final determination if client is NT or Win95. 
730                            This is needed to return the correct error codes in some
731                            circumstances.
732                         */
733                 
734                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
735                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
736                                         set_remote_arch( RA_WIN95);
737                                 }
738                         }
739                 }
740
741                 if (!doencrypt) {
742                         /* both Win95 and WinNT stuff up the password lengths for
743                            non-encrypting systems. Uggh. 
744                            
745                            if passlen1==24 its a win95 system, and its setting the
746                            password length incorrectly. Luckily it still works with the
747                            default code because Win95 will null terminate the password
748                            anyway 
749                            
750                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
751                            setting passlen2 to some random value which really stuffs
752                            things up. we need to fix that one.  */
753                         
754                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
755                                 passlen2 = 0;
756                 }
757                 
758                 /* check for nasty tricks */
759                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
760                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
761                 }
762
763                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
764                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
765                 }
766
767                 /* Save the lanman2 password and the NT md4 password. */
768                 
769                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
770                         doencrypt = False;
771                 }
772
773                 if (doencrypt) {
774                         lm_resp = data_blob(p, passlen1);
775                         nt_resp = data_blob(p+passlen1, passlen2);
776                 } else {
777                         pstring pass;
778                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
779
780 #if 0
781                         /* This was the previous fix. Not sure if it's still valid. JRA. */
782                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
783                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
784                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
785                                         sizeof(pass), passlen1, STR_TERMINATE);
786 #endif
787
788                         if (unic && (passlen2 == 0) && passlen1) {
789                                 /* Only a ascii plaintext password was sent. */
790                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
791                                         passlen1, STR_TERMINATE|STR_ASCII);
792                         } else {
793                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
794                                         sizeof(pass),  unic ? passlen2 : passlen1, 
795                                         STR_TERMINATE);
796                         }
797                         plaintext_password = data_blob(pass, strlen(pass)+1);
798                 }
799                 
800                 p += passlen1 + passlen2;
801                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
802                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
803                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
804                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
805
806                 /* not documented or decoded by Ethereal but there is one more string 
807                    in the extra bytes which is the same as the PrimaryDomain when using 
808                    extended security.  Windows NT 4 and 2003 use this string to store 
809                    the native lanman string. Windows 9x does not include a string here 
810                    at all so we have to check if we have any extra bytes left */
811                 
812                 byte_count = SVAL(inbuf, smb_vwv13);
813                 if ( PTR_DIFF(p, save_p) < byte_count)
814                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
815                 else 
816                         fstrcpy( primary_domain, "null" );
817
818                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
819                          domain, native_os, native_lanman, primary_domain));
820
821                 if ( ra_type == RA_WIN2K ) {
822                         if ( strlen(native_lanman) == 0 )
823                                 ra_lanman_string( primary_domain );
824                         else
825                                 ra_lanman_string( native_lanman );
826                 }
827
828         }
829
830         if (SVAL(inbuf,smb_vwv4) == 0) {
831                 setup_new_vc_session();
832         }
833
834         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
835
836         if (*user) {
837                 if (global_spnego_negotiated) {
838                         
839                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
840                         
841                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
842                         return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
843                 }
844                 fstrcpy(sub_user, user);
845
846                 /* setup the string used by %U */
847                 sub_set_smb_name(user);
848         } else {
849                 fstrcpy(sub_user, lp_guestaccount());
850         }
851
852         sub_set_smb_name(sub_user);
853
854         reload_services(True);
855         
856         if (lp_security() == SEC_SHARE) {
857                 /* in share level we should ignore any passwords */
858
859                 data_blob_free(&lm_resp);
860                 data_blob_free(&nt_resp);
861                 data_blob_clear_free(&plaintext_password);
862
863                 map_username(sub_user);
864                 add_session_user(sub_user);
865                 /* Then force it to null for the benfit of the code below */
866                 *user = 0;
867         }
868         
869         if (!*user) {
870
871                 nt_status = check_guest_password(&server_info);
872
873         } else if (doencrypt) {
874                 if (!negprot_global_auth_context) {
875                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
876                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
877                 }
878                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
879                                                          lm_resp, nt_resp);
880                 if (NT_STATUS_IS_OK(nt_status)) {
881                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
882                                                                                      user_info, 
883                                                                                      &server_info);
884                 }
885         } else {
886                 struct auth_context *plaintext_auth_context = NULL;
887                 const uint8 *chal;
888                 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
889                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
890                         
891                         if (!make_user_info_for_reply(&user_info, 
892                                                       user, domain, chal,
893                                                       plaintext_password)) {
894                                 nt_status = NT_STATUS_NO_MEMORY;
895                         }
896                 
897                         if (NT_STATUS_IS_OK(nt_status)) {
898                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
899                                                                                         user_info, 
900                                                                                         &server_info); 
901                                 
902                                 (plaintext_auth_context->free)(&plaintext_auth_context);
903                         }
904                 }
905         }
906
907         free_user_info(&user_info);
908         
909         if (!NT_STATUS_IS_OK(nt_status)) {
910                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
911         }
912         
913         if (!NT_STATUS_IS_OK(nt_status)) {
914                 data_blob_free(&nt_resp);
915                 data_blob_free(&lm_resp);
916                 data_blob_clear_free(&plaintext_password);
917                 return ERROR_NT(nt_status_squash(nt_status));
918         }
919
920         if (server_info->user_session_key.data) {
921                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
922         } else {
923                 session_key = data_blob(NULL, 0);
924         }
925
926         data_blob_clear_free(&plaintext_password);
927         
928         /* it's ok - setup a reply */
929         set_message(outbuf,3,0,True);
930         if (Protocol >= PROTOCOL_NT1) {
931                 char *p = smb_buf( outbuf );
932                 p += add_signature( outbuf, p );
933                 set_message_end( outbuf, p );
934                 /* perhaps grab OS version here?? */
935         }
936         
937         if (server_info->guest) {
938                 SSVAL(outbuf,smb_vwv2,1);
939         }
940
941         /* register the name and uid as being validated, so further connections
942            to a uid can get through without a password, on the same VC */
943
944         /* register_vuid keeps the server info */
945         sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
946         data_blob_free(&nt_resp);
947         data_blob_free(&lm_resp);
948
949         if (sess_vuid == -1) {
950                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
951         }
952
953         /* current_user_info is changed on new vuid */
954         reload_services( True );
955
956         if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
957                 exit_server("reply_sesssetup_and_X: bad smb signature");
958         }
959
960         SSVAL(outbuf,smb_uid,sess_vuid);
961         SSVAL(inbuf,smb_uid,sess_vuid);
962         
963         if (!done_sesssetup)
964                 max_send = MIN(max_send,smb_bufsize);
965         
966         done_sesssetup = True;
967         
968         END_PROFILE(SMBsesssetupX);
969         return chain_reply(inbuf,outbuf,length,bufsize);
970 }