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