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

source code of glibc/sunrpc/auth_unix.c