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