/* Global list of principals/cache file names for machine credentials */
struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+int limit_to_legacy_enctypes = 0;
+#endif
+
/*==========================*/
/*=== Internal routines ===*/
/*==========================*/
static int select_krb5_ccache(const struct dirent *d);
static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
- struct dirent **d);
+ const char **cctype, struct dirent **d);
static int gssd_get_single_krb5_cred(krb5_context context,
krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache);
static int query_krb5_ccache(const char* cred_cache, char **ret_princname,
* code otherwise.
*/
static int
-gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
+gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
+ const char **cctype, struct dirent **d)
{
struct dirent **namelist;
int n;
int score, best_match_score = 0, err = -EACCES;
memset(&best_match_stat, 0, sizeof(best_match_stat));
+ *cctype = NULL;
*d = NULL;
n = scandir(dirname, &namelist, select_krb5_ccache, 0);
if (n < 0) {
for (i = 0; i < n; i++) {
snprintf(statname, sizeof(statname),
"%s/%s", dirname, namelist[i]->d_name);
- printerr(3, "CC file '%s' being considered, "
+ printerr(3, "CC '%s' being considered, "
"with preferred realm '%s'\n",
statname, preferred_realm ?
preferred_realm : "<none selected>");
- snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname,
- namelist[i]->d_name);
if (lstat(statname, &tmp_stat)) {
- printerr(0, "Error doing stat on file '%s'\n",
+ printerr(0, "Error doing stat on '%s'\n",
statname);
free(namelist[i]);
continue;
}
/* Only pick caches owned by the user (uid) */
if (tmp_stat.st_uid != uid) {
- printerr(3, "CC file '%s' owned by %u, not %u\n",
+ printerr(3, "CC '%s' owned by %u, not %u\n",
statname, tmp_stat.st_uid, uid);
free(namelist[i]);
continue;
}
- if (!S_ISREG(tmp_stat.st_mode)) {
- printerr(3, "CC file '%s' is not a regular file\n",
+ if (!S_ISREG(tmp_stat.st_mode) &&
+ !S_ISDIR(tmp_stat.st_mode)) {
+ printerr(3, "CC '%s' is not a regular "
+ "file or directory\n",
statname);
free(namelist[i]);
continue;
}
if (uid == 0 && !root_uses_machine_creds &&
strstr(namelist[i]->d_name, "_machine_")) {
- printerr(3, "CC file '%s' not available to root\n",
+ printerr(3, "CC '%s' not available to root\n",
statname);
free(namelist[i]);
continue;
}
+ if (S_ISDIR(tmp_stat.st_mode)) {
+ *cctype = "DIR";
+ } else
+ if (S_ISREG(tmp_stat.st_mode)) {
+ *cctype = "FILE";
+ } else {
+ continue;
+ }
+ snprintf(buf, sizeof(buf), "%s:%s/%s", *cctype,
+ dirname, namelist[i]->d_name);
if (!query_krb5_ccache(buf, &princname, &realm)) {
- printerr(3, "CC file '%s' is expired or corrupt\n",
- statname);
+ printerr(3, "CC '%s' is expired or corrupt\n",
+ buf);
free(namelist[i]);
err = -EKEYEXPIRED;
continue;
strcmp(realm, preferred_realm) == 0)
score++;
- printerr(3, "CC file '%s'(%s@%s) passed all checks and"
+ printerr(3, "CC '%s'(%s@%s) passed all checks and"
" has mtime of %u\n",
- statname, princname, realm,
+ buf, princname, realm,
tmp_stat.st_mtime);
/*
* if more than one match is found, return the most
else {
free(namelist[i]);
}
- printerr(3, "CC file '%s/%s' is our "
+ printerr(3, "CC '%s:%s/%s' is our "
"current best match "
"with mtime of %u\n",
- dirname, best_match_dir->d_name,
+ cctype, dirname,
+ best_match_dir->d_name,
best_match_stat.st_mtime);
}
free(princname);
krb5_error_code code;
char **realmnames = NULL;
char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
+ char myhostad[NI_MAXHOST+1];
int i, j, retval;
char *default_realm = NULL;
char *realm;
printerr(1, "%s while getting local hostname\n", k5err);
goto out;
}
+
+ /* Compute the active directory machine name HOST$ */
+ strcpy(myhostad, myhostname);
+ for (i = 0; myhostad[i] != 0; ++i)
+ myhostad[i] = toupper(myhostad[i]);
+ myhostad[i] = '$';
+ myhostad[i+1] = 0;
+
retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
if (retval)
goto out;
if (strcmp(realm, default_realm) == 0)
tried_default = 1;
for (j = 0; svcnames[j] != NULL; j++) {
- code = krb5_build_principal_ext(context, &princ,
- strlen(realm),
- realm,
- strlen(svcnames[j]),
- svcnames[j],
- strlen(myhostname),
- myhostname,
- NULL);
+ char spn[300];
+
+ /*
+ * The special svcname "$" means 'try the active
+ * directory machine account'
+ */
+ if (strcmp(svcnames[j],"$") == 0) {
+ snprintf(spn, sizeof(spn), "%s@%s", myhostad, realm);
+ code = krb5_build_principal_ext(context, &princ,
+ strlen(realm),
+ realm,
+ strlen(myhostad),
+ myhostad,
+ NULL);
+ } else {
+ snprintf(spn, sizeof(spn), "%s/%s@%s",
+ svcnames[j], myhostname, realm);
+ code = krb5_build_principal_ext(context, &princ,
+ strlen(realm),
+ realm,
+ strlen(svcnames[j]),
+ svcnames[j],
+ strlen(myhostname),
+ myhostname,
+ NULL);
+ }
+
if (code) {
k5err = gssd_k5_err_msg(context, code);
- printerr(1, "%s while building principal for "
- "'%s/%s@%s'\n", k5err, svcnames[j],
- myhostname, realm);
+ printerr(1, "%s while building principal for '%s'\n",
+ k5err, spn);
continue;
}
code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte);
krb5_free_principal(context, princ);
if (code) {
k5err = gssd_k5_err_msg(context, code);
- printerr(3, "%s while getting keytab entry for "
- "'%s/%s@%s'\n", k5err, svcnames[j],
- myhostname, realm);
+ printerr(3, "%s while getting keytab entry for '%s'\n",
+ k5err, spn);
} else {
- printerr(3, "Success getting keytab entry for "
- "'%s/%s@%s'\n",
- svcnames[j], myhostname, realm);
+ printerr(3, "Success getting keytab entry for '%s'\n",spn);
retval = 0;
goto out;
}
*/
for (j = 0; svcnames[j] != NULL; j++) {
int found = 0;
+ if (strcmp(svcnames[j],"$") == 0)
+ continue;
code = gssd_search_krb5_keytab(context, kt, realm,
svcnames[j], &found, kte);
if (!code && found) {
* Returns 0 if a ccache was found, and a non-zero error code otherwise.
*/
int
-gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
+gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern)
{
- char buf[MAX_NETOBJ_SZ];
+ char buf[MAX_NETOBJ_SZ], dirname[PATH_MAX];
+ const char *cctype;
struct dirent *d;
- int err;
+ int err, i, j;
printerr(2, "getting credentials for client with uid %u for "
"server %s\n", uid, servername);
- memset(buf, 0, sizeof(buf));
- err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
+
+ for (i = 0, j = 0; dirpattern[i] != '\0'; i++) {
+ switch (dirpattern[i]) {
+ case '%':
+ switch (dirpattern[i + 1]) {
+ case '%':
+ dirname[j++] = dirpattern[i];
+ i++;
+ break;
+ case 'U':
+ j += sprintf(dirname + j, "%lu",
+ (unsigned long) uid);
+ i++;
+ break;
+ }
+ break;
+ default:
+ dirname[j++] = dirpattern[i];
+ break;
+ }
+ }
+ dirname[j] = '\0';
+
+ err = gssd_find_existing_krb5_ccache(uid, dirname, &cctype, &d);
if (err)
return err;
- snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
+ snprintf(buf, sizeof(buf), "%s:%s/%s", cctype, dirname, d->d_name);
free(d);
printerr(2, "using %s as credentials cache for client with "
krb5_keytab kt = NULL;;
int retval = 0;
char *k5err = NULL;
- const char *svcnames[4] = { "root", "nfs", "host", NULL };
+ const char *svcnames[5] = { "$", "root", "nfs", "host", NULL };
/*
* If a specific service name was specified, use it.
* If we failed for any reason to produce global
* list of supported enctypes, use local default here.
*/
- if (krb5_enctypes == NULL)
+ if (krb5_enctypes == NULL || limit_to_legacy_enctypes)
maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
&krb5oid, num_enctypes, enctypes);
else