Blame sunrpc/auth_unix.c

Packit 6c4009
/*
Packit 6c4009
 * Copyright (c) 2010, 2011, Oracle America, Inc.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions are
Packit 6c4009
 * met:
Packit 6c4009
 *
Packit 6c4009
 *     * Redistributions of source code must retain the above copyright
Packit 6c4009
 *       notice, this list of conditions and the following disclaimer.
Packit 6c4009
 *     * Redistributions in binary form must reproduce the above
Packit 6c4009
 *       copyright notice, this list of conditions and the following
Packit 6c4009
 *       disclaimer in the documentation and/or other materials
Packit 6c4009
 *       provided with the distribution.
Packit 6c4009
 *     * Neither the name of the "Oracle America, Inc." nor the names of its
Packit 6c4009
 *       contributors may be used to endorse or promote products derived
Packit 6c4009
 *       from this software without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 6c4009
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 6c4009
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit 6c4009
 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit 6c4009
 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit 6c4009
 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
Packit 6c4009
 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit 6c4009
 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Packit 6c4009
 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit 6c4009
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 6c4009
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
/*
Packit 6c4009
 * auth_unix.c, Implements UNIX style authentication parameters.
Packit 6c4009
 *
Packit 6c4009
 * The system is very weak.  The client uses no encryption for it's
Packit 6c4009
 * credentials and only sends null verifiers.  The server sends backs
Packit 6c4009
 * null verifiers or optionally a verifier that suggests a new short hand
Packit 6c4009
 * for the credentials.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
Packit 6c4009
#include <rpc/types.h>
Packit 6c4009
#include <rpc/xdr.h>
Packit 6c4009
#include <rpc/auth.h>
Packit 6c4009
#include <rpc/auth_unix.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Unix authenticator operations vector
Packit 6c4009
 */
Packit 6c4009
static void authunix_nextverf (AUTH *);
Packit 6c4009
static bool_t authunix_marshal (AUTH *, XDR *);
Packit 6c4009
static bool_t authunix_validate (AUTH *, struct opaque_auth *);
Packit 6c4009
static bool_t authunix_refresh (AUTH *);
Packit 6c4009
static void authunix_destroy (AUTH *);
Packit 6c4009
Packit 6c4009
static const struct auth_ops auth_unix_ops = {
Packit 6c4009
  authunix_nextverf,
Packit 6c4009
  authunix_marshal,
Packit 6c4009
  authunix_validate,
Packit 6c4009
  authunix_refresh,
Packit 6c4009
  authunix_destroy
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * This struct is pointed to by the ah_private field of an auth_handle.
Packit 6c4009
 */
Packit 6c4009
struct audata {
Packit 6c4009
  struct opaque_auth au_origcred;	/* original credentials */
Packit 6c4009
  struct opaque_auth au_shcred;	/* short hand cred */
Packit 6c4009
  u_long au_shfaults;		/* short hand cache faults */
Packit 6c4009
  char au_marshed[MAX_AUTH_BYTES];
Packit 6c4009
  u_int au_mpos;		/* xdr pos at end of marshed */
Packit 6c4009
};
Packit 6c4009
#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
Packit 6c4009
Packit 6c4009
static bool_t marshal_new_auth (AUTH *);
Packit 6c4009
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Create a unix style authenticator.
Packit 6c4009
 * Returns an auth handle with the given stuff in it.
Packit 6c4009
 */
Packit 6c4009
AUTH *
Packit 6c4009
authunix_create (char *machname, uid_t uid, gid_t gid, int len,
Packit 6c4009
		 gid_t *aup_gids)
Packit 6c4009
{
Packit 6c4009
  struct authunix_parms aup;
Packit 6c4009
  char mymem[MAX_AUTH_BYTES];
Packit 6c4009
  struct timeval now;
Packit 6c4009
  XDR xdrs;
Packit 6c4009
  AUTH *auth;
Packit 6c4009
  struct audata *au;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Allocate and set up auth handle
Packit 6c4009
   */
Packit 6c4009
  auth = (AUTH *) mem_alloc (sizeof (*auth));
Packit 6c4009
  au = (struct audata *) mem_alloc (sizeof (*au));
Packit 6c4009
  if (auth == NULL || au == NULL)
Packit 6c4009
    {
Packit 6c4009
no_memory:
Packit 6c4009
      (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
Packit 6c4009
      mem_free (auth, sizeof (*auth));
Packit 6c4009
      mem_free (au, sizeof (*au));
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  auth->ah_ops = (struct auth_ops *) &auth_unix_ops;
Packit 6c4009
  auth->ah_private = (caddr_t) au;
Packit 6c4009
  auth->ah_verf = au->au_shcred = _null_auth;
Packit 6c4009
  au->au_shfaults = 0;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * fill in param struct from the given params
Packit 6c4009
   */
Packit 6c4009
  (void) __gettimeofday (&now, (struct timezone *) 0);
Packit 6c4009
  aup.aup_time = now.tv_sec;
Packit 6c4009
  aup.aup_machname = machname;
Packit 6c4009
  aup.aup_uid = uid;
Packit 6c4009
  aup.aup_gid = gid;
Packit 6c4009
  aup.aup_len = (u_int) len;
Packit 6c4009
  aup.aup_gids = aup_gids;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Serialize the parameters into origcred
Packit 6c4009
   */
Packit 6c4009
  xdrmem_create (&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
Packit 6c4009
  if (!xdr_authunix_parms (&xdrs, &aup))
Packit 6c4009
    abort ();
Packit 6c4009
  au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
Packit 6c4009
  au->au_origcred.oa_flavor = AUTH_UNIX;
Packit 6c4009
  au->au_origcred.oa_base = mem_alloc ((u_int) len);
Packit 6c4009
  if (au->au_origcred.oa_base == NULL)
Packit 6c4009
    goto no_memory;
Packit 6c4009
  memcpy(au->au_origcred.oa_base, mymem, (u_int) len);
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * set auth handle to reflect new cred.
Packit 6c4009
   */
Packit 6c4009
  auth->ah_cred = au->au_origcred;
Packit 6c4009
  marshal_new_auth (auth);
Packit 6c4009
  return auth;
Packit 6c4009
}
Packit 6c4009
libc_hidden_nolink_sunrpc (authunix_create, GLIBC_2_0)
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Returns an auth handle with parameters determined by doing lots of
Packit 6c4009
 * syscalls.
Packit 6c4009
 */
Packit 6c4009
AUTH *
Packit 6c4009
authunix_create_default (void)
Packit 6c4009
{
Packit 6c4009
  char machname[MAX_MACHINE_NAME + 1];
Packit 6c4009
Packit 6c4009
  if (__gethostname (machname, MAX_MACHINE_NAME) == -1)
Packit 6c4009
    abort ();
Packit 6c4009
  machname[MAX_MACHINE_NAME] = 0;
Packit 6c4009
  uid_t uid = __geteuid ();
Packit 6c4009
  gid_t gid = __getegid ();
Packit 6c4009
Packit 6c4009
  int max_nr_groups;
Packit 6c4009
  /* When we have to try a second time, do not use alloca() again.  We
Packit 6c4009
     might have reached the stack limit already.  */
Packit 6c4009
  bool retry = false;
Packit 6c4009
 again:
Packit 6c4009
  /* Ask the kernel how many groups there are exactly.  Note that we
Packit 6c4009
     might have to redo all this if the number of groups has changed
Packit 6c4009
     between the two calls.  */
Packit 6c4009
  max_nr_groups = __getgroups (0, NULL);
Packit 6c4009
Packit 6c4009
  /* Just some random reasonable stack limit.  */
Packit 6c4009
#define ALLOCA_LIMIT (1024 / sizeof (gid_t))
Packit 6c4009
  gid_t *gids = NULL;
Packit 6c4009
  if (max_nr_groups < ALLOCA_LIMIT && ! retry)
Packit 6c4009
    gids = (gid_t *) alloca (max_nr_groups * sizeof (gid_t));
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      gids = (gid_t *) malloc (max_nr_groups * sizeof (gid_t));
Packit 6c4009
      if (gids == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  int len = __getgroups (max_nr_groups, gids);
Packit 6c4009
  if (len == -1)
Packit 6c4009
    {
Packit 6c4009
      if (errno == EINVAL)
Packit 6c4009
	{
Packit 6c4009
	  /* New groups added in the meantime.  Try again.  */
Packit 6c4009
	  if (max_nr_groups >= ALLOCA_LIMIT || retry)
Packit 6c4009
	    free (gids);
Packit 6c4009
	  retry = true;
Packit 6c4009
	  goto again;
Packit 6c4009
	}
Packit 6c4009
      /* No other error can happen.  */
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* This braindamaged Sun code forces us here to truncate the
Packit 6c4009
     list of groups to NGRPS members since the code in
Packit 6c4009
     authuxprot.c transforms a fixed array.  Grrr.  */
Packit 6c4009
  AUTH *result = authunix_create (machname, uid, gid, MIN (NGRPS, len), gids);
Packit 6c4009
Packit 6c4009
  if (max_nr_groups >= ALLOCA_LIMIT || retry)
Packit 6c4009
    free (gids);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#ifdef EXPORT_RPC_SYMBOLS
Packit 6c4009
libc_hidden_def (authunix_create_default)
Packit 6c4009
#else
Packit 6c4009
libc_hidden_nolink_sunrpc (authunix_create_default, GLIBC_2_0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * authunix operations
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
authunix_nextverf (AUTH *auth)
Packit 6c4009
{
Packit 6c4009
  /* no action necessary */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
authunix_marshal (AUTH *auth, XDR *xdrs)
Packit 6c4009
{
Packit 6c4009
  struct audata *au = AUTH_PRIVATE (auth);
Packit 6c4009
Packit 6c4009
  return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
authunix_validate (AUTH *auth, struct opaque_auth *verf)
Packit 6c4009
{
Packit 6c4009
  struct audata *au;
Packit 6c4009
  XDR xdrs;
Packit 6c4009
Packit 6c4009
  if (verf->oa_flavor == AUTH_SHORT)
Packit 6c4009
    {
Packit 6c4009
      au = AUTH_PRIVATE (auth);
Packit 6c4009
      xdrmem_create (&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE);
Packit 6c4009
Packit 6c4009
      if (au->au_shcred.oa_base != NULL)
Packit 6c4009
	{
Packit 6c4009
	  mem_free (au->au_shcred.oa_base,
Packit 6c4009
		    au->au_shcred.oa_length);
Packit 6c4009
	  au->au_shcred.oa_base = NULL;
Packit 6c4009
	}
Packit 6c4009
      if (xdr_opaque_auth (&xdrs, &au->au_shcred))
Packit 6c4009
	{
Packit 6c4009
	  auth->ah_cred = au->au_shcred;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  xdrs.x_op = XDR_FREE;
Packit 6c4009
	  (void) xdr_opaque_auth (&xdrs, &au->au_shcred);
Packit 6c4009
	  au->au_shcred.oa_base = NULL;
Packit 6c4009
	  auth->ah_cred = au->au_origcred;
Packit 6c4009
	}
Packit 6c4009
      marshal_new_auth (auth);
Packit 6c4009
    }
Packit 6c4009
  return TRUE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
authunix_refresh (AUTH *auth)
Packit 6c4009
{
Packit 6c4009
  struct audata *au = AUTH_PRIVATE (auth);
Packit 6c4009
  struct authunix_parms aup;
Packit 6c4009
  struct timeval now;
Packit 6c4009
  XDR xdrs;
Packit 6c4009
  int stat;
Packit 6c4009
Packit 6c4009
  if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
Packit 6c4009
    {
Packit 6c4009
      /* there is no hope.  Punt */
Packit 6c4009
      return FALSE;
Packit 6c4009
    }
Packit 6c4009
  au->au_shfaults++;
Packit 6c4009
Packit 6c4009
  /* first deserialize the creds back into a struct authunix_parms */
Packit 6c4009
  aup.aup_machname = NULL;
Packit 6c4009
  aup.aup_gids = (gid_t *) NULL;
Packit 6c4009
  xdrmem_create (&xdrs, au->au_origcred.oa_base,
Packit 6c4009
		 au->au_origcred.oa_length, XDR_DECODE);
Packit 6c4009
  stat = xdr_authunix_parms (&xdrs, &aup;;
Packit 6c4009
  if (!stat)
Packit 6c4009
    goto done;
Packit 6c4009
Packit 6c4009
  /* update the time and serialize in place */
Packit 6c4009
  (void) __gettimeofday (&now, (struct timezone *) 0);
Packit 6c4009
  aup.aup_time = now.tv_sec;
Packit 6c4009
  xdrs.x_op = XDR_ENCODE;
Packit 6c4009
  XDR_SETPOS (&xdrs, 0);
Packit 6c4009
  stat = xdr_authunix_parms (&xdrs, &aup;;
Packit 6c4009
  if (!stat)
Packit 6c4009
    goto done;
Packit 6c4009
  auth->ah_cred = au->au_origcred;
Packit 6c4009
  marshal_new_auth (auth);
Packit 6c4009
done:
Packit 6c4009
  /* free the struct authunix_parms created by deserializing */
Packit 6c4009
  xdrs.x_op = XDR_FREE;
Packit 6c4009
  (void) xdr_authunix_parms (&xdrs, &aup;;
Packit 6c4009
  XDR_DESTROY (&xdrs);
Packit 6c4009
  return stat;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
authunix_destroy (AUTH *auth)
Packit 6c4009
{
Packit 6c4009
  struct audata *au = AUTH_PRIVATE (auth);
Packit 6c4009
Packit 6c4009
  mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
Packit 6c4009
Packit 6c4009
  if (au->au_shcred.oa_base != NULL)
Packit 6c4009
    mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
Packit 6c4009
Packit 6c4009
  mem_free (auth->ah_private, sizeof (struct audata));
Packit 6c4009
Packit 6c4009
  if (auth->ah_verf.oa_base != NULL)
Packit 6c4009
    mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
Packit 6c4009
Packit 6c4009
  mem_free ((caddr_t) auth, sizeof (*auth));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Marshals (pre-serializes) an auth struct.
Packit 6c4009
 * sets private data, au_marshed and au_mpos
Packit 6c4009
 */
Packit 6c4009
static bool_t
Packit 6c4009
marshal_new_auth (AUTH *auth)
Packit 6c4009
{
Packit 6c4009
  XDR xdr_stream;
Packit 6c4009
  XDR *xdrs = &xdr_stream;
Packit 6c4009
  struct audata *au = AUTH_PRIVATE (auth);
Packit 6c4009
Packit 6c4009
  xdrmem_create (xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
Packit 6c4009
  if ((!xdr_opaque_auth (xdrs, &(auth->ah_cred))) ||
Packit 6c4009
      (!xdr_opaque_auth (xdrs, &(auth->ah_verf))))
Packit 6c4009
    perror (_("auth_unix.c: Fatal marshalling problem"));
Packit 6c4009
  else
Packit 6c4009
    au->au_mpos = XDR_GETPOS (xdrs);
Packit 6c4009
Packit 6c4009
  XDR_DESTROY (xdrs);
Packit 6c4009
Packit 6c4009
  return TRUE;
Packit 6c4009
}