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