#ifdef HAVE_KRB5
+#define DEFAULT_KRB5_PORT 88
+
#define LIBADS_CCACHE_NAME "MEMORY:libads"
/*
krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
}
- DEBUG(10,("kerberos_kinit_password: using [%s] as ccache and config [%s]\n",
+ DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
+ principal,
cache_name ? cache_name: krb5_cc_default_name(ctx),
getenv("KRB5_CONFIG")));
return salt;
}
+/************************************************************************
+ Routine to get the default realm from the kerberos credentials cache.
+ Caller must free if the return value is not NULL.
+************************************************************************/
+
+char *kerberos_get_default_realm_from_ccache( void )
+{
+ char *realm = NULL;
+ krb5_context ctx = NULL;
+ krb5_ccache cc = NULL;
+ krb5_principal princ = NULL;
+
+ initialize_krb5_error_table();
+ if (krb5_init_context(&ctx)) {
+ return NULL;
+ }
+
+ DEBUG(5,("kerberos_get_default_realm_from_ccache: "
+ "Trying to read krb5 cache: %s\n",
+ krb5_cc_default_name(ctx)));
+ if (krb5_cc_default(ctx, &cc)) {
+ DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+ "failed to read default cache\n"));
+ goto out;
+ }
+ if (krb5_cc_get_principal(ctx, cc, &princ)) {
+ DEBUG(0,("kerberos_get_default_realm_from_ccache: "
+ "failed to get default principal\n"));
+ goto out;
+ }
+
+#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
+ realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
+#elif defined(HAVE_KRB5_PRINC_REALM)
+ {
+ krb5_data *realm_data = krb5_princ_realm(ctx, princ);
+ realm = SMB_STRNDUP(realm_data->data, realm_data->length);
+ }
+#endif
+
+ out:
+
+ if (princ) {
+ krb5_free_principal(ctx, princ);
+ }
+ if (cc) {
+ krb5_cc_close(ctx, cc);
+ }
+ if (ctx) {
+ krb5_free_context(ctx);
+ }
+
+ return realm;
+}
+
/************************************************************************
Routine to get the salting principal for this service. This is
NULL);
}
+/************************************************************************
+************************************************************************/
+
+static char *print_kdc_line(char *mem_ctx,
+ const char *prev_line,
+ const struct sockaddr_storage *pss)
+{
+ char *kdc_str = NULL;
+
+ if (pss->ss_family == AF_INET) {
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ prev_line,
+ print_canonical_sockaddr(mem_ctx, pss));
+ } else {
+ char addr[INET6_ADDRSTRLEN];
+ uint16_t port = get_sockaddr_port(pss);
+
+ if (port != 0 && port != DEFAULT_KRB5_PORT) {
+ /* Currently for IPv6 we can't specify a non-default
+ krb5 port with an address, as this requires a ':'.
+ Resolve to a name. */
+ char hostname[MAX_DNS_NAME_LENGTH];
+ int ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(*pss),
+ hostname, sizeof(hostname),
+ NULL, 0,
+ NI_NAMEREQD);
+ if (ret) {
+ DEBUG(0,("print_kdc_line: can't resolve name "
+ "for kdc with non-default port %s. "
+ "Error %s\n.",
+ print_canonical_sockaddr(mem_ctx, pss),
+ gai_strerror(ret)));
+ }
+ /* Success, use host:port */
+ kdc_str = talloc_asprintf(mem_ctx,
+ "%s\tkdc = %s:%u\n",
+ prev_line,
+ hostname,
+ (unsigned int)port);
+ } else {
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ prev_line,
+ print_sockaddr(addr,
+ sizeof(addr),
+ pss));
+ }
+ }
+ return kdc_str;
+}
+
/************************************************************************
Create a string list of available kdc's, possibly searching by sitename.
Does DNS queries.
************************************************************************/
-static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
+static char *get_kdc_ip_string(char *mem_ctx,
+ const char *realm,
+ const char *sitename,
+ struct sockaddr_storage *pss)
{
int i;
struct ip_service *ip_srv_site = NULL;
- struct ip_service *ip_srv_nonsite;
+ struct ip_service *ip_srv_nonsite = NULL;
int count_site = 0;
int count_nonsite;
- char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
- inet_ntoa(primary_ip));
+ char *kdc_str = print_kdc_line(mem_ctx, "", pss);
if (kdc_str == NULL) {
return NULL;
get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
for (i = 0; i < count_site; i++) {
- if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
+ if (addr_equal(&ip_srv_site[i].ss, pss)) {
continue;
}
- /* Append to the string - inefficient but not done often. */
- kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
- kdc_str, inet_ntoa(ip_srv_site[i].ip));
+ /* Append to the string - inefficient
+ * but not done often. */
+ kdc_str = print_kdc_line(mem_ctx,
+ kdc_str,
+ &ip_srv_site[i].ss);
if (!kdc_str) {
SAFE_FREE(ip_srv_site);
return NULL;
for (i = 0; i < count_nonsite; i++) {
int j;
- if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
+ if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
continue;
}
/* Ensure this isn't an IP already seen (YUK! this is n*n....) */
for (j = 0; j < count_site; j++) {
- if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
+ if (addr_equal(&ip_srv_nonsite[i].ss,
+ &ip_srv_site[j].ss)) {
break;
}
/* As the lists are sorted we can break early if nonsite > site. */
}
/* Append to the string - inefficient but not done often. */
- kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
- kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
+ kdc_str = print_kdc_line(mem_ctx,
+ kdc_str,
+ &ip_srv_nonsite[i].ss);
if (!kdc_str) {
SAFE_FREE(ip_srv_site);
SAFE_FREE(ip_srv_nonsite);
run as root or will fail (which is a good thing :-).
************************************************************************/
-bool create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
- const char *sitename, struct in_addr ip)
+bool create_local_private_krb5_conf_for_domain(const char *realm,
+ const char *domain,
+ const char *sitename,
+ struct sockaddr_storage *pss)
{
char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
char *tmpname = NULL;
realm_upper = talloc_strdup(fname, realm);
strupper_m(realm_upper);
- kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
+ kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
if (!kdc_ip_string) {
TALLOC_FREE(dname);
return False;
}
-
- file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
- "[realms]\n\t%s = {\n"
- "\t%s\t}\n",
- realm_upper, realm_upper, kdc_ip_string);
+
+ file_contents = talloc_asprintf(fname,
+ "[libdefaults]\n\tdefault_realm = %s\n"
+ "default_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
+ "default_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
+ "preferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
+ "[realms]\n\t%s = {\n"
+ "\t%s\t}\n",
+ realm_upper, realm_upper, kdc_ip_string);
if (!file_contents) {
TALLOC_FREE(dname);
}
DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
- "file %s with realm %s KDC = %s\n",
- fname, realm_upper, inet_ntoa(ip) ));
+ "file %s with realm %s KDC list = %s\n",
+ fname, realm_upper, kdc_ip_string));
/* Set the environment variable to this file. */
setenv("KRB5_CONFIG", fname, 1);
/* Insanity, sheer insanity..... */
if (strequal(realm, lp_realm())) {
- pstring linkpath;
+ char linkpath[PATH_MAX+1];
int lret;
lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
- linkpath[sizeof(pstring)-1] = '\0';
+ if (lret != -1) {
+ linkpath[lret] = '\0';
+ }
- if (lret == 0 || strcmp(linkpath, fname) == 0) {
+ if (lret != -1 || strcmp(linkpath, fname) == 0) {
/* Symlink already exists. */
TALLOC_FREE(dname);
return True;
/* Try and replace with a symlink. */
if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
+ const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
if (errno != EEXIST) {
DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
"of %s to %s failed. Errno %s\n",
return True; /* Not a fatal error. */
}
- pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
- pstrcat(linkpath, ".saved");
-
/* Yes, this is a race conditon... too bad. */
- if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
+ if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
"of %s to %s failed. Errno %s\n",
- SYSTEM_KRB5_CONF_PATH, linkpath,
+ SYSTEM_KRB5_CONF_PATH, newpath,
strerror(errno) ));
TALLOC_FREE(dname);
return True; /* Not a fatal error. */
}
- if (symlink(fname, "/etc/krb5.conf") == -1) {
+ if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
DEBUG(0,("create_local_private_krb5_conf_for_domain: "
"forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
fname, strerror(errno) ));