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