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