s3: Fix a typo
[nivanova/samba-autobuild/.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 "../libcli/auth/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 = req->sconn;
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(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                         TALLOC_FREE(sampass);
508                 } else {
509                         /*
510                          * User not in passdb, make it up artificially
511                          */
512                         TALLOC_FREE(sampass);
513                         DEBUG(10, ("didn't find user %s in passdb, calling "
514                                    "make_server_info_pw\n", real_username));
515                         ret = make_server_info_pw(&server_info, real_username,
516                                                   pw);
517                 }
518
519                 if ( !NT_STATUS_IS_OK(ret) ) {
520                         DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
521                                  nt_errstr(ret)));
522                         data_blob_free(&ap_rep);
523                         data_blob_free(&session_key);
524                         TALLOC_FREE(mem_ctx);
525                         reply_nterror(req, nt_status_squash(ret));
526                         return;
527                 }
528
529                 /* make_server_info_pw does not set the domain. Without this
530                  * we end up with the local netbios name in substitutions for
531                  * %D. */
532
533                 if (server_info->info3 != NULL) {
534                         server_info->info3->base.domain.string =
535                                 talloc_strdup(server_info->info3, domain);
536                 }
537         }
538
539         server_info->nss_token |= username_was_mapped;
540
541         /* we need to build the token for the user. make_server_info_guest()
542            already does this */
543
544         if ( !server_info->ptok ) {
545                 ret = create_local_token( server_info );
546                 if ( !NT_STATUS_IS_OK(ret) ) {
547                         DEBUG(10,("failed to create local token: %s\n",
548                                 nt_errstr(ret)));
549                         data_blob_free(&ap_rep);
550                         data_blob_free(&session_key);
551                         TALLOC_FREE( mem_ctx );
552                         TALLOC_FREE( server_info );
553                         reply_nterror(req, nt_status_squash(ret));
554                         return;
555                 }
556         }
557
558         if (!is_partial_auth_vuid(sconn, sess_vuid)) {
559                 sess_vuid = register_initial_vuid(sconn);
560         }
561
562         data_blob_free(&server_info->user_session_key);
563         server_info->user_session_key = session_key;
564         session_key = data_blob_null;
565
566         /* register_existing_vuid keeps the server info */
567         /* register_existing_vuid takes ownership of session_key on success,
568          * no need to free after this on success. A better interface would copy
569          * it.... */
570
571         sess_vuid = register_existing_vuid(sconn,
572                                         sess_vuid,
573                                         server_info,
574                                         nullblob,
575                                         client);
576
577         reply_outbuf(req, 4, 0);
578         SSVAL(req->outbuf,smb_uid,sess_vuid);
579
580         if (sess_vuid == UID_FIELD_INVALID ) {
581                 ret = NT_STATUS_LOGON_FAILURE;
582         } else {
583                 /* current_user_info is changed on new vuid */
584                 reload_services( True );
585
586                 SSVAL(req->outbuf, smb_vwv3, 0);
587
588                 if (server_info->guest) {
589                         SSVAL(req->outbuf,smb_vwv2,1);
590                 }
591
592                 SSVAL(req->outbuf, smb_uid, sess_vuid);
593
594                 /* Successful logon. Keep this vuid. */
595                 *p_invalidate_vuid = False;
596         }
597
598         /* wrap that up in a nice GSS-API wrapping */
599         if (NT_STATUS_IS_OK(ret)) {
600                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
601                                 TOK_ID_KRB_AP_REP);
602         } else {
603                 ap_rep_wrapped = data_blob_null;
604         }
605         response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
606                         mechOID);
607         reply_sesssetup_blob(req, response, ret);
608
609         data_blob_free(&ap_rep);
610         data_blob_free(&ap_rep_wrapped);
611         data_blob_free(&response);
612         TALLOC_FREE(mem_ctx);
613 }
614
615 #endif
616
617 /****************************************************************************
618  Send a session setup reply, wrapped in SPNEGO.
619  Get vuid and check first.
620  End the NTLMSSP exchange context if we are OK/complete fail
621  This should be split into two functions, one to handle each
622  leg of the NTLM auth steps.
623 ***************************************************************************/
624
625 static void reply_spnego_ntlmssp(struct smb_request *req,
626                                  uint16 vuid,
627                                  struct auth_ntlmssp_state **auth_ntlmssp_state,
628                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
629                                  const char *OID,
630                                  bool wrap)
631 {
632         DATA_BLOB response;
633         struct auth_serversupplied_info *server_info = NULL;
634         struct smbd_server_connection *sconn = req->sconn;
635
636         if (NT_STATUS_IS_OK(nt_status)) {
637                 server_info = auth_ntlmssp_server_info(talloc_tos(), (*auth_ntlmssp_state));
638         } else {
639                 /* Note that this server_info won't have a session
640                  * key.  But for map to guest, that's exactly the right
641                  * thing - we can't reasonably guess the key the
642                  * client wants, as the password was wrong */
643                 nt_status = do_map_to_guest(nt_status,
644                                             &server_info,
645                                             auth_ntlmssp_get_username(*auth_ntlmssp_state),
646                                             auth_ntlmssp_get_domain(*auth_ntlmssp_state));
647         }
648
649         reply_outbuf(req, 4, 0);
650
651         SSVAL(req->outbuf, smb_uid, vuid);
652
653         if (NT_STATUS_IS_OK(nt_status)) {
654                 DATA_BLOB nullblob = data_blob_null;
655
656                 if (!is_partial_auth_vuid(sconn, vuid)) {
657                         nt_status = NT_STATUS_LOGON_FAILURE;
658                         goto out;
659                 }
660
661                 /* register_existing_vuid keeps the server info */
662                 if (register_existing_vuid(sconn, vuid,
663                                            server_info, nullblob,
664                                            auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
665                                            vuid) {
666                         nt_status = NT_STATUS_LOGON_FAILURE;
667                         goto out;
668                 }
669
670                 /* current_user_info is changed on new vuid */
671                 reload_services( True );
672
673                 SSVAL(req->outbuf, smb_vwv3, 0);
674
675                 if (server_info->guest) {
676                         SSVAL(req->outbuf,smb_vwv2,1);
677                 }
678         }
679
680   out:
681
682         if (wrap) {
683                 response = spnego_gen_auth_response(ntlmssp_blob,
684                                 nt_status, OID);
685         } else {
686                 response = *ntlmssp_blob;
687         }
688
689         reply_sesssetup_blob(req, response, nt_status);
690         if (wrap) {
691                 data_blob_free(&response);
692         }
693
694         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
695            and the other end, that we are not finished yet. */
696
697         if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
698                 /* NB. This is *NOT* an error case. JRA */
699                 auth_ntlmssp_end(auth_ntlmssp_state);
700                 if (!NT_STATUS_IS_OK(nt_status)) {
701                         /* Kill the intermediate vuid */
702                         invalidate_vuid(sconn, vuid);
703                 }
704         }
705 }
706
707 /****************************************************************************
708  Is this a krb5 mechanism ?
709 ****************************************************************************/
710
711 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
712                 DATA_BLOB *pblob_out,
713                 char **kerb_mechOID)
714 {
715         char *OIDs[ASN1_MAX_OIDS];
716         int i;
717         NTSTATUS ret = NT_STATUS_OK;
718
719         *kerb_mechOID = NULL;
720
721         /* parse out the OIDs and the first sec blob */
722         if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
723                 return NT_STATUS_LOGON_FAILURE;
724         }
725
726         /* only look at the first OID for determining the mechToken --
727            according to RFC2478, we should choose the one we want
728            and renegotiate, but i smell a client bug here..
729
730            Problem observed when connecting to a member (samba box)
731            of an AD domain as a user in a Samba domain.  Samba member
732            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
733            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
734            NTLMSSP mechtoken.                 --jerry              */
735
736 #ifdef HAVE_KRB5
737         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
738             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
739                 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
740                 if (*kerb_mechOID == NULL) {
741                         ret = NT_STATUS_NO_MEMORY;
742                 }
743         }
744 #endif
745
746         for (i=0;OIDs[i];i++) {
747                 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
748                 talloc_free(OIDs[i]);
749         }
750         return ret;
751 }
752
753 /****************************************************************************
754  Fall back from krb5 to NTLMSSP.
755 ****************************************************************************/
756
757 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
758                                                 uint16 vuid)
759 {
760         DATA_BLOB response;
761
762         reply_outbuf(req, 4, 0);
763         SSVAL(req->outbuf,smb_uid,vuid);
764
765         DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
766                 "but set to downgrade to NTLMSSP\n"));
767
768         response = spnego_gen_auth_response(NULL,
769                         NT_STATUS_MORE_PROCESSING_REQUIRED,
770                         OID_NTLMSSP);
771         reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
772         data_blob_free(&response);
773 }
774
775 /****************************************************************************
776  Reply to a session setup spnego negotiate packet.
777 ****************************************************************************/
778
779 static void reply_spnego_negotiate(struct smb_request *req,
780                                    uint16 vuid,
781                                    DATA_BLOB blob1,
782                                    struct auth_ntlmssp_state **auth_ntlmssp_state)
783 {
784         DATA_BLOB secblob;
785         DATA_BLOB chal;
786         char *kerb_mech = NULL;
787         NTSTATUS status;
788         struct smbd_server_connection *sconn = req->sconn;
789
790         status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
791         if (!NT_STATUS_IS_OK(status)) {
792                 /* Kill the intermediate vuid */
793                 invalidate_vuid(sconn, vuid);
794                 reply_nterror(req, nt_status_squash(status));
795                 return;
796         }
797
798         DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
799                                 (unsigned long)secblob.length));
800
801 #ifdef HAVE_KRB5
802         if (kerb_mech && ((lp_security()==SEC_ADS) ||
803                                 USE_KERBEROS_KEYTAB) ) {
804                 bool destroy_vuid = True;
805                 reply_spnego_kerberos(req, &secblob, kerb_mech,
806                                       vuid, &destroy_vuid);
807                 data_blob_free(&secblob);
808                 if (destroy_vuid) {
809                         /* Kill the intermediate vuid */
810                         invalidate_vuid(sconn, vuid);
811                 }
812                 SAFE_FREE(kerb_mech);
813                 return;
814         }
815 #endif
816
817         if (*auth_ntlmssp_state) {
818                 auth_ntlmssp_end(auth_ntlmssp_state);
819         }
820
821         if (kerb_mech) {
822                 data_blob_free(&secblob);
823                 /* The mechtoken is a krb5 ticket, but
824                  * we need to fall back to NTLM. */
825                 reply_spnego_downgrade_to_ntlmssp(req, vuid);
826                 SAFE_FREE(kerb_mech);
827                 return;
828         }
829
830         status = auth_ntlmssp_start(auth_ntlmssp_state);
831         if (!NT_STATUS_IS_OK(status)) {
832                 /* Kill the intermediate vuid */
833                 invalidate_vuid(sconn, vuid);
834                 reply_nterror(req, nt_status_squash(status));
835                 return;
836         }
837
838         status = auth_ntlmssp_update(*auth_ntlmssp_state,
839                                         secblob, &chal);
840
841         data_blob_free(&secblob);
842
843         reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
844                              &chal, status, OID_NTLMSSP, true);
845
846         data_blob_free(&chal);
847
848         /* already replied */
849         return;
850 }
851
852 /****************************************************************************
853  Reply to a session setup spnego auth packet.
854 ****************************************************************************/
855
856 static void reply_spnego_auth(struct smb_request *req,
857                               uint16 vuid,
858                               DATA_BLOB blob1,
859                               struct auth_ntlmssp_state **auth_ntlmssp_state)
860 {
861         DATA_BLOB auth = data_blob_null;
862         DATA_BLOB auth_reply = data_blob_null;
863         DATA_BLOB secblob = data_blob_null;
864         NTSTATUS status = NT_STATUS_LOGON_FAILURE;
865         struct smbd_server_connection *sconn = req->sconn;
866
867         if (!spnego_parse_auth(blob1, &auth)) {
868 #if 0
869                 file_save("auth.dat", blob1.data, blob1.length);
870 #endif
871                 /* Kill the intermediate vuid */
872                 invalidate_vuid(sconn, vuid);
873
874                 reply_nterror(req, nt_status_squash(
875                                       NT_STATUS_LOGON_FAILURE));
876                 return;
877         }
878
879         if (auth.data[0] == ASN1_APPLICATION(0)) {
880                 /* Might be a second negTokenTarg packet */
881                 char *kerb_mech = NULL;
882
883                 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
884
885                 if (!NT_STATUS_IS_OK(status)) {
886                         /* Kill the intermediate vuid */
887                         invalidate_vuid(sconn, vuid);
888                         reply_nterror(req, nt_status_squash(status));
889                         return;
890                 }
891
892                 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
893                                 (unsigned long)secblob.length));
894 #ifdef HAVE_KRB5
895                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
896                                         USE_KERBEROS_KEYTAB)) {
897                         bool destroy_vuid = True;
898                         reply_spnego_kerberos(req, &secblob, kerb_mech,
899                                               vuid, &destroy_vuid);
900                         data_blob_free(&secblob);
901                         data_blob_free(&auth);
902                         if (destroy_vuid) {
903                                 /* Kill the intermediate vuid */
904                                 invalidate_vuid(sconn, vuid);
905                         }
906                         SAFE_FREE(kerb_mech);
907                         return;
908                 }
909 #endif
910                 /* Can't blunder into NTLMSSP auth if we have
911                  * a krb5 ticket. */
912
913                 if (kerb_mech) {
914                         /* Kill the intermediate vuid */
915                         invalidate_vuid(sconn, vuid);
916                         DEBUG(3,("reply_spnego_auth: network "
917                                 "misconfiguration, client sent us a "
918                                 "krb5 ticket and kerberos security "
919                                 "not enabled\n"));
920                         reply_nterror(req, nt_status_squash(
921                                         NT_STATUS_LOGON_FAILURE));
922                         SAFE_FREE(kerb_mech);
923                 }
924         }
925
926         /* If we get here it wasn't a negTokenTarg auth packet. */
927         data_blob_free(&secblob);
928
929         if (!*auth_ntlmssp_state) {
930                 status = auth_ntlmssp_start(auth_ntlmssp_state);
931                 if (!NT_STATUS_IS_OK(status)) {
932                         /* Kill the intermediate vuid */
933                         invalidate_vuid(sconn, vuid);
934                         reply_nterror(req, nt_status_squash(status));
935                         return;
936                 }
937         }
938
939         status = auth_ntlmssp_update(*auth_ntlmssp_state,
940                                         auth, &auth_reply);
941
942         data_blob_free(&auth);
943
944         /* Don't send the mechid as we've already sent this (RFC4178). */
945
946         reply_spnego_ntlmssp(req, vuid,
947                              auth_ntlmssp_state,
948                              &auth_reply, status, NULL, true);
949
950         data_blob_free(&auth_reply);
951
952         /* and tell smbd that we have already replied to this packet */
953         return;
954 }
955
956 /****************************************************************************
957  Delete an entry on the list.
958 ****************************************************************************/
959
960 static void delete_partial_auth(struct smbd_server_connection *sconn,
961                                 struct pending_auth_data *pad)
962 {
963         if (!pad) {
964                 return;
965         }
966         DLIST_REMOVE(sconn->smb1.pd_list, pad);
967         data_blob_free(&pad->partial_data);
968         SAFE_FREE(pad);
969 }
970
971 /****************************************************************************
972  Search for a partial SPNEGO auth fragment matching an smbpid.
973 ****************************************************************************/
974
975 static struct pending_auth_data *get_pending_auth_data(
976                 struct smbd_server_connection *sconn,
977                 uint16_t smbpid)
978 {
979         struct pending_auth_data *pad;
980 /*
981  * NOTE: using the smbpid here is completely wrong...
982  *       see [MS-SMB]
983  *       3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
984  */
985         for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
986                 if (pad->smbpid == smbpid) {
987                         break;
988                 }
989         }
990         return pad;
991 }
992
993 /****************************************************************************
994  Check the size of an SPNEGO blob. If we need more return
995  NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
996  the blob to be more than 64k.
997 ****************************************************************************/
998
999 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
1000                                            uint16 smbpid, uint16 vuid,
1001                                            DATA_BLOB *pblob)
1002 {
1003         struct pending_auth_data *pad = NULL;
1004         ASN1_DATA *data;
1005         size_t needed_len = 0;
1006
1007         pad = get_pending_auth_data(sconn, smbpid);
1008
1009         /* Ensure we have some data. */
1010         if (pblob->length == 0) {
1011                 /* Caller can cope. */
1012                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
1013                 delete_partial_auth(sconn, pad);
1014                 return NT_STATUS_OK;
1015         }
1016
1017         /* Were we waiting for more data ? */
1018         if (pad) {
1019                 DATA_BLOB tmp_blob;
1020                 size_t copy_len = MIN(65536, pblob->length);
1021
1022                 /* Integer wrap paranoia.... */
1023
1024                 if (pad->partial_data.length + copy_len <
1025                                 pad->partial_data.length ||
1026                     pad->partial_data.length + copy_len < copy_len) {
1027
1028                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
1029                                 "pad->partial_data.length = %u, "
1030                                 "copy_len = %u\n",
1031                                 (unsigned int)pad->partial_data.length,
1032                                 (unsigned int)copy_len ));
1033
1034                         delete_partial_auth(sconn, pad);
1035                         return NT_STATUS_INVALID_PARAMETER;
1036                 }
1037
1038                 DEBUG(10,("check_spnego_blob_complete: "
1039                         "pad->partial_data.length = %u, "
1040                         "pad->needed_len = %u, "
1041                         "copy_len = %u, "
1042                         "pblob->length = %u,\n",
1043                         (unsigned int)pad->partial_data.length,
1044                         (unsigned int)pad->needed_len,
1045                         (unsigned int)copy_len,
1046                         (unsigned int)pblob->length ));
1047
1048                 tmp_blob = data_blob(NULL,
1049                                 pad->partial_data.length + copy_len);
1050
1051                 /* Concatenate the two (up to copy_len) bytes. */
1052                 memcpy(tmp_blob.data,
1053                         pad->partial_data.data,
1054                         pad->partial_data.length);
1055                 memcpy(tmp_blob.data + pad->partial_data.length,
1056                         pblob->data,
1057                         copy_len);
1058
1059                 /* Replace the partial data. */
1060                 data_blob_free(&pad->partial_data);
1061                 pad->partial_data = tmp_blob;
1062                 ZERO_STRUCT(tmp_blob);
1063
1064                 /* Are we done ? */
1065                 if (pblob->length >= pad->needed_len) {
1066                         /* Yes, replace pblob. */
1067                         data_blob_free(pblob);
1068                         *pblob = pad->partial_data;
1069                         ZERO_STRUCT(pad->partial_data);
1070                         delete_partial_auth(sconn, pad);
1071                         return NT_STATUS_OK;
1072                 }
1073
1074                 /* Still need more data. */
1075                 pad->needed_len -= copy_len;
1076                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1077         }
1078
1079         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1080             (pblob->data[0] != ASN1_CONTEXT(1))) {
1081                 /* Not something we can determine the
1082                  * length of.
1083                  */
1084                 return NT_STATUS_OK;
1085         }
1086
1087         /* This is a new SPNEGO sessionsetup - see if
1088          * the data given in this blob is enough.
1089          */
1090
1091         data = asn1_init(NULL);
1092         if (data == NULL) {
1093                 return NT_STATUS_NO_MEMORY;
1094         }
1095
1096         asn1_load(data, *pblob);
1097         asn1_start_tag(data, pblob->data[0]);
1098         if (data->has_error || data->nesting == NULL) {
1099                 asn1_free(data);
1100                 /* Let caller catch. */
1101                 return NT_STATUS_OK;
1102         }
1103
1104         /* Integer wrap paranoia.... */
1105
1106         if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1107             data->nesting->taglen + data->nesting->start < data->nesting->start) {
1108
1109                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1110                         "data.nesting->taglen = %u, "
1111                         "data.nesting->start = %u\n",
1112                         (unsigned int)data->nesting->taglen,
1113                         (unsigned int)data->nesting->start ));
1114
1115                 asn1_free(data);
1116                 return NT_STATUS_INVALID_PARAMETER;
1117         }
1118
1119         /* Total length of the needed asn1 is the tag length
1120          * plus the current offset. */
1121
1122         needed_len = data->nesting->taglen + data->nesting->start;
1123         asn1_free(data);
1124
1125         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1126                 "pblob->length = %u\n",
1127                 (unsigned int)needed_len,
1128                 (unsigned int)pblob->length ));
1129
1130         if (needed_len <= pblob->length) {
1131                 /* Nothing to do - blob is complete. */
1132                 return NT_STATUS_OK;
1133         }
1134
1135         /* Refuse the blob if it's bigger than 64k. */
1136         if (needed_len > 65536) {
1137                 DEBUG(2,("check_spnego_blob_complete: needed_len "
1138                         "too large (%u)\n",
1139                         (unsigned int)needed_len ));
1140                 return NT_STATUS_INVALID_PARAMETER;
1141         }
1142
1143         /* We must store this blob until complete. */
1144         if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1145                 return NT_STATUS_NO_MEMORY;
1146         }
1147         pad->needed_len = needed_len - pblob->length;
1148         pad->partial_data = data_blob(pblob->data, pblob->length);
1149         if (pad->partial_data.data == NULL) {
1150                 SAFE_FREE(pad);
1151                 return NT_STATUS_NO_MEMORY;
1152         }
1153         pad->smbpid = smbpid;
1154         pad->vuid = vuid;
1155         DLIST_ADD(sconn->smb1.pd_list, pad);
1156
1157         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1158 }
1159
1160 /****************************************************************************
1161  Reply to a session setup command.
1162  conn POINTER CAN BE NULL HERE !
1163 ****************************************************************************/
1164
1165 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1166 {
1167         const uint8 *p;
1168         DATA_BLOB blob1;
1169         size_t bufrem;
1170         char *tmp;
1171         const char *native_os;
1172         const char *native_lanman;
1173         const char *primary_domain;
1174         const char *p2;
1175         uint16 data_blob_len = SVAL(req->vwv+7, 0);
1176         enum remote_arch_types ra_type = get_remote_arch();
1177         int vuid = req->vuid;
1178         user_struct *vuser = NULL;
1179         NTSTATUS status = NT_STATUS_OK;
1180         uint16 smbpid = req->smbpid;
1181         struct smbd_server_connection *sconn = req->sconn;
1182
1183         DEBUG(3,("Doing spnego session setup\n"));
1184
1185         if (global_client_caps == 0) {
1186                 global_client_caps = IVAL(req->vwv+10, 0);
1187
1188                 if (!(global_client_caps & CAP_STATUS32)) {
1189                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1190                 }
1191
1192         }
1193
1194         p = req->buf;
1195
1196         if (data_blob_len == 0) {
1197                 /* an invalid request */
1198                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1199                 return;
1200         }
1201
1202         bufrem = smbreq_bufrem(req, p);
1203         /* pull the spnego blob */
1204         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1205
1206 #if 0
1207         file_save("negotiate.dat", blob1.data, blob1.length);
1208 #endif
1209
1210         p2 = (char *)req->buf + blob1.length;
1211
1212         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1213                                      STR_TERMINATE);
1214         native_os = tmp ? tmp : "";
1215
1216         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1217                                      STR_TERMINATE);
1218         native_lanman = tmp ? tmp : "";
1219
1220         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1221                                      STR_TERMINATE);
1222         primary_domain = tmp ? tmp : "";
1223
1224         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1225                 native_os, native_lanman, primary_domain));
1226
1227         if ( ra_type == RA_WIN2K ) {
1228                 /* Vista sets neither the OS or lanman strings */
1229
1230                 if ( !strlen(native_os) && !strlen(native_lanman) )
1231                         set_remote_arch(RA_VISTA);
1232
1233                 /* Windows 2003 doesn't set the native lanman string,
1234                    but does set primary domain which is a bug I think */
1235
1236                 if ( !strlen(native_lanman) ) {
1237                         ra_lanman_string( primary_domain );
1238                 } else {
1239                         ra_lanman_string( native_lanman );
1240                 }
1241         }
1242
1243         /* Did we get a valid vuid ? */
1244         if (!is_partial_auth_vuid(sconn, vuid)) {
1245                 /* No, then try and see if this is an intermediate sessionsetup
1246                  * for a large SPNEGO packet. */
1247                 struct pending_auth_data *pad;
1248                 pad = get_pending_auth_data(sconn, smbpid);
1249                 if (pad) {
1250                         DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1251                                 "pending vuid %u\n",
1252                                 (unsigned int)pad->vuid ));
1253                         vuid = pad->vuid;
1254                 }
1255         }
1256
1257         /* Do we have a valid vuid now ? */
1258         if (!is_partial_auth_vuid(sconn, vuid)) {
1259                 /* No, start a new authentication setup. */
1260                 vuid = register_initial_vuid(sconn);
1261                 if (vuid == UID_FIELD_INVALID) {
1262                         data_blob_free(&blob1);
1263                         reply_nterror(req, nt_status_squash(
1264                                               NT_STATUS_INVALID_PARAMETER));
1265                         return;
1266                 }
1267         }
1268
1269         vuser = get_partial_auth_user_struct(sconn, vuid);
1270         /* This MUST be valid. */
1271         if (!vuser) {
1272                 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1273         }
1274
1275         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1276          * sessionsetup requests as the Windows limit on the security blob
1277          * field is 4k. Bug #4400. JRA.
1278          */
1279
1280         status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1281         if (!NT_STATUS_IS_OK(status)) {
1282                 if (!NT_STATUS_EQUAL(status,
1283                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1284                         /* Real error - kill the intermediate vuid */
1285                         invalidate_vuid(sconn, vuid);
1286                 }
1287                 data_blob_free(&blob1);
1288                 reply_nterror(req, nt_status_squash(status));
1289                 return;
1290         }
1291
1292         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1293
1294                 /* its a negTokenTarg packet */
1295
1296                 reply_spnego_negotiate(req, vuid, blob1,
1297                                        &vuser->auth_ntlmssp_state);
1298                 data_blob_free(&blob1);
1299                 return;
1300         }
1301
1302         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1303
1304                 /* its a auth packet */
1305
1306                 reply_spnego_auth(req, vuid, blob1,
1307                                   &vuser->auth_ntlmssp_state);
1308                 data_blob_free(&blob1);
1309                 return;
1310         }
1311
1312         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1313                 DATA_BLOB chal;
1314
1315                 if (!vuser->auth_ntlmssp_state) {
1316                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1317                         if (!NT_STATUS_IS_OK(status)) {
1318                                 /* Kill the intermediate vuid */
1319                                 invalidate_vuid(sconn, vuid);
1320                                 data_blob_free(&blob1);
1321                                 reply_nterror(req, nt_status_squash(status));
1322                                 return;
1323                         }
1324                 }
1325
1326                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1327                                                 blob1, &chal);
1328
1329                 data_blob_free(&blob1);
1330
1331                 reply_spnego_ntlmssp(req, vuid,
1332                                      &vuser->auth_ntlmssp_state,
1333                                      &chal, status, OID_NTLMSSP, false);
1334                 data_blob_free(&chal);
1335                 return;
1336         }
1337
1338         /* what sort of packet is this? */
1339         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1340
1341         data_blob_free(&blob1);
1342
1343         reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1344 }
1345
1346 /****************************************************************************
1347  On new VC == 0, shutdown *all* old connections and users.
1348  It seems that only NT4.x does this. At W2K and above (XP etc.).
1349  a new session setup with VC==0 is ignored.
1350 ****************************************************************************/
1351
1352 static int shutdown_other_smbds(const struct connections_key *key,
1353                                 const struct connections_data *crec,
1354                                 void *private_data)
1355 {
1356         const char *ip = (const char *)private_data;
1357
1358         if (!process_exists(crec->pid)) {
1359                 return 0;
1360         }
1361
1362         if (procid_is_me(&crec->pid)) {
1363                 return 0;
1364         }
1365
1366         if (strcmp(ip, crec->addr) != 0) {
1367                 return 0;
1368         }
1369
1370         DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1371                  "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1372
1373         messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1374                        &data_blob_null);
1375         return 0;
1376 }
1377
1378 static void setup_new_vc_session(void)
1379 {
1380         char addr[INET6_ADDRSTRLEN];
1381
1382         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1383                 "compatible we would close all old resources.\n"));
1384 #if 0
1385         conn_close_all();
1386         invalidate_all_vuids();
1387 #endif
1388         if (lp_reset_on_zero_vc()) {
1389                 connections_forall_read(shutdown_other_smbds,
1390                         CONST_DISCARD(void *,
1391                         client_addr(get_client_fd(),addr,sizeof(addr))));
1392         }
1393 }
1394
1395 /****************************************************************************
1396  Reply to a session setup command.
1397 ****************************************************************************/
1398
1399 void reply_sesssetup_and_X(struct smb_request *req)
1400 {
1401         int sess_vuid;
1402         int smb_bufsize;
1403         DATA_BLOB lm_resp;
1404         DATA_BLOB nt_resp;
1405         DATA_BLOB plaintext_password;
1406         char *tmp;
1407         const char *user;
1408         fstring sub_user; /* Sanitised username for substituion */
1409         const char *domain;
1410         const char *native_os;
1411         const char *native_lanman;
1412         const char *primary_domain;
1413         struct auth_usersupplied_info *user_info = NULL;
1414         struct auth_serversupplied_info *server_info = NULL;
1415         uint16 smb_flag2 = req->flags2;
1416
1417         NTSTATUS nt_status;
1418         struct smbd_server_connection *sconn = smbd_server_conn;
1419
1420         bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1421
1422         START_PROFILE(SMBsesssetupX);
1423
1424         ZERO_STRUCT(lm_resp);
1425         ZERO_STRUCT(nt_resp);
1426         ZERO_STRUCT(plaintext_password);
1427
1428         DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1429
1430         /* a SPNEGO session setup has 12 command words, whereas a normal
1431            NT1 session setup has 13. See the cifs spec. */
1432         if (req->wct == 12 &&
1433             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1434
1435                 if (!sconn->smb1.negprot.spnego) {
1436                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1437                                  "at SPNEGO session setup when it was not "
1438                                  "negotiated.\n"));
1439                         reply_nterror(req, nt_status_squash(
1440                                               NT_STATUS_LOGON_FAILURE));
1441                         END_PROFILE(SMBsesssetupX);
1442                         return;
1443                 }
1444
1445                 if (SVAL(req->vwv+4, 0) == 0) {
1446                         setup_new_vc_session();
1447                 }
1448
1449                 reply_sesssetup_and_X_spnego(req);
1450                 END_PROFILE(SMBsesssetupX);
1451                 return;
1452         }
1453
1454         smb_bufsize = SVAL(req->vwv+2, 0);
1455
1456         if (get_Protocol() < PROTOCOL_NT1) {
1457                 uint16 passlen1 = SVAL(req->vwv+7, 0);
1458
1459                 /* Never do NT status codes with protocols before NT1 as we
1460                  * don't get client caps. */
1461                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1462
1463                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1464                         reply_nterror(req, nt_status_squash(
1465                                               NT_STATUS_INVALID_PARAMETER));
1466                         END_PROFILE(SMBsesssetupX);
1467                         return;
1468                 }
1469
1470                 if (doencrypt) {
1471                         lm_resp = data_blob(req->buf, passlen1);
1472                 } else {
1473                         plaintext_password = data_blob(req->buf, passlen1+1);
1474                         /* Ensure null termination */
1475                         plaintext_password.data[passlen1] = 0;
1476                 }
1477
1478                 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1479                                        req->buf + passlen1, STR_TERMINATE);
1480                 user = tmp ? tmp : "";
1481
1482                 domain = "";
1483
1484         } else {
1485                 uint16 passlen1 = SVAL(req->vwv+7, 0);
1486                 uint16 passlen2 = SVAL(req->vwv+8, 0);
1487                 enum remote_arch_types ra_type = get_remote_arch();
1488                 const uint8_t *p = req->buf;
1489                 const uint8_t *save_p = req->buf;
1490                 uint16 byte_count;
1491
1492
1493                 if(global_client_caps == 0) {
1494                         global_client_caps = IVAL(req->vwv+11, 0);
1495
1496                         if (!(global_client_caps & CAP_STATUS32)) {
1497                                 remove_from_common_flags2(
1498                                                 FLAGS2_32_BIT_ERROR_CODES);
1499                         }
1500
1501                         /* client_caps is used as final determination if
1502                          * client is NT or Win95. This is needed to return
1503                          * the correct error codes in some circumstances.
1504                         */
1505
1506                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1507                                         ra_type == RA_WIN95) {
1508                                 if(!(global_client_caps & (CAP_NT_SMBS|
1509                                                         CAP_STATUS32))) {
1510                                         set_remote_arch( RA_WIN95);
1511                                 }
1512                         }
1513                 }
1514
1515                 if (!doencrypt) {
1516                         /* both Win95 and WinNT stuff up the password
1517                          * lengths for non-encrypting systems. Uggh.
1518
1519                            if passlen1==24 its a win95 system, and its setting
1520                            the password length incorrectly. Luckily it still
1521                            works with the default code because Win95 will null
1522                            terminate the password anyway
1523
1524                            if passlen1>0 and passlen2>0 then maybe its a NT box
1525                            and its setting passlen2 to some random value which
1526                            really stuffs things up. we need to fix that one.  */
1527
1528                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1529                                         passlen2 != 1) {
1530                                 passlen2 = 0;
1531                         }
1532                 }
1533
1534                 /* check for nasty tricks */
1535                 if (passlen1 > MAX_PASS_LEN
1536                     || passlen1 > smbreq_bufrem(req, p)) {
1537                         reply_nterror(req, nt_status_squash(
1538                                               NT_STATUS_INVALID_PARAMETER));
1539                         END_PROFILE(SMBsesssetupX);
1540                         return;
1541                 }
1542
1543                 if (passlen2 > MAX_PASS_LEN
1544                     || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1545                         reply_nterror(req, nt_status_squash(
1546                                               NT_STATUS_INVALID_PARAMETER));
1547                         END_PROFILE(SMBsesssetupX);
1548                         return;
1549                 }
1550
1551                 /* Save the lanman2 password and the NT md4 password. */
1552
1553                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1554                         doencrypt = False;
1555                 }
1556
1557                 if (doencrypt) {
1558                         lm_resp = data_blob(p, passlen1);
1559                         nt_resp = data_blob(p+passlen1, passlen2);
1560                 } else if (lp_security() != SEC_SHARE) {
1561                         /*
1562                          * In share level we should ignore any passwords, so
1563                          * only read them if we're not.
1564                          */
1565                         char *pass = NULL;
1566                         bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1567
1568                         if (unic && (passlen2 == 0) && passlen1) {
1569                                 /* Only a ascii plaintext password was sent. */
1570                                 (void)srvstr_pull_talloc(talloc_tos(),
1571                                                         req->inbuf,
1572                                                         req->flags2,
1573                                                         &pass,
1574                                                         req->buf,
1575                                                         passlen1,
1576                                                         STR_TERMINATE|STR_ASCII);
1577                         } else {
1578                                 (void)srvstr_pull_talloc(talloc_tos(),
1579                                                         req->inbuf,
1580                                                         req->flags2,
1581                                                         &pass,
1582                                                         req->buf,
1583                                                         unic ? passlen2 : passlen1,
1584                                                         STR_TERMINATE);
1585                         }
1586                         if (!pass) {
1587                                 reply_nterror(req, nt_status_squash(
1588                                               NT_STATUS_INVALID_PARAMETER));
1589                                 END_PROFILE(SMBsesssetupX);
1590                                 return;
1591                         }
1592                         plaintext_password = data_blob(pass, strlen(pass)+1);
1593                 }
1594
1595                 p += passlen1 + passlen2;
1596
1597                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1598                                             STR_TERMINATE);
1599                 user = tmp ? tmp : "";
1600
1601                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1602                                             STR_TERMINATE);
1603                 domain = tmp ? tmp : "";
1604
1605                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1606                                             STR_TERMINATE);
1607                 native_os = tmp ? tmp : "";
1608
1609                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1610                                             STR_TERMINATE);
1611                 native_lanman = tmp ? tmp : "";
1612
1613                 /* not documented or decoded by Ethereal but there is one more
1614                  * string in the extra bytes which is the same as the
1615                  * PrimaryDomain when using extended security.  Windows NT 4
1616                  * and 2003 use this string to store the native lanman string.
1617                  * Windows 9x does not include a string here at all so we have
1618                  * to check if we have any extra bytes left */
1619
1620                 byte_count = SVAL(req->vwv+13, 0);
1621                 if ( PTR_DIFF(p, save_p) < byte_count) {
1622                         p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1623                                                     STR_TERMINATE);
1624                         primary_domain = tmp ? tmp : "";
1625                 } else {
1626                         primary_domain = talloc_strdup(talloc_tos(), "null");
1627                 }
1628
1629                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
1630                         "PrimaryDomain=[%s]\n",
1631                         domain, native_os, native_lanman, primary_domain));
1632
1633                 if ( ra_type == RA_WIN2K ) {
1634                         if ( strlen(native_lanman) == 0 )
1635                                 ra_lanman_string( primary_domain );
1636                         else
1637                                 ra_lanman_string( native_lanman );
1638                 }
1639
1640         }
1641
1642         if (SVAL(req->vwv+4, 0) == 0) {
1643                 setup_new_vc_session();
1644         }
1645
1646         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1647                                 domain, user, get_remote_machine_name()));
1648
1649         if (*user) {
1650                 if (sconn->smb1.negprot.spnego) {
1651
1652                         /* This has to be here, because this is a perfectly
1653                          * valid behaviour for guest logons :-( */
1654
1655                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1656                                 "at 'normal' session setup after "
1657                                 "negotiating spnego.\n"));
1658                         reply_nterror(req, nt_status_squash(
1659                                               NT_STATUS_LOGON_FAILURE));
1660                         END_PROFILE(SMBsesssetupX);
1661                         return;
1662                 }
1663                 fstrcpy(sub_user, user);
1664         } else {
1665                 fstrcpy(sub_user, lp_guestaccount());
1666         }
1667
1668         sub_set_smb_name(sub_user);
1669
1670         reload_services(True);
1671
1672         if (lp_security() == SEC_SHARE) {
1673                 /* In share level we should ignore any passwords */
1674
1675                 data_blob_free(&lm_resp);
1676                 data_blob_free(&nt_resp);
1677                 data_blob_clear_free(&plaintext_password);
1678
1679                 map_username(sub_user);
1680                 add_session_user(sconn, sub_user);
1681                 add_session_workgroup(sconn, domain);
1682                 /* Then force it to null for the benfit of the code below */
1683                 user = "";
1684         }
1685
1686         if (!*user) {
1687
1688                 nt_status = check_guest_password(&server_info);
1689
1690         } else if (doencrypt) {
1691                 struct auth_context *negprot_auth_context = NULL;
1692                 negprot_auth_context = sconn->smb1.negprot.auth_context;
1693                 if (!negprot_auth_context) {
1694                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
1695                                 "session setup without negprot denied!\n"));
1696                         reply_nterror(req, nt_status_squash(
1697                                               NT_STATUS_LOGON_FAILURE));
1698                         END_PROFILE(SMBsesssetupX);
1699                         return;
1700                 }
1701                 nt_status = make_user_info_for_reply_enc(&user_info, user,
1702                                                 domain,
1703                                                 lm_resp, nt_resp);
1704                 if (NT_STATUS_IS_OK(nt_status)) {
1705                         nt_status = negprot_auth_context->check_ntlm_password(
1706                                         negprot_auth_context,
1707                                         user_info,
1708                                         &server_info);
1709                 }
1710         } else {
1711                 struct auth_context *plaintext_auth_context = NULL;
1712
1713                 nt_status = make_auth_context_subsystem(
1714                                 &plaintext_auth_context);
1715
1716                 if (NT_STATUS_IS_OK(nt_status)) {
1717                         uint8_t chal[8];
1718
1719                         plaintext_auth_context->get_ntlm_challenge(
1720                                         plaintext_auth_context, chal);
1721
1722                         if (!make_user_info_for_reply(&user_info,
1723                                                       user, domain, chal,
1724                                                       plaintext_password)) {
1725                                 nt_status = NT_STATUS_NO_MEMORY;
1726                         }
1727
1728                         if (NT_STATUS_IS_OK(nt_status)) {
1729                                 nt_status = plaintext_auth_context->check_ntlm_password(
1730                                                 plaintext_auth_context,
1731                                                 user_info,
1732                                                 &server_info);
1733
1734                                 (plaintext_auth_context->free)(
1735                                                 &plaintext_auth_context);
1736                         }
1737                 }
1738         }
1739
1740         free_user_info(&user_info);
1741
1742         if (!NT_STATUS_IS_OK(nt_status)) {
1743                 nt_status = do_map_to_guest(nt_status, &server_info,
1744                                 user, domain);
1745         }
1746
1747         if (!NT_STATUS_IS_OK(nt_status)) {
1748                 data_blob_free(&nt_resp);
1749                 data_blob_free(&lm_resp);
1750                 data_blob_clear_free(&plaintext_password);
1751                 reply_nterror(req, nt_status_squash(nt_status));
1752                 END_PROFILE(SMBsesssetupX);
1753                 return;
1754         }
1755
1756         /* Ensure we can't possible take a code path leading to a
1757          * null defref. */
1758         if (!server_info) {
1759                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1760                 END_PROFILE(SMBsesssetupX);
1761                 return;
1762         }
1763
1764         if (!server_info->ptok) {
1765                 nt_status = create_local_token(server_info);
1766
1767                 if (!NT_STATUS_IS_OK(nt_status)) {
1768                         DEBUG(10, ("create_local_token failed: %s\n",
1769                                    nt_errstr(nt_status)));
1770                         data_blob_free(&nt_resp);
1771                         data_blob_free(&lm_resp);
1772                         data_blob_clear_free(&plaintext_password);
1773                         reply_nterror(req, nt_status_squash(nt_status));
1774                         END_PROFILE(SMBsesssetupX);
1775                         return;
1776                 }
1777         }
1778
1779         data_blob_clear_free(&plaintext_password);
1780
1781         /* it's ok - setup a reply */
1782         reply_outbuf(req, 3, 0);
1783         if (get_Protocol() >= PROTOCOL_NT1) {
1784                 push_signature(&req->outbuf);
1785                 /* perhaps grab OS version here?? */
1786         }
1787
1788         if (server_info->guest) {
1789                 SSVAL(req->outbuf,smb_vwv2,1);
1790         }
1791
1792         /* register the name and uid as being validated, so further connections
1793            to a uid can get through without a password, on the same VC */
1794
1795         if (lp_security() == SEC_SHARE) {
1796                 sess_vuid = UID_FIELD_INVALID;
1797                 TALLOC_FREE(server_info);
1798         } else {
1799                 /* Ignore the initial vuid. */
1800                 sess_vuid = register_initial_vuid(sconn);
1801                 if (sess_vuid == UID_FIELD_INVALID) {
1802                         data_blob_free(&nt_resp);
1803                         data_blob_free(&lm_resp);
1804                         reply_nterror(req, nt_status_squash(
1805                                               NT_STATUS_LOGON_FAILURE));
1806                         END_PROFILE(SMBsesssetupX);
1807                         return;
1808                 }
1809                 /* register_existing_vuid keeps the server info */
1810                 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1811                                         server_info,
1812                                         nt_resp.data ? nt_resp : lm_resp,
1813                                         sub_user);
1814                 if (sess_vuid == UID_FIELD_INVALID) {
1815                         data_blob_free(&nt_resp);
1816                         data_blob_free(&lm_resp);
1817                         reply_nterror(req, nt_status_squash(
1818                                               NT_STATUS_LOGON_FAILURE));
1819                         END_PROFILE(SMBsesssetupX);
1820                         return;
1821                 }
1822
1823                 /* current_user_info is changed on new vuid */
1824                 reload_services( True );
1825         }
1826
1827         data_blob_free(&nt_resp);
1828         data_blob_free(&lm_resp);
1829
1830         SSVAL(req->outbuf,smb_uid,sess_vuid);
1831         SSVAL(req->inbuf,smb_uid,sess_vuid);
1832         req->vuid = sess_vuid;
1833
1834         if (!sconn->smb1.sessions.done_sesssetup) {
1835                 sconn->smb1.sessions.max_send =
1836                         MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1837         }
1838         sconn->smb1.sessions.done_sesssetup = true;
1839
1840         END_PROFILE(SMBsesssetupX);
1841         chain_reply(req);
1842         return;
1843 }