X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fkrb5_util.c;h=238927622f614c284970b2e5d2360f21046c8f51;hp=d23654ff1b9c581ebb713370efc8d93f88158f1a;hb=1c787f1471d733f8a90b46924945c59de7478bac;hpb=12af21aca517dfbaec465447d8336bcc4769f71d diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c index d23654f..2389276 100644 --- a/utils/gssd/krb5_util.c +++ b/utils/gssd/krb5_util.c @@ -129,13 +129,17 @@ /* 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, @@ -174,7 +178,8 @@ select_krb5_ccache(const struct dirent *d) * 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; @@ -188,6 +193,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) 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) { @@ -199,41 +205,51 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) 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 : ""); - 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; @@ -244,9 +260,9 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) 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 @@ -280,10 +296,11 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) 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); @@ -613,24 +630,32 @@ out: * and has *any* instance (hostname), return 1. * Otherwise return 0, indicating no match. */ +#ifdef HAVE_KRB5 static int -realm_and_service_match(krb5_context context, krb5_principal p, - const char *realm, const char *service) +realm_and_service_match(krb5_principal p, const char *realm, const char *service) { -#ifdef HAVE_KRB5 /* Must have two components */ if (p->length != 2) return 0; + if ((strlen(realm) == p->realm.length) && (strncmp(realm, p->realm.data, p->realm.length) == 0) && (strlen(service) == p->data[0].length) && (strncmp(service, p->data[0].data, p->data[0].length) == 0)) return 1; + + return 0; +} #else +static int +realm_and_service_match(krb5_context context, krb5_principal p, + const char *realm, const char *service) +{ const char *name, *inst; if (p->name.name_string.len != 2) return 0; + name = krb5_principal_get_comp_string(context, p, 0); inst = krb5_principal_get_comp_string(context, p, 1); if (name == NULL || inst == NULL) @@ -638,9 +663,10 @@ realm_and_service_match(krb5_context context, krb5_principal p, if ((strcmp(realm, p->realm) == 0) && (strcmp(service, name) == 0)) return 1; -#endif + return 0; } +#endif /* * Search the given keytab file looking for an entry with the given @@ -662,7 +688,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, krb5_kt_cursor cursor; krb5_error_code code; struct gssd_k5_kt_princ *ple; - int retval = -1; + int retval = -1, status; char kt_name[BUFSIZ]; char *pname; char *k5err = NULL; @@ -705,8 +731,12 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, printerr(4, "Processing keytab entry for principal '%s'\n", pname); /* Use the first matching keytab entry found */ - if ((realm_and_service_match(context, kte->principal, realm, - service))) { +#ifdef HAVE_KRB5 + status = realm_and_service_match(kte->principal, realm, service); +#else + status = realm_and_service_match(context, kte->principal, realm, service); +#endif + if (status) { printerr(4, "We WILL use this entry (%s)\n", pname); ple = get_ple_by_princ(context, kte->principal); /* @@ -755,6 +785,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, 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; @@ -776,6 +807,14 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, 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; @@ -820,32 +859,47 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, 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; } @@ -857,6 +911,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, */ 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) { @@ -983,17 +1039,18 @@ int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname) { char buf[MAX_NETOBJ_SZ]; + const char *cctype; struct dirent *d; int err; 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); + 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 " @@ -1147,7 +1204,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, 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. @@ -1272,7 +1329,7 @@ gssd_k5_get_default_realm(char **def_realm) */ int -limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) +limit_krb5_enctypes(struct rpc_gss_sec *sec) { u_int maj_stat, min_stat; gss_cred_id_t credh; @@ -1303,7 +1360,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) * 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