xref: /openbsd/lib/libc/rpc/auth_unix.c (revision 891d7ab6)
1 /*	$OpenBSD: auth_unix.c,v 1.22 2010/09/01 14:43:34 millert Exp $ */
2 
3 /*
4  * Copyright (c) 2010, Oracle America, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials
15  *       provided with the distribution.
16  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * auth_unix.c, Implements UNIX style authentication parameters.
36  *
37  * The system is very weak.  The client uses no encryption for it's
38  * credentials and only sends null verifiers.  The server sends backs
39  * null verifiers or optionally a verifier that suggests a new short hand
40  * for the credentials.
41  *
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 
49 #include <rpc/types.h>
50 #include <rpc/xdr.h>
51 #include <rpc/rpc.h>
52 #include <rpc/auth.h>
53 #include <rpc/auth_unix.h>
54 
55 /*
56  * Unix authenticator operations vector
57  */
58 static void	authunix_nextverf(struct __rpc_auth *);
59 static bool_t	authunix_marshal(struct __rpc_auth *, XDR *);
60 static bool_t	authunix_validate(struct __rpc_auth *, struct opaque_auth *);
61 static bool_t	authunix_refresh(struct __rpc_auth *);
62 static void	authunix_destroy(struct __rpc_auth *);
63 
64 static struct auth_ops auth_unix_ops = {
65 	authunix_nextverf,
66 	authunix_marshal,
67 	authunix_validate,
68 	authunix_refresh,
69 	authunix_destroy
70 };
71 
72 /*
73  * This struct is pointed to by the ah_private field of an auth_handle.
74  */
75 struct audata {
76 	struct opaque_auth	au_origcred;	/* original credentials */
77 	struct opaque_auth	au_shcred;	/* short hand cred */
78 	u_long			au_shfaults;	/* short hand cache faults */
79 	char			au_marshed[MAX_AUTH_BYTES];
80 	u_int			au_mpos;	/* xdr pos at end of marshed */
81 };
82 #define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
83 
84 static void marshal_new_auth(AUTH *auth);
85 
86 
87 /*
88  * Create a unix style authenticator.
89  * Returns an auth handle with the given stuff in it.
90  */
91 AUTH *
92 authunix_create(char *machname, int uid, int gid, int len, int *aup_gids)
93 {
94 	struct authunix_parms aup;
95 	char mymem[MAX_AUTH_BYTES];
96 	struct timeval now;
97 	XDR xdrs;
98 	AUTH *auth;
99 	struct audata *au;
100 
101 	/*
102 	 * Allocate and set up auth handle
103 	 */
104 	auth = (AUTH *)mem_alloc(sizeof(*auth));
105 #ifndef KERNEL
106 	if (auth == NULL) {
107 		(void)fprintf(stderr, "authunix_create: out of memory\n");
108 		return (NULL);
109 	}
110 #endif
111 	au = (struct audata *)mem_alloc(sizeof(*au));
112 #ifndef KERNEL
113 	if (au == NULL) {
114 		(void)fprintf(stderr, "authunix_create: out of memory\n");
115 		free(auth);
116 		return (NULL);
117 	}
118 #endif
119 	auth->ah_ops = &auth_unix_ops;
120 	auth->ah_private = (caddr_t)au;
121 	auth->ah_verf = au->au_shcred = _null_auth;
122 	au->au_shfaults = 0;
123 
124 	/*
125 	 * fill in param struct from the given params
126 	 */
127 	(void)gettimeofday(&now,  NULL);
128 	aup.aup_time = now.tv_sec;
129 	aup.aup_machname = machname;
130 	aup.aup_uid = uid;
131 	aup.aup_gid = gid;
132 	aup.aup_len = (u_int)len;
133 	aup.aup_gids = aup_gids;
134 
135 	/*
136 	 * Serialize the parameters into origcred
137 	 */
138 	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
139 	if (!xdr_authunix_parms(&xdrs, &aup))
140 		goto authfail;
141 	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
142 	au->au_origcred.oa_flavor = AUTH_UNIX;
143 #ifdef KERNEL
144 	au->au_origcred.oa_base = mem_alloc((u_int) len);
145 #else
146 	if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) {
147 		(void)fprintf(stderr, "authunix_create: out of memory\n");
148 		goto authfail;
149 	}
150 #endif
151 	memcpy(au->au_origcred.oa_base, mymem, (u_int)len);
152 
153 	/*
154 	 * set auth handle to reflect new cred.
155 	 */
156 	auth->ah_cred = au->au_origcred;
157 	marshal_new_auth(auth);
158 	return (auth);
159 
160 authfail:
161 	XDR_DESTROY(&xdrs);
162 	free(au);
163 	free(auth);
164 	return (NULL);
165 }
166 
167 
168 /*
169  * Some servers will refuse mounts if the group list is larger
170  * than it expects (like 8). This allows the application to set
171  * the maximum size of the group list that will be sent.
172  */
173 static int maxgrplist = NGRPS;
174 
175 void
176 set_rpc_maxgrouplist(int num)
177 {
178 	if (num < NGRPS)
179 		maxgrplist = num;
180 }
181 
182 /*
183  * Returns an auth handle with parameters determined by doing lots of
184  * syscalls.
185  */
186 AUTH *
187 authunix_create_default(void)
188 {
189 	int len, i;
190 	char machname[MAX_MACHINE_NAME + 1];
191 	uid_t uid;
192 	gid_t gid;
193 	gid_t gids[NGRPS];
194 	int gids2[NGRPS];
195 
196 	if (gethostname(machname, sizeof machname) == -1)
197 		return (NULL);
198 	machname[MAX_MACHINE_NAME] = 0;
199 	uid = geteuid();
200 	gid = getegid();
201 	if ((len = getgroups(NGRPS, gids)) < 0)
202 		return (NULL);
203 	if (len > maxgrplist)
204 		len = maxgrplist;
205 	for (i = 0; i < len; i++)
206 		gids2[i] = gids[i];
207 	return (authunix_create(machname, uid, gid, len, gids2));
208 }
209 
210 /*
211  * authunix operations
212  */
213 /* ARGSUSED */
214 static void
215 authunix_nextverf(AUTH *auth)
216 {
217 	/* no action necessary */
218 }
219 
220 static bool_t
221 authunix_marshal(AUTH *auth, XDR *xdrs)
222 {
223 	struct audata *au = AUTH_PRIVATE(auth);
224 
225 	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
226 }
227 
228 static bool_t
229 authunix_validate(AUTH *auth, struct opaque_auth *verf)
230 {
231 	struct audata *au;
232 	XDR xdrs;
233 
234 	if (verf->oa_flavor == AUTH_SHORT) {
235 		au = AUTH_PRIVATE(auth);
236 		xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE);
237 
238 		if (au->au_shcred.oa_base != NULL) {
239 			mem_free(au->au_shcred.oa_base,
240 			    au->au_shcred.oa_length);
241 			au->au_shcred.oa_base = NULL;
242 		}
243 		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
244 			auth->ah_cred = au->au_shcred;
245 		} else {
246 			xdrs.x_op = XDR_FREE;
247 			(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
248 			au->au_shcred.oa_base = NULL;
249 			auth->ah_cred = au->au_origcred;
250 		}
251 		marshal_new_auth(auth);
252 	}
253 	return (TRUE);
254 }
255 
256 static bool_t
257 authunix_refresh(AUTH *auth)
258 {
259 	struct audata *au = AUTH_PRIVATE(auth);
260 	struct authunix_parms aup;
261 	struct timeval now;
262 	XDR xdrs;
263 	int stat;
264 
265 	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
266 		/* there is no hope.  Punt */
267 		return (FALSE);
268 	}
269 	au->au_shfaults ++;
270 
271 	/* first deserialize the creds back into a struct authunix_parms */
272 	aup.aup_machname = NULL;
273 	aup.aup_gids = NULL;
274 	xdrmem_create(&xdrs, au->au_origcred.oa_base,
275 	    au->au_origcred.oa_length, XDR_DECODE);
276 	stat = xdr_authunix_parms(&xdrs, &aup);
277 	if (! stat)
278 		goto done;
279 
280 	/* update the time and serialize in place */
281 	(void)gettimeofday(&now, NULL);
282 	aup.aup_time = now.tv_sec;
283 	xdrs.x_op = XDR_ENCODE;
284 	XDR_SETPOS(&xdrs, 0);
285 	stat = xdr_authunix_parms(&xdrs, &aup);
286 	if (! stat)
287 		goto done;
288 	auth->ah_cred = au->au_origcred;
289 	marshal_new_auth(auth);
290 done:
291 	/* free the struct authunix_parms created by deserializing */
292 	xdrs.x_op = XDR_FREE;
293 	(void)xdr_authunix_parms(&xdrs, &aup);
294 	XDR_DESTROY(&xdrs);
295 	return (stat);
296 }
297 
298 static void
299 authunix_destroy(AUTH *auth)
300 {
301 	struct audata *au = AUTH_PRIVATE(auth);
302 
303 	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
304 
305 	if (au->au_shcred.oa_base != NULL)
306 		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
307 
308 	mem_free(auth->ah_private, sizeof(struct audata));
309 
310 	if (auth->ah_verf.oa_base != NULL)
311 		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
312 
313 	mem_free((caddr_t)auth, sizeof(*auth));
314 }
315 
316 /*
317  * Marshals (pre-serializes) an auth struct.
318  * sets private data, au_marshed and au_mpos
319  */
320 static void
321 marshal_new_auth(AUTH *auth)
322 {
323 	XDR		xdr_stream;
324 	XDR	*xdrs = &xdr_stream;
325 	struct audata *au = AUTH_PRIVATE(auth);
326 
327 	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
328 	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
329 	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
330 		perror("auth_none.c - Fatal marshalling problem");
331 	} else {
332 		au->au_mpos = XDR_GETPOS(xdrs);
333 	}
334 	XDR_DESTROY(xdrs);
335 }
336