Example #1
0
static enum nss_status
lookup (const char *name, const char *type, struct passwd *pwd,
	char *buffer, size_t buflen, int *errnop)
{
  struct parser_data *data = (void *) buffer;
  size_t linebuflen;
  void *context;
  char **list;
  int parse_res;
  size_t len;
  int olderr = errno;

  context = _nss_hesiod_init ();
  if (context == NULL)
    return NSS_STATUS_UNAVAIL;

  list = hesiod_resolve (context, name, type);
  if (list == NULL)
    {
      int err = errno;
      hesiod_end (context);
      __set_errno (olderr);
      return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
    }

  linebuflen = buffer + buflen - data->linebuffer;
  len = strlen (*list) + 1;
  if (linebuflen < len)
    {
      hesiod_free_list (context, list);
      hesiod_end (context);
      *errnop = ERANGE;
      return NSS_STATUS_TRYAGAIN;
    }

  memcpy (data->linebuffer, *list, len);
  hesiod_free_list (context, list);
  hesiod_end (context);

  parse_res = _nss_files_parse_pwent (buffer, pwd, data, buflen, errnop);
  if (parse_res < 1)
    {
      __set_errno (olderr);
      return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
    }

  return NSS_STATUS_SUCCESS;
}
Example #2
0
struct hesiod_postoffice *hesiod_getmailhost(void *context, const char *user)
{
  char *p, **list;
  struct hesiod_postoffice *po;

  /* Get the result, sanity-check it, and copy it into linebuf. */
  list = hesiod_resolve(context, user, "pobox");
  if (!list)
      return NULL;
  p = malloc(strlen(*list) + 1);
  if (!p)
    {
      hesiod_free_list(context, list);
      errno = ENOMEM;
      return NULL;
    }
  strcpy(p, *list);
  hesiod_free_list(context, list);

  /* Allocate memory for the result. */
  po = (struct hesiod_postoffice *) malloc(sizeof(struct hesiod_postoffice));
  if (!po)
    {
      free(p);
      errno = ENOMEM;
      return NULL;
    }

  /* Break up linebuf into fields. */
  po->hesiod_po_type = p;
  while (!isspace((unsigned char)*p))
    p++;
  *p++ = 0;
  po->hesiod_po_host = p;
  while (!isspace((unsigned char)*p))
    p++;
  *p++ = 0;
  po->hesiod_po_name = p;

  return po;
}
Example #3
0
static enum nss_status
internal_gid_from_group (void *context, const char *groupname, gid_t *group)
{
  char **grp_res;
  enum nss_status status = NSS_STATUS_NOTFOUND;

  grp_res = hesiod_resolve (context, groupname, "group");
  if (grp_res != NULL && *grp_res != NULL)
    {
      char *p = *grp_res;

      /* Skip to third field.  */
      while (*p != '\0' && *p != ':')
	++p;
      if (*p != '\0')
	++p;
      while (*p != '\0' && *p != ':')
	++p;
      if (*p != '\0')
	{
	  char *endp;
	  char *q = ++p;
	  long int val;

	  while (*q != '\0' && *q != ':')
	    ++q;

	  val = strtol (p, &endp, 10);
	  if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
	    {
	      *group = val;
	      if (endp == q && endp != p)
		status = NSS_STATUS_SUCCESS;
	    }
        }
      hesiod_free_list (context, grp_res);
    }
  return status;
}
Example #4
0
static struct passwd *getpwcommon(void *context, const char *arg, int which)
{
  char *p, **list;
  struct passwd *pw;

  /* Get the response and copy the first entry into a buffer. */
  list = hesiod_resolve(context, arg, which ? "uid" : "passwd");
  if (!list)
    return NULL;
  p = malloc(strlen(*list) + 1);
  if (!p)
    {
      hesiod_free_list(context, list);
      errno = ENOMEM;
      return NULL;
    }
  strcpy(p, *list);
  hesiod_free_list(context, list);

  /* Allocate memory for the result. */
  pw = (struct passwd *) malloc(sizeof(struct passwd));
  if (!pw)
    {
      free(p);
      errno = ENOMEM;
      return NULL;
    }

  /* Split up buf into fields. */
  pw->pw_name = p;
  p = next_field(p);
  pw->pw_passwd = p;
  p = next_field(p);
  pw->pw_uid = atoi(p);
  p = next_field(p);
  pw->pw_gid = atoi(p);
  p = next_field(p);
  pw->pw_gecos = p;
  p = next_field(p);
  pw->pw_dir = p;
  p = next_field(p);
  pw->pw_shell = p;
  while (*p && *p != '\n')
    p++;
  *p = 0;

#ifdef HAVE_PW_QUOTA
  pw->pw_quota = 0;
#endif
#ifdef HAVE_PW_COMMENT
  pw->pw_comment = "";
#endif
#ifdef HAVE_PW_CLASS
  pw->pw_class = "";
#endif
#ifdef HAVE_PW_CHANGE
  pw->pw_change = 0;
#endif
#ifdef HAVE_PW_EXPIRE
  pw->pw_expire = 0;
#endif

  return pw;
}
Example #5
0
/*
 * __grscan_dns
 *	Search Hesiod for the next desired entry.
 *	If search is zero, return the next entry.
 *	If search is non-zero, look for a specific name (if name != NULL),
 *	or a specific gid (if name == NULL).
 */
int
__grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
	struct __grstate_dns *state, int search, const char *name, gid_t gid)
{
	const char	**curzone;
	char		**hp, *ep;
	int		rv;

	static const char *zones_gid_group[] = {
		"gid",
		"group",
		NULL
	};

	static const char *zones_group[] = {
		"group",
		NULL
	};

	_DIAGASSERT(retval != NULL);
	_DIAGASSERT(grp != NULL);
	_DIAGASSERT(buffer != NULL);
	_DIAGASSERT(state != NULL);
	/* name is NULL to indicate searching for gid */

	*retval = 0;

	if (state->context == NULL) {	/* only start if Hesiod not setup */
		rv = __grstart_dns(state);
		if (rv != NS_SUCCESS)
			return rv;
	}

 next_dns_entry:
	hp = NULL;
	rv = NS_NOTFOUND;

	if (! search) {			/* find next entry */
		if (state->num == -1)		/* exhausted search */
			return NS_NOTFOUND;
						/* find group-NNN */
		snprintf(buffer, buflen, "group-%u", state->num);
		state->num++;
		curzone = zones_group;
	} else if (name) {		/* find group name */
		snprintf(buffer, buflen, "%s", name);
		curzone = zones_group;
	} else {			/* find gid */
		snprintf(buffer, buflen, "%u", (unsigned int)gid);
		curzone = zones_gid_group;
	}

	for (; *curzone; curzone++) {		/* search zones */
		hp = hesiod_resolve(state->context, buffer, *curzone);
		if (hp != NULL)
			break;
		if (errno != ENOENT) {
			rv = NS_UNAVAIL;
			goto dnsgrscan_out;
		}
	}
	if (*curzone == NULL) {
		if (! search)
			state->num = -1;
		goto dnsgrscan_out;
	}

	if ((ep = strchr(hp[0], '\n')) != NULL)
		*ep = '\0';				/* clear trailing \n */
	if (_gr_parse(hp[0], grp, buffer, buflen)) {	/* validate line */
		if (! search) {				/* just want this one */
			rv = NS_SUCCESS;
		} else if ((name && strcmp(name, grp->gr_name) == 0) ||
		    (!name && gid == grp->gr_gid)) {	/* want specific */
			rv = NS_SUCCESS;
		}
	} else {					/* dodgy entry */
		if (!search) {			/* try again if ! searching */
			hesiod_free_list(state->context, hp);
			goto next_dns_entry;
		}
	}

 dnsgrscan_out:
	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
		*retval = errno;
	if (hp)
		hesiod_free_list(state->context, hp);
	return rv;
}
Example #6
0
int 
main(int argc, char **argv)
{
	char  **list, **p, *bindname, *name, *type;
	int     lflag = 0, errflg = 0, bflag = 0, c;
	void   *context;

	while ((c = getopt(argc, argv, "lb")) != -1) {
		switch (c) {
		case 'l':
			lflag = 1;
			break;
		case 'b':
			bflag = 1;
			break;
		default:
			errflg++;
			break;
		}
	}
	if (argc - optind != 2 || errflg) {
		fprintf(stderr, "usage: hesinfo [-bl] name type\n");
		fprintf(stderr, "\t-l selects long format\n");
		fprintf(stderr, "\t-b also does hes_to_bind conversion\n");
		exit(2);
	}
	name = argv[optind];
	type = argv[optind + 1];

	if (hesiod_init(&context) < 0) {
		if (errno == ENOEXEC)
			warnx(
			    "hesiod_init: Invalid Hesiod configuration file.");
		else
			warn("hesiod_init");
	}
	/* Display bind name if requested. */
	if (bflag) {
		if (lflag)
			printf("hes_to_bind(%s, %s) expands to\n", name, type);
		bindname = hesiod_to_bind(context, name, type);
		if (!bindname) {
			if (lflag)
				printf("nothing\n");
			if (errno == ENOENT)
				warnx("hesiod_to_bind: Unknown rhs-extension.");
			else
				warn("hesiod_to_bind");
			exit(1);
		}
		printf("%s\n", bindname);
		free(bindname);
		if (lflag)
			printf("which ");
	}
	if (lflag)
		printf("resolves to\n");

	/* Do the hesiod resolve and check for errors. */
	list = hesiod_resolve(context, name, type);
	if (!list) {
		if (lflag)
			printf("nothing\n");
		if (errno == ENOENT)
			warnx("hesiod_resolve: Hesiod name not found.");
		else
			warn("hesiod_resolve");
		exit(1);
	}
	/* Display the results. */
	for (p = list; *p; p++)
		printf("%s\n", *p);

	hesiod_free_list(context, list);
	hesiod_end(context);
	exit(0);
}
Example #7
0
static void printer_hes_callback(void *arg, int status, int timeouts,
				 unsigned char *abuf, int alen)
{
  struct printer_poll_args *pargs = (struct printer_poll_args *) arg;
  struct serverstate *state = pargs->state;
  struct printer *printer = pargs->printer;
  char **vec = NULL, *p, *q;

  if (status == ARES_EDESTRUCTION)
    {
      syslog(LOG_DEBUG, "printer_hes_callback: printer %s hesiod query "
	     "halted for channel destruction", printer->name);
      free(pargs);
      return;
    }

  if (status != ARES_SUCCESS)
    {
      syslog(LOG_ERR, "printer_hes_callback: could not resolve Hesiod pcap "
	     "for printer %s: %s", printer->name,
	     ares_strerror(status));
      goto failure;
    }

  /* Parse the result buffer into text records. */
  vec = hesiod_parse_result(state->hescontext, abuf, alen);
  if (!vec || !*vec)
    {
      syslog(LOG_ERR, "printer_hes_callback: could not parse Hesiod pcap "
	     "result for printer %s: %m", printer->name);
      goto failure;
    }

  /* Look for the print server name. */
  p = strchr(*vec, ':');
  while (p)
    {
      if (strncmp(p + 1, "rm=", 3) == 0)
	break;
      p = strchr(p + 1, ':');
    }
  if (!p)
    {
      syslog(LOG_ERR, "printer_hes_callback: can't find print server name in "
	     "Hesiod pcap result for printer %s", printer->name);
      goto failure;
    }
  p += 4;
  q = p;
  while (*q && *q != ':')
    q++;
  *q = 0;

  syslog(LOG_DEBUG, "printer_hes_callback: printer %s starting query for %s",
	 printer->name, p);
  ares_gethostbyname(state->channel, p, AF_INET, printer_host_callback, pargs);
  hesiod_free_list(state->hescontext, vec);
  return;

failure:
  if (vec)
    hesiod_free_list(state->hescontext, vec);
  printer->timer = timer_set_rel(60, printer_poll, pargs);
}
Example #8
0
/* Retrieve the user's hesiod groups and stuff them into *groups, with a
 * count in *ngroups.  Also put the user's primary gid into *primary_gid.
 * Return 0 on success and -1 on failure.
 */
static int retrieve_hesgroups(const char *username, struct hesgroup **groups,
			      int *ngroups, gid_t *primary_gid)
{
  char **grplistvec, **primarygidvec, *primary_name, buf[64], *p, *q;
  int n, len;
  struct hesgroup *hesgroups;
  struct passwd *pwd;
  void *hescontext;

  /* Look up the user's primary group in hesiod to retrieve the primary
   * group name.  Start by finding the gid. */
  pwd = al__getpwnam(username);
  if (!pwd)
    return -1;
  *primary_gid = pwd->pw_gid;
  al__free_passwd(pwd);

  /* Initialize the hesiod context. */
  if (hesiod_init(&hescontext) != 0)
    return -1;

  /* Now do the hesiod resolve.  If it fails with ENOENT, assume the user
   * has a local account and return no groups. */
  sprintf(buf, "%lu", (unsigned long) *primary_gid);
  primarygidvec = hesiod_resolve(hescontext, buf, "gid");
  if (!primarygidvec && errno == ENOENT)
    {
      *groups = NULL;
      *ngroups = 0;
      hesiod_end(hescontext);
      return 0;
    }
  if (!primarygidvec || !*primarygidvec || **primarygidvec == ':')
    {
      if (primarygidvec)
	hesiod_free_list(hescontext, primarygidvec);
      hesiod_end(hescontext);
      return -1;
    }

  /* Copy the name part into primary_name. */
  p = strchr(*primarygidvec, ':');
  len = (p) ? p - *primarygidvec : strlen(*primarygidvec);
  primary_name = malloc(len + 1);
  if (!primary_name)
    {
      hesiod_free_list(hescontext, primarygidvec);
      hesiod_end(hescontext);
      return -1;
    }
  memcpy(primary_name, *primarygidvec, len);
  primary_name[len] = 0;
  hesiod_free_list(hescontext, primarygidvec);

  /* Look up the Hesiod group list.  It's okay if there isn't one. */
  grplistvec = hesiod_resolve(hescontext, username, "grplist");
  if ((!grplistvec && errno != ENOENT) || (grplistvec && !*grplistvec))
    {
      if (grplistvec)
	hesiod_free_list(hescontext, grplistvec);
      hesiod_end(hescontext);
      free(primary_name);
      return -1;
    }

  /* Get a close upper bound on the number of group entries we'll need. */
  if (grplistvec)
    {
      n = 0;
      for (p = *grplistvec; *p; p++)
	{
	  if (*p == ':')
	    n++;
	}
      n = (n + 1) / 2 + 1;
    }
  else
    n = 1;

  /* Allocate memory. */
  hesgroups = malloc(n * sizeof(struct hesgroup));
  if (!hesgroups)
    {
      if (grplistvec)
	hesiod_free_list(hescontext, grplistvec);
      hesiod_end(hescontext);
      free(primary_name);
      return -1;
    }

  /* Start off the list with the primary gid. */
  hesgroups[0].name = primary_name;
  hesgroups[0].gid = *primary_gid;
  hesgroups[0].present = 0;
  n = 1;
  
  /* Now get the entries from grplistvec, if we got one. */
  p = (grplistvec) ? *grplistvec : NULL;
  while (p)
    {
      /* Find the end of the group name.  Stop if we hit the end, if we
       * have a zero-length group name, or if we have a non-numeric gid. */
      q = strchr(p, ':');
      if (!q || q == p || !isdigit((unsigned char)*(q + 1)))
	break;

      if (atoi(q + 1) >= MIN_HES_GROUP)
	{
	  hesgroups[n].name = malloc(q - p + 1);
	  if (!hesgroups[n].name)
	    {
	      free_hesgroups(hesgroups, n);
	      hesiod_free_list(hescontext, grplistvec);
	      hesiod_end(hescontext);
	      return -1;
	    }
	  memcpy(hesgroups[n].name, p, q - p);
	  hesgroups[n].name[q - p] = 0;
	  hesgroups[n].gid = atoi(q + 1);
	  hesgroups[n].present = 0;
	  n++;
	}
      p = strchr(q + 1, ':');
      if (p)
	p++;
    }

  /* Clean up allocated memory and return. */
  if (grplistvec)
    hesiod_free_list(hescontext, grplistvec);
  hesiod_end(hescontext);
  *ngroups = n;
  *groups = hesgroups;
  return 0;
}
Example #9
0
enum nss_status
_nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
			    long int *size, gid_t **groupsp, long int limit,
			    int *errnop)
{
  enum nss_status status = NSS_STATUS_SUCCESS;
  char **list = NULL;
  char *p;
  void *context;
  gid_t *groups = *groupsp;
  int save_errno;

  context = _nss_hesiod_init ();
  if (context == NULL)
    return NSS_STATUS_UNAVAIL;

  list = hesiod_resolve (context, user, "grplist");

  if (list == NULL)
    {
      hesiod_end (context);
      return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
    }

  save_errno = errno;

  p = *list;
  while (*p != '\0')
    {
      char *endp;
      char *q;
      long int val;

      status = NSS_STATUS_NOTFOUND;

      q = p;
      while (*q != '\0' && *q != ':' && *q != ',')
	++q;

      if (*q != '\0')
	*q++ = '\0';

      __set_errno (0);
      val = strtol (p, &endp, 10);
      /* Test whether the number is representable in a variable of
         type `gid_t'.  If not ignore the number.  */
      if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
	  && errno == 0)
	{
	  if (*endp == '\0' && endp != p)
	    {
	      group = val;
	      status = NSS_STATUS_SUCCESS;
	    }
	  else
	    status = internal_gid_from_group (context, p, &group);

	  if (status == NSS_STATUS_SUCCESS
	      && !internal_gid_in_list (groups, group, *start))
	    {
	      if (__builtin_expect (*start == *size, 0))
		{
		  /* Need a bigger buffer.  */
		  gid_t *newgroups;
		  long int newsize;

		  if (limit > 0 && *size == limit)
		    /* We reached the maximum.  */
		    goto done;

		  if (limit <= 0)
		    newsize = 2 * *size;
		  else
		    newsize = MIN (limit, 2 * *size);

		  newgroups = realloc (groups, newsize * sizeof (*groups));
		  if (newgroups == NULL)
		    goto done;
		  *groupsp = groups = newgroups;
		  *size = newsize;
		}

	      groups[(*start)++] = group;
	    }
	}

      p = q;
    }

  __set_errno (save_errno);

 done:
  hesiod_free_list (context, list);
  hesiod_end (context);

  return NSS_STATUS_SUCCESS;
}
Example #10
0
/* This function takes a hesiod (name, type) and returns a DNS
 * name which is to be resolved.
 */
char *hesiod_to_bind(void *context, const char *name, const char *type)
{
  struct hesiod_p *ctx = (struct hesiod_p *) context;
  char bindname[MAXDNAME], *p, *ret, *idn_ret, **rhs_list = NULL;
  const char *rhs;
  int len, rc;

  if (strlen(name) > sizeof(bindname) - 1)
    {
      errno = EMSGSIZE;
      return NULL;
    }
  strcpy(bindname, name);

  /* Find the right right hand side to use, possibly truncating bindname. */
  p = strchr(bindname, '@');
  if (p)
    {
      *p++ = 0;
      if (strchr(p, '.'))
	rhs = name + (p - bindname);
      else
	{
	  rhs_list = hesiod_resolve(context, p, "rhs-extension");
	  if (rhs_list)
	    rhs = *rhs_list;
	  else
	    {
	      errno = ENOENT;
	      return NULL;
	    }
	}
    } else
      rhs = ctx->rhs;

  /* See if we have enough room. */
  len = strlen(bindname) + 1 + strlen(type);
  if (ctx->lhs)
    len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
  len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
  if (len > sizeof(bindname) - 1)
    {
      if (rhs_list)
	hesiod_free_list(context, rhs_list);
      errno = EMSGSIZE;
      return NULL;
    }

  /* Put together the rest of the domain. */
  strcat(bindname, ".");
  strcat(bindname, type);
  if (ctx->lhs)
    {
      if (ctx->lhs[0] != '.')
	strcat(bindname, ".");
      strcat(bindname, ctx->lhs);
    }
  if (rhs[0] != '.')
    strcat(bindname, ".");
  strcat(bindname, rhs);

  /* rhs_list is no longer needed, since we're done with rhs. */
  if (rhs_list)
    hesiod_free_list(context, rhs_list);

  /* Make a copy of the result and return it to the caller. */
#ifdef HAVE_LIBIDN
  rc = idna_to_ascii_lz(bindname, &idn_ret, 0);
  if (rc != IDNA_SUCCESS)
    {
      errno = EINVAL;
      return NULL;
    }
  ret = strdup(idn_ret);
  idn_free(idn_ret);
#else
  ret = strdup(bindname);
#endif
  if (!ret)
    {
      errno = ENOMEM;
      return NULL;
    }
  return ret;
}