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