Localize rpcgen
[platform/upstream/glibc.git] / sunrpc / auth_unix.c
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 <libintl.h>
47 #include <sys/param.h>
48 #include <wchar.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
56 /*
57  * Unix authenticator operations vector
58  */
59 static void authunix_nextverf (AUTH *);
60 static bool_t authunix_marshal (AUTH *, XDR *);
61 static bool_t authunix_validate (AUTH *, struct opaque_auth *);
62 static bool_t authunix_refresh (AUTH *);
63 static void authunix_destroy (AUTH *);
64
65 static const struct auth_ops auth_unix_ops = {
66   authunix_nextverf,
67   authunix_marshal,
68   authunix_validate,
69   authunix_refresh,
70   authunix_destroy
71 };
72
73 /*
74  * This struct is pointed to by the ah_private field of an auth_handle.
75  */
76 struct audata {
77   struct opaque_auth au_origcred;       /* original credentials */
78   struct opaque_auth au_shcred; /* short hand cred */
79   u_long au_shfaults;           /* short hand cache faults */
80   char au_marshed[MAX_AUTH_BYTES];
81   u_int au_mpos;                /* xdr pos at end of marshed */
82 };
83 #define AUTH_PRIVATE(auth)      ((struct audata *)auth->ah_private)
84
85 static bool_t marshal_new_auth (AUTH *) internal_function;
86
87
88 /*
89  * Create a unix style authenticator.
90  * Returns an auth handle with the given stuff in it.
91  */
92 AUTH *
93 authunix_create (char *machname, uid_t uid, gid_t gid, int len,
94                  gid_t *aup_gids)
95 {
96   struct authunix_parms aup;
97   char mymem[MAX_AUTH_BYTES];
98   struct timeval now;
99   XDR xdrs;
100   AUTH *auth;
101   struct audata *au;
102
103   /*
104    * Allocate and set up auth handle
105    */
106   auth = (AUTH *) mem_alloc (sizeof (*auth));
107   au = (struct audata *) mem_alloc (sizeof (*au));
108   if (auth == NULL || au == NULL)
109     {
110 no_memory:
111       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
112       mem_free (auth, sizeof (*auth));
113       mem_free (au, sizeof (*au));
114       return NULL;
115     }
116   auth->ah_ops = (struct auth_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) __gettimeofday (&now, (struct timezone *) 0);
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     abort ();
138   au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
139   au->au_origcred.oa_flavor = AUTH_UNIX;
140   au->au_origcred.oa_base = mem_alloc ((u_int) len);
141   if (au->au_origcred.oa_base == NULL)
142     goto no_memory;
143   memcpy(au->au_origcred.oa_base, mymem, (u_int) len);
144
145   /*
146    * set auth handle to reflect new cred.
147    */
148   auth->ah_cred = au->au_origcred;
149   marshal_new_auth (auth);
150   return auth;
151 }
152 libc_hidden_nolink_sunrpc (authunix_create, GLIBC_2_0)
153
154 /*
155  * Returns an auth handle with parameters determined by doing lots of
156  * syscalls.
157  */
158 AUTH *
159 authunix_create_default (void)
160 {
161   char machname[MAX_MACHINE_NAME + 1];
162
163   if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
164     abort ();
165   machname[MAX_MACHINE_NAME] = 0;
166   uid_t uid = __geteuid ();
167   gid_t gid = __getegid ();
168
169   int max_nr_groups;
170   /* When we have to try a second time, do not use alloca() again.  We
171      might have reached the stack limit already.  */
172   bool retry = false;
173  again:
174   /* Ask the kernel how many groups there are exactly.  Note that we
175      might have to redo all this if the number of groups has changed
176      between the two calls.  */
177   max_nr_groups = __getgroups (0, NULL);
178
179   /* Just some random reasonable stack limit.  */
180 #define ALLOCA_LIMIT (1024 / sizeof (gid_t))
181   gid_t *gids = NULL;
182   if (max_nr_groups < ALLOCA_LIMIT && ! retry)
183     gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
184   else
185     {
186       gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
187       if (gids == NULL)
188         return NULL;
189     }
190
191   int len = __getgroups (max_nr_groups, gids);
192   if (len == -1)
193     {
194       if (errno == EINVAL)
195         {
196           /* New groups added in the meantime.  Try again.  */
197           if (max_nr_groups >= ALLOCA_LIMIT || retry)
198             free (gids);
199           retry = true;
200           goto again;
201         }
202       /* No other error can happen.  */
203       abort ();
204     }
205
206   /* This braindamaged Sun code forces us here to truncate the
207      list of groups to NGRPS members since the code in
208      authuxprot.c transforms a fixed array.  Grrr.  */
209   AUTH *result = authunix_create (machname, uid, gid, MIN (NGRPS, len), gids);
210
211   if (max_nr_groups >= ALLOCA_LIMIT || retry)
212     free (gids);
213
214   return result;
215 }
216 #ifdef EXPORT_RPC_SYMBOLS
217 libc_hidden_def (authunix_create_default)
218 #else
219 libc_hidden_nolink_sunrpc (authunix_create_default, GLIBC_2_0)
220 #endif
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       xdrmem_create (&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE);
250
251       if (au->au_shcred.oa_base != NULL)
252         {
253           mem_free (au->au_shcred.oa_base,
254                     au->au_shcred.oa_length);
255           au->au_shcred.oa_base = NULL;
256         }
257       if (xdr_opaque_auth (&xdrs, &au->au_shcred))
258         {
259           auth->ah_cred = au->au_shcred;
260         }
261       else
262         {
263           xdrs.x_op = XDR_FREE;
264           (void) xdr_opaque_auth (&xdrs, &au->au_shcred);
265           au->au_shcred.oa_base = NULL;
266           auth->ah_cred = au->au_origcred;
267         }
268       marshal_new_auth (auth);
269     }
270   return TRUE;
271 }
272
273 static bool_t
274 authunix_refresh (AUTH *auth)
275 {
276   struct audata *au = AUTH_PRIVATE (auth);
277   struct authunix_parms aup;
278   struct timeval now;
279   XDR xdrs;
280   int stat;
281
282   if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
283     {
284       /* there is no hope.  Punt */
285       return FALSE;
286     }
287   au->au_shfaults++;
288
289   /* first deserialize the creds back into a struct authunix_parms */
290   aup.aup_machname = NULL;
291   aup.aup_gids = (gid_t *) NULL;
292   xdrmem_create (&xdrs, au->au_origcred.oa_base,
293                  au->au_origcred.oa_length, XDR_DECODE);
294   stat = xdr_authunix_parms (&xdrs, &aup);
295   if (!stat)
296     goto done;
297
298   /* update the time and serialize in place */
299   (void) __gettimeofday (&now, (struct timezone *) 0);
300   aup.aup_time = now.tv_sec;
301   xdrs.x_op = XDR_ENCODE;
302   XDR_SETPOS (&xdrs, 0);
303   stat = xdr_authunix_parms (&xdrs, &aup);
304   if (!stat)
305     goto done;
306   auth->ah_cred = au->au_origcred;
307   marshal_new_auth (auth);
308 done:
309   /* free the struct authunix_parms created by deserializing */
310   xdrs.x_op = XDR_FREE;
311   (void) xdr_authunix_parms (&xdrs, &aup);
312   XDR_DESTROY (&xdrs);
313   return stat;
314 }
315
316 static void
317 authunix_destroy (AUTH *auth)
318 {
319   struct audata *au = AUTH_PRIVATE (auth);
320
321   mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
322
323   if (au->au_shcred.oa_base != NULL)
324     mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
325
326   mem_free (auth->ah_private, sizeof (struct audata));
327
328   if (auth->ah_verf.oa_base != NULL)
329     mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
330
331   mem_free ((caddr_t) auth, sizeof (*auth));
332 }
333
334 /*
335  * Marshals (pre-serializes) an auth struct.
336  * sets private data, au_marshed and au_mpos
337  */
338 static bool_t
339 internal_function
340 marshal_new_auth (AUTH *auth)
341 {
342   XDR xdr_stream;
343   XDR *xdrs = &xdr_stream;
344   struct audata *au = AUTH_PRIVATE (auth);
345
346   xdrmem_create (xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
347   if ((!xdr_opaque_auth (xdrs, &(auth->ah_cred))) ||
348       (!xdr_opaque_auth (xdrs, &(auth->ah_verf))))
349     perror (_("auth_unix.c: Fatal marshalling problem"));
350   else
351     au->au_mpos = XDR_GETPOS (xdrs);
352
353   XDR_DESTROY (xdrs);
354
355   return TRUE;
356 }