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