summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/gssd/gssd_proc.c62
-rw-r--r--utils/gssd/krb5_util.c22
-rw-r--r--utils/gssd/krb5_util.h3
3 files changed, 74 insertions, 13 deletions
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 799a207..33a31c3 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -883,7 +883,8 @@ int create_auth_rpc_client(struct clnt_info *clp,
* context on behalf of the kernel
*/
static void
-process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+ char *service)
{
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
@@ -906,7 +907,31 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
- if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
+ /*
+ * If "service" is specified, then the kernel is indicating that
+ * we must use machine credentials for this request. (Regardless
+ * of the uid value or the setting of root_uses_machine_creds.)
+ * If the service value is "*", then any service name can be used.
+ * Otherwise, it specifies the service name that should be used.
+ * (For now, the values of service will only be "*" or "nfs".)
+ *
+ * Restricting gssd to use "nfs" service name is needed for when
+ * the NFS server is doing a callback to the NFS client. In this
+ * case, the NFS server has to authenticate itself as "nfs" --
+ * even if there are other service keys such as "host" or "root"
+ * in the keytab.
+ *
+ * Another case when the kernel may specify the service attribute
+ * is when gssd is being asked to create the context for a
+ * SETCLIENT_ID operation. In this case, machine credentials
+ * must be used for the authentication. However, the service name
+ * used for this case is not important.
+ *
+ */
+ printerr(2, "%s: service is '%s'\n", __func__,
+ service ? service : "<null>");
+ if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
+ service == NULL)) {
/* Tell krb5 gss which credentials cache to use */
for (dirname = ccachesearch; *dirname != NULL; dirname++) {
if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
@@ -917,12 +942,13 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname)
}
}
if (create_resp != 0) {
- if (uid == 0 && root_uses_machine_creds == 1) {
+ if (uid == 0 && (root_uses_machine_creds == 1 ||
+ service != NULL)) {
int nocache = 0;
int success = 0;
do {
gssd_refresh_krb5_machine_credential(clp->servername,
- NULL, nocache);
+ NULL, service);
/*
* Get a list of credential cache names and try each
* of them until one works or we've tried them all
@@ -1066,7 +1092,7 @@ handle_krb5_upcall(struct clnt_info *clp)
return;
}
- return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL);
+ return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
}
void
@@ -1092,6 +1118,7 @@ handle_gssd_upcall(struct clnt_info *clp)
char *p;
char *mech = NULL;
char *target = NULL;
+ char *service = NULL;
printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
@@ -1148,8 +1175,30 @@ handle_gssd_upcall(struct clnt_info *clp)
}
}
+ /*
+ * read the service name
+ *
+ * The presence of attribute "service=" indicates that machine
+ * credentials should be used for this request. If the value
+ * is "*", then any machine credentials available can be used.
+ * If the value is anything else, then machine credentials for
+ * the specified service name (always "nfs" for now) should be
+ * used.
+ */
+ if ((p = strstr(lbuf, "service=")) != NULL) {
+ service = malloc(lbuflen);
+ if (!service)
+ goto out;
+ if (sscanf(p, "service=%s", service) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse service type "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ }
+
if (strcmp(mech, "krb5") == 0)
- process_krb5_upcall(clp, uid, clp->gssd_fd, target);
+ process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
else if (strcmp(mech, "spkm3") == 0)
process_spkm3_upcall(clp, uid, clp->gssd_fd);
else
@@ -1160,6 +1209,7 @@ out:
free(lbuf);
free(mech);
free(target);
+ free(service);
return;
}
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index 78e9775..c3c131b 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -797,10 +797,9 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
*/
static int
find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
- krb5_keytab_entry *kte)
+ krb5_keytab_entry *kte, const char **svcnames)
{
krb5_error_code code;
- const char *svcnames[] = { "root", "nfs", "host", NULL };
char **realmnames = NULL;
char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
int i, j, retval;
@@ -1096,7 +1095,8 @@ gssd_get_krb5_machine_cred_list(char ***list)
for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
if (ple->ccname) {
/* Make sure cred is up-to-date before returning it */
- retval = gssd_refresh_krb5_machine_credential(NULL, ple, 0);
+ retval = gssd_refresh_krb5_machine_credential(NULL, ple,
+ NULL);
if (retval)
continue;
if (i + 1 > listsize) {
@@ -1186,14 +1186,24 @@ gssd_destroy_krb5_machine_creds(void)
*/
int
gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple, int nocache)
+ struct gssd_k5_kt_princ *ple,
+ char *service)
{
krb5_error_code code = 0;
krb5_context context;
krb5_keytab kt = NULL;;
int retval = 0;
char *k5err = NULL;
+ const char *svcnames[4] = { "root", "nfs", "host", NULL };
+ /*
+ * If a specific service name was specified, use it.
+ * Otherwise, use the default list.
+ */
+ if (service != NULL && strcmp(service, "*") != 0) {
+ svcnames[0] = service;
+ svcnames[1] = NULL;
+ }
if (hostname == NULL && ple == NULL)
return EINVAL;
@@ -1216,7 +1226,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
if (ple == NULL) {
krb5_keytab_entry kte;
- code = find_keytab_entry(context, kt, hostname, &kte);
+ code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
if (code) {
printerr(0, "ERROR: %s: no usable keytab entry found "
"in keytab %s for connection with host %s\n",
@@ -1241,7 +1251,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
goto out;
}
}
- retval = gssd_get_single_krb5_cred(context, kt, ple, nocache);
+ retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
out:
if (kt)
krb5_kt_close(context, kt);
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
index 4b6b281..4602cc3 100644
--- a/utils/gssd/krb5_util.h
+++ b/utils/gssd/krb5_util.h
@@ -30,7 +30,8 @@ void gssd_free_krb5_machine_cred_list(char **list);
void gssd_setup_krb5_machine_gss_ccache(char *servername);
void gssd_destroy_krb5_machine_creds(void);
int gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple, int nocache);
+ struct gssd_k5_kt_princ *ple,
+ char *service);
char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
void gssd_k5_get_default_realm(char **def_realm);