2004-11-18 Alexandre Oliva <aoliva@redhat.com>
[glibc.git] / sunrpc / auth_unix.c
blob1cf18cb6b30ad71f1a81149fda520775a184373c
1 /*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
30 * Copyright (C) 1984, Sun Microsystems, Inc.
33 * auth_unix.c, Implements UNIX style authentication parameters.
35 * The system is very weak. The client uses no encryption for it's
36 * credentials and only sends null verifiers. The server sends backs
37 * null verifiers or optionally a verifier that suggests a new short hand
38 * for the credentials.
41 #include <errno.h>
42 #include <limits.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <libintl.h>
48 #include <sys/param.h>
50 #include <rpc/types.h>
51 #include <rpc/xdr.h>
52 #include <rpc/auth.h>
53 #include <rpc/auth_unix.h>
55 #ifdef USE_IN_LIBIO
56 # include <wchar.h>
57 #endif
60 * Unix authenticator operations vector
62 static void authunix_nextverf (AUTH *);
63 static bool_t authunix_marshal (AUTH *, XDR *);
64 static bool_t authunix_validate (AUTH *, struct opaque_auth *);
65 static bool_t authunix_refresh (AUTH *);
66 static void authunix_destroy (AUTH *);
68 static struct auth_ops auth_unix_ops = {
69 authunix_nextverf,
70 authunix_marshal,
71 authunix_validate,
72 authunix_refresh,
73 authunix_destroy
77 * This struct is pointed to by the ah_private field of an auth_handle.
79 struct audata {
80 struct opaque_auth au_origcred; /* original credentials */
81 struct opaque_auth au_shcred; /* short hand cred */
82 u_long au_shfaults; /* short hand cache faults */
83 char au_marshed[MAX_AUTH_BYTES];
84 u_int au_mpos; /* xdr pos at end of marshed */
86 #define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
88 static bool_t marshal_new_auth (AUTH *) internal_function;
92 * Create a unix style authenticator.
93 * Returns an auth handle with the given stuff in it.
95 AUTH *
96 authunix_create (char *machname, uid_t uid, gid_t gid, int len,
97 gid_t *aup_gids)
99 struct authunix_parms aup;
100 char mymem[MAX_AUTH_BYTES];
101 struct timeval now;
102 XDR xdrs;
103 AUTH *auth;
104 struct audata *au;
107 * Allocate and set up auth handle
109 auth = (AUTH *) mem_alloc (sizeof (*auth));
110 au = (struct audata *) mem_alloc (sizeof (*au));
111 if (auth == NULL || au == NULL)
113 no_memory:
114 #ifdef USE_IN_LIBIO
115 if (_IO_fwide (stderr, 0) > 0)
116 (void) __fwprintf (stderr, L"%s",
117 _("authunix_create: out of memory\n"));
118 else
119 #endif
120 (void) fputs (_("authunix_create: out of memory\n"), stderr);
121 mem_free (auth, sizeof (*auth));
122 mem_free (au, sizeof (*au));
123 return NULL;
125 auth->ah_ops = &auth_unix_ops;
126 auth->ah_private = (caddr_t) au;
127 auth->ah_verf = au->au_shcred = _null_auth;
128 au->au_shfaults = 0;
131 * fill in param struct from the given params
133 (void) __gettimeofday (&now, (struct timezone *) 0);
134 aup.aup_time = now.tv_sec;
135 aup.aup_machname = machname;
136 aup.aup_uid = uid;
137 aup.aup_gid = gid;
138 aup.aup_len = (u_int) len;
139 aup.aup_gids = aup_gids;
142 * Serialize the parameters into origcred
144 INTUSE(xdrmem_create) (&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
145 if (!INTUSE(xdr_authunix_parms) (&xdrs, &aup))
146 abort ();
147 au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
148 au->au_origcred.oa_flavor = AUTH_UNIX;
149 au->au_origcred.oa_base = mem_alloc ((u_int) len);
150 if (au->au_origcred.oa_base == NULL)
151 goto no_memory;
152 memcpy(au->au_origcred.oa_base, mymem, (u_int) len);
155 * set auth handle to reflect new cred.
157 auth->ah_cred = au->au_origcred;
158 marshal_new_auth (auth);
159 return auth;
161 INTDEF (authunix_create)
164 * Returns an auth handle with parameters determined by doing lots of
165 * syscalls.
167 AUTH *
168 authunix_create_default (void)
170 char machname[MAX_MACHINE_NAME + 1];
172 if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
173 abort ();
174 machname[MAX_MACHINE_NAME] = 0;
175 uid_t uid = __geteuid ();
176 gid_t gid = __getegid ();
178 int max_nr_groups;
179 /* When we have to try a second time, do not use alloca() again. We
180 might have reached the stack limit already. */
181 bool retry = false;
182 again:
183 /* Ask the kernel how many groups there are exactly. Note that we
184 might have to redo all this if the number of groups has changed
185 between the two calls. */
186 max_nr_groups = __getgroups (0, NULL);
188 /* Just some random reasonable stack limit. */
189 #define ALLOCA_LIMIT (1024 / sizeof (gid_t))
190 gid_t *gids = NULL;
191 if (max_nr_groups < ALLOCA_LIMIT && ! retry)
192 gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
193 else
195 gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
196 if (gids == NULL)
197 return NULL;
200 int len = __getgroups (max_nr_groups, gids);
201 if (len == -1)
203 if (errno == EINVAL)
205 /* New groups added in the meantime. Try again. */
206 if (max_nr_groups >= ALLOCA_LIMIT || retry)
207 free (gids);
208 retry = true;
209 goto again;
211 /* No other error can happen. */
212 abort ();
215 /* This braindamaged Sun code forces us here to truncate the
216 list of groups to NGRPS members since the code in
217 authuxprot.c transforms a fixed array. Grrr. */
218 AUTH *result = INTUSE(authunix_create) (machname, uid, gid, MIN (NGRPS, len),
219 gids);
221 if (max_nr_groups >= ALLOCA_LIMIT || retry)
222 free (gids);
224 return result;
226 INTDEF (authunix_create_default)
229 * authunix operations
232 static void
233 authunix_nextverf (AUTH *auth)
235 /* no action necessary */
238 static bool_t
239 authunix_marshal (AUTH *auth, XDR *xdrs)
241 struct audata *au = AUTH_PRIVATE (auth);
243 return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
246 static bool_t
247 authunix_validate (AUTH *auth, struct opaque_auth *verf)
249 struct audata *au;
250 XDR xdrs;
252 if (verf->oa_flavor == AUTH_SHORT)
254 au = AUTH_PRIVATE (auth);
255 INTUSE(xdrmem_create) (&xdrs, verf->oa_base, verf->oa_length,
256 XDR_DECODE);
258 if (au->au_shcred.oa_base != NULL)
260 mem_free (au->au_shcred.oa_base,
261 au->au_shcred.oa_length);
262 au->au_shcred.oa_base = NULL;
264 if (INTUSE(xdr_opaque_auth) (&xdrs, &au->au_shcred))
266 auth->ah_cred = au->au_shcred;
268 else
270 xdrs.x_op = XDR_FREE;
271 (void) INTUSE(xdr_opaque_auth) (&xdrs, &au->au_shcred);
272 au->au_shcred.oa_base = NULL;
273 auth->ah_cred = au->au_origcred;
275 marshal_new_auth (auth);
277 return TRUE;
280 static bool_t
281 authunix_refresh (AUTH *auth)
283 struct audata *au = AUTH_PRIVATE (auth);
284 struct authunix_parms aup;
285 struct timeval now;
286 XDR xdrs;
287 int stat;
289 if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
291 /* there is no hope. Punt */
292 return FALSE;
294 au->au_shfaults++;
296 /* first deserialize the creds back into a struct authunix_parms */
297 aup.aup_machname = NULL;
298 aup.aup_gids = (gid_t *) NULL;
299 INTUSE(xdrmem_create) (&xdrs, au->au_origcred.oa_base,
300 au->au_origcred.oa_length, XDR_DECODE);
301 stat = INTUSE(xdr_authunix_parms) (&xdrs, &aup);
302 if (!stat)
303 goto done;
305 /* update the time and serialize in place */
306 (void) __gettimeofday (&now, (struct timezone *) 0);
307 aup.aup_time = now.tv_sec;
308 xdrs.x_op = XDR_ENCODE;
309 XDR_SETPOS (&xdrs, 0);
310 stat = INTUSE(xdr_authunix_parms) (&xdrs, &aup);
311 if (!stat)
312 goto done;
313 auth->ah_cred = au->au_origcred;
314 marshal_new_auth (auth);
315 done:
316 /* free the struct authunix_parms created by deserializing */
317 xdrs.x_op = XDR_FREE;
318 (void) INTUSE(xdr_authunix_parms) (&xdrs, &aup);
319 XDR_DESTROY (&xdrs);
320 return stat;
323 static void
324 authunix_destroy (AUTH *auth)
326 struct audata *au = AUTH_PRIVATE (auth);
328 mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
330 if (au->au_shcred.oa_base != NULL)
331 mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
333 mem_free (auth->ah_private, sizeof (struct audata));
335 if (auth->ah_verf.oa_base != NULL)
336 mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
338 mem_free ((caddr_t) auth, sizeof (*auth));
342 * Marshals (pre-serializes) an auth struct.
343 * sets private data, au_marshed and au_mpos
345 static bool_t
346 internal_function
347 marshal_new_auth (AUTH *auth)
349 XDR xdr_stream;
350 XDR *xdrs = &xdr_stream;
351 struct audata *au = AUTH_PRIVATE (auth);
353 INTUSE(xdrmem_create) (xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
354 if ((!INTUSE(xdr_opaque_auth) (xdrs, &(auth->ah_cred))) ||
355 (!INTUSE(xdr_opaque_auth) (xdrs, &(auth->ah_verf))))
356 perror (_("auth_none.c - Fatal marshalling problem"));
357 else
358 au->au_mpos = XDR_GETPOS (xdrs);
360 XDR_DESTROY (xdrs);
362 return TRUE;