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