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)
194 krb5_context ctx = NULL;
195 krb5_error_code code = 0;
196 krb5_ccache cc = NULL;
197 krb5_principal me = NULL;
199 krb5_get_init_creds_opt *opt = NULL;
200 smb_krb5_addresses *addr = NULL;
202 ZERO_STRUCT(my_creds);
204 initialize_krb5_error_table();
205 if ((code = krb5_init_context(&ctx)))
208 if (time_offset != 0) {
209 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
212 DEBUG(10,("kerberos_kinit_password: using [%s] as ccache and config [%s]\n",
213 cache_name ? cache_name: krb5_cc_default_name(ctx),
214 getenv("KRB5_CONFIG")));
216 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
220 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
224 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
228 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
229 krb5_get_init_creds_opt_set_forwardable(opt, True);
232 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
235 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
237 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
242 if (add_netbios_addr) {
243 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
246 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
249 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
250 kerb_prompter, NULL, 0, NULL, opt))) {
254 if ((code = krb5_cc_initialize(ctx, cc, me))) {
258 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
263 *expire_time = (time_t) my_creds.times.endtime;
266 if (renew_till_time) {
267 *renew_till_time = (time_t) my_creds.times.renew_till;
270 krb5_free_cred_contents(ctx, &my_creds);
272 krb5_free_principal(ctx, me);
275 smb_krb5_free_addresses(ctx, addr);
278 smb_krb5_get_init_creds_opt_free(ctx, opt);
281 krb5_cc_close(ctx, cc);
284 krb5_free_context(ctx);
291 /* run kinit to setup our ccache */
292 int ads_kinit_password(ADS_STRUCT *ads)
296 const char *account_name;
300 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
301 account_name = lp_workgroup();
303 /* always use the sAMAccountName for security = domain */
304 /* global_myname()$@REA.LM */
305 if ( lp_security() == SEC_DOMAIN ) {
306 fstr_sprintf( acct_name, "%s$", global_myname() );
307 account_name = acct_name;
310 /* This looks like host/global_myname()@REA.LM */
311 account_name = ads->auth.user_name;
314 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
315 return KRB5_CC_NOMEM;
318 if (!ads->auth.password) {
320 return KRB5_LIBOS_CANTREADPWD;
323 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
324 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable);
327 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
328 s, error_message(ret)));
334 int ads_kdestroy(const char *cc_name)
336 krb5_error_code code;
337 krb5_context ctx = NULL;
338 krb5_ccache cc = NULL;
340 initialize_krb5_error_table();
341 if ((code = krb5_init_context (&ctx))) {
342 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
343 error_message(code)));
348 if ((code = krb5_cc_default(ctx, &cc))) {
349 krb5_free_context(ctx);
353 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
354 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
355 error_message(code)));
356 krb5_free_context(ctx);
361 if ((code = krb5_cc_destroy (ctx, cc))) {
362 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
363 error_message(code)));
366 krb5_free_context (ctx);
370 /************************************************************************
371 Routine to fetch the salting principal for a service. Active
372 Directory may use a non-obvious principal name to generate the salt
373 when it determines the key to use for encrypting tickets for a service,
374 and hopefully we detected that when we joined the domain.
375 ************************************************************************/
377 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
382 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
386 ret = (char *)secrets_fetch(key, NULL);
391 /************************************************************************
392 Return the standard DES salt key
393 ************************************************************************/
395 char* kerberos_standard_des_salt( void )
399 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
401 fstrcat( salt, lp_realm() );
403 return SMB_STRDUP( salt );
406 /************************************************************************
407 ************************************************************************/
409 static char* des_salt_key( void )
413 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
418 /************************************************************************
419 ************************************************************************/
421 BOOL kerberos_secrets_store_des_salt( const char* salt )
426 if ( (key = des_salt_key()) == NULL ) {
427 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
432 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
433 secrets_delete( key );
437 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
439 ret = secrets_store( key, salt, strlen(salt)+1 );
446 /************************************************************************
447 ************************************************************************/
449 char* kerberos_secrets_fetch_des_salt( void )
453 if ( (key = des_salt_key()) == NULL ) {
454 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
458 salt = (char*)secrets_fetch( key, NULL );
466 /************************************************************************
467 Routine to get the salting principal for this service. This is
468 maintained for backwards compatibilty with releases prior to 3.0.24.
469 Since we store the salting principal string only at join, we may have
470 to look for the older tdb keys. Caller must free if return is not null.
471 ************************************************************************/
473 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
474 krb5_principal host_princ,
477 char *unparsed_name = NULL, *salt_princ_s = NULL;
478 krb5_principal ret_princ = NULL;
480 /* lookup new key first */
482 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
484 /* look under the old key. If this fails, just use the standard key */
486 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
487 return (krb5_principal)NULL;
489 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
490 /* fall back to host/machine.realm@REALM */
491 salt_princ_s = kerberos_standard_des_salt();
495 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
499 SAFE_FREE(unparsed_name);
500 SAFE_FREE(salt_princ_s);
505 /************************************************************************
506 Routine to set the salting principal for this service. Active
507 Directory may use a non-obvious principal name to generate the salt
508 when it determines the key to use for encrypting tickets for a service,
509 and hopefully we detected that when we joined the domain.
510 Setting principal to NULL deletes this entry.
511 ************************************************************************/
513 BOOL kerberos_secrets_store_salting_principal(const char *service,
515 const char *principal)
519 krb5_context context = NULL;
520 krb5_principal princ = NULL;
521 char *princ_s = NULL;
522 char *unparsed_name = NULL;
524 krb5_init_context(&context);
528 if (strchr_m(service, '@')) {
529 asprintf(&princ_s, "%s", service);
531 asprintf(&princ_s, "%s@%s", service, lp_realm());
534 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
538 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
542 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
547 if ((principal != NULL) && (strlen(principal) > 0)) {
548 ret = secrets_store(key, principal, strlen(principal) + 1);
550 ret = secrets_delete(key);
557 SAFE_FREE(unparsed_name);
560 krb5_free_context(context);
567 /************************************************************************
568 ************************************************************************/
570 int kerberos_kinit_password(const char *principal,
571 const char *password,
573 const char *cache_name)
575 return kerberos_kinit_password_ext(principal,
586 /************************************************************************
587 Create a string list of available kdc's, possibly searching by sitename.
589 ************************************************************************/
591 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
593 struct ip_service *ip_srv_site;
594 struct ip_service *ip_srv_nonsite;
595 int count_site, count_nonsite, i;
596 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
597 inet_ntoa(primary_ip));
599 if (kdc_str == NULL) {
603 /* Get the KDC's only in this site. */
607 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
609 for (i = 0; i < count_site; i++) {
610 if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
613 /* Append to the string - inefficient but not done often. */
614 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
615 kdc_str, inet_ntoa(ip_srv_site[i].ip));
617 SAFE_FREE(ip_srv_site);
625 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
627 for (i = 0; i < count_nonsite; i++) {
630 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
634 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
635 for (j = 0; j < count_site; j++) {
636 if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
639 /* As the lists are sorted we can break early if nonsite > site. */
640 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
648 /* Append to the string - inefficient but not done often. */
649 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
650 kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
652 SAFE_FREE(ip_srv_site);
653 SAFE_FREE(ip_srv_nonsite);
659 SAFE_FREE(ip_srv_site);
660 SAFE_FREE(ip_srv_nonsite);
662 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
668 /************************************************************************
669 Create a specific krb5.conf file in the private directory pointing
670 at a specific kdc for a realm. Keyed off domain name. Sets
671 KRB5_CONFIG environment variable to point to this file. Must be
672 run as root or will fail (which is a good thing :-).
673 ************************************************************************/
675 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
676 const char *sitename, struct in_addr ip)
678 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
679 char *tmpname = NULL;
681 char *file_contents = NULL;
682 char *kdc_ip_string = NULL;
686 char *realm_upper = NULL;
691 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
692 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
693 "failed to create directory %s. Error was %s\n",
694 dname, strerror(errno) ));
699 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
705 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
711 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
712 fname, realm, domain ));
714 realm_upper = talloc_strdup(fname, realm);
715 strupper_m(realm_upper);
717 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
718 if (!kdc_ip_string) {
723 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
724 "[realms]\n\t%s = {\n"
726 realm_upper, realm_upper, kdc_ip_string);
728 if (!file_contents) {
733 flen = strlen(file_contents);
735 fd = smb_mkstemp(tmpname);
737 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
738 " for file %s. Errno %s\n",
739 tmpname, strerror(errno) ));
742 if (fchmod(fd, 0644)==-1) {
743 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
745 tmpname, strerror(errno) ));
752 ret = write(fd, file_contents, flen);
754 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
755 " returned %d (should be %u). Errno %s\n",
756 (int)ret, (unsigned int)flen, strerror(errno) ));
763 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
764 " Errno %s\n", strerror(errno) ));
770 if (rename(tmpname, fname) == -1) {
771 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
772 "of %s to %s failed. Errno %s\n",
773 tmpname, fname, strerror(errno) ));
779 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
780 "file %s with realm %s KDC = %s\n",
781 fname, realm_upper, inet_ntoa(ip) ));
783 /* Set the environment variable to this file. */
784 setenv("KRB5_CONFIG", fname, 1);
786 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
788 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
789 /* Insanity, sheer insanity..... */
791 if (strequal(realm, lp_realm())) {
795 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
796 linkpath[sizeof(pstring)-1] = '\0';
798 if (lret == 0 || strcmp(linkpath, fname) == 0) {
799 /* Symlink already exists. */
804 /* Try and replace with a symlink. */
805 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
806 if (errno != EEXIST) {
807 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
808 "of %s to %s failed. Errno %s\n",
809 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
811 return True; /* Not a fatal error. */
814 pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
815 pstrcat(linkpath, ".saved");
817 /* Yes, this is a race conditon... too bad. */
818 if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
819 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
820 "of %s to %s failed. Errno %s\n",
821 SYSTEM_KRB5_CONF_PATH, linkpath,
824 return True; /* Not a fatal error. */
827 if (symlink(fname, "/etc/krb5.conf") == -1) {
828 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
829 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
830 fname, strerror(errno) ));
832 return True; /* Not a fatal error. */