r23726: Explicitly pass down the FLAGS2 field to srvstr_pull_buf. The next
[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
1033         DEBUG(3,("Doing spnego session setup\n"));
1034
1035         if (global_client_caps == 0) {
1036                 global_client_caps = IVAL(inbuf,smb_vwv10);
1037
1038                 if (!(global_client_caps & CAP_STATUS32)) {
1039                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1040                 }
1041
1042         }
1043                 
1044         p = (uint8 *)smb_buf(inbuf);
1045
1046         if (data_blob_len == 0) {
1047                 /* an invalid request */
1048                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1049         }
1050
1051         bufrem = smb_bufrem(inbuf, p);
1052         /* pull the spnego blob */
1053         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1054
1055 #if 0
1056         file_save("negotiate.dat", blob1.data, blob1.length);
1057 #endif
1058
1059         p2 = inbuf + smb_vwv13 + data_blob_len;
1060         p2 += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), native_os, p2,
1061                               sizeof(native_os), STR_TERMINATE);
1062         p2 += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), native_lanman, p2,
1063                               sizeof(native_lanman), STR_TERMINATE);
1064         p2 += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), primary_domain, p2,
1065                               sizeof(primary_domain), STR_TERMINATE);
1066         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
1067                 native_os, native_lanman, primary_domain));
1068
1069         if ( ra_type == RA_WIN2K ) {
1070                 /* Vista sets neither the OS or lanman strings */
1071
1072                 if ( !strlen(native_os) && !strlen(native_lanman) )
1073                         set_remote_arch(RA_VISTA);
1074                 
1075                 /* Windows 2003 doesn't set the native lanman string, 
1076                    but does set primary domain which is a bug I think */
1077                            
1078                 if ( !strlen(native_lanman) ) {
1079                         ra_lanman_string( primary_domain );
1080                 } else {
1081                         ra_lanman_string( native_lanman );
1082                 }
1083         }
1084                 
1085         vuser = get_partial_auth_user_struct(vuid);
1086         if (!vuser) {
1087                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1088                 if (pad) {
1089                         DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
1090                                 (unsigned int)pad->vuid ));
1091                         vuid = pad->vuid;
1092                         vuser = get_partial_auth_user_struct(vuid);
1093                 }
1094         }
1095
1096         if (!vuser) {
1097                 vuid = register_vuid(NULL, data_blob_null, data_blob_null, NULL);
1098                 if (vuid == UID_FIELD_INVALID ) {
1099                         data_blob_free(&blob1);
1100                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1101                 }
1102         
1103                 vuser = get_partial_auth_user_struct(vuid);
1104         }
1105
1106         if (!vuser) {
1107                 data_blob_free(&blob1);
1108                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1109         }
1110         
1111         SSVAL(outbuf,smb_uid,vuid);
1112
1113         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1114          * sessionsetup requests as the Windows limit on the security blob
1115          * field is 4k. Bug #4400. JRA.
1116          */
1117
1118         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1119         if (!NT_STATUS_IS_OK(status)) {
1120                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1121                         /* Real error - kill the intermediate vuid */
1122                         invalidate_vuid(vuid);
1123                 }
1124                 data_blob_free(&blob1);
1125                 return ERROR_NT(nt_status_squash(status));
1126         }
1127
1128         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1129                 /* its a negTokenTarg packet */
1130                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1131                                              &vuser->auth_ntlmssp_state);
1132                 data_blob_free(&blob1);
1133                 return ret;
1134         }
1135
1136         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1137                 /* its a auth packet */
1138                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1139                                         &vuser->auth_ntlmssp_state);
1140                 data_blob_free(&blob1);
1141                 return ret;
1142         }
1143
1144         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1145                 DATA_BLOB chal;
1146                 if (!vuser->auth_ntlmssp_state) {
1147                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1148                         if (!NT_STATUS_IS_OK(status)) {
1149                                 /* Kill the intermediate vuid */
1150                                 invalidate_vuid(vuid);
1151                                 data_blob_free(&blob1);
1152                                 return ERROR_NT(nt_status_squash(status));
1153                         }
1154                 }
1155
1156                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1157                                                 blob1, &chal);
1158                 
1159                 data_blob_free(&blob1);
1160                 
1161                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
1162                                            &vuser->auth_ntlmssp_state,
1163                                            &chal, status, False);
1164                 data_blob_free(&chal);
1165                 return -1;
1166         }
1167
1168         /* what sort of packet is this? */
1169         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1170
1171         data_blob_free(&blob1);
1172
1173         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1174 }
1175
1176 /****************************************************************************
1177  On new VC == 0, shutdown *all* old connections and users.
1178  It seems that only NT4.x does this. At W2K and above (XP etc.).
1179  a new session setup with VC==0 is ignored.
1180 ****************************************************************************/
1181
1182 static int shutdown_other_smbds(struct db_record *rec,
1183                                 const struct connections_key *key,
1184                                 const struct connections_data *crec,
1185                                 void *private_data)
1186 {
1187         const char *ip = (const char *)private_data;
1188
1189         if (!process_exists(crec->pid)) {
1190                 return 0;
1191         }
1192
1193         if (procid_is_me(&crec->pid)) {
1194                 return 0;
1195         }
1196
1197         if (strcmp(ip, crec->addr) != 0) {
1198                 return 0;
1199         }
1200
1201         messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1202                        &data_blob_null);
1203         return 0;
1204 }
1205
1206 static void setup_new_vc_session(void)
1207 {
1208         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1209 #if 0
1210         conn_close_all();
1211         invalidate_all_vuids();
1212 #endif
1213         if (lp_reset_on_zero_vc()) {
1214                 connections_forall(shutdown_other_smbds, client_addr());
1215         }
1216 }
1217
1218 /****************************************************************************
1219  Reply to a session setup command.
1220 ****************************************************************************/
1221
1222 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1223                           int length,int bufsize)
1224 {
1225         int sess_vuid;
1226         int   smb_bufsize;    
1227         DATA_BLOB lm_resp;
1228         DATA_BLOB nt_resp;
1229         DATA_BLOB plaintext_password;
1230         fstring user;
1231         fstring sub_user; /* Sainitised username for substituion */
1232         fstring domain;
1233         fstring native_os;
1234         fstring native_lanman;
1235         fstring primary_domain;
1236         static BOOL done_sesssetup = False;
1237         auth_usersupplied_info *user_info = NULL;
1238         auth_serversupplied_info *server_info = NULL;
1239
1240         NTSTATUS nt_status;
1241
1242         BOOL doencrypt = global_encrypted_passwords_negotiated;
1243
1244         DATA_BLOB session_key;
1245         
1246         START_PROFILE(SMBsesssetupX);
1247
1248         ZERO_STRUCT(lm_resp);
1249         ZERO_STRUCT(nt_resp);
1250         ZERO_STRUCT(plaintext_password);
1251
1252         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1253
1254         /* a SPNEGO session setup has 12 command words, whereas a normal
1255            NT1 session setup has 13. See the cifs spec. */
1256         if (CVAL(inbuf, smb_wct) == 12 &&
1257             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1258                 if (!global_spnego_negotiated) {
1259                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1260                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1261                 }
1262
1263                 if (SVAL(inbuf,smb_vwv4) == 0) {
1264                         setup_new_vc_session();
1265                 }
1266                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1267         }
1268
1269         smb_bufsize = SVAL(inbuf,smb_vwv2);
1270
1271         if (Protocol < PROTOCOL_NT1) {
1272                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1273
1274                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1275                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1276
1277                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1278                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1279                 }
1280
1281                 if (doencrypt) {
1282                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
1283                 } else {
1284                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1285                         /* Ensure null termination */
1286                         plaintext_password.data[passlen1] = 0;
1287                 }
1288
1289                 srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), user,
1290                                 smb_buf(inbuf)+passlen1, sizeof(user),
1291                                 STR_TERMINATE);
1292                 *domain = 0;
1293
1294         } else {
1295                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1296                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1297                 enum remote_arch_types ra_type = get_remote_arch();
1298                 char *p = smb_buf(inbuf);    
1299                 char *save_p = smb_buf(inbuf);
1300                 uint16 byte_count;
1301                         
1302
1303                 if(global_client_caps == 0) {
1304                         global_client_caps = IVAL(inbuf,smb_vwv11);
1305                 
1306                         if (!(global_client_caps & CAP_STATUS32)) {
1307                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1308                         }
1309
1310                         /* client_caps is used as final determination if client is NT or Win95. 
1311                            This is needed to return the correct error codes in some
1312                            circumstances.
1313                         */
1314                 
1315                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1316                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1317                                         set_remote_arch( RA_WIN95);
1318                                 }
1319                         }
1320                 }
1321
1322                 if (!doencrypt) {
1323                         /* both Win95 and WinNT stuff up the password lengths for
1324                            non-encrypting systems. Uggh. 
1325                            
1326                            if passlen1==24 its a win95 system, and its setting the
1327                            password length incorrectly. Luckily it still works with the
1328                            default code because Win95 will null terminate the password
1329                            anyway 
1330                            
1331                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
1332                            setting passlen2 to some random value which really stuffs
1333                            things up. we need to fix that one.  */
1334                         
1335                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1336                                 passlen2 = 0;
1337                 }
1338                 
1339                 /* check for nasty tricks */
1340                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1341                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1342                 }
1343
1344                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1345                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1346                 }
1347
1348                 /* Save the lanman2 password and the NT md4 password. */
1349                 
1350                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1351                         doencrypt = False;
1352                 }
1353
1354                 if (doencrypt) {
1355                         lm_resp = data_blob(p, passlen1);
1356                         nt_resp = data_blob(p+passlen1, passlen2);
1357                 } else {
1358                         pstring pass;
1359                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1360
1361 #if 0
1362                         /* This was the previous fix. Not sure if it's still valid. JRA. */
1363                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1364                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
1365                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1366                                         sizeof(pass), passlen1, STR_TERMINATE);
1367 #endif
1368
1369                         if (unic && (passlen2 == 0) && passlen1) {
1370                                 /* Only a ascii plaintext password was sent. */
1371                                 srvstr_pull(inbuf, SVAL(inbuf, smb_flg2), pass,
1372                                             smb_buf(inbuf), sizeof(pass),
1373                                             passlen1, STR_TERMINATE|STR_ASCII);
1374                         } else {
1375                                 srvstr_pull(inbuf, SVAL(inbuf, smb_flg2), pass,
1376                                             smb_buf(inbuf), sizeof(pass),
1377                                             unic ? passlen2 : passlen1,
1378                                             STR_TERMINATE);
1379                         }
1380                         plaintext_password = data_blob(pass, strlen(pass)+1);
1381                 }
1382                 
1383                 p += passlen1 + passlen2;
1384                 p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), user, p,
1385                                      sizeof(user), STR_TERMINATE);
1386                 p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), domain, p,
1387                                      sizeof(domain), STR_TERMINATE);
1388                 p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), native_os,
1389                                      p, sizeof(native_os), STR_TERMINATE);
1390                 p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2),
1391                                      native_lanman, p, sizeof(native_lanman),
1392                                      STR_TERMINATE);
1393
1394                 /* not documented or decoded by Ethereal but there is one more string 
1395                    in the extra bytes which is the same as the PrimaryDomain when using 
1396                    extended security.  Windows NT 4 and 2003 use this string to store 
1397                    the native lanman string. Windows 9x does not include a string here 
1398                    at all so we have to check if we have any extra bytes left */
1399                 
1400                 byte_count = SVAL(inbuf, smb_vwv13);
1401                 if ( PTR_DIFF(p, save_p) < byte_count)
1402                         p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2),
1403                                              primary_domain, p,
1404                                              sizeof(primary_domain),
1405                                              STR_TERMINATE);
1406                 else 
1407                         fstrcpy( primary_domain, "null" );
1408
1409                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1410                          domain, native_os, native_lanman, primary_domain));
1411
1412                 if ( ra_type == RA_WIN2K ) {
1413                         if ( strlen(native_lanman) == 0 )
1414                                 ra_lanman_string( primary_domain );
1415                         else
1416                                 ra_lanman_string( native_lanman );
1417                 }
1418
1419         }
1420
1421         if (SVAL(inbuf,smb_vwv4) == 0) {
1422                 setup_new_vc_session();
1423         }
1424
1425         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1426
1427         if (*user) {
1428                 if (global_spnego_negotiated) {
1429                         
1430                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1431                         
1432                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1433                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1434                 }
1435                 fstrcpy(sub_user, user);
1436         } else {
1437                 fstrcpy(sub_user, lp_guestaccount());
1438         }
1439
1440         sub_set_smb_name(sub_user);
1441
1442         reload_services(True);
1443         
1444         if (lp_security() == SEC_SHARE) {
1445                 /* in share level we should ignore any passwords */
1446
1447                 data_blob_free(&lm_resp);
1448                 data_blob_free(&nt_resp);
1449                 data_blob_clear_free(&plaintext_password);
1450
1451                 map_username(sub_user);
1452                 add_session_user(sub_user);
1453                 add_session_workgroup(domain);
1454                 /* Then force it to null for the benfit of the code below */
1455                 *user = 0;
1456         }
1457         
1458         if (!*user) {
1459
1460                 nt_status = check_guest_password(&server_info);
1461
1462         } else if (doencrypt) {
1463                 if (!negprot_global_auth_context) {
1464                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1465                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1466                 }
1467                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1468                                                          lm_resp, nt_resp);
1469                 if (NT_STATUS_IS_OK(nt_status)) {
1470                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1471                                                                                      user_info, 
1472                                                                                      &server_info);
1473                 }
1474         } else {
1475                 struct auth_context *plaintext_auth_context = NULL;
1476                 const uint8 *chal;
1477
1478                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1479
1480                 if (NT_STATUS_IS_OK(nt_status)) {
1481                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1482                         
1483                         if (!make_user_info_for_reply(&user_info, 
1484                                                       user, domain, chal,
1485                                                       plaintext_password)) {
1486                                 nt_status = NT_STATUS_NO_MEMORY;
1487                         }
1488                 
1489                         if (NT_STATUS_IS_OK(nt_status)) {
1490                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1491                                                                                         user_info, 
1492                                                                                         &server_info); 
1493                                 
1494                                 (plaintext_auth_context->free)(&plaintext_auth_context);
1495                         }
1496                 }
1497         }
1498
1499         free_user_info(&user_info);
1500         
1501         if (!NT_STATUS_IS_OK(nt_status)) {
1502                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1503         }
1504         
1505         if (!NT_STATUS_IS_OK(nt_status)) {
1506                 data_blob_free(&nt_resp);
1507                 data_blob_free(&lm_resp);
1508                 data_blob_clear_free(&plaintext_password);
1509                 return ERROR_NT(nt_status_squash(nt_status));
1510         }
1511
1512         /* Ensure we can't possible take a code path leading to a null defref. */
1513         if (!server_info) {
1514                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1515         }
1516
1517         nt_status = create_local_token(server_info);
1518         if (!NT_STATUS_IS_OK(nt_status)) {
1519                 DEBUG(10, ("create_local_token failed: %s\n",
1520                            nt_errstr(nt_status)));
1521                 data_blob_free(&nt_resp);
1522                 data_blob_free(&lm_resp);
1523                 data_blob_clear_free(&plaintext_password);
1524                 return ERROR_NT(nt_status_squash(nt_status));
1525         }
1526
1527         if (server_info->user_session_key.data) {
1528                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1529         } else {
1530                 session_key = data_blob_null;
1531         }
1532
1533         data_blob_clear_free(&plaintext_password);
1534         
1535         /* it's ok - setup a reply */
1536         set_message(inbuf,outbuf,3,0,True);
1537         if (Protocol >= PROTOCOL_NT1) {
1538                 char *p = smb_buf( outbuf );
1539                 p += add_signature( outbuf, p );
1540                 set_message_end(inbuf, outbuf, p );
1541                 /* perhaps grab OS version here?? */
1542         }
1543         
1544         if (server_info->guest) {
1545                 SSVAL(outbuf,smb_vwv2,1);
1546         }
1547
1548         /* register the name and uid as being validated, so further connections
1549            to a uid can get through without a password, on the same VC */
1550
1551         if (lp_security() == SEC_SHARE) {
1552                 sess_vuid = UID_FIELD_INVALID;
1553                 data_blob_free(&session_key);
1554                 TALLOC_FREE(server_info);
1555         } else {
1556                 /* register_vuid keeps the server info */
1557                 sess_vuid = register_vuid(server_info, session_key,
1558                                           nt_resp.data ? nt_resp : lm_resp,
1559                                           sub_user);
1560                 if (sess_vuid == UID_FIELD_INVALID) {
1561                         data_blob_free(&nt_resp);
1562                         data_blob_free(&lm_resp);
1563                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1564                 }
1565
1566                 /* current_user_info is changed on new vuid */
1567                 reload_services( True );
1568
1569                 sessionsetup_start_signing_engine(server_info, inbuf);
1570         }
1571
1572         data_blob_free(&nt_resp);
1573         data_blob_free(&lm_resp);
1574         
1575         SSVAL(outbuf,smb_uid,sess_vuid);
1576         SSVAL(inbuf,smb_uid,sess_vuid);
1577         
1578         if (!done_sesssetup)
1579                 max_send = MIN(max_send,smb_bufsize);
1580         
1581         done_sesssetup = True;
1582         
1583         END_PROFILE(SMBsesssetupX);
1584         return chain_reply(inbuf,outbuf,length,bufsize);
1585 }