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