Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd4: fix gss-proxy 4.1 mounts for some AD principals

The principal name on a gss cred is used to setup the NFSv4.0 callback,
which has to have a client principal name to authenticate to.

That code wants the name to be in the form servicetype@hostname.
rpc.svcgssd passes down such names (and passes down no principal name at
all in the case the principal isn't a service principal).

gss-proxy always passes down the principal name, and passes it down in
the form servicetype/hostname@REALM. So we've been munging the name
gss-proxy passes down into the format the NFSv4.0 callback code expects,
or throwing away the name if we can't.

Since the introduction of the MACH_CRED enforcement in NFSv4.1, we've
also been using the principal name to verify that certain operations are
done as the same principal as was used on the original EXCHANGE_ID call.

For that application, the original name passed down by gss-proxy is also
useful.

Lack of that name in some cases was causing some kerberized NFSv4.1
mount failures in an Active Directory environment.

This fix only works in the gss-proxy case. The fix for legacy
rpc.svcgssd would be more involved, and rpc.svcgssd already has other
problems in the AD case.

Reported-and-tested-by: James Ralston <ralston@pobox.com>
Acked-by: Simo Sorce <simo@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

+20 -2
+9 -1
fs/nfsd/nfs4state.c
··· 1875 1875 ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal); 1876 1876 if (ret) 1877 1877 return ret; 1878 + ret = strdup_if_nonnull(&target->cr_raw_principal, 1879 + source->cr_raw_principal); 1880 + if (ret) 1881 + return ret; 1878 1882 target->cr_flavor = source->cr_flavor; 1879 1883 target->cr_uid = source->cr_uid; 1880 1884 target->cr_gid = source->cr_gid; ··· 1982 1978 return false; 1983 1979 if (!svc_rqst_integrity_protected(rqstp)) 1984 1980 return false; 1981 + if (cl->cl_cred.cr_raw_principal) 1982 + return 0 == strcmp(cl->cl_cred.cr_raw_principal, 1983 + cr->cr_raw_principal); 1985 1984 if (!cr->cr_principal) 1986 1985 return false; 1987 1986 return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); ··· 2397 2390 * Which is a bug, really. Anyway, we can't enforce 2398 2391 * MACH_CRED in that case, better to give up now: 2399 2392 */ 2400 - if (!new->cl_cred.cr_principal) { 2393 + if (!new->cl_cred.cr_principal && 2394 + !new->cl_cred.cr_raw_principal) { 2401 2395 status = nfserr_serverfault; 2402 2396 goto out_nolock; 2403 2397 }
+8 -1
include/linux/sunrpc/svcauth.h
··· 23 23 kgid_t cr_gid; 24 24 struct group_info *cr_group_info; 25 25 u32 cr_flavor; /* pseudoflavor */ 26 - char *cr_principal; /* for gss */ 26 + /* name of form servicetype/hostname@REALM, passed down by 27 + * gss-proxy: */ 28 + char *cr_raw_principal; 29 + /* name of form servicetype@hostname, passed down by 30 + * rpc.svcgssd, or computed from the above: */ 31 + char *cr_principal; 27 32 struct gss_api_mech *cr_gss_mech; 28 33 }; 29 34 30 35 static inline void init_svc_cred(struct svc_cred *cred) 31 36 { 32 37 cred->cr_group_info = NULL; 38 + cred->cr_raw_principal = NULL; 33 39 cred->cr_principal = NULL; 34 40 cred->cr_gss_mech = NULL; 35 41 } ··· 44 38 { 45 39 if (cred->cr_group_info) 46 40 put_group_info(cred->cr_group_info); 41 + kfree(cred->cr_raw_principal); 47 42 kfree(cred->cr_principal); 48 43 gss_mech_put(cred->cr_gss_mech); 49 44 init_svc_cred(cred);
+3
net/sunrpc/auth_gss/gss_rpc_upcall.c
··· 326 326 if (data->found_creds && client_name.data != NULL) { 327 327 char *c; 328 328 329 + data->creds.cr_raw_principal = kstrndup(client_name.data, 330 + client_name.len, GFP_KERNEL); 331 + 329 332 data->creds.cr_principal = kstrndup(client_name.data, 330 333 client_name.len, GFP_KERNEL); 331 334 if (data->creds.cr_principal) {