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 3 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, CONST_DISCARD(char *,password),
256 if ((code = krb5_cc_initialize(ctx, cc, me))) {
260 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
265 *expire_time = (time_t) my_creds.times.endtime;
268 if (renew_till_time) {
269 *renew_till_time = (time_t) my_creds.times.renew_till;
278 *ntstatus = NT_STATUS_OK;
282 /* try to get ntstatus code out of krb5_error when we have it
283 * inside the krb5_get_init_creds_opt - gd */
285 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
290 /* fall back to self-made-mapping */
291 *ntstatus = krb5_to_nt_status(code);
295 krb5_free_cred_contents(ctx, &my_creds);
297 krb5_free_principal(ctx, me);
300 smb_krb5_free_addresses(ctx, addr);
303 smb_krb5_get_init_creds_opt_free(ctx, opt);
306 krb5_cc_close(ctx, cc);
309 krb5_free_context(ctx);
316 /* run kinit to setup our ccache */
317 int ads_kinit_password(ADS_STRUCT *ads)
321 const char *account_name;
325 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
326 account_name = lp_workgroup();
328 /* always use the sAMAccountName for security = domain */
329 /* global_myname()$@REA.LM */
330 if ( lp_security() == SEC_DOMAIN ) {
331 fstr_sprintf( acct_name, "%s$", global_myname() );
332 account_name = acct_name;
335 /* This looks like host/global_myname()@REA.LM */
336 account_name = ads->auth.user_name;
339 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
340 return KRB5_CC_NOMEM;
343 if (!ads->auth.password) {
345 return KRB5_LIBOS_CANTREADPWD;
348 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
349 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
353 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
354 s, error_message(ret)));
360 int ads_kdestroy(const char *cc_name)
362 krb5_error_code code;
363 krb5_context ctx = NULL;
364 krb5_ccache cc = NULL;
366 initialize_krb5_error_table();
367 if ((code = krb5_init_context (&ctx))) {
368 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
369 error_message(code)));
374 if ((code = krb5_cc_default(ctx, &cc))) {
375 krb5_free_context(ctx);
379 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
380 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
381 error_message(code)));
382 krb5_free_context(ctx);
387 if ((code = krb5_cc_destroy (ctx, cc))) {
388 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
389 error_message(code)));
392 krb5_free_context (ctx);
396 /************************************************************************
397 Routine to fetch the salting principal for a service. Active
398 Directory may use a non-obvious principal name to generate the salt
399 when it determines the key to use for encrypting tickets for a service,
400 and hopefully we detected that when we joined the domain.
401 ************************************************************************/
403 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
408 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
412 ret = (char *)secrets_fetch(key, NULL);
417 /************************************************************************
418 Return the standard DES salt key
419 ************************************************************************/
421 char* kerberos_standard_des_salt( void )
425 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
427 fstrcat( salt, lp_realm() );
429 return SMB_STRDUP( salt );
432 /************************************************************************
433 ************************************************************************/
435 static char* des_salt_key( void )
439 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
444 /************************************************************************
445 ************************************************************************/
447 BOOL kerberos_secrets_store_des_salt( const char* salt )
452 if ( (key = des_salt_key()) == NULL ) {
453 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
458 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
459 secrets_delete( key );
463 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
465 ret = secrets_store( key, salt, strlen(salt)+1 );
472 /************************************************************************
473 ************************************************************************/
475 char* kerberos_secrets_fetch_des_salt( void )
479 if ( (key = des_salt_key()) == NULL ) {
480 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
484 salt = (char*)secrets_fetch( key, NULL );
492 /************************************************************************
493 Routine to get the salting principal for this service. This is
494 maintained for backwards compatibilty with releases prior to 3.0.24.
495 Since we store the salting principal string only at join, we may have
496 to look for the older tdb keys. Caller must free if return is not null.
497 ************************************************************************/
499 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
500 krb5_principal host_princ,
503 char *unparsed_name = NULL, *salt_princ_s = NULL;
504 krb5_principal ret_princ = NULL;
506 /* lookup new key first */
508 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
510 /* look under the old key. If this fails, just use the standard key */
512 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
513 return (krb5_principal)NULL;
515 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
516 /* fall back to host/machine.realm@REALM */
517 salt_princ_s = kerberos_standard_des_salt();
521 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
525 SAFE_FREE(unparsed_name);
526 SAFE_FREE(salt_princ_s);
531 /************************************************************************
532 Routine to set the salting principal for this service. Active
533 Directory may use a non-obvious principal name to generate the salt
534 when it determines the key to use for encrypting tickets for a service,
535 and hopefully we detected that when we joined the domain.
536 Setting principal to NULL deletes this entry.
537 ************************************************************************/
539 BOOL kerberos_secrets_store_salting_principal(const char *service,
541 const char *principal)
545 krb5_context context = NULL;
546 krb5_principal princ = NULL;
547 char *princ_s = NULL;
548 char *unparsed_name = NULL;
550 krb5_init_context(&context);
554 if (strchr_m(service, '@')) {
555 asprintf(&princ_s, "%s", service);
557 asprintf(&princ_s, "%s@%s", service, lp_realm());
560 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
564 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
568 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
573 if ((principal != NULL) && (strlen(principal) > 0)) {
574 ret = secrets_store(key, principal, strlen(principal) + 1);
576 ret = secrets_delete(key);
583 SAFE_FREE(unparsed_name);
586 krb5_free_context(context);
593 /************************************************************************
594 ************************************************************************/
596 int kerberos_kinit_password(const char *principal,
597 const char *password,
599 const char *cache_name)
601 return kerberos_kinit_password_ext(principal,
613 /************************************************************************
614 Create a string list of available kdc's, possibly searching by sitename.
616 ************************************************************************/
618 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
620 struct ip_service *ip_srv_site;
621 struct ip_service *ip_srv_nonsite;
622 int count_site, count_nonsite, i;
623 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
624 inet_ntoa(primary_ip));
626 if (kdc_str == NULL) {
630 /* Get the KDC's only in this site. */
634 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
636 for (i = 0; i < count_site; i++) {
637 if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
640 /* Append to the string - inefficient but not done often. */
641 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
642 kdc_str, inet_ntoa(ip_srv_site[i].ip));
644 SAFE_FREE(ip_srv_site);
652 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
654 for (i = 0; i < count_nonsite; i++) {
657 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
661 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
662 for (j = 0; j < count_site; j++) {
663 if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
666 /* As the lists are sorted we can break early if nonsite > site. */
667 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
675 /* Append to the string - inefficient but not done often. */
676 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
677 kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
679 SAFE_FREE(ip_srv_site);
680 SAFE_FREE(ip_srv_nonsite);
686 SAFE_FREE(ip_srv_site);
687 SAFE_FREE(ip_srv_nonsite);
689 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
695 /************************************************************************
696 Create a specific krb5.conf file in the private directory pointing
697 at a specific kdc for a realm. Keyed off domain name. Sets
698 KRB5_CONFIG environment variable to point to this file. Must be
699 run as root or will fail (which is a good thing :-).
700 ************************************************************************/
702 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
703 const char *sitename, struct in_addr ip)
705 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
706 char *tmpname = NULL;
708 char *file_contents = NULL;
709 char *kdc_ip_string = NULL;
713 char *realm_upper = NULL;
718 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
719 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
720 "failed to create directory %s. Error was %s\n",
721 dname, strerror(errno) ));
726 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
732 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
738 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
739 fname, realm, domain ));
741 realm_upper = talloc_strdup(fname, realm);
742 strupper_m(realm_upper);
744 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
745 if (!kdc_ip_string) {
750 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
751 "[realms]\n\t%s = {\n"
753 realm_upper, realm_upper, kdc_ip_string);
755 if (!file_contents) {
760 flen = strlen(file_contents);
762 fd = smb_mkstemp(tmpname);
764 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
765 " for file %s. Errno %s\n",
766 tmpname, strerror(errno) ));
769 if (fchmod(fd, 0644)==-1) {
770 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
772 tmpname, strerror(errno) ));
779 ret = write(fd, file_contents, flen);
781 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
782 " returned %d (should be %u). Errno %s\n",
783 (int)ret, (unsigned int)flen, strerror(errno) ));
790 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
791 " Errno %s\n", strerror(errno) ));
797 if (rename(tmpname, fname) == -1) {
798 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
799 "of %s to %s failed. Errno %s\n",
800 tmpname, fname, strerror(errno) ));
806 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
807 "file %s with realm %s KDC = %s\n",
808 fname, realm_upper, inet_ntoa(ip) ));
810 /* Set the environment variable to this file. */
811 setenv("KRB5_CONFIG", fname, 1);
813 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
815 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
816 /* Insanity, sheer insanity..... */
818 if (strequal(realm, lp_realm())) {
822 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
823 linkpath[sizeof(pstring)-1] = '\0';
825 if (lret == 0 || strcmp(linkpath, fname) == 0) {
826 /* Symlink already exists. */
831 /* Try and replace with a symlink. */
832 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
833 if (errno != EEXIST) {
834 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
835 "of %s to %s failed. Errno %s\n",
836 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
838 return True; /* Not a fatal error. */
841 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
842 pstrcat(linkpath, ".saved");
844 /* Yes, this is a race conditon... too bad. */
845 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
846 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
847 "of %s to %s failed. Errno %s\n",
848 SYSTEM_KRB5_CONF_PATH, linkpath,
851 return True; /* Not a fatal error. */
854 if (symlink(fname, "/etc/krb5.conf") == -1) {
855 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
856 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
857 fname, strerror(errno) ));
859 return True; /* Not a fatal error. */