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