X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/dc0fc8f2227eaf41141653427ab3f22806bc819a..4094297a53a478f9ed7c4160ed63842a19717ba9:/libutil/login_cap.c diff --git a/libutil/login_cap.c b/libutil/login_cap.c index af27766..9c8d4a6 100644 --- a/libutil/login_cap.c +++ b/libutil/login_cap.c @@ -24,25 +24,25 @@ * conditions are met. * * Low-level routines relating to the user capabilities database - * - * $FreeBSD$ */ -#include -#include -#include -#include -#include -#include +#include +__FBSDID("$FreeBSD$"); #include #include #include #include -#include +#include +#include #include -#include #include +#include +#include +#include +#include +#include +#include /* * allocstr() @@ -59,10 +59,12 @@ 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 const char ** internal_array = NULL; + +static char path_login_conf[] = _PATH_LOGIN_CONF; static char * -allocstr(char *str) +allocstr(const char *str) { char *p; @@ -77,10 +79,10 @@ allocstr(char *str) } -static char ** +static const char ** allocarray(size_t sz) { - char **p; + static const char **p; if (sz <= internal_arraysz) p = internal_array; @@ -94,31 +96,32 @@ allocarray(size_t sz) /* * arrayize() - * Turn a simple string seperated by any of + * Turn a simple string separated 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) +static const char ** +arrayize(const char *str, const char *chars, int *size) { int i; - char *ptr; - char **res = NULL; + char *ptr; + const char *cptr; + const char **res = NULL; /* count the sub-strings */ - for (i = 0, ptr = str; *ptr; i++) { - int count = strcspn(ptr, chars); - ptr += count; - if (*ptr) - ++ptr; + for (i = 0, cptr = str; *cptr; i++) { + int count = strcspn(cptr, chars); + cptr += count; + if (*cptr) + ++cptr; } /* alloc the array */ if ((ptr = allocstr(str)) != NULL) { if ((res = allocarray(++i)) == NULL) - free(str); + free((void *)(uintptr_t)(const void *)str); else { /* now split the string */ i = 0; @@ -152,6 +155,7 @@ login_close(login_cap_t * lc) if (lc) { free(lc->lc_style); free(lc->lc_class); + free(lc->lc_cap); free(lc); if (--lc_object_count == 0) { free(internal_string); @@ -167,12 +171,16 @@ login_close(login_cap_t * lc) /* - * login_getclassbyname() get the login class by its name. + * 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. + * LOGIN_DEFCLASS (i.e., "default") is fetched. + * If the name given is LOGIN_MECLASS and + * 'pwd' argument is non-NULL and contains an non-NULL + * dir entry, then the file _FILE_LOGIN_CONF is picked + * up from that directory and used before the system + * login database. In that case the system login database + * is looked up using LOGIN_MECLASS, too, which is a bug. * Return a filled-out login_cap_t structure, including * class name, and the capability record buffer. */ @@ -183,17 +191,23 @@ login_getclassbyname(char const *name, const struct passwd *pwd) login_cap_t *lc; if ((lc = malloc(sizeof(login_cap_t))) != NULL) { - int r, i = 0; + int r, me, i = 0; uid_t euid = 0; gid_t egid = 0; const char *msg = NULL; - const char *dir = (pwd == NULL) ? NULL : pwd->pw_dir; + const char *dir; char userpath[MAXPATHLEN]; static char *login_dbarray[] = { NULL, NULL, NULL }; - /* Switch to user mode before checking/reading its ~/.login_conf */ - /* - some NFSes have root read access disabled. */ + me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); + dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; + /* + * Switch to user mode before checking/reading its ~/.login_conf + * - some NFSes have root read access disabled. + * + * XXX: This fails to configure additional groups. + */ if (dir) { euid = geteuid(); egid = getegid(); @@ -203,12 +217,14 @@ login_getclassbyname(char const *name, const struct passwd *pwd) if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, _FILE_LOGIN_CONF) < MAXPATHLEN) { - login_dbarray[i] = userpath; if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) - i++; /* only use 'secure' data */ + login_dbarray[i++] = userpath; } - if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1) - login_dbarray[i++] = _PATH_LOGIN_CONF; + /* + * XXX: Why to add the system database if the class is `me'? + */ + if (_secure_path(path_login_conf, 0, 0) != -1) + login_dbarray[i++] = path_login_conf; login_dbarray[i] = NULL; memset(lc, 0, sizeof(login_cap_t)); @@ -217,13 +233,13 @@ login_getclassbyname(char const *name, const struct passwd *pwd) if (name == NULL || *name == '\0') name = LOGIN_DEFCLASS; - switch (cgetent(&lc->lc_cap, login_dbarray, (char*)name)) { + switch (cgetent(&lc->lc_cap, login_dbarray, name)) { case -1: /* Failed, entry does not exist */ - if (strcmp(name, LOGIN_MECLASS) == 0) + if (me) break; /* Don't retry default on 'me' */ if (i == 0) r = -1; - else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0) + else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) close(r); /* * If there's at least one login class database, @@ -235,9 +251,9 @@ login_getclassbyname(char const *name, const struct passwd *pwd) /* fall-back to default class */ name = LOGIN_DEFCLASS; msg = "%s: no default/fallback class '%s'"; - if (cgetent(&lc->lc_cap, login_dbarray, (char*)name) != 0 && r >= 0) + if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) break; - /* Fallthru - just return system defaults */ + /* FALLTHROUGH - just return system defaults */ case 0: /* success! */ if ((lc->lc_class = strdup(name)) != NULL) { if (dir) { @@ -291,12 +307,13 @@ login_getclass(const char *cls) /* - * login_getclass() + * login_getpwclass() * 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"). + * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged + * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. * Return a filled-out login_cap_t structure, including * class name, and the capability record buffer. */ @@ -311,14 +328,18 @@ login_getpwclass(const struct passwd *pwd) if (cls == NULL || *cls == '\0') cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; } + /* + * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', + * so NULL can be passed instead of pwd for more safety. + */ return login_getclassbyname(cls, pwd); } /* * login_getuserclass() - * Get the login class for a given password entry, allowing user - * overrides via ~/.login_conf. + * Get the `me' login class, allowing user overrides via ~/.login_conf. + * Note that user overrides are allowed only in the `me' class. */ login_cap_t * @@ -328,16 +349,15 @@ login_getuserclass(const struct passwd *pwd) } - /* * login_getcapstr() * Given a login_cap entry, and a capability name, return the - * value defined for that capability, a defualt if not found, or + * value defined for that capability, a default if not found, or * an error string on error. */ -char * -login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) +const char * +login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) { char *res; int ret; @@ -345,7 +365,7 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') return def; - if ((ret = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; return (ret >= 0) ? res : error; } @@ -358,14 +378,14 @@ login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *error) * strings. */ -char ** +const char ** login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) { - char *lstring; + const char *lstring; if (chars == NULL) chars = ", \t"; - if ((lstring = login_getcapstr(lc, (char*)cap, NULL, NULL)) != NULL) + if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) return arrayize(lstring, chars, NULL); return NULL; } @@ -379,22 +399,22 @@ login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) * If there is an error of any kind, return . */ -char * -login_getpath(login_cap_t *lc, const char *cap, char * error) +const char * +login_getpath(login_cap_t *lc, const char *cap, const char *error) { - char *str; - - if ((str = login_getcapstr(lc, (char*)cap, NULL, NULL)) == NULL) - str = error; - else { - char *ptr = str; - - while (*ptr) { - int count = strcspn(ptr, ", \t"); - ptr += count; - if (*ptr) - *ptr++ = ':'; - } + const char *str; + char *ptr; + int count; + + str = login_getcapstr(lc, cap, NULL, NULL); + if (str == NULL) + return error; + ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ + while (*ptr) { + count = strcspn(ptr, ", \t"); + ptr += count; + if (*ptr) + *ptr++ = ':'; } return str; } @@ -528,7 +548,7 @@ login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) * If there's an error, return . */ - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; else if (r < 0) { errno = ERANGE; @@ -615,10 +635,10 @@ login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) /* * For BSDI compatibility, try for the tag= first */ - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) { + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) { long lval; /* string capability not present, so try for tag# as numeric */ - if ((r = cgetnum(lc->lc_cap, (char *)cap, &lval)) == -1) + if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) return def; /* Not there, so return default */ else if (r >= 0) return (rlim_t)lval; @@ -664,7 +684,7 @@ login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) if (lc == NULL || lc->lc_cap == NULL) return def; - if ((r = cgetstr(lc->lc_cap, (char *)cap, &res)) == -1) + if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) return def; else if (r < 0) { errno = ERANGE; @@ -722,7 +742,7 @@ login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) /* * login_getcapbool() - * From the login_cap_t , check for the existance of the capability + * From the login_cap_t , check for the existence of the capability * of . Return if ->lc_cap is NULL, otherwise return * the whether or not exists there. */ @@ -732,7 +752,7 @@ 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); + return (cgetcap(lc->lc_cap, cap, ':') != NULL); } @@ -756,18 +776,18 @@ login_getcapbool(login_cap_t *lc, const char *cap, int def) * login_getstyle(lc, "skey", "network"); */ -char * -login_getstyle(login_cap_t *lc, char *style, const char *auth) +const char * +login_getstyle(login_cap_t *lc, const char *style, const char *auth) { int i; - char **authtypes = NULL; + const char **authtypes = NULL; char *auths= NULL; char realauth[64]; - static char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; + static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; if (auth != NULL && *auth != '\0') { - if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < sizeof realauth) + if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) authtypes = login_getcaplist(lc, realauth, NULL); } @@ -778,7 +798,7 @@ login_getstyle(login_cap_t *lc, char *style, const char *auth) authtypes = defauthtypes; /* - * We have at least one authtype now; auths is a comma-seperated + * We have at least one authtype now; auths is a comma-separated * (or space-separated) list of authentication types. We have to * convert from this to an array of char*'s; authtypes then gets this. */