]> git.samba.org - samba.git/blob - source/smbd/sesssetup.c
fix alignment bug hitting Solaris with "reset in zero vc" activated
[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", BUFFER_SIZE - (p - outbuf), STR_TERMINATE);
72         p += srvstr_push(outbuf, p, lanman, BUFFER_SIZE - (p - outbuf), STR_TERMINATE);
73         p += srvstr_push(outbuf, p, lp_workgroup(), BUFFER_SIZE - (p - outbuf), 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_intermediate_vuid(vuid);
628         }
629
630         return ret;
631 }
632
633 /****************************************************************************
634  Is this a krb5 mechanism ?
635 ****************************************************************************/
636
637 static 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_intermediate_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_intermediate_vuid(vuid);
708                 }
709                 return ret;
710         }
711 #endif
712
713         if (got_kerberos_mechanism) {
714                 invalidate_intermediate_vuid(vuid);
715                 DEBUG(3,("reply_spnego_negotiate: network "
716                         "misconfiguration, client sent us a "
717                         "krb5 ticket and kerberos security "
718                         "not enabled"));
719                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
720         }
721
722         if (*auth_ntlmssp_state) {
723                 auth_ntlmssp_end(auth_ntlmssp_state);
724         }
725
726         status = auth_ntlmssp_start(auth_ntlmssp_state);
727         if (!NT_STATUS_IS_OK(status)) {
728                 /* Kill the intermediate vuid */
729                 invalidate_intermediate_vuid(vuid);
730                 return ERROR_NT(nt_status_squash(status));
731         }
732
733         status = auth_ntlmssp_update(*auth_ntlmssp_state, 
734                                         secblob, &chal);
735
736         data_blob_free(&secblob);
737
738         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
739                              &chal, status, True);
740
741         data_blob_free(&chal);
742
743         /* already replied */
744         return -1;
745 }
746
747 /****************************************************************************
748  Reply to a session setup spnego auth packet.
749 ****************************************************************************/
750
751 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
752                              uint16 vuid,
753                              int length, int bufsize,
754                              DATA_BLOB blob1,
755                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
756 {
757         DATA_BLOB auth = data_blob(NULL,0);
758         DATA_BLOB auth_reply = data_blob(NULL,0);
759         DATA_BLOB secblob = data_blob(NULL,0);
760         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
761
762         if (!spnego_parse_auth(blob1, &auth)) {
763 #if 0
764                 file_save("auth.dat", blob1.data, blob1.length);
765 #endif
766                 /* Kill the intermediate vuid */
767                 invalidate_intermediate_vuid(vuid);
768
769                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
770         }
771
772         if (auth.data[0] == ASN1_APPLICATION(0)) {
773                 /* Might be a second negTokenTarg packet */
774
775                 BOOL got_krb5_mechanism = False;
776                 status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
777                 if (NT_STATUS_IS_OK(status)) {
778                         DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
779 #ifdef HAVE_KRB5
780                         if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
781                                 BOOL destroy_vuid = True;
782                                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
783                                                                 length, bufsize, &secblob, &destroy_vuid);
784                                 data_blob_free(&secblob);
785                                 data_blob_free(&auth);
786                                 if (destroy_vuid) {
787                                         /* Kill the intermediate vuid */
788                                         invalidate_intermediate_vuid(vuid);
789                                 }
790                                 return ret;
791                         }
792 #endif
793                 }
794         }
795
796         /* If we get here it wasn't a negTokenTarg auth packet. */
797         data_blob_free(&secblob);
798
799         if (!*auth_ntlmssp_state) {
800                 /* Kill the intermediate vuid */
801                 invalidate_intermediate_vuid(vuid);
802
803                 /* auth before negotiatiate? */
804                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
805         }
806
807         status = auth_ntlmssp_update(*auth_ntlmssp_state,
808                                         auth, &auth_reply);
809
810         data_blob_free(&auth);
811
812         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
813                              auth_ntlmssp_state,
814                              &auth_reply, status, True);
815
816         data_blob_free(&auth_reply);
817
818         /* and tell smbd that we have already replied to this packet */
819         return -1;
820 }
821
822 /****************************************************************************
823  List to store partial SPNEGO auth fragments.
824 ****************************************************************************/
825
826 static struct pending_auth_data *pd_list;
827
828 /****************************************************************************
829  Delete an entry on the list.
830 ****************************************************************************/
831
832 static void delete_partial_auth(struct pending_auth_data *pad)
833 {
834         if (!pad) {
835                 return;
836         }
837         DLIST_REMOVE(pd_list, pad);
838         data_blob_free(&pad->partial_data);
839         SAFE_FREE(pad);
840 }
841
842 /****************************************************************************
843  Search for a partial SPNEGO auth fragment matching an smbpid.
844 ****************************************************************************/
845
846 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
847 {
848         struct pending_auth_data *pad;
849
850         for (pad = pd_list; pad; pad = pad->next) {
851                 if (pad->smbpid == smbpid) {
852                         break;
853                 }
854         }
855         return pad;
856 }
857
858 /****************************************************************************
859  Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
860  else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
861 ****************************************************************************/
862
863 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
864 {
865         struct pending_auth_data *pad = NULL;
866         ASN1_DATA data;
867         size_t needed_len = 0;
868
869         pad = get_pending_auth_data(smbpid);
870
871         /* Ensure we have some data. */
872         if (pblob->length == 0) {
873                 /* Caller can cope. */
874                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
875                 delete_partial_auth(pad);
876                 return NT_STATUS_OK;
877         }
878
879         /* Were we waiting for more data ? */
880         if (pad) {
881                 DATA_BLOB tmp_blob;
882                 size_t copy_len = MIN(65536, pblob->length);
883
884                 /* Integer wrap paranoia.... */
885
886                 if (pad->partial_data.length + copy_len < pad->partial_data.length ||
887                     pad->partial_data.length + copy_len < copy_len) {
888
889                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
890                                 "pad->partial_data.length = %u, "
891                                 "copy_len = %u\n",
892                                 (unsigned int)pad->partial_data.length,
893                                 (unsigned int)copy_len ));
894
895                         delete_partial_auth(pad);
896                         return NT_STATUS_INVALID_PARAMETER;
897                 }
898
899                 DEBUG(10,("check_spnego_blob_complete: "
900                         "pad->partial_data.length = %u, "
901                         "pad->needed_len = %u, "
902                         "copy_len = %u, "
903                         "pblob->length = %u,\n",
904                         (unsigned int)pad->partial_data.length,
905                         (unsigned int)pad->needed_len,
906                         (unsigned int)copy_len,
907                         (unsigned int)pblob->length ));
908
909                 tmp_blob = data_blob(NULL,
910                                 pad->partial_data.length + copy_len);
911
912                 /* Concatenate the two (up to copy_len) bytes. */
913                 memcpy(tmp_blob.data,
914                         pad->partial_data.data,
915                         pad->partial_data.length);
916                 memcpy(tmp_blob.data + pad->partial_data.length,
917                         pblob->data,
918                         copy_len);
919
920                 /* Replace the partial data. */
921                 data_blob_free(&pad->partial_data);
922                 pad->partial_data = tmp_blob;
923                 ZERO_STRUCT(tmp_blob);
924
925                 /* Are we done ? */
926                 if (pblob->length >= pad->needed_len) {
927                         /* Yes, replace pblob. */
928                         data_blob_free(pblob);
929                         *pblob = pad->partial_data;
930                         ZERO_STRUCT(pad->partial_data);
931                         delete_partial_auth(pad);
932                         return NT_STATUS_OK;
933                 }
934
935                 /* Still need more data. */
936                 pad->needed_len -= copy_len;
937                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
938         }
939
940         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
941             (pblob->data[0] != ASN1_CONTEXT(1))) {
942                 /* Not something we can determine the
943                  * length of.
944                  */
945                 return NT_STATUS_OK;
946         }
947
948         /* This is a new SPNEGO sessionsetup - see if
949          * the data given in this blob is enough.
950          */
951
952         asn1_load(&data, *pblob);
953         asn1_start_tag(&data, pblob->data[0]);
954         if (data.has_error || data.nesting == NULL) {
955                 asn1_free(&data);
956                 /* Let caller catch. */
957                 return NT_STATUS_OK;
958         }
959
960         /* Integer wrap paranoia.... */
961
962         if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
963             data.nesting->taglen + data.nesting->start < data.nesting->start) {
964
965                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
966                         "data.nesting->taglen = %u, "
967                         "data.nesting->start = %u\n",
968                         (unsigned int)data.nesting->taglen,
969                         (unsigned int)data.nesting->start ));
970
971                 asn1_free(&data);
972                 return NT_STATUS_INVALID_PARAMETER;
973         }
974
975         /* Total length of the needed asn1 is the tag length
976          * plus the current offset. */
977
978         needed_len = data.nesting->taglen + data.nesting->start;
979         asn1_free(&data);
980
981         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
982                 "pblob->length = %u\n",
983                 (unsigned int)needed_len,
984                 (unsigned int)pblob->length ));
985
986         if (needed_len <= pblob->length) {
987                 /* Nothing to do - blob is complete. */
988                 return NT_STATUS_OK;
989         }
990
991         /* Refuse the blob if it's bigger than 64k. */
992         if (needed_len > 65536) {
993                 DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
994                         (unsigned int)needed_len ));
995                 return NT_STATUS_INVALID_PARAMETER;
996         }
997
998         /* We must store this blob until complete. */
999         pad = SMB_MALLOC(sizeof(struct pending_auth_data));
1000         if (!pad) {
1001                 return NT_STATUS_NO_MEMORY;
1002         }
1003         pad->needed_len = needed_len - pblob->length;
1004         pad->partial_data = data_blob(pblob->data, pblob->length);
1005         if (pad->partial_data.data == NULL) {
1006                 SAFE_FREE(pad);
1007                 return NT_STATUS_NO_MEMORY;
1008         }
1009         pad->smbpid = smbpid;
1010         pad->vuid = vuid;
1011         DLIST_ADD(pd_list, pad);
1012
1013         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1014 }
1015
1016 /****************************************************************************
1017  Reply to a session setup command.
1018  conn POINTER CAN BE NULL HERE !
1019 ****************************************************************************/
1020
1021 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
1022                                         char *outbuf,
1023                                         int length,int bufsize)
1024 {
1025         uint8 *p;
1026         DATA_BLOB blob1;
1027         int ret;
1028         size_t bufrem;
1029         fstring native_os, native_lanman, primary_domain;
1030         char *p2;
1031         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
1032         enum remote_arch_types ra_type = get_remote_arch();
1033         int vuid = SVAL(inbuf,smb_uid);
1034         user_struct *vuser = NULL;
1035         NTSTATUS status = NT_STATUS_OK;
1036         uint16 smbpid = SVAL(inbuf,smb_pid);
1037
1038         DEBUG(3,("Doing spnego session setup\n"));
1039
1040         if (global_client_caps == 0) {
1041                 global_client_caps = IVAL(inbuf,smb_vwv10);
1042
1043                 if (!(global_client_caps & CAP_STATUS32)) {
1044                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1045                 }
1046
1047         }
1048                 
1049         p = (uint8 *)smb_buf(inbuf);
1050
1051         if (data_blob_len == 0) {
1052                 /* an invalid request */
1053                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1054         }
1055
1056         bufrem = smb_bufrem(inbuf, p);
1057         /* pull the spnego blob */
1058         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1059
1060 #if 0
1061         file_save("negotiate.dat", blob1.data, blob1.length);
1062 #endif
1063
1064         p2 = inbuf + smb_vwv13 + data_blob_len;
1065         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
1066         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
1067         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
1068         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
1069                 native_os, native_lanman, primary_domain));
1070
1071         if ( ra_type == RA_WIN2K ) {
1072                 /* Vista sets neither the OS or lanman strings */
1073
1074                 if ( !strlen(native_os) && !strlen(native_lanman) )
1075                         set_remote_arch(RA_VISTA);
1076                 
1077                 /* Windows 2003 doesn't set the native lanman string, 
1078                    but does set primary domain which is a bug I think */
1079                            
1080                 if ( !strlen(native_lanman) ) {
1081                         ra_lanman_string( primary_domain );
1082                 } else {
1083                         ra_lanman_string( native_lanman );
1084                 }
1085         }
1086                 
1087         vuser = get_partial_auth_user_struct(vuid);
1088         if (!vuser) {
1089                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1090                 if (pad) {
1091                         DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
1092                                 (unsigned int)pad->vuid ));
1093                         vuid = pad->vuid;
1094                         vuser = get_partial_auth_user_struct(vuid);
1095                 }
1096         }
1097
1098         if (!vuser) {
1099                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
1100                 if (vuid == UID_FIELD_INVALID ) {
1101                         data_blob_free(&blob1);
1102                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1103                 }
1104         
1105                 vuser = get_partial_auth_user_struct(vuid);
1106         }
1107
1108         if (!vuser) {
1109                 data_blob_free(&blob1);
1110                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1111         }
1112         
1113         SSVAL(outbuf,smb_uid,vuid);
1114
1115         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1116          * sessionsetup requests as the Windows limit on the security blob
1117          * field is 4k. Bug #4400. JRA.
1118          */
1119
1120         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1121         if (!NT_STATUS_IS_OK(status)) {
1122                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1123                         /* Real error - kill the intermediate vuid */
1124                         invalidate_intermediate_vuid(vuid);
1125                 }
1126                 data_blob_free(&blob1);
1127                 return ERROR_NT(nt_status_squash(status));
1128         }
1129
1130         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1131                 /* its a negTokenTarg packet */
1132                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1133                                              &vuser->auth_ntlmssp_state);
1134                 data_blob_free(&blob1);
1135                 return ret;
1136         }
1137
1138         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1139                 /* its a auth packet */
1140                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1141                                         &vuser->auth_ntlmssp_state);
1142                 data_blob_free(&blob1);
1143                 return ret;
1144         }
1145
1146         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1147                 DATA_BLOB chal;
1148                 if (!vuser->auth_ntlmssp_state) {
1149                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1150                         if (!NT_STATUS_IS_OK(status)) {
1151                                 /* Kill the intermediate vuid */
1152                                 invalidate_intermediate_vuid(vuid);
1153                                 data_blob_free(&blob1);
1154                                 return ERROR_NT(nt_status_squash(status));
1155                         }
1156                 }
1157
1158                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1159                                                 blob1, &chal);
1160                 
1161                 data_blob_free(&blob1);
1162                 
1163                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
1164                                            &vuser->auth_ntlmssp_state,
1165                                            &chal, status, False);
1166                 data_blob_free(&chal);
1167                 return -1;
1168         }
1169
1170         /* what sort of packet is this? */
1171         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1172
1173         data_blob_free(&blob1);
1174
1175         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1176 }
1177
1178 /****************************************************************************
1179  On new VC == 0, shutdown *all* old connections and users.
1180  It seems that only NT4.x does this. At W2K and above (XP etc.).
1181  a new session setup with VC==0 is ignored.
1182 ****************************************************************************/
1183
1184 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1185                                 void *p)
1186 {
1187         struct sessionid sessionid;
1188         const char *ip = (const char *)p;
1189
1190         SMB_ASSERT(dbuf.dsize == sizeof(sessionid));
1191         memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
1192
1193         if (!process_exists(pid_to_procid(sessionid.pid))) {
1194                 return 0;
1195         }
1196
1197         if (sessionid.pid == sys_getpid()) {
1198                 return 0;
1199         }
1200
1201         if (strcmp(ip, sessionid.ip_addr) != 0) {
1202                 return 0;
1203         }
1204
1205         message_send_pid(pid_to_procid(sessionid.pid), MSG_SHUTDOWN,
1206                          NULL, 0, True);
1207         return 0;
1208 }
1209
1210 static void setup_new_vc_session(void)
1211 {
1212         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1213 #if 0
1214         conn_close_all();
1215         invalidate_all_vuids();
1216 #endif
1217         if (lp_reset_on_zero_vc()) {
1218                 session_traverse(shutdown_other_smbds, client_addr());
1219         }
1220 }
1221
1222 /****************************************************************************
1223  Reply to a session setup command.
1224 ****************************************************************************/
1225
1226 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1227                           int length,int bufsize)
1228 {
1229         int sess_vuid;
1230         int   smb_bufsize;    
1231         DATA_BLOB lm_resp;
1232         DATA_BLOB nt_resp;
1233         DATA_BLOB plaintext_password;
1234         fstring user;
1235         fstring sub_user; /* Sainitised username for substituion */
1236         fstring domain;
1237         fstring native_os;
1238         fstring native_lanman;
1239         fstring primary_domain;
1240         static BOOL done_sesssetup = False;
1241         auth_usersupplied_info *user_info = NULL;
1242         auth_serversupplied_info *server_info = NULL;
1243
1244         NTSTATUS nt_status;
1245
1246         BOOL doencrypt = global_encrypted_passwords_negotiated;
1247
1248         DATA_BLOB session_key;
1249         
1250         START_PROFILE(SMBsesssetupX);
1251
1252         ZERO_STRUCT(lm_resp);
1253         ZERO_STRUCT(nt_resp);
1254         ZERO_STRUCT(plaintext_password);
1255
1256         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1257
1258         /* a SPNEGO session setup has 12 command words, whereas a normal
1259            NT1 session setup has 13. See the cifs spec. */
1260         if (CVAL(inbuf, smb_wct) == 12 &&
1261             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1262                 if (!global_spnego_negotiated) {
1263                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1264                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1265                 }
1266
1267                 if (SVAL(inbuf,smb_vwv4) == 0) {
1268                         setup_new_vc_session();
1269                 }
1270                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1271         }
1272
1273         smb_bufsize = SVAL(inbuf,smb_vwv2);
1274
1275         if (Protocol < PROTOCOL_NT1) {
1276                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1277
1278                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1279                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1280
1281                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1282                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1283                 }
1284
1285                 if (doencrypt) {
1286                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
1287                 } else {
1288                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1289                         /* Ensure null termination */
1290                         plaintext_password.data[passlen1] = 0;
1291                 }
1292
1293                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
1294                 *domain = 0;
1295
1296         } else {
1297                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1298                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1299                 enum remote_arch_types ra_type = get_remote_arch();
1300                 char *p = smb_buf(inbuf);    
1301                 char *save_p = smb_buf(inbuf);
1302                 uint16 byte_count;
1303                         
1304
1305                 if(global_client_caps == 0) {
1306                         global_client_caps = IVAL(inbuf,smb_vwv11);
1307                 
1308                         if (!(global_client_caps & CAP_STATUS32)) {
1309                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1310                         }
1311
1312                         /* client_caps is used as final determination if client is NT or Win95. 
1313                            This is needed to return the correct error codes in some
1314                            circumstances.
1315                         */
1316                 
1317                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1318                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1319                                         set_remote_arch( RA_WIN95);
1320                                 }
1321                         }
1322                 }
1323
1324                 if (!doencrypt) {
1325                         /* both Win95 and WinNT stuff up the password lengths for
1326                            non-encrypting systems. Uggh. 
1327                            
1328                            if passlen1==24 its a win95 system, and its setting the
1329                            password length incorrectly. Luckily it still works with the
1330                            default code because Win95 will null terminate the password
1331                            anyway 
1332                            
1333                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
1334                            setting passlen2 to some random value which really stuffs
1335                            things up. we need to fix that one.  */
1336                         
1337                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1338                                 passlen2 = 0;
1339                 }
1340                 
1341                 /* check for nasty tricks */
1342                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1343                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1344                 }
1345
1346                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1347                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1348                 }
1349
1350                 /* Save the lanman2 password and the NT md4 password. */
1351                 
1352                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1353                         doencrypt = False;
1354                 }
1355
1356                 if (doencrypt) {
1357                         lm_resp = data_blob(p, passlen1);
1358                         nt_resp = data_blob(p+passlen1, passlen2);
1359                 } else {
1360                         pstring pass;
1361                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1362
1363 #if 0
1364                         /* This was the previous fix. Not sure if it's still valid. JRA. */
1365                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1366                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
1367                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1368                                         sizeof(pass), passlen1, STR_TERMINATE);
1369 #endif
1370
1371                         if (unic && (passlen2 == 0) && passlen1) {
1372                                 /* Only a ascii plaintext password was sent. */
1373                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
1374                                         passlen1, STR_TERMINATE|STR_ASCII);
1375                         } else {
1376                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
1377                                         sizeof(pass),  unic ? passlen2 : passlen1, 
1378                                         STR_TERMINATE);
1379                         }
1380                         plaintext_password = data_blob(pass, strlen(pass)+1);
1381                 }
1382                 
1383                 p += passlen1 + passlen2;
1384                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
1385                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
1386                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
1387                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
1388
1389                 /* not documented or decoded by Ethereal but there is one more string 
1390                    in the extra bytes which is the same as the PrimaryDomain when using 
1391                    extended security.  Windows NT 4 and 2003 use this string to store 
1392                    the native lanman string. Windows 9x does not include a string here 
1393                    at all so we have to check if we have any extra bytes left */
1394                 
1395                 byte_count = SVAL(inbuf, smb_vwv13);
1396                 if ( PTR_DIFF(p, save_p) < byte_count)
1397                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1398                 else 
1399                         fstrcpy( primary_domain, "null" );
1400
1401                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1402                          domain, native_os, native_lanman, primary_domain));
1403
1404                 if ( ra_type == RA_WIN2K ) {
1405                         if ( strlen(native_lanman) == 0 )
1406                                 ra_lanman_string( primary_domain );
1407                         else
1408                                 ra_lanman_string( native_lanman );
1409                 }
1410
1411         }
1412
1413         if (SVAL(inbuf,smb_vwv4) == 0) {
1414                 setup_new_vc_session();
1415         }
1416
1417         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1418
1419         if (*user) {
1420                 if (global_spnego_negotiated) {
1421                         
1422                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1423                         
1424                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1425                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1426                 }
1427                 fstrcpy(sub_user, user);
1428         } else {
1429                 fstrcpy(sub_user, lp_guestaccount());
1430         }
1431
1432         sub_set_smb_name(sub_user);
1433
1434         reload_services(True);
1435         
1436         if (lp_security() == SEC_SHARE) {
1437                 /* in share level we should ignore any passwords */
1438
1439                 data_blob_free(&lm_resp);
1440                 data_blob_free(&nt_resp);
1441                 data_blob_clear_free(&plaintext_password);
1442
1443                 map_username(sub_user);
1444                 add_session_user(sub_user);
1445                 add_session_workgroup(domain);
1446                 /* Then force it to null for the benfit of the code below */
1447                 *user = 0;
1448         }
1449         
1450         if (!*user) {
1451
1452                 nt_status = check_guest_password(&server_info);
1453
1454         } else if (doencrypt) {
1455                 if (!negprot_global_auth_context) {
1456                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1457                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1458                 }
1459                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1460                                                          lm_resp, nt_resp);
1461                 if (NT_STATUS_IS_OK(nt_status)) {
1462                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1463                                                                                      user_info, 
1464                                                                                      &server_info);
1465                 }
1466         } else {
1467                 struct auth_context *plaintext_auth_context = NULL;
1468                 const uint8 *chal;
1469
1470                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1471
1472                 if (NT_STATUS_IS_OK(nt_status)) {
1473                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1474                         
1475                         if (!make_user_info_for_reply(&user_info, 
1476                                                       user, domain, chal,
1477                                                       plaintext_password)) {
1478                                 nt_status = NT_STATUS_NO_MEMORY;
1479                         }
1480                 
1481                         if (NT_STATUS_IS_OK(nt_status)) {
1482                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1483                                                                                         user_info, 
1484                                                                                         &server_info); 
1485                                 
1486                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1487                         }
1488                 }
1489         }
1490
1491         free_user_info(&user_info);
1492         
1493         if (!NT_STATUS_IS_OK(nt_status)) {
1494                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1495         }
1496         
1497         if (!NT_STATUS_IS_OK(nt_status)) {
1498                 data_blob_free(&nt_resp);
1499                 data_blob_free(&lm_resp);
1500                 data_blob_clear_free(&plaintext_password);
1501                 return ERROR_NT(nt_status_squash(nt_status));
1502         }
1503
1504         /* Ensure we can't possible take a code path leading to a null defref. */
1505         if (!server_info) {
1506                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1507         }
1508
1509         nt_status = create_local_token(server_info);
1510         if (!NT_STATUS_IS_OK(nt_status)) {
1511                 DEBUG(10, ("create_local_token failed: %s\n",
1512                            nt_errstr(nt_status)));
1513                 data_blob_free(&nt_resp);
1514                 data_blob_free(&lm_resp);
1515                 data_blob_clear_free(&plaintext_password);
1516                 return ERROR_NT(nt_status_squash(nt_status));
1517         }
1518
1519         if (server_info->user_session_key.data) {
1520                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1521         } else {
1522                 session_key = data_blob(NULL, 0);
1523         }
1524
1525         data_blob_clear_free(&plaintext_password);
1526         
1527         /* it's ok - setup a reply */
1528         set_message(outbuf,3,0,True);
1529         if (Protocol >= PROTOCOL_NT1) {
1530                 char *p = smb_buf( outbuf );
1531                 p += add_signature( outbuf, p );
1532                 set_message_end( outbuf, p );
1533                 /* perhaps grab OS version here?? */
1534         }
1535         
1536         if (server_info->guest) {
1537                 SSVAL(outbuf,smb_vwv2,1);
1538         }
1539
1540         /* register the name and uid as being validated, so further connections
1541            to a uid can get through without a password, on the same VC */
1542
1543         if (lp_security() == SEC_SHARE) {
1544                 sess_vuid = UID_FIELD_INVALID;
1545                 data_blob_free(&session_key);
1546                 TALLOC_FREE(server_info);
1547         } else {
1548                 /* register_vuid keeps the server info */
1549                 sess_vuid = register_vuid(server_info, session_key,
1550                                           nt_resp.data ? nt_resp : lm_resp,
1551                                           sub_user);
1552                 if (sess_vuid == UID_FIELD_INVALID) {
1553                         data_blob_free(&nt_resp);
1554                         data_blob_free(&lm_resp);
1555                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1556                 }
1557
1558                 /* current_user_info is changed on new vuid */
1559                 reload_services( True );
1560
1561                 sessionsetup_start_signing_engine(server_info, inbuf);
1562         }
1563
1564         data_blob_free(&nt_resp);
1565         data_blob_free(&lm_resp);
1566         
1567         SSVAL(outbuf,smb_uid,sess_vuid);
1568         SSVAL(inbuf,smb_uid,sess_vuid);
1569         
1570         if (!done_sesssetup)
1571                 max_send = MIN(max_send,smb_bufsize);
1572         
1573         done_sesssetup = True;
1574         
1575         END_PROFILE(SMBsesssetupX);
1576         return chain_reply(inbuf,outbuf,length,bufsize);
1577 }