1/*	$OpenBSD: auth_unix.c,v 1.30 2022/02/14 03:38:59 guenther 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 its
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 */
58static void	authunix_nextverf(struct __rpc_auth *);
59static bool_t	authunix_marshal(struct __rpc_auth *, XDR *);
60static bool_t	authunix_validate(struct __rpc_auth *, struct opaque_auth *);
61static bool_t	authunix_refresh(struct __rpc_auth *);
62static void	authunix_destroy(struct __rpc_auth *);
63
64static const 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 */
75struct 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
84static 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 */
91AUTH *
92authunix_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		return (NULL);
108#endif
109	au = (struct audata *)mem_alloc(sizeof(*au));
110#ifndef KERNEL
111	if (au == NULL) {
112		free(auth);
113		return (NULL);
114	}
115#endif
116	auth->ah_ops = &auth_unix_ops;
117	auth->ah_private = (caddr_t)au;
118	auth->ah_verf = au->au_shcred = _null_auth;
119	au->au_shfaults = 0;
120
121	/*
122	 * fill in param struct from the given params
123	 */
124	(void)WRAP(gettimeofday)(&now,  NULL);
125	aup.aup_time = now.tv_sec;
126	aup.aup_machname = machname;
127	aup.aup_uid = uid;
128	aup.aup_gid = gid;
129	aup.aup_len = (u_int)len;
130	aup.aup_gids = aup_gids;
131
132	/*
133	 * Serialize the parameters into origcred
134	 */
135	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
136	if (!xdr_authunix_parms(&xdrs, &aup))
137		goto authfail;
138	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
139	au->au_origcred.oa_flavor = AUTH_UNIX;
140#ifdef KERNEL
141	au->au_origcred.oa_base = mem_alloc((u_int) len);
142#else
143	if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL)
144		goto authfail;
145#endif
146	memcpy(au->au_origcred.oa_base, mymem, (u_int)len);
147
148	/*
149	 * set auth handle to reflect new cred.
150	 */
151	auth->ah_cred = au->au_origcred;
152	marshal_new_auth(auth);
153	return (auth);
154
155authfail:
156	XDR_DESTROY(&xdrs);
157	free(au);
158	free(auth);
159	return (NULL);
160}
161DEF_WEAK(authunix_create);
162
163
164/*
165 * Some servers will refuse mounts if the group list is larger
166 * than it expects (like 8). This allows the application to set
167 * the maximum size of the group list that will be sent.
168 */
169static int maxgrplist = NGRPS;
170
171void
172set_rpc_maxgrouplist(int num)
173{
174	if (num < NGRPS)
175		maxgrplist = num;
176}
177
178/*
179 * Returns an auth handle with parameters determined by doing lots of
180 * syscalls.
181 */
182AUTH *
183authunix_create_default(void)
184{
185	int len, i;
186	char machname[MAX_MACHINE_NAME + 1];
187	uid_t uid;
188	gid_t gid;
189	gid_t gids[NGRPS];
190	int gids2[NGRPS];
191
192	if (gethostname(machname, sizeof machname) == -1)
193		return (NULL);
194	machname[MAX_MACHINE_NAME] = 0;
195	uid = geteuid();
196	gid = getegid();
197	if ((len = getgroups(NGRPS, gids)) == -1)
198		return (NULL);
199	if (len > maxgrplist)
200		len = maxgrplist;
201	for (i = 0; i < len; i++)
202		gids2[i] = gids[i];
203	return (authunix_create(machname, uid, gid, len, gids2));
204}
205DEF_WEAK(authunix_create_default);
206
207/*
208 * authunix operations
209 */
210static void
211authunix_nextverf(AUTH *auth)
212{
213	/* no action necessary */
214}
215
216static bool_t
217authunix_marshal(AUTH *auth, XDR *xdrs)
218{
219	struct audata *au = AUTH_PRIVATE(auth);
220
221	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
222}
223
224static bool_t
225authunix_validate(AUTH *auth, struct opaque_auth *verf)
226{
227	struct audata *au;
228	XDR xdrs;
229
230	if (verf->oa_flavor == AUTH_SHORT) {
231		au = AUTH_PRIVATE(auth);
232		xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE);
233
234		if (au->au_shcred.oa_base != NULL) {
235			mem_free(au->au_shcred.oa_base,
236			    au->au_shcred.oa_length);
237			au->au_shcred.oa_base = NULL;
238		}
239		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
240			auth->ah_cred = au->au_shcred;
241		} else {
242			xdrs.x_op = XDR_FREE;
243			(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
244			au->au_shcred.oa_base = NULL;
245			auth->ah_cred = au->au_origcred;
246		}
247		marshal_new_auth(auth);
248	}
249	return (TRUE);
250}
251
252static bool_t
253authunix_refresh(AUTH *auth)
254{
255	struct audata *au = AUTH_PRIVATE(auth);
256	struct authunix_parms aup;
257	struct timeval now;
258	XDR xdrs;
259	int stat;
260
261	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
262		/* there is no hope.  Punt */
263		return (FALSE);
264	}
265	au->au_shfaults ++;
266
267	/* first deserialize the creds back into a struct authunix_parms */
268	aup.aup_machname = NULL;
269	aup.aup_gids = NULL;
270	xdrmem_create(&xdrs, au->au_origcred.oa_base,
271	    au->au_origcred.oa_length, XDR_DECODE);
272	stat = xdr_authunix_parms(&xdrs, &aup);
273	if (! stat)
274		goto done;
275
276	/* update the time and serialize in place */
277	(void)WRAP(gettimeofday)(&now, NULL);
278	aup.aup_time = now.tv_sec;
279	xdrs.x_op = XDR_ENCODE;
280	XDR_SETPOS(&xdrs, 0);
281	stat = xdr_authunix_parms(&xdrs, &aup);
282	if (! stat)
283		goto done;
284	auth->ah_cred = au->au_origcred;
285	marshal_new_auth(auth);
286done:
287	/* free the struct authunix_parms created by deserializing */
288	xdrs.x_op = XDR_FREE;
289	(void)xdr_authunix_parms(&xdrs, &aup);
290	XDR_DESTROY(&xdrs);
291	return (stat);
292}
293
294static void
295authunix_destroy(AUTH *auth)
296{
297	struct audata *au = AUTH_PRIVATE(auth);
298
299	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
300
301	if (au->au_shcred.oa_base != NULL)
302		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
303
304	mem_free(auth->ah_private, sizeof(struct audata));
305
306	if (auth->ah_verf.oa_base != NULL)
307		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
308
309	mem_free((caddr_t)auth, sizeof(*auth));
310}
311
312/*
313 * Marshals (pre-serializes) an auth struct.
314 * sets private data, au_marshed and au_mpos
315 */
316static void
317marshal_new_auth(AUTH *auth)
318{
319	XDR		xdr_stream;
320	XDR	*xdrs = &xdr_stream;
321	struct audata *au = AUTH_PRIVATE(auth);
322
323	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
324	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
325	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
326		/* XXX nothing we can do */
327	} else {
328		au->au_mpos = XDR_GETPOS(xdrs);
329	}
330	XDR_DESTROY(xdrs);
331}
332