(authunix_create_default): Don't allocate huge arrays on the stack.
[kopensolaris-gnu/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 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 #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;
124     }
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;
129
130   /*
131    * fill in param struct from the given params
132    */
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;
140
141   /*
142    * Serialize the parameters into origcred
143    */
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);
153
154   /*
155    * set auth handle to reflect new cred.
156    */
157   auth->ah_cred = au->au_origcred;
158   marshal_new_auth (auth);
159   return auth;
160 }
161 INTDEF (authunix_create)
162
163 /*
164  * Returns an auth handle with parameters determined by doing lots of
165  * syscalls.
166  */
167 AUTH *
168 authunix_create_default (void)
169 {
170   char machname[MAX_MACHINE_NAME + 1];
171
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 ();
177
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);
187
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
194     {
195       gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
196       if (gids == NULL)
197         return NULL;
198     }
199
200   int len = __getgroups (max_nr_groups, gids);
201   if (len == -1)
202     {
203       if (errno == EINVAL)
204         {
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;
210         }
211       /* No other error can happen.  */
212       abort ();
213     }
214
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);
220
221   if (max_nr_groups >= ALLOCA_LIMIT || retry)
222     free (gids);
223
224   return result;
225 }
226 INTDEF (authunix_create_default)
227
228 /*
229  * authunix operations
230  */
231
232 static void
233 authunix_nextverf (AUTH *auth)
234 {
235   /* no action necessary */
236 }
237
238 static bool_t
239 authunix_marshal (AUTH *auth, XDR *xdrs)
240 {
241   struct audata *au = AUTH_PRIVATE (auth);
242
243   return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
244 }
245
246 static bool_t
247 authunix_validate (AUTH *auth, struct opaque_auth *verf)
248 {
249   struct audata *au;
250   XDR xdrs;
251
252   if (verf->oa_flavor == AUTH_SHORT)
253     {
254       au = AUTH_PRIVATE (auth);
255       INTUSE(xdrmem_create) (&xdrs, verf->oa_base, verf->oa_length,
256                              XDR_DECODE);
257
258       if (au->au_shcred.oa_base != NULL)
259         {
260           mem_free (au->au_shcred.oa_base,
261                     au->au_shcred.oa_length);
262           au->au_shcred.oa_base = NULL;
263         }
264       if (INTUSE(xdr_opaque_auth) (&xdrs, &au->au_shcred))
265         {
266           auth->ah_cred = au->au_shcred;
267         }
268       else
269         {
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;
274         }
275       marshal_new_auth (auth);
276     }
277   return TRUE;
278 }
279
280 static bool_t
281 authunix_refresh (AUTH *auth)
282 {
283   struct audata *au = AUTH_PRIVATE (auth);
284   struct authunix_parms aup;
285   struct timeval now;
286   XDR xdrs;
287   int stat;
288
289   if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
290     {
291       /* there is no hope.  Punt */
292       return FALSE;
293     }
294   au->au_shfaults++;
295
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;
304
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;
321 }
322
323 static void
324 authunix_destroy (AUTH *auth)
325 {
326   struct audata *au = AUTH_PRIVATE (auth);
327
328   mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
329
330   if (au->au_shcred.oa_base != NULL)
331     mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
332
333   mem_free (auth->ah_private, sizeof (struct audata));
334
335   if (auth->ah_verf.oa_base != NULL)
336     mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
337
338   mem_free ((caddr_t) auth, sizeof (*auth));
339 }
340
341 /*
342  * Marshals (pre-serializes) an auth struct.
343  * sets private data, au_marshed and au_mpos
344  */
345 static bool_t
346 internal_function
347 marshal_new_auth (AUTH *auth)
348 {
349   XDR xdr_stream;
350   XDR *xdrs = &xdr_stream;
351   struct audata *au = AUTH_PRIVATE (auth);
352
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);
359
360   XDR_DESTROY (xdrs);
361
362   return TRUE;
363 }