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