sunrpc: Remove internal_function attribute
[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 #include <shlib-compat.h>
50
51 #include <rpc/types.h>
52 #include <rpc/xdr.h>
53 #include <rpc/auth.h>
54 #include <rpc/auth_unix.h>
55
56
57 /*
58  * Unix authenticator operations vector
59  */
60 static void authunix_nextverf (AUTH *);
61 static bool_t authunix_marshal (AUTH *, XDR *);
62 static bool_t authunix_validate (AUTH *, struct opaque_auth *);
63 static bool_t authunix_refresh (AUTH *);
64 static void authunix_destroy (AUTH *);
65
66 static const struct auth_ops auth_unix_ops = {
67   authunix_nextverf,
68   authunix_marshal,
69   authunix_validate,
70   authunix_refresh,
71   authunix_destroy
72 };
73
74 /*
75  * This struct is pointed to by the ah_private field of an auth_handle.
76  */
77 struct audata {
78   struct opaque_auth au_origcred;       /* original credentials */
79   struct opaque_auth au_shcred; /* short hand cred */
80   u_long au_shfaults;           /* short hand cache faults */
81   char au_marshed[MAX_AUTH_BYTES];
82   u_int au_mpos;                /* xdr pos at end of marshed */
83 };
84 #define AUTH_PRIVATE(auth)      ((struct audata *)auth->ah_private)
85
86 static bool_t marshal_new_auth (AUTH *);
87
88
89 /*
90  * Create a unix style authenticator.
91  * Returns an auth handle with the given stuff in it.
92  */
93 AUTH *
94 authunix_create (char *machname, uid_t uid, gid_t gid, int len,
95                  gid_t *aup_gids)
96 {
97   struct authunix_parms aup;
98   char mymem[MAX_AUTH_BYTES];
99   struct timeval now;
100   XDR xdrs;
101   AUTH *auth;
102   struct audata *au;
103
104   /*
105    * Allocate and set up auth handle
106    */
107   auth = (AUTH *) mem_alloc (sizeof (*auth));
108   au = (struct audata *) mem_alloc (sizeof (*au));
109   if (auth == NULL || au == NULL)
110     {
111 no_memory:
112       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
113       mem_free (auth, sizeof (*auth));
114       mem_free (au, sizeof (*au));
115       return NULL;
116     }
117   auth->ah_ops = (struct auth_ops *) &auth_unix_ops;
118   auth->ah_private = (caddr_t) au;
119   auth->ah_verf = au->au_shcred = _null_auth;
120   au->au_shfaults = 0;
121
122   /*
123    * fill in param struct from the given params
124    */
125   (void) __gettimeofday (&now, (struct timezone *) 0);
126   aup.aup_time = now.tv_sec;
127   aup.aup_machname = machname;
128   aup.aup_uid = uid;
129   aup.aup_gid = gid;
130   aup.aup_len = (u_int) len;
131   aup.aup_gids = aup_gids;
132
133   /*
134    * Serialize the parameters into origcred
135    */
136   xdrmem_create (&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
137   if (!xdr_authunix_parms (&xdrs, &aup))
138     abort ();
139   au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
140   au->au_origcred.oa_flavor = AUTH_UNIX;
141   au->au_origcred.oa_base = mem_alloc ((u_int) len);
142   if (au->au_origcred.oa_base == NULL)
143     goto no_memory;
144   memcpy(au->au_origcred.oa_base, mymem, (u_int) len);
145
146   /*
147    * set auth handle to reflect new cred.
148    */
149   auth->ah_cred = au->au_origcred;
150   marshal_new_auth (auth);
151   return auth;
152 }
153 libc_hidden_nolink_sunrpc (authunix_create, GLIBC_2_0)
154
155 /*
156  * Returns an auth handle with parameters determined by doing lots of
157  * syscalls.
158  */
159 AUTH *
160 authunix_create_default (void)
161 {
162   char machname[MAX_MACHINE_NAME + 1];
163
164   if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
165     abort ();
166   machname[MAX_MACHINE_NAME] = 0;
167   uid_t uid = __geteuid ();
168   gid_t gid = __getegid ();
169
170   int max_nr_groups;
171   /* When we have to try a second time, do not use alloca() again.  We
172      might have reached the stack limit already.  */
173   bool retry = false;
174  again:
175   /* Ask the kernel how many groups there are exactly.  Note that we
176      might have to redo all this if the number of groups has changed
177      between the two calls.  */
178   max_nr_groups = __getgroups (0, NULL);
179
180   /* Just some random reasonable stack limit.  */
181 #define ALLOCA_LIMIT (1024 / sizeof (gid_t))
182   gid_t *gids = NULL;
183   if (max_nr_groups < ALLOCA_LIMIT && ! retry)
184     gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
185   else
186     {
187       gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
188       if (gids == NULL)
189         return NULL;
190     }
191
192   int len = __getgroups (max_nr_groups, gids);
193   if (len == -1)
194     {
195       if (errno == EINVAL)
196         {
197           /* New groups added in the meantime.  Try again.  */
198           if (max_nr_groups >= ALLOCA_LIMIT || retry)
199             free (gids);
200           retry = true;
201           goto again;
202         }
203       /* No other error can happen.  */
204       abort ();
205     }
206
207   /* This braindamaged Sun code forces us here to truncate the
208      list of groups to NGRPS members since the code in
209      authuxprot.c transforms a fixed array.  Grrr.  */
210   AUTH *result = authunix_create (machname, uid, gid, MIN (NGRPS, len), gids);
211
212   if (max_nr_groups >= ALLOCA_LIMIT || retry)
213     free (gids);
214
215   return result;
216 }
217 #ifdef EXPORT_RPC_SYMBOLS
218 libc_hidden_def (authunix_create_default)
219 #else
220 libc_hidden_nolink_sunrpc (authunix_create_default, GLIBC_2_0)
221 #endif
222
223 /*
224  * authunix operations
225  */
226
227 static void
228 authunix_nextverf (AUTH *auth)
229 {
230   /* no action necessary */
231 }
232
233 static bool_t
234 authunix_marshal (AUTH *auth, XDR *xdrs)
235 {
236   struct audata *au = AUTH_PRIVATE (auth);
237
238   return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
239 }
240
241 static bool_t
242 authunix_validate (AUTH *auth, struct opaque_auth *verf)
243 {
244   struct audata *au;
245   XDR xdrs;
246
247   if (verf->oa_flavor == AUTH_SHORT)
248     {
249       au = AUTH_PRIVATE (auth);
250       xdrmem_create (&xdrs, verf->oa_base, verf->oa_length, 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 (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) 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   xdrmem_create (&xdrs, au->au_origcred.oa_base,
294                  au->au_origcred.oa_length, XDR_DECODE);
295   stat = 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 = 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) 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 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 }