2 Unix SMB/CIFS implementation.
3 kerberos utility library
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Remus Koos 2001
6 Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
7 Copyright (C) Jeremy Allison 2004.
8 Copyright (C) Gerald Carter 2006.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #define LIBADS_CCACHE_NAME "MEMORY:libads"
32 we use a prompter to avoid a crash bug in the kerberos libs when
33 dealing with empty passwords
34 this prompter is just a string copy ...
36 static krb5_error_code
37 kerb_prompter(krb5_context ctx, void *data,
41 krb5_prompt prompts[])
43 if (num_prompts == 0) return 0;
45 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
46 if (prompts[0].reply->length > 0) {
48 strncpy(prompts[0].reply->data, (const char *)data,
49 prompts[0].reply->length-1);
50 prompts[0].reply->length = strlen(prompts[0].reply->data);
52 prompts[0].reply->length = 0;
58 static BOOL smb_krb5_err_io_nstatus(TALLOC_CTX *mem_ctx,
59 DATA_BLOB *edata_blob,
60 KRB5_EDATA_NTSTATUS *edata)
65 if (!mem_ctx || !edata_blob || !edata)
68 if (!prs_init(&ps, edata_blob->length, mem_ctx, UNMARSHALL))
71 if (!prs_copy_data_in(&ps, (char *)edata_blob->data, edata_blob->length))
74 prs_set_offset(&ps, 0);
76 if (!prs_ntstatus("ntstatus", &ps, 1, &edata->ntstatus))
79 if (!prs_uint32("unknown1", &ps, 1, &edata->unknown1))
82 if (!prs_uint32("unknown2", &ps, 1, &edata->unknown2)) /* only seen 00000001 here */
92 static BOOL smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
96 DATA_BLOB unwrapped_edata;
98 KRB5_EDATA_NTSTATUS parsed_edata;
100 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
101 edata = data_blob(error->e_data->data, error->e_data->length);
103 edata = data_blob(error->e_data.data, error->e_data.length);
104 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
107 dump_data(10, edata.data, edata.length);
108 #endif /* DEVELOPER */
110 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
111 if (mem_ctx == NULL) {
112 data_blob_free(&edata);
116 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
117 data_blob_free(&edata);
118 TALLOC_FREE(mem_ctx);
122 data_blob_free(&edata);
124 if (!smb_krb5_err_io_nstatus(mem_ctx, &unwrapped_edata, &parsed_edata)) {
125 data_blob_free(&unwrapped_edata);
126 TALLOC_FREE(mem_ctx);
130 data_blob_free(&unwrapped_edata);
133 *nt_status = parsed_edata.ntstatus;
136 TALLOC_FREE(mem_ctx);
141 static BOOL smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
142 krb5_get_init_creds_opt *opt,
146 krb5_error *error = NULL;
148 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
149 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
151 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
152 error_message(ret)));
155 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
158 DEBUG(1,("no krb5_error\n"));
162 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
163 if (!error->e_data) {
165 if (error->e_data.data == NULL) {
166 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
167 DEBUG(1,("no edata in krb5_error\n"));
168 krb5_free_error(ctx, error);
172 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
174 krb5_free_error(ctx, error);
180 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
181 place in default cache location.
184 int kerberos_kinit_password_ext(const char *principal,
185 const char *password,
188 time_t *renew_till_time,
189 const char *cache_name,
191 BOOL add_netbios_addr,
192 time_t renewable_time,
195 krb5_context ctx = NULL;
196 krb5_error_code code = 0;
197 krb5_ccache cc = NULL;
198 krb5_principal me = NULL;
200 krb5_get_init_creds_opt *opt = NULL;
201 smb_krb5_addresses *addr = NULL;
203 ZERO_STRUCT(my_creds);
205 initialize_krb5_error_table();
206 if ((code = krb5_init_context(&ctx)))
209 if (time_offset != 0) {
210 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
213 DEBUG(10,("kerberos_kinit_password: using [%s] as ccache and config [%s]\n",
214 cache_name ? cache_name: krb5_cc_default_name(ctx),
215 getenv("KRB5_CONFIG")));
217 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
221 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
225 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
229 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
230 krb5_get_init_creds_opt_set_forwardable(opt, True);
233 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
236 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
238 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
243 if (add_netbios_addr) {
244 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
247 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
250 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
251 kerb_prompter, NULL, 0, NULL, opt))) {
255 if ((code = krb5_cc_initialize(ctx, cc, me))) {
259 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
264 *expire_time = (time_t) my_creds.times.endtime;
267 if (renew_till_time) {
268 *renew_till_time = (time_t) my_creds.times.renew_till;
277 *ntstatus = NT_STATUS_OK;
281 /* try to get ntstatus code out of krb5_error when we have it
282 * inside the krb5_get_init_creds_opt - gd */
284 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
289 /* fall back to self-made-mapping */
290 *ntstatus = krb5_to_nt_status(code);
294 krb5_free_cred_contents(ctx, &my_creds);
296 krb5_free_principal(ctx, me);
299 smb_krb5_free_addresses(ctx, addr);
302 smb_krb5_get_init_creds_opt_free(ctx, opt);
305 krb5_cc_close(ctx, cc);
308 krb5_free_context(ctx);
315 /* run kinit to setup our ccache */
316 int ads_kinit_password(ADS_STRUCT *ads)
320 const char *account_name;
324 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
325 account_name = lp_workgroup();
327 /* always use the sAMAccountName for security = domain */
328 /* global_myname()$@REA.LM */
329 if ( lp_security() == SEC_DOMAIN ) {
330 fstr_sprintf( acct_name, "%s$", global_myname() );
331 account_name = acct_name;
334 /* This looks like host/global_myname()@REA.LM */
335 account_name = ads->auth.user_name;
338 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
339 return KRB5_CC_NOMEM;
342 if (!ads->auth.password) {
344 return KRB5_LIBOS_CANTREADPWD;
347 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
348 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
352 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
353 s, error_message(ret)));
359 int ads_kdestroy(const char *cc_name)
361 krb5_error_code code;
362 krb5_context ctx = NULL;
363 krb5_ccache cc = NULL;
365 initialize_krb5_error_table();
366 if ((code = krb5_init_context (&ctx))) {
367 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
368 error_message(code)));
373 if ((code = krb5_cc_default(ctx, &cc))) {
374 krb5_free_context(ctx);
378 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
379 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
380 error_message(code)));
381 krb5_free_context(ctx);
386 if ((code = krb5_cc_destroy (ctx, cc))) {
387 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
388 error_message(code)));
391 krb5_free_context (ctx);
395 /************************************************************************
396 Routine to fetch the salting principal for a service. Active
397 Directory may use a non-obvious principal name to generate the salt
398 when it determines the key to use for encrypting tickets for a service,
399 and hopefully we detected that when we joined the domain.
400 ************************************************************************/
402 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
407 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
411 ret = (char *)secrets_fetch(key, NULL);
416 /************************************************************************
417 Return the standard DES salt key
418 ************************************************************************/
420 char* kerberos_standard_des_salt( void )
424 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
426 fstrcat( salt, lp_realm() );
428 return SMB_STRDUP( salt );
431 /************************************************************************
432 ************************************************************************/
434 static char* des_salt_key( void )
438 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
443 /************************************************************************
444 ************************************************************************/
446 BOOL kerberos_secrets_store_des_salt( const char* salt )
451 if ( (key = des_salt_key()) == NULL ) {
452 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
457 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
458 secrets_delete( key );
462 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
464 ret = secrets_store( key, salt, strlen(salt)+1 );
471 /************************************************************************
472 ************************************************************************/
474 char* kerberos_secrets_fetch_des_salt( void )
478 if ( (key = des_salt_key()) == NULL ) {
479 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
483 salt = (char*)secrets_fetch( key, NULL );
491 /************************************************************************
492 Routine to get the salting principal for this service. This is
493 maintained for backwards compatibilty with releases prior to 3.0.24.
494 Since we store the salting principal string only at join, we may have
495 to look for the older tdb keys. Caller must free if return is not null.
496 ************************************************************************/
498 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
499 krb5_principal host_princ,
502 char *unparsed_name = NULL, *salt_princ_s = NULL;
503 krb5_principal ret_princ = NULL;
505 /* lookup new key first */
507 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
509 /* look under the old key. If this fails, just use the standard key */
511 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
512 return (krb5_principal)NULL;
514 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
515 /* fall back to host/machine.realm@REALM */
516 salt_princ_s = kerberos_standard_des_salt();
520 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
524 SAFE_FREE(unparsed_name);
525 SAFE_FREE(salt_princ_s);
530 /************************************************************************
531 Routine to set the salting principal for this service. Active
532 Directory may use a non-obvious principal name to generate the salt
533 when it determines the key to use for encrypting tickets for a service,
534 and hopefully we detected that when we joined the domain.
535 Setting principal to NULL deletes this entry.
536 ************************************************************************/
538 BOOL kerberos_secrets_store_salting_principal(const char *service,
540 const char *principal)
544 krb5_context context = NULL;
545 krb5_principal princ = NULL;
546 char *princ_s = NULL;
547 char *unparsed_name = NULL;
549 krb5_init_context(&context);
553 if (strchr_m(service, '@')) {
554 asprintf(&princ_s, "%s", service);
556 asprintf(&princ_s, "%s@%s", service, lp_realm());
559 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
563 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
567 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
572 if ((principal != NULL) && (strlen(principal) > 0)) {
573 ret = secrets_store(key, principal, strlen(principal) + 1);
575 ret = secrets_delete(key);
582 SAFE_FREE(unparsed_name);
585 krb5_free_context(context);
592 /************************************************************************
593 ************************************************************************/
595 int kerberos_kinit_password(const char *principal,
596 const char *password,
598 const char *cache_name)
600 return kerberos_kinit_password_ext(principal,
612 /************************************************************************
613 Create a string list of available kdc's, possibly searching by sitename.
615 ************************************************************************/
617 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
619 struct ip_service *ip_srv_site;
620 struct ip_service *ip_srv_nonsite;
621 int count_site, count_nonsite, i;
622 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
623 inet_ntoa(primary_ip));
625 if (kdc_str == NULL) {
629 /* Get the KDC's only in this site. */
633 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
635 for (i = 0; i < count_site; i++) {
636 if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
639 /* Append to the string - inefficient but not done often. */
640 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
641 kdc_str, inet_ntoa(ip_srv_site[i].ip));
643 SAFE_FREE(ip_srv_site);
651 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
653 for (i = 0; i < count_nonsite; i++) {
656 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
660 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
661 for (j = 0; j < count_site; j++) {
662 if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
665 /* As the lists are sorted we can break early if nonsite > site. */
666 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
674 /* Append to the string - inefficient but not done often. */
675 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
676 kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
678 SAFE_FREE(ip_srv_site);
679 SAFE_FREE(ip_srv_nonsite);
685 SAFE_FREE(ip_srv_site);
686 SAFE_FREE(ip_srv_nonsite);
688 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
694 /************************************************************************
695 Create a specific krb5.conf file in the private directory pointing
696 at a specific kdc for a realm. Keyed off domain name. Sets
697 KRB5_CONFIG environment variable to point to this file. Must be
698 run as root or will fail (which is a good thing :-).
699 ************************************************************************/
701 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
702 const char *sitename, struct in_addr ip)
704 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
705 char *tmpname = NULL;
707 char *file_contents = NULL;
708 char *kdc_ip_string = NULL;
712 char *realm_upper = NULL;
717 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
718 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
719 "failed to create directory %s. Error was %s\n",
720 dname, strerror(errno) ));
725 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
731 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
737 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
738 fname, realm, domain ));
740 realm_upper = talloc_strdup(fname, realm);
741 strupper_m(realm_upper);
743 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
744 if (!kdc_ip_string) {
749 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
750 "[realms]\n\t%s = {\n"
752 realm_upper, realm_upper, kdc_ip_string);
754 if (!file_contents) {
759 flen = strlen(file_contents);
761 fd = smb_mkstemp(tmpname);
763 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
764 " for file %s. Errno %s\n",
765 tmpname, strerror(errno) ));
768 if (fchmod(fd, 0644)==-1) {
769 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
771 tmpname, strerror(errno) ));
778 ret = write(fd, file_contents, flen);
780 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
781 " returned %d (should be %u). Errno %s\n",
782 (int)ret, (unsigned int)flen, strerror(errno) ));
789 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
790 " Errno %s\n", strerror(errno) ));
796 if (rename(tmpname, fname) == -1) {
797 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
798 "of %s to %s failed. Errno %s\n",
799 tmpname, fname, strerror(errno) ));
805 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
806 "file %s with realm %s KDC = %s\n",
807 fname, realm_upper, inet_ntoa(ip) ));
809 /* Set the environment variable to this file. */
810 setenv("KRB5_CONFIG", fname, 1);
812 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
814 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
815 /* Insanity, sheer insanity..... */
817 if (strequal(realm, lp_realm())) {
821 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
822 linkpath[sizeof(pstring)-1] = '\0';
824 if (lret == 0 || strcmp(linkpath, fname) == 0) {
825 /* Symlink already exists. */
830 /* Try and replace with a symlink. */
831 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
832 if (errno != EEXIST) {
833 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
834 "of %s to %s failed. Errno %s\n",
835 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
837 return True; /* Not a fatal error. */
840 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
841 pstrcat(linkpath, ".saved");
843 /* Yes, this is a race conditon... too bad. */
844 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
845 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
846 "of %s to %s failed. Errno %s\n",
847 SYSTEM_KRB5_CONF_PATH, linkpath,
850 return True; /* Not a fatal error. */
853 if (symlink(fname, "/etc/krb5.conf") == -1) {
854 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
855 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
856 fname, strerror(errno) ));
858 return True; /* Not a fatal error. */