summaryrefslogtreecommitdiffstats
path: root/libutil
diff options
context:
space:
mode:
authorDavid Nugent <davidn@FreeBSD.org>1997-01-04 16:50:08 +0000
committerDavid Nugent <davidn@FreeBSD.org>1997-01-04 16:50:08 +0000
commitdcc82deaf0f0224d8d7b211f93dc4dc0e02e4cbf (patch)
tree9d6072c9d7c943a86e84f0623ce76bca2546d628 /libutil
parent9008dd56db6c0ee59af0f584754131c6467c10fe (diff)
downloadpw-darwin-dcc82deaf0f0224d8d7b211f93dc4dc0e02e4cbf.tar.gz
pw-darwin-dcc82deaf0f0224d8d7b211f93dc4dc0e02e4cbf.tar.zst
pw-darwin-dcc82deaf0f0224d8d7b211f93dc4dc0e02e4cbf.zip
Library functions relating to the login class capabilities database,
including manpages. See also login_cap.h.
Diffstat (limited to 'libutil')
-rw-r--r--libutil/login_cap.c564
1 files changed, 564 insertions, 0 deletions
diff --git a/libutil/login_cap.c b/libutil/login_cap.c
new file mode 100644
index 0000000..21ff02f
--- /dev/null
+++ b/libutil/login_cap.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 1996 by
+ * Sean Eric Fagan <sef@kithrup.com>
+ * David Nugent <davidn@blaze.net.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Low-level routines relating to the user capabilities database
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <login_cap.h>
+
+#ifdef RLIM_LONG
+# define STRTOV strtol
+#else
+# define STRTOV strtoq
+#endif
+
+static int lc_object_count = 0;
+
+static size_t internal_stringsz = 0;
+static char * internal_string = NULL;
+static size_t internal_arraysz = 0;
+static char ** internal_array = NULL;
+
+static char *
+allocstr(char * str)
+{
+ char * p;
+ size_t sz = strlen(str) + 1; /* realloc() only if necessary */
+ if (sz <= internal_stringsz)
+ p = internal_string;
+ else if ((p = realloc(internal_string, sz)) != NULL) {
+ internal_stringsz = sz;
+ internal_string = strcpy(p, str);
+ }
+ return p;
+}
+
+static char **
+allocarray(size_t sz)
+{
+ char ** p;
+ if (sz <= internal_arraysz)
+ p = internal_array;
+ else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
+ internal_arraysz = sz;
+ internal_array = p;
+ }
+ return p;
+}
+
+
+/*
+ * arrayize()
+ * Turn a simple string <str> seperated by any of
+ * the set of <chars> into an array. The last element
+ * of the array will be NULL, as is proper.
+ * Free using freearraystr()
+ */
+
+static char **
+arrayize(char *str, const char *chars, int *size)
+{
+ int i;
+ char *ptr;
+ char **res = NULL;
+
+ for (i = 0, ptr = str; *ptr; i++) {
+ int count = strcspn(ptr, chars);
+ ptr = ptr + count + 1;
+ }
+
+ if ((ptr = allocstr(str)) == NULL) {
+ res = NULL;
+ i = 0;
+ } else if ((res = allocarray(++i)) == NULL) {
+ free(str);
+ i = 0;
+ } else {
+ for (i = 0; *ptr; i++) {
+ int count = strcspn(ptr, chars);
+ res[i] = ptr;
+ ptr += count;
+ if (*ptr)
+ *ptr++ = '\0';
+ }
+ res[i] = 0;
+ }
+ if (size)
+ *size = i;
+ return res;
+}
+
+static void
+freearraystr(char ** array)
+{
+ /*
+ * the array[0] should be free'd, and then array.
+ */
+ if (array) {
+ free(array[0]);
+ free(array);
+ }
+}
+
+
+/*
+ * login_close()
+ * Frees up all resources relating to a login class
+ *
+ */
+
+void
+login_close(login_cap_t * lc)
+{
+ if (lc) {
+ free(lc->lc_style);
+ free(lc->lc_class);
+ free(lc);
+ if (--lc_object_count == 0) {
+ free(internal_string);
+ free(internal_array);
+ internal_array = NULL;
+ internal_string = NULL;
+ cgetclose();
+ }
+ }
+}
+
+
+/*
+ * login_getclassbyname() get the login class by its name.
+ * If the name given is NULL or empty, the default class
+ * LOGIN_DEFCLASS (ie. "default") is fetched. If the
+ * 'dir' argument contains a non-NULL non-empty string,
+ * then the file _FILE_LOGIN_CONF is picked up from that
+ * directory instead of the system login database.
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclassbyname(char const * name, char const * dir)
+{
+ login_cap_t *lc = malloc(sizeof(login_cap_t));
+
+ if (lc != NULL) {
+ int i = 0;
+ char userpath[MAXPATHLEN];
+ static char *login_dbarray[] = { NULL, NULL, NULL };
+
+ if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN)
+ login_dbarray[i++] = userpath;
+ else
+ login_dbarray[i++] = _PATH_LOGIN_CONF;
+ login_dbarray[i ] = NULL;
+
+ lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
+
+ if ((name == NULL || cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0) &&
+ cgetent(&lc->lc_cap, login_dbarray, (char*)(name = LOGIN_DEFCLASS)) != 0) {
+ free(lc);
+ lc = NULL;
+ } else {
+ ++lc_object_count;
+ lc->lc_class = strdup(name);
+ }
+ }
+
+ return lc;
+}
+
+
+
+/*
+ * login_getclass()
+ * Get the login class for a given password entry from
+ * the system (only) login class database.
+ * If the password entry's class field is not set, or
+ * the class specified does not exist, then use the
+ * default of LOGIN_DEFCLASS (ie. "default").
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getclass(const struct passwd *pwd)
+{
+ const char * class = (pwd == NULL) ? NULL : pwd->pw_class;
+ if (pwd->pw_class == NULL || *pwd->pw_class == '\0')
+ class = (pwd->pw_uid == 0) ? "root" : NULL; /* Kludge for 'root' user(s) */
+ return login_getclassbyname(class, 0);
+}
+
+
+/*
+ * login_getuserclass()
+ * Get the login class for a given password entry, allowing user
+ * overrides via ~/.login_conf.
+ * ### WAS: If the password entry's class field is not set,
+ * ####### or the class specified does not exist, then use
+ * If an entry with the recordid "me" does not exist, then use
+ * the default of LOGIN_DEFCLASS (ie. "default").
+ * Return a filled-out login_cap_t structure, including
+ * class name, and the capability record buffer.
+ */
+
+login_cap_t *
+login_getuserclass(const struct passwd *pwd)
+{
+ const char * class = "me"; /* (pwd == NULL) ? NULL : pwd->pw_class; */
+ const char * home = (pwd == NULL) ? NULL : pwd->pw_dir;
+ return login_getclassbyname(class, home);
+}
+
+
+
+/*
+ * login_getcapstr()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability, a defualt if not found, or
+ * an error string on error.
+ */
+
+char *
+login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error)
+{
+ char *res;
+ int ret;
+
+ if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
+ return def;
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
+ return def;
+ } else if (ret >= 0)
+ return res;
+ else
+ return error;
+}
+
+
+/*
+ * login_getcaplist()
+ * Given a login_cap entry, and a capability name, return the
+ * value defined for that capability split into an array of
+ * strings.
+ */
+
+char **
+login_getcaplist(login_cap_t *lc, const char * cap, const char * chars)
+{
+ char * lstring;
+
+ if (chars == NULL)
+ chars = ". \t";
+ if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL)
+ return arrayize(lstring, chars, NULL);
+ return NULL;
+}
+
+
+/*
+ * login_getpath()
+ * From the login_cap_t <lc>, get the capability <cap> which is
+ * formatted as either a space or comma delimited list of paths
+ * and append them all into a string and separate by semicolons.
+ * If there is an error of any kind, return <error>.
+ */
+
+char *
+login_getpath(login_cap_t *lc, const char *cap, char * error)
+{
+ char *ptr, *str = login_getcapstr(lc, (char*)cap, NULL, NULL);
+
+ if (str == NULL || (ptr = allocstr(str)) == NULL)
+ str = error;
+ else {
+ while (*ptr) {
+ int count = strcspn(ptr, ", \t");
+ ptr += count;
+ if (*ptr)
+ *ptr++ = ':';
+ }
+ }
+ return str;
+}
+
+
+/*
+ * login_getcaptime()
+ * From the login_cap_t <lc>, get the capability <cap>, which is
+ * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
+ * present in <lc>, return <def>; if there is an error of some kind,
+ * return <error>.
+ */
+
+rlim_t
+login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *res, *ep;
+ int ret;
+ rlim_t tot = 0, tim;
+
+ errno = 0;
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * Look for <cap> in lc_cap.
+ * If it's not there (-1), return <def>.
+ * If there's an error, return <error>.
+ */
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
+ return def;
+ else if (ret < 0)
+ return error;
+
+ /*
+ * "inf" and "infinity" are two special cases for this.
+ */
+ if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
+ return RLIM_INFINITY;
+
+ /*
+ * Now go through the string, turning something like 1h2m3s into
+ * an integral value. Whee.
+ */
+
+ errno = 0;
+ while (*res) {
+ tim = STRTOV(res, &ep, 0);
+ if ((ep == NULL) || (ep == res) || errno) {
+ return error;
+ }
+ /* Look for suffixes */
+ switch (*ep++) {
+ case 0:
+ ep--; break; /* end of string */
+ case 's': case 'S': /* seconds */
+ break;
+ case 'm': case 'M': /* minutes */
+ tim *= 60L;
+ break;
+ case 'h': case 'H': /* hours */
+ tim *= (60L * 60L);
+ break;
+ case 'd': case 'D': /* days */
+ tim *= (60L * 60L * 24L);
+ break;
+ case 'w': case 'W': /* weeks */
+ tim *= (60L * 60L * 24L * 7L);
+ case 'y': case 'Y': /* Years */
+ /* I refuse to take leap years into account here. Sue me. */
+ tim *= (60L * 60L * 24L * 365L);
+ default:
+ return error;
+ }
+ res = ep;
+ tot += tim;
+ }
+ return tot;
+}
+
+
+/*
+ * login_getcapnum()
+ * From the login_cap_t <lc>, extract the numerical value <cap>.
+ * If it is not present, return <def> for a default, and return
+ * <error> if there is an error.
+ * Like login_getcaptime(), only it only converts to a number, not
+ * to a time; "infinity" and "inf" are 'special.'
+ */
+
+rlim_t
+login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
+{
+ char *ep, *res;
+ int ret;
+ rlim_t val;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ /*
+ * For BSDI compatibility, try for the tag=<val> first
+ */
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) {
+ long lval;
+ /*
+ * String capability not present, so try for tag#<val> as numeric
+ */
+ if ((ret = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1)
+ return def; /* Not there, so return default */
+ else if (ret < 0)
+ return error;
+ return (rlim_t)lval;
+ }
+ else if (ret < 0)
+ return error;
+
+ if (!strcasecmp(res, "infinity") || !strcasecmp(res, "inf"))
+ return RLIM_INFINITY;
+
+ errno = 0;
+ val = STRTOV(res, &ep, 0);
+ if ((ep == NULL) || (ep == res) || errno)
+ return error;
+ return val;
+}
+
+
+/*
+ * login_getcapsize()
+ * From the login_cap_t <lc>, extract the capability <cap>, which is
+ * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
+ * If not present, return <def>, or <error> if there is an error of
+ * some sort.
+ */
+
+rlim_t
+login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) {
+ char *ep, *res;
+ int ret;
+ rlim_t val;
+ rlim_t mult;
+
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+
+ if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1)
+ return def;
+ else if (ret < 0)
+ return error;
+
+ errno = 0;
+ val = STRTOV(res, &ep, 0);
+ if ((res == NULL) || (res == ep) || errno)
+ return error;
+ switch (*ep) {
+ case 0: /* end of string */
+ mult = 1; break;
+ case 'b': case 'B': /* 512-byte blocks */
+ mult = 512; break;
+ case 'k': case 'K': /* 1024-byte Kilobytes */
+ mult = 1024; break;
+ case 'm': case 'M': /* 1024-k kbytes */
+ mult = 1024 * 1024; break;
+ case 'g': case 'G': /* 1Gbyte */
+ mult = 1024 * 1024 * 1024; break;
+#ifndef RLIM_LONG
+ case 't': case 'T': /* 1TBte */
+ mult = 1024LL * 1024LL * 1024LL * 1024LL; break;
+#endif
+ default:
+ return error;
+ }
+ return val * mult;
+}
+
+
+/*
+ * login_getcapbool()
+ * From the login_cap_t <lc>, check for the existance of the capability
+ * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
+ * the whether or not <cap> exists there.
+ */
+
+int
+login_getcapbool(login_cap_t *lc, const char *cap, int def)
+{
+ if (lc == NULL || lc->lc_cap == NULL)
+ return def;
+ return (cgetcap(lc->lc_cap, (char *)cap, ':') != NULL);
+}
+
+
+/*
+ * login_getstyle()
+ * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
+ * and optionally a style <style>, find the style that best suits these
+ * rules:
+ * 1. If <auth> is non-null, look for an "auth-<auth>=" string
+ * in the capability; if not present, default to "auth=".
+ * 2. If there is no auth list found from (1), default to
+ * "passwd" as an authorization list.
+ * 3. If <style> is non-null, look for <style> in the list of
+ * authorization methods found from (2); if <style> is NULL, default
+ * to LOGIN_DEFSTYLE ("passwd").
+ * 4. If the chosen style is found in the chosen list of authorization
+ * methods, return that; otherwise, return NULL.
+ * E.g.:
+ * login_getstyle(lc, NULL, "ftp");
+ * login_getstyle(lc, "login", NULL);
+ * login_getstyle(lc, "skey", "network");
+ */
+
+char *
+login_getstyle(login_cap_t *lc, char *style, const char *auth)
+{
+ int i;
+ char **authtypes = NULL;
+ char *auths= NULL;
+ char realauth[64];
+
+ static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
+
+ if (auth != NULL && *auth != '\0' &&
+ snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth)
+ authtypes = login_getcaplist(lc, realauth, NULL);
+
+ if (authtypes == NULL)
+ authtypes = login_getcaplist(lc, "auth", NULL);
+
+ if (authtypes == NULL)
+ authtypes = defauthtypes;
+
+ /*
+ * We have at least one authtype now; auths is a comma-seperated
+ * (or space-separated) list of authentication types. We have to
+ * convert from this to an array of char*'s; authtypes then gets this.
+ */
+ i = 0;
+ if (style != NULL && *style != '\0') {
+ while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
+ i++;
+ }
+ lc->lc_style = NULL;
+ if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
+ lc->lc_style = auths;
+
+ return lc->lc_style;
+}
+
+