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