From dcc82deaf0f0224d8d7b211f93dc4dc0e02e4cbf Mon Sep 17 00:00:00 2001 From: David Nugent Date: Sat, 4 Jan 1997 16:50:08 +0000 Subject: Library functions relating to the login class capabilities database, including manpages. See also login_cap.h. --- libutil/login_cap.c | 564 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 libutil/login_cap.c (limited to 'libutil') 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 + * David Nugent + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 seperated by any of + * the set of 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 , get the capability 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 . + */ + +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 , get the capability , which is + * formatted as a time (e.g., "=10h3m2s"). If is not + * present in , return ; if there is an error of some kind, + * return . + */ + +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 in lc_cap. + * If it's not there (-1), return . + * If there's an error, return . + */ + + 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 , extract the numerical value . + * If it is not present, return for a default, and return + * 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= first + */ + if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { + long lval; + /* + * String capability not present, so try for tag# 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 , extract the capability , which is + * formatted as a size (e.g., "=10M"); it can also be "infinity". + * If not present, return , or 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 , check for the existance of the capability + * of . Return if ->lc_cap is NULL, otherwise return + * the whether or not 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 , and optionally a type of auth , + * and optionally a style