hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame nis/nss_nisplus/nisplus-publickey.c

Packit 6c4009
/* Copyright (c) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <nss.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <syslog.h>
Packit 6c4009
#include <rpc/rpc.h>
Packit 6c4009
#include <rpcsvc/nis.h>
Packit 6c4009
#include <rpc/key_prot.h>
Packit 6c4009
extern int xdecrypt (char *, char *);
Packit 6c4009
Packit 6c4009
#include <nss-nisplus.h>
Packit 6c4009
Packit 6c4009
/* If we haven't found the entry, we give a SUCCESS and an empty key back. */
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
Packit 6c4009
{
Packit 6c4009
  nis_result *res;
Packit 6c4009
  enum nss_status retval;
Packit 6c4009
  char buf[NIS_MAXNAMELEN + 2];
Packit 6c4009
  size_t slen;
Packit 6c4009
  char *domain, *cptr;
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  pkey[0] = 0;
Packit 6c4009
Packit 6c4009
  if (netname == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  domain = strchr (netname, '@');
Packit 6c4009
  if (!domain)
Packit 6c4009
    return NSS_STATUS_UNAVAIL;
Packit 6c4009
  domain++;
Packit 6c4009
Packit 6c4009
  slen = snprintf (buf, NIS_MAXNAMELEN,
Packit 6c4009
		   "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
Packit 6c4009
		   netname, domain);
Packit 6c4009
Packit 6c4009
  if (slen >= NIS_MAXNAMELEN)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (buf[slen - 1] != '.')
Packit 6c4009
    {
Packit 6c4009
      buf[slen++] = '.';
Packit 6c4009
      buf[slen] = '\0';
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
Packit 6c4009
		  NULL, NULL);
Packit 6c4009
Packit 6c4009
  if (res == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ENOMEM;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
  retval = niserr2nss (res->status);
Packit 6c4009
Packit 6c4009
  if (retval != NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
	*errnop = errno;
Packit 6c4009
      if (res->status == NIS_NOTFOUND)
Packit 6c4009
	retval = NSS_STATUS_SUCCESS;
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return retval;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (NIS_RES_NUMOBJ (res) > 1)
Packit 6c4009
    {
Packit 6c4009
      /*
Packit 6c4009
       * More than one principal with same uid?
Packit 6c4009
       * something wrong with cred table. Should be unique
Packit 6c4009
       * Warn user and continue.
Packit 6c4009
       */
Packit 6c4009
      syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_SUCCESS;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  len = ENTRY_LEN (NIS_RES_OBJECT (res), 3);
Packit 6c4009
  memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len);
Packit 6c4009
  pkey[len] = 0;
Packit 6c4009
  cptr = strchr (pkey, ':');
Packit 6c4009
  if (cptr)
Packit 6c4009
    cptr[0] = '\0';
Packit 6c4009
  nis_freeresult (res);
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
Packit 6c4009
			   int *errnop)
Packit 6c4009
{
Packit 6c4009
  nis_result *res;
Packit 6c4009
  enum nss_status retval;
Packit 6c4009
  char buf[NIS_MAXNAMELEN + 2];
Packit 6c4009
  size_t slen;
Packit 6c4009
  char *domain, *cptr;
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  skey[0] = 0;
Packit 6c4009
Packit 6c4009
  if (netname == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  domain = strchr (netname, '@');
Packit 6c4009
  if (!domain)
Packit 6c4009
    return NSS_STATUS_UNAVAIL;
Packit 6c4009
  domain++;
Packit 6c4009
Packit 6c4009
  slen = snprintf (buf, NIS_MAXNAMELEN,
Packit 6c4009
		   "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
Packit 6c4009
		   netname, domain);
Packit 6c4009
Packit 6c4009
  if (slen >= NIS_MAXNAMELEN)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (buf[slen - 1] != '.')
Packit 6c4009
    {
Packit 6c4009
      buf[slen++] = '.';
Packit 6c4009
      buf[slen] = '\0';
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
Packit 6c4009
		  NULL, NULL);
Packit 6c4009
Packit 6c4009
  if (res == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ENOMEM;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
  retval = niserr2nss (res->status);
Packit 6c4009
Packit 6c4009
  if (retval != NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
	*errnop = errno;
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return retval;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (NIS_RES_NUMOBJ (res) > 1)
Packit 6c4009
    {
Packit 6c4009
      /*
Packit 6c4009
       * More than one principal with same uid?
Packit 6c4009
       * something wrong with cred table. Should be unique
Packit 6c4009
       * Warn user and continue.
Packit 6c4009
       */
Packit 6c4009
      syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_SUCCESS;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  len = ENTRY_LEN (NIS_RES_OBJECT (res), 4);
Packit 6c4009
  memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len);
Packit 6c4009
  buf[len] = '\0';
Packit 6c4009
  cptr = strchr (buf, ':');
Packit 6c4009
  if (cptr)
Packit 6c4009
    cptr[0] = '\0';
Packit 6c4009
  nis_freeresult (res);
Packit 6c4009
Packit 6c4009
  if (!xdecrypt (buf, passwd))
Packit 6c4009
    return NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
Packit 6c4009
    return NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  buf[HEXKEYBYTES] = 0;
Packit 6c4009
  strcpy (skey, buf);
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Parse information from the passed string.
Packit 6c4009
   The format of the string passed is gid,grp,grp, ...  */
Packit 6c4009
static enum nss_status
Packit 6c4009
parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
Packit 6c4009
	       int *errnop)
Packit 6c4009
{
Packit 6c4009
  char *ep;
Packit 6c4009
  int gidlen;
Packit 6c4009
Packit 6c4009
  if (!s || (!isdigit (*s)))
Packit 6c4009
    {
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: missing group id list in `%s'"), s);
Packit 6c4009
      return NSS_STATUS_NOTFOUND;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *gidp = strtoul (s, &ep, 10);
Packit 6c4009
Packit 6c4009
  gidlen = 0;
Packit 6c4009
Packit 6c4009
  /* After strtoul() ep should point to the marker ',', which means
Packit 6c4009
     here starts a new value.
Packit 6c4009
Packit 6c4009
     The Sun man pages show that GIDLIST should contain at least NGRPS
Packit 6c4009
     elements.  Limiting the number written by this value is the best
Packit 6c4009
     we can do.  */
Packit 6c4009
  while (ep != NULL && *ep == ',' && gidlen < NGRPS)
Packit 6c4009
    {
Packit 6c4009
      ep++;
Packit 6c4009
      s = ep;
Packit 6c4009
      gidlist[gidlen++] = strtoul (s, &ep, 10);
Packit 6c4009
    }
Packit 6c4009
  *gidlenp = gidlen;
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
Packit 6c4009
		       gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
Packit 6c4009
{
Packit 6c4009
  char *domain;
Packit 6c4009
  nis_result *res;
Packit 6c4009
  char sname[NIS_MAXNAMELEN + 2]; /*  search criteria + table name */
Packit 6c4009
  size_t slen;
Packit 6c4009
  char principal[NIS_MAXNAMELEN + 1];
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  /* 1.  Get home domain of user. */
Packit 6c4009
  domain = strchr (netname, '@');
Packit 6c4009
  if (! domain)
Packit 6c4009
    return NSS_STATUS_UNAVAIL;
Packit 6c4009
Packit 6c4009
  ++domain;  /* skip '@' */
Packit 6c4009
Packit 6c4009
  /* 2.  Get user's nisplus principal name.  */
Packit 6c4009
  slen = snprintf (sname, NIS_MAXNAMELEN,
Packit 6c4009
		   "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
Packit 6c4009
		   netname, domain);
Packit 6c4009
Packit 6c4009
  if (slen >= NIS_MAXNAMELEN)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (sname[slen - 1] != '.')
Packit 6c4009
    {
Packit 6c4009
      sname[slen++] = '.';
Packit 6c4009
      sname[slen] = '\0';
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* must use authenticated call here */
Packit 6c4009
  /* XXX but we cant, for now. XXX */
Packit 6c4009
  res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
Packit 6c4009
		  NULL, NULL);
Packit 6c4009
  if (res == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ENOMEM;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
  switch (res->status)
Packit 6c4009
    {
Packit 6c4009
    case NIS_SUCCESS:
Packit 6c4009
    case NIS_S_SUCCESS:
Packit 6c4009
      break;   /* go and do something useful */
Packit 6c4009
    case NIS_NOTFOUND:
Packit 6c4009
    case NIS_PARTIAL:
Packit 6c4009
    case NIS_NOSUCHNAME:
Packit 6c4009
    case NIS_NOSUCHTABLE:
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_NOTFOUND;
Packit 6c4009
    case NIS_S_NOTFOUND:
Packit 6c4009
    case NIS_TRYAGAIN:
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
Packit 6c4009
	      nis_sperrno (res->status));
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      *errnop = errno;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    default:
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
Packit 6c4009
	      nis_sperrno (res->status));
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (NIS_RES_NUMOBJ (res) > 1)
Packit 6c4009
    /*
Packit 6c4009
     * A netname belonging to more than one principal?
Packit 6c4009
     * Something wrong with cred table. should be unique.
Packit 6c4009
     * Warn user and continue.
Packit 6c4009
     */
Packit 6c4009
    syslog (LOG_ALERT,
Packit 6c4009
	    _("netname2user: DES entry for %s in directory %s not unique"),
Packit 6c4009
	    netname, domain);
Packit 6c4009
Packit 6c4009
  len = ENTRY_LEN (NIS_RES_OBJECT (res), 0);
Packit 6c4009
  strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len);
Packit 6c4009
  principal[len] = '\0';
Packit 6c4009
  nis_freeresult (res);
Packit 6c4009
Packit 6c4009
  if (principal[0] == '\0')
Packit 6c4009
    return NSS_STATUS_UNAVAIL;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * 3.  Use principal name to look up uid/gid information in
Packit 6c4009
   *     LOCAL entry in **local** cred table.
Packit 6c4009
   */
Packit 6c4009
  domain = nis_local_directory ();
Packit 6c4009
  if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
Packit 6c4009
    {
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
Packit 6c4009
	      principal);
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  slen = snprintf (sname, sizeof  (sname),
Packit 6c4009
		   "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
Packit 6c4009
		   principal, domain);
Packit 6c4009
Packit 6c4009
  if (sname[slen - 1] != '.')
Packit 6c4009
    {
Packit 6c4009
      sname[slen++] = '.';
Packit 6c4009
      sname[slen] = '\0';
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* must use authenticated call here */
Packit 6c4009
  /* XXX but we cant, for now. XXX */
Packit 6c4009
  res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
Packit 6c4009
		  NULL, NULL);
Packit 6c4009
  if (res == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ENOMEM;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
  switch(res->status)
Packit 6c4009
    {
Packit 6c4009
    case NIS_NOTFOUND:
Packit 6c4009
    case NIS_PARTIAL:
Packit 6c4009
    case NIS_NOSUCHNAME:
Packit 6c4009
    case NIS_NOSUCHTABLE:
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_NOTFOUND;
Packit 6c4009
    case NIS_S_NOTFOUND:
Packit 6c4009
    case NIS_TRYAGAIN:
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
Packit 6c4009
	      nis_sperrno (res->status));
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      *errnop = errno;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    case NIS_SUCCESS:
Packit 6c4009
    case NIS_S_SUCCESS:
Packit 6c4009
      break;   /* go and do something useful */
Packit 6c4009
    default:
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
Packit 6c4009
	      nis_sperrno (res->status));
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (NIS_RES_NUMOBJ (res) > 1)
Packit 6c4009
    /*
Packit 6c4009
     * A principal can have more than one LOCAL entry?
Packit 6c4009
     * Something wrong with cred table.
Packit 6c4009
     * Warn user and continue.
Packit 6c4009
     */
Packit 6c4009
    syslog (LOG_ALERT,
Packit 6c4009
	    _("netname2user: LOCAL entry for %s in directory %s not unique"),
Packit 6c4009
	    netname, domain);
Packit 6c4009
  /* Fetch the uid */
Packit 6c4009
  *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10);
Packit 6c4009
Packit 6c4009
  if (*uidp == 0)
Packit 6c4009
    {
Packit 6c4009
      syslog (LOG_ERR, _("netname2user: should not have uid 0"));
Packit 6c4009
      nis_freeresult (res);
Packit 6c4009
      return NSS_STATUS_NOTFOUND;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
Packit 6c4009
		 gidp, gidlenp, gidlist, errnop);
Packit 6c4009
Packit 6c4009
  nis_freeresult (res);
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}