[BZ #5979]
[jlayton/glibc.git] / sunrpc / auth_unix.c
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.
8  *
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.
12  *
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.
16  *
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.
20  *
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.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  */
29 /*
30  * Copyright (C) 1984, Sun Microsystems, Inc.
31  */
32 /*
33  * auth_unix.c, Implements UNIX style authentication parameters.
34  *
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.
39  */
40
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>
49
50 #include <rpc/types.h>
51 #include <rpc/xdr.h>
52 #include <rpc/auth.h>
53 #include <rpc/auth_unix.h>
54
55 #ifdef USE_IN_LIBIO
56 # include <wchar.h>
57 #endif
58
59 /*
60  * Unix authenticator operations vector
61  */
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 *);
67
68 static const struct auth_ops auth_unix_ops = {
69   authunix_nextverf,
70   authunix_marshal,
71   authunix_validate,
72   authunix_refresh,
73   authunix_destroy
74 };
75
76 /*
77  * This struct is pointed to by the ah_private field of an auth_handle.
78  */
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 */
85 };
86 #define AUTH_PRIVATE(auth)      ((struct audata *)auth->ah_private)
87
88 static bool_t marshal_new_auth (AUTH *) internal_function;
89
90
91 /*
92  * Create a unix style authenticator.
93  * Returns an auth handle with the given stuff in it.
94  */
95 AUTH *
96 authunix_create (char *machname, uid_t uid, gid_t gid, int len,
97                  gid_t *aup_gids)
98 {
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;
105
106   /*
107    * Allocate and set up auth handle
108    */
109   auth = (AUTH *) mem_alloc (sizeof (*auth));
110   au = (struct audata *) mem_alloc (sizeof (*au));
111   if (auth == NULL || au == NULL)
112     {
113 no_memory:
114       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
115       mem_free (auth, sizeof (*auth));
116       mem_free (au, sizeof (*au));
117       return NULL;
118     }
119   auth->ah_ops = (struct auth_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, (struct timezone *) 0);
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   INTUSE(xdrmem_create) (&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
139   if (!INTUSE(xdr_authunix_parms) (&xdrs, &aup))
140     abort ();
141   au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
142   au->au_origcred.oa_flavor = AUTH_UNIX;
143   au->au_origcred.oa_base = mem_alloc ((u_int) len);
144   if (au->au_origcred.oa_base == NULL)
145     goto no_memory;
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 }
155 INTDEF (authunix_create)
156
157 /*
158  * Returns an auth handle with parameters determined by doing lots of
159  * syscalls.
160  */
161 AUTH *
162 authunix_create_default (void)
163 {
164   char machname[MAX_MACHINE_NAME + 1];
165
166   if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
167     abort ();
168   machname[MAX_MACHINE_NAME] = 0;
169   uid_t uid = __geteuid ();
170   gid_t gid = __getegid ();
171
172   int max_nr_groups;
173   /* When we have to try a second time, do not use alloca() again.  We
174      might have reached the stack limit already.  */
175   bool retry = false;
176  again:
177   /* Ask the kernel how many groups there are exactly.  Note that we
178      might have to redo all this if the number of groups has changed
179      between the two calls.  */
180   max_nr_groups = __getgroups (0, NULL);
181
182   /* Just some random reasonable stack limit.  */
183 #define ALLOCA_LIMIT (1024 / sizeof (gid_t))
184   gid_t *gids = NULL;
185   if (max_nr_groups < ALLOCA_LIMIT && ! retry)
186     gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
187   else
188     {
189       gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
190       if (gids == NULL)
191         return NULL;
192     }
193
194   int len = __getgroups (max_nr_groups, gids);
195   if (len == -1)
196     {
197       if (errno == EINVAL)
198         {
199           /* New groups added in the meantime.  Try again.  */
200           if (max_nr_groups >= ALLOCA_LIMIT || retry)
201             free (gids);
202           retry = true;
203           goto again;
204         }
205       /* No other error can happen.  */
206       abort ();
207     }
208
209   /* This braindamaged Sun code forces us here to truncate the
210      list of groups to NGRPS members since the code in
211      authuxprot.c transforms a fixed array.  Grrr.  */
212   AUTH *result = INTUSE(authunix_create) (machname, uid, gid, MIN (NGRPS, len),
213                                           gids);
214
215   if (max_nr_groups >= ALLOCA_LIMIT || retry)
216     free (gids);
217
218   return result;
219 }
220 INTDEF (authunix_create_default)
221
222 /*
223  * authunix operations
224  */
225
226 static void
227 authunix_nextverf (AUTH *auth)
228 {
229   /* no action necessary */
230 }
231
232 static bool_t
233 authunix_marshal (AUTH *auth, XDR *xdrs)
234 {
235   struct audata *au = AUTH_PRIVATE (auth);
236
237   return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
238 }
239
240 static bool_t
241 authunix_validate (AUTH *auth, struct opaque_auth *verf)
242 {
243   struct audata *au;
244   XDR xdrs;
245
246   if (verf->oa_flavor == AUTH_SHORT)
247     {
248       au = AUTH_PRIVATE (auth);
249       INTUSE(xdrmem_create) (&xdrs, verf->oa_base, verf->oa_length,
250                              XDR_DECODE);
251
252       if (au->au_shcred.oa_base != NULL)
253         {
254           mem_free (au->au_shcred.oa_base,
255                     au->au_shcred.oa_length);
256           au->au_shcred.oa_base = NULL;
257         }
258       if (INTUSE(xdr_opaque_auth) (&xdrs, &au->au_shcred))
259         {
260           auth->ah_cred = au->au_shcred;
261         }
262       else
263         {
264           xdrs.x_op = XDR_FREE;
265           (void) INTUSE(xdr_opaque_auth) (&xdrs, &au->au_shcred);
266           au->au_shcred.oa_base = NULL;
267           auth->ah_cred = au->au_origcred;
268         }
269       marshal_new_auth (auth);
270     }
271   return TRUE;
272 }
273
274 static bool_t
275 authunix_refresh (AUTH *auth)
276 {
277   struct audata *au = AUTH_PRIVATE (auth);
278   struct authunix_parms aup;
279   struct timeval now;
280   XDR xdrs;
281   int stat;
282
283   if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
284     {
285       /* there is no hope.  Punt */
286       return FALSE;
287     }
288   au->au_shfaults++;
289
290   /* first deserialize the creds back into a struct authunix_parms */
291   aup.aup_machname = NULL;
292   aup.aup_gids = (gid_t *) NULL;
293   INTUSE(xdrmem_create) (&xdrs, au->au_origcred.oa_base,
294                          au->au_origcred.oa_length, XDR_DECODE);
295   stat = INTUSE(xdr_authunix_parms) (&xdrs, &aup);
296   if (!stat)
297     goto done;
298
299   /* update the time and serialize in place */
300   (void) __gettimeofday (&now, (struct timezone *) 0);
301   aup.aup_time = now.tv_sec;
302   xdrs.x_op = XDR_ENCODE;
303   XDR_SETPOS (&xdrs, 0);
304   stat = INTUSE(xdr_authunix_parms) (&xdrs, &aup);
305   if (!stat)
306     goto done;
307   auth->ah_cred = au->au_origcred;
308   marshal_new_auth (auth);
309 done:
310   /* free the struct authunix_parms created by deserializing */
311   xdrs.x_op = XDR_FREE;
312   (void) INTUSE(xdr_authunix_parms) (&xdrs, &aup);
313   XDR_DESTROY (&xdrs);
314   return stat;
315 }
316
317 static void
318 authunix_destroy (AUTH *auth)
319 {
320   struct audata *au = AUTH_PRIVATE (auth);
321
322   mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
323
324   if (au->au_shcred.oa_base != NULL)
325     mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
326
327   mem_free (auth->ah_private, sizeof (struct audata));
328
329   if (auth->ah_verf.oa_base != NULL)
330     mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
331
332   mem_free ((caddr_t) auth, sizeof (*auth));
333 }
334
335 /*
336  * Marshals (pre-serializes) an auth struct.
337  * sets private data, au_marshed and au_mpos
338  */
339 static bool_t
340 internal_function
341 marshal_new_auth (AUTH *auth)
342 {
343   XDR xdr_stream;
344   XDR *xdrs = &xdr_stream;
345   struct audata *au = AUTH_PRIVATE (auth);
346
347   INTUSE(xdrmem_create) (xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
348   if ((!INTUSE(xdr_opaque_auth) (xdrs, &(auth->ah_cred))) ||
349       (!INTUSE(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 }