1 /*
2  * linux/net/sunrpc/svcauth.c
3  *
4  * The generic interface for RPC authentication on the server side.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  *
8  * CHANGES
9  * 19-Apr-2000 Chris Evans      - Security fix
10  */
11 
12 #include <linux/types.h>
13 #include <linux/sched.h>
14 #include <linux/sunrpc/types.h>
15 #include <linux/sunrpc/xdr.h>
16 #include <linux/sunrpc/svcauth.h>
17 #include <linux/sunrpc/svcsock.h>
18 
19 #define RPCDBG_FACILITY	RPCDBG_AUTH
20 
21 /*
22  * Type of authenticator function
23  */
24 typedef void	(*auth_fn_t)(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
25 
26 /*
27  * Builtin auth flavors
28  */
29 static void	svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
30 static void	svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
31 
32 /*
33  * Max number of authentication flavors we support
34  */
35 #define RPC_SVCAUTH_MAX	8
36 
37 /*
38  * Table of authenticators
39  */
40 static auth_fn_t	authtab[RPC_SVCAUTH_MAX] = {
41 	svcauth_null,
42 	svcauth_unix,
43 	NULL,
44 };
45 
46 void
svc_authenticate(struct svc_rqst * rqstp,u32 * statp,u32 * authp)47 svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
48 {
49 	u32		flavor;
50 	auth_fn_t	func;
51 
52 	*statp = rpc_success;
53 	*authp = rpc_auth_ok;
54 
55 	svc_getlong(&rqstp->rq_argbuf, flavor);
56 	flavor = ntohl(flavor);
57 
58 	dprintk("svc: svc_authenticate (%d)\n", flavor);
59 	if (flavor >= RPC_SVCAUTH_MAX || !(func = authtab[flavor])) {
60 		*authp = rpc_autherr_badcred;
61 		return;
62 	}
63 
64 	rqstp->rq_cred.cr_flavor = flavor;
65 	func(rqstp, statp, authp);
66 }
67 
68 int
svc_auth_register(u32 flavor,auth_fn_t func)69 svc_auth_register(u32 flavor, auth_fn_t func)
70 {
71 	if (flavor >= RPC_SVCAUTH_MAX || authtab[flavor])
72 		return -EINVAL;
73 	authtab[flavor] = func;
74 	return 0;
75 }
76 
77 void
svc_auth_unregister(u32 flavor)78 svc_auth_unregister(u32 flavor)
79 {
80 	if (flavor < RPC_SVCAUTH_MAX)
81 		authtab[flavor] = NULL;
82 }
83 
84 static void
svcauth_null(struct svc_rqst * rqstp,u32 * statp,u32 * authp)85 svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
86 {
87 	struct svc_buf	*argp = &rqstp->rq_argbuf;
88 	struct svc_buf	*resp = &rqstp->rq_resbuf;
89 
90 	if ((argp->len -= 3) < 0) {
91 		*statp = rpc_garbage_args;
92 		return;
93 	}
94 	if (*(argp->buf)++ != 0) {	/* we already skipped the flavor */
95 		dprintk("svc: bad null cred\n");
96 		*authp = rpc_autherr_badcred;
97 		return;
98 	}
99 	if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) {
100 		dprintk("svc: bad null verf\n");
101 		*authp = rpc_autherr_badverf;
102 		return;
103 	}
104 
105 	/* Signal that mapping to nobody uid/gid is required */
106 	rqstp->rq_cred.cr_uid = (uid_t) -1;
107 	rqstp->rq_cred.cr_gid = (gid_t) -1;
108 	rqstp->rq_cred.cr_groups[0] = NOGROUP;
109 
110 	/* Put NULL verifier */
111 	rqstp->rq_verfed = 1;
112 	svc_putlong(resp, RPC_AUTH_NULL);
113 	svc_putlong(resp, 0);
114 }
115 
116 static void
svcauth_unix(struct svc_rqst * rqstp,u32 * statp,u32 * authp)117 svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
118 {
119 	struct svc_buf	*argp = &rqstp->rq_argbuf;
120 	struct svc_buf	*resp = &rqstp->rq_resbuf;
121 	struct svc_cred	*cred = &rqstp->rq_cred;
122 	u32		*bufp = argp->buf, slen, i;
123 	int		len   = argp->len;
124 
125 	if ((len -= 3) < 0) {
126 		*statp = rpc_garbage_args;
127 		return;
128 	}
129 
130 	bufp++;					/* length */
131 	bufp++;					/* time stamp */
132 	slen = (ntohl(*bufp++) + 3) >> 2;	/* machname length */
133 	if (slen > 64 || (len -= slen + 3) < 0)
134 		goto badcred;
135 	bufp += slen;				/* skip machname */
136 
137 	cred->cr_uid = ntohl(*bufp++);		/* uid */
138 	cred->cr_gid = ntohl(*bufp++);		/* gid */
139 
140 	slen = ntohl(*bufp++);			/* gids length */
141 	if (slen > 16 || (len -= slen + 2) < 0)
142 		goto badcred;
143 	for (i = 0; i < NGROUPS && i < slen; i++)
144 		cred->cr_groups[i] = ntohl(*bufp++);
145 	if (i < NGROUPS)
146 		cred->cr_groups[i] = NOGROUP;
147 	bufp += (slen - i);
148 
149 	if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) {
150 		*authp = rpc_autherr_badverf;
151 		return;
152 	}
153 
154 	argp->buf = bufp;
155 	argp->len = len;
156 
157 	/* Put NULL verifier */
158 	rqstp->rq_verfed = 1;
159 	svc_putlong(resp, RPC_AUTH_NULL);
160 	svc_putlong(resp, 0);
161 
162 	return;
163 
164 badcred:
165 	*authp = rpc_autherr_badcred;
166 }
167