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