r21845: Refactor the sessionsetupX code a little to allow us
[jerry/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 extern struct auth_context *negprot_global_auth_context;
27 extern BOOL global_encrypted_passwords_negotiated;
28 extern BOOL global_spnego_negotiated;
29 extern enum protocol_types Protocol;
30 extern int max_send;
31
32 uint32 global_client_caps = 0;
33
34 /*
35   on a logon error possibly map the error to success if "map to guest"
36   is set approriately
37 */
38 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39                                 const char *user, const char *domain)
40 {
41         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
43                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44                         DEBUG(3,("No such user %s [%s] - using guest account\n",
45                                  user, domain));
46                         status = make_server_info_guest(server_info);
47                 }
48         }
49
50         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52                         DEBUG(3,("Registered username %s for guest access\n",user));
53                         status = make_server_info_guest(server_info);
54                 }
55         }
56
57         return status;
58 }
59
60 /****************************************************************************
61  Add the standard 'Samba' signature to the end of the session setup.
62 ****************************************************************************/
63
64 static int add_signature(char *outbuf, char *p)
65 {
66         char *start = p;
67         fstring lanman;
68
69         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
70
71         p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72         p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73         p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
74
75         return PTR_DIFF(p, start);
76 }
77
78 /****************************************************************************
79  Start the signing engine if needed. Don't fail signing here.
80 ****************************************************************************/
81
82 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
83 {
84         if (!server_info->guest && !srv_signing_started()) {
85                 /* We need to start the signing engine
86                  * here but a W2K client sends the old
87                  * "BSRSPYL " signature instead of the
88                  * correct one. Subsequent packets will
89                  * be correct.
90                  */
91                 srv_check_sign_mac(inbuf, False);
92         }
93 }
94
95 /****************************************************************************
96  Send a security blob via a session setup reply.
97 ****************************************************************************/
98
99 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
100                                  DATA_BLOB blob, NTSTATUS nt_status)
101 {
102         char *p;
103
104         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105                 ERROR_NT(nt_status_squash(nt_status));
106         } else {
107                 set_message(outbuf,4,0,True);
108
109                 nt_status = nt_status_squash(nt_status);
110                 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
111                 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
112                 SSVAL(outbuf, smb_vwv3, blob.length);
113                 p = smb_buf(outbuf);
114
115                 /* should we cap this? */
116                 memcpy(p, blob.data, blob.length);
117                 p += blob.length;
118
119                 p += add_signature( outbuf, p );
120
121                 set_message_end(outbuf,p);
122         }
123
124         show_msg(outbuf);
125         return send_smb(smbd_server_fd(),outbuf);
126 }
127
128 /****************************************************************************
129  Do a 'guest' logon, getting back the 
130 ****************************************************************************/
131
132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
133 {
134         struct auth_context *auth_context;
135         auth_usersupplied_info *user_info = NULL;
136         
137         NTSTATUS nt_status;
138         unsigned char chal[8];
139
140         ZERO_STRUCT(chal);
141
142         DEBUG(3,("Got anonymous request\n"));
143
144         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
145                 return nt_status;
146         }
147
148         if (!make_user_info_guest(&user_info)) {
149                 (auth_context->free)(&auth_context);
150                 return NT_STATUS_NO_MEMORY;
151         }
152         
153         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
154         (auth_context->free)(&auth_context);
155         free_user_info(&user_info);
156         return nt_status;
157 }
158
159
160 #ifdef HAVE_KRB5
161
162 #if 0
163 /* Experiment that failed. See "only happens with a KDC" comment below. */
164 /****************************************************************************
165  Cerate a clock skew error blob for a Windows client.
166 ****************************************************************************/
167
168 static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
169 {
170         krb5_context context = NULL;
171         krb5_error_code kerr = 0;
172         krb5_data reply;
173         krb5_principal host_princ = NULL;
174         char *host_princ_s = NULL;
175         BOOL ret = False;
176
177         *pblob_out = data_blob(NULL,0);
178
179         kerr = krb5_init_context(&context);
180         if (kerr) {
181                 return False;
182         }
183         /* Create server principal. */
184         asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
185         if (!host_princ_s) {
186                 goto out;
187         }
188         strlower_m(host_princ_s);
189
190         kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
191         if (kerr) {
192                 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
193                         host_princ_s, error_message(kerr) ));
194                 goto out;
195         }
196         
197         kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
198         if (kerr) {
199                 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
200                         error_message(kerr) ));
201                 goto out;
202         }
203
204         *pblob_out = data_blob(reply.data, reply.length);
205         kerberos_free_data_contents(context,&reply);
206         ret = True;
207
208   out:
209
210         if (host_princ_s) {
211                 SAFE_FREE(host_princ_s);
212         }
213         if (host_princ) {
214                 krb5_free_principal(context, host_princ);
215         }
216         krb5_free_context(context);
217         return ret;
218 }
219 #endif
220
221 /****************************************************************************
222  Reply to a session setup spnego negotiate packet for kerberos.
223 ****************************************************************************/
224
225 static int reply_spnego_kerberos(connection_struct *conn, 
226                                  char *inbuf, char *outbuf,
227                                  int length, int bufsize,
228                                  DATA_BLOB *secblob,
229                                  BOOL *p_invalidate_vuid)
230 {
231         TALLOC_CTX *mem_ctx;
232         DATA_BLOB ticket;
233         char *client, *p, *domain;
234         fstring netbios_domain_name;
235         struct passwd *pw;
236         fstring user;
237         int sess_vuid;
238         NTSTATUS ret;
239         PAC_DATA *pac_data;
240         DATA_BLOB ap_rep, ap_rep_wrapped, response;
241         auth_serversupplied_info *server_info = NULL;
242         DATA_BLOB session_key = data_blob(NULL, 0);
243         uint8 tok_id[2];
244         DATA_BLOB nullblob = data_blob(NULL, 0);
245         fstring real_username;
246         BOOL map_domainuser_to_guest = False;
247         BOOL username_was_mapped;
248         PAC_LOGON_INFO *logon_info = NULL;
249
250         ZERO_STRUCT(ticket);
251         ZERO_STRUCT(pac_data);
252         ZERO_STRUCT(ap_rep);
253         ZERO_STRUCT(ap_rep_wrapped);
254         ZERO_STRUCT(response);
255
256         /* Normally we will always invalidate the intermediate vuid. */
257         *p_invalidate_vuid = True;
258
259         mem_ctx = talloc_init("reply_spnego_kerberos");
260         if (mem_ctx == NULL) {
261                 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
262         }
263
264         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
265                 talloc_destroy(mem_ctx);
266                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
267         }
268
269         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
270
271         data_blob_free(&ticket);
272
273         if (!NT_STATUS_IS_OK(ret)) {
274 #if 0
275                 /* Experiment that failed. See "only happens with a KDC" comment below. */
276
277                 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
278
279                         /*
280                          * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
281                          * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
282                          * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
283                          * clock and continues rather than giving an error. JRA.
284                          * -- Looks like this only happens with a KDC. JRA.
285                          */
286
287                         BOOL ok = make_krb5_skew_error(&ap_rep);
288                         if (!ok) {
289                                 talloc_destroy(mem_ctx);
290                                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
291                         }
292                         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
293                         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
294                         reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
295
296                         /*
297                          * In this one case we don't invalidate the intermediate vuid.
298                          * as we're expecting the client to re-use it for the next
299                          * sessionsetupX packet. JRA.
300                          */
301
302                         *p_invalidate_vuid = False;
303
304                         data_blob_free(&ap_rep);
305                         data_blob_free(&ap_rep_wrapped);
306                         data_blob_free(&response);
307                         talloc_destroy(mem_ctx);
308                         return -1; /* already replied */
309                 }
310 #else
311                 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
312                         ret = NT_STATUS_LOGON_FAILURE;
313                 }
314 #endif
315                 DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); 
316                 talloc_destroy(mem_ctx);
317                 return ERROR_NT(nt_status_squash(ret));
318         }
319
320         DEBUG(3,("Ticket name is [%s]\n", client));
321
322         p = strchr_m(client, '@');
323         if (!p) {
324                 DEBUG(3,("Doesn't look like a valid principal\n"));
325                 data_blob_free(&ap_rep);
326                 data_blob_free(&session_key);
327                 SAFE_FREE(client);
328                 talloc_destroy(mem_ctx);
329                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
330         }
331
332         *p = 0;
333
334         /* save the PAC data if we have it */
335
336         if (pac_data) {
337                 logon_info = get_logon_info_from_pac(pac_data);
338                 if (logon_info) {
339                         netsamlogon_cache_store( client, &logon_info->info3 );
340                 }
341         }
342
343         if (!strequal(p+1, lp_realm())) {
344                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
345                 if (!lp_allow_trusted_domains()) {
346                         data_blob_free(&ap_rep);
347                         data_blob_free(&session_key);
348                         SAFE_FREE(client);
349                         talloc_destroy(mem_ctx);
350                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
351                 }
352         }
353
354         /* this gives a fully qualified user name (ie. with full realm).
355            that leads to very long usernames, but what else can we do? */
356
357         domain = p+1;
358
359         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
360
361                 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
362                 domain = netbios_domain_name;
363                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
364
365         } else {
366
367                 /* If we have winbind running, we can (and must) shorten the
368                    username by using the short netbios name. Otherwise we will
369                    have inconsistent user names. With Kerberos, we get the
370                    fully qualified realm, with ntlmssp we get the short
371                    name. And even w2k3 does use ntlmssp if you for example
372                    connect to an ip address. */
373
374                 struct winbindd_request wb_request;
375                 struct winbindd_response wb_response;
376                 NSS_STATUS wb_result;
377
378                 ZERO_STRUCT(wb_request);
379                 ZERO_STRUCT(wb_response);
380
381                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
382
383                 fstrcpy(wb_request.domain_name, domain);
384
385                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
386                                              &wb_request, &wb_response);
387
388                 if (wb_result == NSS_STATUS_SUCCESS) {
389
390                         fstrcpy(netbios_domain_name,
391                                 wb_response.data.domain_info.name);
392                         domain = netbios_domain_name;
393
394                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
395                 } else {
396                         DEBUG(3, ("Could not find short name -- winbind "
397                                   "not running?\n"));
398                 }
399         }
400
401         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
402         
403         /* lookup the passwd struct, create a new user if necessary */
404
405         username_was_mapped = map_username( user );
406
407         pw = smb_getpwnam( mem_ctx, user, real_username, True );
408
409         if (pw) {
410                 /* if a real user check pam account restrictions */
411                 /* only really perfomed if "obey pam restriction" is true */
412                 /* do this before an eventual mappign to guest occurs */
413                 ret = smb_pam_accountcheck(pw->pw_name);
414                 if (  !NT_STATUS_IS_OK(ret)) {
415                         DEBUG(1, ("PAM account restriction prevents user login\n"));
416                         data_blob_free(&ap_rep);
417                         data_blob_free(&session_key);
418                         TALLOC_FREE(mem_ctx);
419                         return ERROR_NT(nt_status_squash(ret));
420                 }
421         }
422
423         if (!pw) {
424
425                 /* this was originally the behavior of Samba 2.2, if a user
426                    did not have a local uid but has been authenticated, then 
427                    map them to a guest account */
428
429                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
430                         map_domainuser_to_guest = True;
431                         fstrcpy(user,lp_guestaccount());
432                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
433                 } 
434
435                 /* extra sanity check that the guest account is valid */
436
437                 if ( !pw ) {
438                         DEBUG(1,("Username %s is invalid on this system\n", user));
439                         SAFE_FREE(client);
440                         data_blob_free(&ap_rep);
441                         data_blob_free(&session_key);
442                         TALLOC_FREE(mem_ctx);
443                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
444                 }
445         }
446
447         /* setup the string used by %U */
448         
449         sub_set_smb_name( real_username );
450         reload_services(True);
451
452         if ( map_domainuser_to_guest ) {
453                 make_server_info_guest(&server_info);
454         } else if (logon_info) {
455                 /* pass the unmapped username here since map_username() 
456                    will be called again from inside make_server_info_info3() */
457                 
458                 ret = make_server_info_info3(mem_ctx, client, domain, 
459                                              &server_info, &logon_info->info3);
460                 if ( !NT_STATUS_IS_OK(ret) ) {
461                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
462                                  nt_errstr(ret)));
463                         SAFE_FREE(client);
464                         data_blob_free(&ap_rep);
465                         data_blob_free(&session_key);
466                         TALLOC_FREE(mem_ctx);
467                         return ERROR_NT(nt_status_squash(ret));
468                 }
469
470         } else {
471                 ret = make_server_info_pw(&server_info, real_username, pw);
472
473                 if ( !NT_STATUS_IS_OK(ret) ) {
474                         DEBUG(1,("make_server_info_pw failed: %s!\n",
475                                  nt_errstr(ret)));
476                         SAFE_FREE(client);
477                         data_blob_free(&ap_rep);
478                         data_blob_free(&session_key);
479                         TALLOC_FREE(mem_ctx);
480                         return ERROR_NT(nt_status_squash(ret));
481                 }
482
483                 /* make_server_info_pw does not set the domain. Without this
484                  * we end up with the local netbios name in substitutions for
485                  * %D. */
486
487                 if (server_info->sam_account != NULL) {
488                         pdb_set_domain(server_info->sam_account, domain, PDB_SET);
489                 }
490         }
491
492         server_info->was_mapped |= username_was_mapped;
493         
494         /* we need to build the token for the user. make_server_info_guest()
495            already does this */
496         
497         if ( !server_info->ptok ) {
498                 ret = create_local_token( server_info );
499                 if ( !NT_STATUS_IS_OK(ret) ) {
500                         SAFE_FREE(client);
501                         data_blob_free(&ap_rep);
502                         data_blob_free(&session_key);
503                         TALLOC_FREE( mem_ctx );
504                         TALLOC_FREE( server_info );
505                         return ERROR_NT(nt_status_squash(ret));
506                 }
507         }
508
509         /* register_vuid keeps the server info */
510         /* register_vuid takes ownership of session_key, no need to free after this.
511            A better interface would copy it.... */
512         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
513
514         SAFE_FREE(client);
515
516         if (sess_vuid == UID_FIELD_INVALID ) {
517                 ret = NT_STATUS_LOGON_FAILURE;
518         } else {
519                 /* current_user_info is changed on new vuid */
520                 reload_services( True );
521
522                 set_message(outbuf,4,0,True);
523                 SSVAL(outbuf, smb_vwv3, 0);
524                         
525                 if (server_info->guest) {
526                         SSVAL(outbuf,smb_vwv2,1);
527                 }
528                 
529                 SSVAL(outbuf, smb_uid, sess_vuid);
530
531                 sessionsetup_start_signing_engine(server_info, inbuf);
532         }
533
534         /* wrap that up in a nice GSS-API wrapping */
535         if (NT_STATUS_IS_OK(ret)) {
536                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
537         } else {
538                 ap_rep_wrapped = data_blob(NULL, 0);
539         }
540         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
541         reply_sesssetup_blob(conn, outbuf, response, ret);
542
543         data_blob_free(&ap_rep);
544         data_blob_free(&ap_rep_wrapped);
545         data_blob_free(&response);
546         TALLOC_FREE(mem_ctx);
547
548         return -1; /* already replied */
549 }
550 #endif
551
552 /****************************************************************************
553  Send a session setup reply, wrapped in SPNEGO.
554  Get vuid and check first.
555  End the NTLMSSP exchange context if we are OK/complete fail
556  This should be split into two functions, one to handle each
557  leg of the NTLM auth steps.
558 ***************************************************************************/
559
560 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
561                                  uint16 vuid,
562                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
563                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
564                                  BOOL wrap) 
565 {
566         BOOL ret;
567         DATA_BLOB response;
568         struct auth_serversupplied_info *server_info = NULL;
569
570         if (NT_STATUS_IS_OK(nt_status)) {
571                 server_info = (*auth_ntlmssp_state)->server_info;
572         } else {
573                 nt_status = do_map_to_guest(nt_status, 
574                                             &server_info, 
575                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
576                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
577         }
578
579         if (NT_STATUS_IS_OK(nt_status)) {
580                 int sess_vuid;
581                 DATA_BLOB nullblob = data_blob(NULL, 0);
582                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
583
584                 /* register_vuid keeps the server info */
585                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
586                 (*auth_ntlmssp_state)->server_info = NULL;
587
588                 if (sess_vuid == UID_FIELD_INVALID ) {
589                         nt_status = NT_STATUS_LOGON_FAILURE;
590                 } else {
591                         
592                         /* current_user_info is changed on new vuid */
593                         reload_services( True );
594
595                         set_message(outbuf,4,0,True);
596                         SSVAL(outbuf, smb_vwv3, 0);
597                         
598                         if (server_info->guest) {
599                                 SSVAL(outbuf,smb_vwv2,1);
600                         }
601                         
602                         SSVAL(outbuf,smb_uid,sess_vuid);
603
604                         sessionsetup_start_signing_engine(server_info, inbuf);
605                 }
606         }
607
608         if (wrap) {
609                 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
610         } else {
611                 response = *ntlmssp_blob;
612         }
613
614         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
615         if (wrap) {
616                 data_blob_free(&response);
617         }
618
619         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
620            and the other end, that we are not finished yet. */
621
622         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
623                 /* NB. This is *NOT* an error case. JRA */
624                 auth_ntlmssp_end(auth_ntlmssp_state);
625                 /* Kill the intermediate vuid */
626                 invalidate_vuid(vuid);
627         }
628
629         return ret;
630 }
631
632 /****************************************************************************
633  Is this a krb5 mechanism ?
634 ****************************************************************************/
635
636 static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
637 {
638         char *OIDs[ASN1_MAX_OIDS];
639         int i;
640
641         *p_is_krb5 = False;
642
643         /* parse out the OIDs and the first sec blob */
644         if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
645                 return NT_STATUS_LOGON_FAILURE;
646         }
647
648         /* only look at the first OID for determining the mechToken --
649            accoirding to RFC2478, we should choose the one we want 
650            and renegotiate, but i smell a client bug here..  
651            
652            Problem observed when connecting to a member (samba box) 
653            of an AD domain as a user in a Samba domain.  Samba member 
654            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
655            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
656            NTLMSSP mechtoken.                 --jerry              */
657
658 #ifdef HAVE_KRB5        
659         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
660             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
661                 *p_is_krb5 = True;
662         }
663 #endif
664                 
665         for (i=0;OIDs[i];i++) {
666                 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
667                 free(OIDs[i]);
668         }
669         return NT_STATUS_OK;
670 }
671
672 /****************************************************************************
673  Reply to a session setup spnego negotiate packet.
674 ****************************************************************************/
675
676 static int reply_spnego_negotiate(connection_struct *conn, 
677                                   char *inbuf,
678                                   char *outbuf,
679                                   uint16 vuid,
680                                   int length, int bufsize,
681                                   DATA_BLOB blob1,
682                                   AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
683 {
684         DATA_BLOB secblob;
685         DATA_BLOB chal;
686         BOOL got_kerberos_mechanism = False;
687         NTSTATUS status;
688
689         status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
690         if (!NT_STATUS_IS_OK(status)) {
691                 /* Kill the intermediate vuid */
692                 invalidate_vuid(vuid);
693                 return ERROR_NT(nt_status_squash(status));
694         }
695
696         DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
697
698 #ifdef HAVE_KRB5
699         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
700                 BOOL destroy_vuid = True;
701                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
702                                                 length, bufsize, &secblob, &destroy_vuid);
703                 data_blob_free(&secblob);
704                 if (destroy_vuid) {
705                         /* Kill the intermediate vuid */
706                         invalidate_vuid(vuid);
707                 }
708                 return ret;
709         }
710 #endif
711
712         if (*auth_ntlmssp_state) {
713                 auth_ntlmssp_end(auth_ntlmssp_state);
714         }
715
716         status = auth_ntlmssp_start(auth_ntlmssp_state);
717         if (!NT_STATUS_IS_OK(status)) {
718                 /* Kill the intermediate vuid */
719                 invalidate_vuid(vuid);
720                 return ERROR_NT(nt_status_squash(status));
721         }
722
723         status = auth_ntlmssp_update(*auth_ntlmssp_state, 
724                                         secblob, &chal);
725
726         data_blob_free(&secblob);
727
728         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
729                              &chal, status, True);
730
731         data_blob_free(&chal);
732
733         /* already replied */
734         return -1;
735 }
736
737 /****************************************************************************
738  Reply to a session setup spnego auth packet.
739 ****************************************************************************/
740
741 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
742                              uint16 vuid,
743                              int length, int bufsize,
744                              DATA_BLOB blob1,
745                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
746 {
747         DATA_BLOB auth = data_blob(NULL,0);
748         DATA_BLOB auth_reply = data_blob(NULL,0);
749         DATA_BLOB secblob = data_blob(NULL,0);
750         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
751
752         if (!spnego_parse_auth(blob1, &auth)) {
753 #if 0
754                 file_save("auth.dat", blob1.data, blob1.length);
755 #endif
756                 /* Kill the intermediate vuid */
757                 invalidate_vuid(vuid);
758
759                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
760         }
761
762         if (auth.data[0] == ASN1_APPLICATION(0)) {
763                 /* Might be a second negTokenTarg packet */
764
765                 BOOL got_krb5_mechanism = False;
766                 status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
767                 if (NT_STATUS_IS_OK(status)) {
768                         DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
769 #ifdef HAVE_KRB5
770                         if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
771                                 BOOL destroy_vuid = True;
772                                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
773                                                                 length, bufsize, &secblob, &destroy_vuid);
774                                 data_blob_free(&secblob);
775                                 data_blob_free(&auth);
776                                 if (destroy_vuid) {
777                                         /* Kill the intermediate vuid */
778                                         invalidate_vuid(vuid);
779                                 }
780                                 return ret;
781                         }
782 #endif
783                 }
784         }
785
786         /* If we get here it wasn't a negTokenTarg auth packet. */
787         data_blob_free(&secblob);
788         
789         if (!*auth_ntlmssp_state) {
790                 /* Kill the intermediate vuid */
791                 invalidate_vuid(vuid);
792
793                 /* auth before negotiatiate? */
794                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
795         }
796         
797         status = auth_ntlmssp_update(*auth_ntlmssp_state, 
798                                         auth, &auth_reply);
799
800         data_blob_free(&auth);
801
802         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
803                              auth_ntlmssp_state,
804                              &auth_reply, status, True);
805                 
806         data_blob_free(&auth_reply);
807
808         /* and tell smbd that we have already replied to this packet */
809         return -1;
810 }
811
812 /****************************************************************************
813  List to store partial SPNEGO auth fragments.
814 ****************************************************************************/
815
816 static struct pending_auth_data *pd_list;
817
818 /****************************************************************************
819  Delete an entry on the list.
820 ****************************************************************************/
821
822 static void delete_partial_auth(struct pending_auth_data *pad)
823 {
824         if (!pad) {
825                 return;
826         }
827         DLIST_REMOVE(pd_list, pad);
828         data_blob_free(&pad->partial_data);
829         SAFE_FREE(pad);
830 }
831
832 /****************************************************************************
833  Search for a partial SPNEGO auth fragment matching an smbpid.
834 ****************************************************************************/
835
836 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
837 {
838         struct pending_auth_data *pad;
839
840         for (pad = pd_list; pad; pad = pad->next) {
841                 if (pad->smbpid == smbpid) {
842                         break;
843                 }
844         }
845         return pad;
846 }
847
848 /****************************************************************************
849  Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
850  else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
851 ****************************************************************************/
852
853 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
854 {
855         struct pending_auth_data *pad = NULL;
856         ASN1_DATA data;
857         size_t needed_len = 0;
858
859         pad = get_pending_auth_data(smbpid);
860
861         /* Ensure we have some data. */
862         if (pblob->length == 0) {
863                 /* Caller can cope. */
864                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
865                 delete_partial_auth(pad);
866                 return NT_STATUS_OK;
867         }
868
869         /* Were we waiting for more data ? */
870         if (pad) {
871                 DATA_BLOB tmp_blob;
872                 size_t copy_len = MIN(65536, pblob->length);
873
874                 /* Integer wrap paranoia.... */
875
876                 if (pad->partial_data.length + copy_len < pad->partial_data.length ||
877                     pad->partial_data.length + copy_len < copy_len) {
878
879                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
880                                 "pad->partial_data.length = %u, "
881                                 "copy_len = %u\n",
882                                 (unsigned int)pad->partial_data.length,
883                                 (unsigned int)copy_len ));
884
885                         delete_partial_auth(pad);
886                         return NT_STATUS_INVALID_PARAMETER;
887                 }
888
889                 DEBUG(10,("check_spnego_blob_complete: "
890                         "pad->partial_data.length = %u, "
891                         "pad->needed_len = %u, "
892                         "copy_len = %u, "
893                         "pblob->length = %u,\n",
894                         (unsigned int)pad->partial_data.length,
895                         (unsigned int)pad->needed_len,
896                         (unsigned int)copy_len,
897                         (unsigned int)pblob->length ));
898
899                 tmp_blob = data_blob(NULL,
900                                 pad->partial_data.length + copy_len);
901
902                 /* Concatenate the two (up to copy_len) bytes. */
903                 memcpy(tmp_blob.data,
904                         pad->partial_data.data,
905                         pad->partial_data.length);
906                 memcpy(tmp_blob.data + pad->partial_data.length,
907                         pblob->data,
908                         copy_len);
909
910                 /* Replace the partial data. */
911                 data_blob_free(&pad->partial_data);
912                 pad->partial_data = tmp_blob;
913                 ZERO_STRUCT(tmp_blob);
914
915                 /* Are we done ? */
916                 if (pblob->length >= pad->needed_len) {
917                         /* Yes, replace pblob. */
918                         data_blob_free(pblob);
919                         *pblob = pad->partial_data;
920                         ZERO_STRUCT(pad->partial_data);
921                         delete_partial_auth(pad);
922                         return NT_STATUS_OK;
923                 }
924
925                 /* Still need more data. */
926                 pad->needed_len -= copy_len;
927                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
928         }
929
930         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
931             (pblob->data[0] != ASN1_CONTEXT(1))) {
932                 /* Not something we can determine the
933                  * length of.
934                  */
935                 return NT_STATUS_OK;
936         }
937
938         /* This is a new SPNEGO sessionsetup - see if
939          * the data given in this blob is enough.
940          */
941
942         asn1_load(&data, *pblob);
943         asn1_start_tag(&data, pblob->data[0]);
944         if (data.has_error || data.nesting == NULL) {
945                 asn1_free(&data);
946                 /* Let caller catch. */
947                 return NT_STATUS_OK;
948         }
949
950         /* Integer wrap paranoia.... */
951
952         if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
953             data.nesting->taglen + data.nesting->start < data.nesting->start) {
954
955                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
956                         "data.nesting->taglen = %u, "
957                         "data.nesting->start = %u\n",
958                         (unsigned int)data.nesting->taglen,
959                         (unsigned int)data.nesting->start ));
960
961                 asn1_free(&data);
962                 return NT_STATUS_INVALID_PARAMETER;
963         }
964
965         /* Total length of the needed asn1 is the tag length
966          * plus the current offset. */
967
968         needed_len = data.nesting->taglen + data.nesting->start;
969         asn1_free(&data);
970
971         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
972                 "pblob->length = %u\n",
973                 (unsigned int)needed_len,
974                 (unsigned int)pblob->length ));
975
976         if (needed_len <= pblob->length) {
977                 /* Nothing to do - blob is complete. */
978                 return NT_STATUS_OK;
979         }
980
981         /* Refuse the blob if it's bigger than 64k. */
982         if (needed_len > 65536) {
983                 DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
984                         (unsigned int)needed_len ));
985                 return NT_STATUS_INVALID_PARAMETER;
986         }
987
988         /* We must store this blob until complete. */
989         pad = SMB_MALLOC(sizeof(struct pending_auth_data));
990         if (!pad) {
991                 return NT_STATUS_NO_MEMORY;
992         }
993         pad->needed_len = needed_len - pblob->length;
994         pad->partial_data = data_blob(pblob->data, pblob->length);
995         if (pad->partial_data.data == NULL) {
996                 SAFE_FREE(pad);
997                 return NT_STATUS_NO_MEMORY;
998         }
999         pad->smbpid = smbpid;
1000         pad->vuid = vuid;
1001         DLIST_ADD(pd_list, pad);
1002
1003         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1004 }
1005
1006 /****************************************************************************
1007  Reply to a session setup command.
1008  conn POINTER CAN BE NULL HERE !
1009 ****************************************************************************/
1010
1011 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
1012                                         char *outbuf,
1013                                         int length,int bufsize)
1014 {
1015         uint8 *p;
1016         DATA_BLOB blob1;
1017         int ret;
1018         size_t bufrem;
1019         fstring native_os, native_lanman, primary_domain;
1020         char *p2;
1021         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
1022         enum remote_arch_types ra_type = get_remote_arch();
1023         int vuid = SVAL(inbuf,smb_uid);
1024         user_struct *vuser = NULL;
1025         NTSTATUS status = NT_STATUS_OK;
1026         uint16 smbpid = SVAL(inbuf,smb_pid);
1027
1028         DEBUG(3,("Doing spnego session setup\n"));
1029
1030         if (global_client_caps == 0) {
1031                 global_client_caps = IVAL(inbuf,smb_vwv10);
1032
1033                 if (!(global_client_caps & CAP_STATUS32)) {
1034                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1035                 }
1036
1037         }
1038                 
1039         p = (uint8 *)smb_buf(inbuf);
1040
1041         if (data_blob_len == 0) {
1042                 /* an invalid request */
1043                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1044         }
1045
1046         bufrem = smb_bufrem(inbuf, p);
1047         /* pull the spnego blob */
1048         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1049
1050 #if 0
1051         file_save("negotiate.dat", blob1.data, blob1.length);
1052 #endif
1053
1054         p2 = inbuf + smb_vwv13 + data_blob_len;
1055         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
1056         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
1057         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
1058         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
1059                 native_os, native_lanman, primary_domain));
1060
1061         if ( ra_type == RA_WIN2K ) {
1062                 /* Windows 2003 doesn't set the native lanman string, 
1063                    but does set primary domain which is a bug I think */
1064                            
1065                 if ( !strlen(native_lanman) ) {
1066                         ra_lanman_string( primary_domain );
1067                 } else {
1068                         ra_lanman_string( native_lanman );
1069                 }
1070         }
1071                 
1072         vuser = get_partial_auth_user_struct(vuid);
1073         if (!vuser) {
1074                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1075                 if (pad) {
1076                         DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
1077                                 (unsigned int)pad->vuid ));
1078                         vuid = pad->vuid;
1079                         vuser = get_partial_auth_user_struct(vuid);
1080                 }
1081         }
1082
1083         if (!vuser) {
1084                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
1085                 if (vuid == UID_FIELD_INVALID ) {
1086                         data_blob_free(&blob1);
1087                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1088                 }
1089         
1090                 vuser = get_partial_auth_user_struct(vuid);
1091         }
1092
1093         if (!vuser) {
1094                 data_blob_free(&blob1);
1095                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1096         }
1097         
1098         SSVAL(outbuf,smb_uid,vuid);
1099
1100         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1101          * sessionsetup requests as the Windows limit on the security blob
1102          * field is 4k. Bug #4400. JRA.
1103          */
1104
1105         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1106         if (!NT_STATUS_IS_OK(status)) {
1107                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1108                         /* Real error - kill the intermediate vuid */
1109                         invalidate_vuid(vuid);
1110                 }
1111                 data_blob_free(&blob1);
1112                 return ERROR_NT(nt_status_squash(status));
1113         }
1114
1115         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1116                 /* its a negTokenTarg packet */
1117                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1118                                              &vuser->auth_ntlmssp_state);
1119                 data_blob_free(&blob1);
1120                 return ret;
1121         }
1122
1123         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1124                 /* its a auth packet */
1125                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1126                                         &vuser->auth_ntlmssp_state);
1127                 data_blob_free(&blob1);
1128                 return ret;
1129         }
1130
1131         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1132                 DATA_BLOB chal;
1133                 if (!vuser->auth_ntlmssp_state) {
1134                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1135                         if (!NT_STATUS_IS_OK(status)) {
1136                                 /* Kill the intermediate vuid */
1137                                 invalidate_vuid(vuid);
1138                                 data_blob_free(&blob1);
1139                                 return ERROR_NT(nt_status_squash(status));
1140                         }
1141                 }
1142
1143                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1144                                                 blob1, &chal);
1145                 
1146                 data_blob_free(&blob1);
1147                 
1148                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
1149                                            &vuser->auth_ntlmssp_state,
1150                                            &chal, status, False);
1151                 data_blob_free(&chal);
1152                 return -1;
1153         }
1154
1155         /* what sort of packet is this? */
1156         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1157
1158         data_blob_free(&blob1);
1159
1160         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1161 }
1162
1163 /****************************************************************************
1164  On new VC == 0, shutdown *all* old connections and users.
1165  It seems that only NT4.x does this. At W2K and above (XP etc.).
1166  a new session setup with VC==0 is ignored.
1167 ****************************************************************************/
1168
1169 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1170                                 void *p)
1171 {
1172         struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
1173         const char *ip = (const char *)p;
1174
1175         if (!process_exists(pid_to_procid(sessionid->pid))) {
1176                 return 0;
1177         }
1178
1179         if (sessionid->pid == sys_getpid()) {
1180                 return 0;
1181         }
1182
1183         if (strcmp(ip, sessionid->ip_addr) != 0) {
1184                 return 0;
1185         }
1186
1187         message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
1188                          NULL, 0, True);
1189         return 0;
1190 }
1191
1192 static void setup_new_vc_session(void)
1193 {
1194         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1195 #if 0
1196         conn_close_all();
1197         invalidate_all_vuids();
1198 #endif
1199         if (lp_reset_on_zero_vc()) {
1200                 session_traverse(shutdown_other_smbds, client_addr());
1201         }
1202 }
1203
1204 /****************************************************************************
1205  Reply to a session setup command.
1206 ****************************************************************************/
1207
1208 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1209                           int length,int bufsize)
1210 {
1211         int sess_vuid;
1212         int   smb_bufsize;    
1213         DATA_BLOB lm_resp;
1214         DATA_BLOB nt_resp;
1215         DATA_BLOB plaintext_password;
1216         fstring user;
1217         fstring sub_user; /* Sainitised username for substituion */
1218         fstring domain;
1219         fstring native_os;
1220         fstring native_lanman;
1221         fstring primary_domain;
1222         static BOOL done_sesssetup = False;
1223         auth_usersupplied_info *user_info = NULL;
1224         auth_serversupplied_info *server_info = NULL;
1225
1226         NTSTATUS nt_status;
1227
1228         BOOL doencrypt = global_encrypted_passwords_negotiated;
1229
1230         DATA_BLOB session_key;
1231         
1232         START_PROFILE(SMBsesssetupX);
1233
1234         ZERO_STRUCT(lm_resp);
1235         ZERO_STRUCT(nt_resp);
1236         ZERO_STRUCT(plaintext_password);
1237
1238         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1239
1240         /* a SPNEGO session setup has 12 command words, whereas a normal
1241            NT1 session setup has 13. See the cifs spec. */
1242         if (CVAL(inbuf, smb_wct) == 12 &&
1243             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1244                 if (!global_spnego_negotiated) {
1245                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1246                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1247                 }
1248
1249                 if (SVAL(inbuf,smb_vwv4) == 0) {
1250                         setup_new_vc_session();
1251                 }
1252                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1253         }
1254
1255         smb_bufsize = SVAL(inbuf,smb_vwv2);
1256
1257         if (Protocol < PROTOCOL_NT1) {
1258                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1259
1260                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1261                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1262
1263                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1264                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1265                 }
1266
1267                 if (doencrypt) {
1268                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
1269                 } else {
1270                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1271                         /* Ensure null termination */
1272                         plaintext_password.data[passlen1] = 0;
1273                 }
1274
1275                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
1276                 *domain = 0;
1277
1278         } else {
1279                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1280                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1281                 enum remote_arch_types ra_type = get_remote_arch();
1282                 char *p = smb_buf(inbuf);    
1283                 char *save_p = smb_buf(inbuf);
1284                 uint16 byte_count;
1285                         
1286
1287                 if(global_client_caps == 0) {
1288                         global_client_caps = IVAL(inbuf,smb_vwv11);
1289                 
1290                         if (!(global_client_caps & CAP_STATUS32)) {
1291                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1292                         }
1293
1294                         /* client_caps is used as final determination if client is NT or Win95. 
1295                            This is needed to return the correct error codes in some
1296                            circumstances.
1297                         */
1298                 
1299                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1300                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1301                                         set_remote_arch( RA_WIN95);
1302                                 }
1303                         }
1304                 }
1305
1306                 if (!doencrypt) {
1307                         /* both Win95 and WinNT stuff up the password lengths for
1308                            non-encrypting systems. Uggh. 
1309                            
1310                            if passlen1==24 its a win95 system, and its setting the
1311                            password length incorrectly. Luckily it still works with the
1312                            default code because Win95 will null terminate the password
1313                            anyway 
1314                            
1315                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
1316                            setting passlen2 to some random value which really stuffs
1317                            things up. we need to fix that one.  */
1318                         
1319                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1320                                 passlen2 = 0;
1321                 }
1322                 
1323                 /* check for nasty tricks */
1324                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1325                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1326                 }
1327
1328                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1329                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1330                 }
1331
1332                 /* Save the lanman2 password and the NT md4 password. */
1333                 
1334                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1335                         doencrypt = False;
1336                 }
1337
1338                 if (doencrypt) {
1339                         lm_resp = data_blob(p, passlen1);
1340                         nt_resp = data_blob(p+passlen1, passlen2);
1341                 } else {
1342                         pstring pass;
1343                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1344
1345 #if 0
1346                         /* This was the previous fix. Not sure if it's still valid. JRA. */
1347                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1348                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
1349                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1350                                         sizeof(pass), passlen1, STR_TERMINATE);
1351 #endif
1352
1353                         if (unic && (passlen2 == 0) && passlen1) {
1354                                 /* Only a ascii plaintext password was sent. */
1355                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
1356                                         passlen1, STR_TERMINATE|STR_ASCII);
1357                         } else {
1358                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
1359                                         sizeof(pass),  unic ? passlen2 : passlen1, 
1360                                         STR_TERMINATE);
1361                         }
1362                         plaintext_password = data_blob(pass, strlen(pass)+1);
1363                 }
1364                 
1365                 p += passlen1 + passlen2;
1366                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
1367                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
1368                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
1369                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
1370
1371                 /* not documented or decoded by Ethereal but there is one more string 
1372                    in the extra bytes which is the same as the PrimaryDomain when using 
1373                    extended security.  Windows NT 4 and 2003 use this string to store 
1374                    the native lanman string. Windows 9x does not include a string here 
1375                    at all so we have to check if we have any extra bytes left */
1376                 
1377                 byte_count = SVAL(inbuf, smb_vwv13);
1378                 if ( PTR_DIFF(p, save_p) < byte_count)
1379                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1380                 else 
1381                         fstrcpy( primary_domain, "null" );
1382
1383                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1384                          domain, native_os, native_lanman, primary_domain));
1385
1386                 if ( ra_type == RA_WIN2K ) {
1387                         if ( strlen(native_lanman) == 0 )
1388                                 ra_lanman_string( primary_domain );
1389                         else
1390                                 ra_lanman_string( native_lanman );
1391                 }
1392
1393         }
1394
1395         if (SVAL(inbuf,smb_vwv4) == 0) {
1396                 setup_new_vc_session();
1397         }
1398
1399         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1400
1401         if (*user) {
1402                 if (global_spnego_negotiated) {
1403                         
1404                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1405                         
1406                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1407                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1408                 }
1409                 fstrcpy(sub_user, user);
1410         } else {
1411                 fstrcpy(sub_user, lp_guestaccount());
1412         }
1413
1414         sub_set_smb_name(sub_user);
1415
1416         reload_services(True);
1417         
1418         if (lp_security() == SEC_SHARE) {
1419                 /* in share level we should ignore any passwords */
1420
1421                 data_blob_free(&lm_resp);
1422                 data_blob_free(&nt_resp);
1423                 data_blob_clear_free(&plaintext_password);
1424
1425                 map_username(sub_user);
1426                 add_session_user(sub_user);
1427                 add_session_workgroup(domain);
1428                 /* Then force it to null for the benfit of the code below */
1429                 *user = 0;
1430         }
1431         
1432         if (!*user) {
1433
1434                 nt_status = check_guest_password(&server_info);
1435
1436         } else if (doencrypt) {
1437                 if (!negprot_global_auth_context) {
1438                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1439                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1440                 }
1441                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1442                                                          lm_resp, nt_resp);
1443                 if (NT_STATUS_IS_OK(nt_status)) {
1444                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1445                                                                                      user_info, 
1446                                                                                      &server_info);
1447                 }
1448         } else {
1449                 struct auth_context *plaintext_auth_context = NULL;
1450                 const uint8 *chal;
1451
1452                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1453
1454                 if (NT_STATUS_IS_OK(nt_status)) {
1455                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1456                         
1457                         if (!make_user_info_for_reply(&user_info, 
1458                                                       user, domain, chal,
1459                                                       plaintext_password)) {
1460                                 nt_status = NT_STATUS_NO_MEMORY;
1461                         }
1462                 
1463                         if (NT_STATUS_IS_OK(nt_status)) {
1464                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1465                                                                                         user_info, 
1466                                                                                         &server_info); 
1467                                 
1468                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1469                         }
1470                 }
1471         }
1472
1473         free_user_info(&user_info);
1474         
1475         if (!NT_STATUS_IS_OK(nt_status)) {
1476                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1477         }
1478         
1479         if (!NT_STATUS_IS_OK(nt_status)) {
1480                 data_blob_free(&nt_resp);
1481                 data_blob_free(&lm_resp);
1482                 data_blob_clear_free(&plaintext_password);
1483                 return ERROR_NT(nt_status_squash(nt_status));
1484         }
1485
1486         /* Ensure we can't possible take a code path leading to a null defref. */
1487         if (!server_info) {
1488                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1489         }
1490
1491         nt_status = create_local_token(server_info);
1492         if (!NT_STATUS_IS_OK(nt_status)) {
1493                 DEBUG(10, ("create_local_token failed: %s\n",
1494                            nt_errstr(nt_status)));
1495                 data_blob_free(&nt_resp);
1496                 data_blob_free(&lm_resp);
1497                 data_blob_clear_free(&plaintext_password);
1498                 return ERROR_NT(nt_status_squash(nt_status));
1499         }
1500
1501         if (server_info->user_session_key.data) {
1502                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1503         } else {
1504                 session_key = data_blob(NULL, 0);
1505         }
1506
1507         data_blob_clear_free(&plaintext_password);
1508         
1509         /* it's ok - setup a reply */
1510         set_message(outbuf,3,0,True);
1511         if (Protocol >= PROTOCOL_NT1) {
1512                 char *p = smb_buf( outbuf );
1513                 p += add_signature( outbuf, p );
1514                 set_message_end( outbuf, p );
1515                 /* perhaps grab OS version here?? */
1516         }
1517         
1518         if (server_info->guest) {
1519                 SSVAL(outbuf,smb_vwv2,1);
1520         }
1521
1522         /* register the name and uid as being validated, so further connections
1523            to a uid can get through without a password, on the same VC */
1524
1525         if (lp_security() == SEC_SHARE) {
1526                 sess_vuid = UID_FIELD_INVALID;
1527                 data_blob_free(&session_key);
1528                 TALLOC_FREE(server_info);
1529         } else {
1530                 /* register_vuid keeps the server info */
1531                 sess_vuid = register_vuid(server_info, session_key,
1532                                           nt_resp.data ? nt_resp : lm_resp,
1533                                           sub_user);
1534                 if (sess_vuid == UID_FIELD_INVALID) {
1535                         data_blob_free(&nt_resp);
1536                         data_blob_free(&lm_resp);
1537                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1538                 }
1539
1540                 /* current_user_info is changed on new vuid */
1541                 reload_services( True );
1542
1543                 sessionsetup_start_signing_engine(server_info, inbuf);
1544         }
1545
1546         data_blob_free(&nt_resp);
1547         data_blob_free(&lm_resp);
1548         
1549         SSVAL(outbuf,smb_uid,sess_vuid);
1550         SSVAL(inbuf,smb_uid,sess_vuid);
1551         
1552         if (!done_sesssetup)
1553                 max_send = MIN(max_send,smb_bufsize);
1554         
1555         done_sesssetup = True;
1556         
1557         END_PROFILE(SMBsesssetupX);
1558         return chain_reply(inbuf,outbuf,length,bufsize);
1559 }