/* * linux/net/sunrpc/svcauth.c * * The generic interface for RPC authentication on the server side. * * Copyright (C) 1995, 1996 Olaf Kirch * * CHANGES * 19-Apr-2000 Chris Evans - Security fix */ #include #include #include #include #include #include #define RPCDBG_FACILITY RPCDBG_AUTH /* * Type of authenticator function */ typedef void (*auth_fn_t)(struct svc_rqst *rqstp, u32 *statp, u32 *authp); /* * Builtin auth flavors */ static void svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp); static void svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp); /* * Max number of authentication flavors we support */ #define RPC_SVCAUTH_MAX 8 /* * Table of authenticators */ static auth_fn_t authtab[RPC_SVCAUTH_MAX] = { svcauth_null, svcauth_unix, NULL, }; void svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp) { u32 flavor; auth_fn_t func; *statp = rpc_success; *authp = rpc_auth_ok; svc_getlong(&rqstp->rq_argbuf, flavor); flavor = ntohl(flavor); dprintk("svc: svc_authenticate (%d)\n", flavor); if (flavor >= RPC_SVCAUTH_MAX || !(func = authtab[flavor])) { *authp = rpc_autherr_badcred; return; } rqstp->rq_cred.cr_flavor = flavor; func(rqstp, statp, authp); } int svc_auth_register(u32 flavor, auth_fn_t func) { if (flavor >= RPC_SVCAUTH_MAX || authtab[flavor]) return -EINVAL; authtab[flavor] = func; return 0; } void svc_auth_unregister(u32 flavor) { if (flavor < RPC_SVCAUTH_MAX) authtab[flavor] = NULL; } static void svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp) { struct svc_buf *argp = &rqstp->rq_argbuf; struct svc_buf *resp = &rqstp->rq_resbuf; if ((argp->len -= 3) < 0) { *statp = rpc_garbage_args; return; } if (*(argp->buf)++ != 0) { /* we already skipped the flavor */ dprintk("svc: bad null cred\n"); *authp = rpc_autherr_badcred; return; } if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) { dprintk("svc: bad null verf\n"); *authp = rpc_autherr_badverf; return; } /* Signal that mapping to nobody uid/gid is required */ rqstp->rq_cred.cr_uid = (uid_t) -1; rqstp->rq_cred.cr_gid = (gid_t) -1; rqstp->rq_cred.cr_groups[0] = NOGROUP; /* Put NULL verifier */ rqstp->rq_verfed = 1; svc_putlong(resp, RPC_AUTH_NULL); svc_putlong(resp, 0); } static void svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp) { struct svc_buf *argp = &rqstp->rq_argbuf; struct svc_buf *resp = &rqstp->rq_resbuf; struct svc_cred *cred = &rqstp->rq_cred; u32 *bufp = argp->buf, slen, i; int len = argp->len; if ((len -= 3) < 0) { *statp = rpc_garbage_args; return; } bufp++; /* length */ bufp++; /* time stamp */ slen = (ntohl(*bufp++) + 3) >> 2; /* machname length */ if (slen > 64 || (len -= slen + 3) < 0) goto badcred; bufp += slen; /* skip machname */ cred->cr_uid = ntohl(*bufp++); /* uid */ cred->cr_gid = ntohl(*bufp++); /* gid */ slen = ntohl(*bufp++); /* gids length */ if (slen > 16 || (len -= slen + 2) < 0) goto badcred; for (i = 0; i < NGROUPS && i < slen; i++) cred->cr_groups[i] = ntohl(*bufp++); if (i < NGROUPS) cred->cr_groups[i] = NOGROUP; bufp += (slen - i); if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) { *authp = rpc_autherr_badverf; return; } argp->buf = bufp; argp->len = len; /* Put NULL verifier */ rqstp->rq_verfed = 1; svc_putlong(resp, RPC_AUTH_NULL); svc_putlong(resp, 0); return; badcred: *authp = rpc_autherr_badcred; }