168bbf3adSDavid Nugent /*- 268bbf3adSDavid Nugent * Copyright (c) 1996 by 368bbf3adSDavid Nugent * Sean Eric Fagan <sef@kithrup.com> 468bbf3adSDavid Nugent * David Nugent <davidn@blaze.net.au> 568bbf3adSDavid Nugent * All rights reserved. 668bbf3adSDavid Nugent * 756c04344SDavid Nugent * Portions copyright (c) 1995,1997 856c04344SDavid Nugent * Berkeley Software Design, Inc. 956c04344SDavid Nugent * All rights reserved. 1056c04344SDavid Nugent * 1168bbf3adSDavid Nugent * Redistribution and use in source and binary forms, with or without 1268bbf3adSDavid Nugent * modification, is permitted provided that the following conditions 1368bbf3adSDavid Nugent * are met: 1468bbf3adSDavid Nugent * 1. Redistributions of source code must retain the above copyright 1568bbf3adSDavid Nugent * notice immediately at the beginning of the file, without modification, 1668bbf3adSDavid Nugent * this list of conditions, and the following disclaimer. 1768bbf3adSDavid Nugent * 2. Redistributions in binary form must reproduce the above copyright 1868bbf3adSDavid Nugent * notice, this list of conditions and the following disclaimer in the 1968bbf3adSDavid Nugent * documentation and/or other materials provided with the distribution. 2068bbf3adSDavid Nugent * 3. This work was done expressly for inclusion into FreeBSD. Other use 2168bbf3adSDavid Nugent * is permitted provided this notation is included. 2268bbf3adSDavid Nugent * 4. Absolutely no warranty of function or purpose is made by the authors. 2368bbf3adSDavid Nugent * 5. Modifications may be freely made to this file providing the above 2468bbf3adSDavid Nugent * conditions are met. 2568bbf3adSDavid Nugent * 2668bbf3adSDavid Nugent * Low-level routines relating to the user capabilities database 2768bbf3adSDavid Nugent */ 2868bbf3adSDavid Nugent 298719c58fSMatthew Dillon #include <sys/cdefs.h> 3068bbf3adSDavid Nugent #include <sys/types.h> 3168bbf3adSDavid Nugent #include <sys/time.h> 3268bbf3adSDavid Nugent #include <sys/resource.h> 3368bbf3adSDavid Nugent #include <sys/param.h> 340ebec5d3SMark Murray #include <errno.h> 350ebec5d3SMark Murray #include <fcntl.h> 3656c04344SDavid Nugent #include <libutil.h> 3768bbf3adSDavid Nugent #include <login_cap.h> 380ebec5d3SMark Murray #include <pwd.h> 390ebec5d3SMark Murray #include <stdio.h> 400ebec5d3SMark Murray #include <stdlib.h> 410ebec5d3SMark Murray #include <string.h> 420ebec5d3SMark Murray #include <syslog.h> 430ebec5d3SMark Murray #include <unistd.h> 4468bbf3adSDavid Nugent 4556c04344SDavid Nugent /* 4656c04344SDavid Nugent * allocstr() 4756c04344SDavid Nugent * Manage a single static pointer for handling a local char* buffer, 4856c04344SDavid Nugent * resizing as necessary to contain the string. 4956c04344SDavid Nugent * 5056c04344SDavid Nugent * allocarray() 5156c04344SDavid Nugent * Manage a static array for handling a group of strings, resizing 5256c04344SDavid Nugent * when necessary. 5356c04344SDavid Nugent */ 5468bbf3adSDavid Nugent 5568bbf3adSDavid Nugent static int lc_object_count = 0; 5668bbf3adSDavid Nugent 5768bbf3adSDavid Nugent static size_t internal_stringsz = 0; 5868bbf3adSDavid Nugent static char * internal_string = NULL; 5968bbf3adSDavid Nugent static size_t internal_arraysz = 0; 60547fa0d9SMark Murray static const char ** internal_array = NULL; 6168bbf3adSDavid Nugent 62b8a5cd86SDag-Erling Smørgrav static char path_login_conf[] = _PATH_LOGIN_CONF; 63b8a5cd86SDag-Erling Smørgrav 6468bbf3adSDavid Nugent static char * 65547fa0d9SMark Murray allocstr(const char *str) 6668bbf3adSDavid Nugent { 6768bbf3adSDavid Nugent char *p; 6856c04344SDavid Nugent 6968bbf3adSDavid Nugent size_t sz = strlen(str) + 1; /* realloc() only if necessary */ 7068bbf3adSDavid Nugent if (sz <= internal_stringsz) 711c594de5SDavid Nugent p = strcpy(internal_string, str); 7268bbf3adSDavid Nugent else if ((p = realloc(internal_string, sz)) != NULL) { 7368bbf3adSDavid Nugent internal_stringsz = sz; 7468bbf3adSDavid Nugent internal_string = strcpy(p, str); 7568bbf3adSDavid Nugent } 7668bbf3adSDavid Nugent return p; 7768bbf3adSDavid Nugent } 7868bbf3adSDavid Nugent 7956c04344SDavid Nugent 80547fa0d9SMark Murray static const char ** 8168bbf3adSDavid Nugent allocarray(size_t sz) 8268bbf3adSDavid Nugent { 83547fa0d9SMark Murray static const char **p; 8456c04344SDavid Nugent 8568bbf3adSDavid Nugent if (sz <= internal_arraysz) 8668bbf3adSDavid Nugent p = internal_array; 87efa8af7cSPedro F. Giffuni else if ((p = reallocarray(internal_array, sz, sizeof(char*))) != NULL) { 8868bbf3adSDavid Nugent internal_arraysz = sz; 8968bbf3adSDavid Nugent internal_array = p; 9068bbf3adSDavid Nugent } 9168bbf3adSDavid Nugent return p; 9268bbf3adSDavid Nugent } 9368bbf3adSDavid Nugent 9468bbf3adSDavid Nugent 9568bbf3adSDavid Nugent /* 96f32db406SSean Eric Fagan * This is a variant of strcspn, which checks for quoted 97f32db406SSean Eric Fagan * strings. That is,: 98f32db406SSean Eric Fagan * strcspn_quote("how 'now, brown' cow", ",", NULL); 99f32db406SSean Eric Fagan * will return the index for the nul, rather than the comma, because 100f32db406SSean Eric Fagan * the string is quoted. It does not handle escaped characters 101f32db406SSean Eric Fagan * at this time. 102f32db406SSean Eric Fagan */ 103f32db406SSean Eric Fagan static size_t 104f32db406SSean Eric Fagan strcspn_quote(const char *str, const char *exclude, int *is_quoted) 105f32db406SSean Eric Fagan { 106f32db406SSean Eric Fagan size_t indx = 0; 107f32db406SSean Eric Fagan char quote = 0; 108f32db406SSean Eric Fagan 109f32db406SSean Eric Fagan if (str == NULL) 110f32db406SSean Eric Fagan return 0; 111f32db406SSean Eric Fagan 112f32db406SSean Eric Fagan if (is_quoted) 113f32db406SSean Eric Fagan *is_quoted = 0; 114f32db406SSean Eric Fagan 115f32db406SSean Eric Fagan for (indx = 0; str[indx] != 0; indx++) { 116f32db406SSean Eric Fagan if (quote && str[indx] == quote) { 117f32db406SSean Eric Fagan if (is_quoted) 118f32db406SSean Eric Fagan *is_quoted = 1; 119f32db406SSean Eric Fagan quote = 0; 120f32db406SSean Eric Fagan continue; 121f32db406SSean Eric Fagan } 122f32db406SSean Eric Fagan if (quote == 0 && 123f32db406SSean Eric Fagan (str[indx] == '\'' || str[indx] == '"')) { 124f32db406SSean Eric Fagan quote = str[indx]; 125f32db406SSean Eric Fagan continue; 126f32db406SSean Eric Fagan } 127f32db406SSean Eric Fagan if (quote == 0 && 128f32db406SSean Eric Fagan strchr(exclude, str[indx]) != NULL) 129f32db406SSean Eric Fagan return indx; 130f32db406SSean Eric Fagan } 131f32db406SSean Eric Fagan return indx; 132f32db406SSean Eric Fagan } 133f32db406SSean Eric Fagan 134f32db406SSean Eric Fagan /* 135f32db406SSean Eric Fagan * Remove quotes from the given string. 136f32db406SSean Eric Fagan * It's a very simplistic approach: the first 137f32db406SSean Eric Fagan * single or double quote it finds, it looks for 138f32db406SSean Eric Fagan * the next one, and if it finds it, moves the 139f32db406SSean Eric Fagan * entire string backwards in two chunks 140f32db406SSean Eric Fagan * (first quote + 1 to first quote, length 141f32db406SSean Eric Fagan * rest of string, and then second quote + 1 142f32db406SSean Eric Fagan * to second quote, length rest of the string). 143f32db406SSean Eric Fagan */ 144f32db406SSean Eric Fagan static void 145f32db406SSean Eric Fagan remove_quotes(char *str) 146f32db406SSean Eric Fagan { 147f32db406SSean Eric Fagan static const char *quote_chars = "'\""; 148f32db406SSean Eric Fagan char qc = 0; 149f32db406SSean Eric Fagan int found = 0; 150f32db406SSean Eric Fagan 151f32db406SSean Eric Fagan do { 152f32db406SSean Eric Fagan char *loc = NULL; 153f32db406SSean Eric Fagan 154f32db406SSean Eric Fagan found = 0; 155f32db406SSean Eric Fagan /* 156f32db406SSean Eric Fagan * If qc is 0, then we haven't found 157f32db406SSean Eric Fagan * a quote yet, so do a strcspn search. 158f32db406SSean Eric Fagan */ 159f32db406SSean Eric Fagan if (qc == 0) { 160f32db406SSean Eric Fagan size_t indx; 161f32db406SSean Eric Fagan indx = strcspn(str, quote_chars); 162f32db406SSean Eric Fagan if (str[indx] == '\0') 163f32db406SSean Eric Fagan return; /* We're done */ 164f32db406SSean Eric Fagan loc = str + indx; 165f32db406SSean Eric Fagan qc = str[indx]; 166f32db406SSean Eric Fagan } else { 167f32db406SSean Eric Fagan /* 168f32db406SSean Eric Fagan * We've found a quote character, 169f32db406SSean Eric Fagan * so use strchr to find the next one. 170f32db406SSean Eric Fagan */ 171f32db406SSean Eric Fagan loc = strchr(str, qc); 172f32db406SSean Eric Fagan if (loc == NULL) 173f32db406SSean Eric Fagan return; 174f32db406SSean Eric Fagan qc = 0; 175f32db406SSean Eric Fagan } 176f32db406SSean Eric Fagan if (loc) { 177f32db406SSean Eric Fagan /* 178f32db406SSean Eric Fagan * This gives us the location of the 179f32db406SSean Eric Fagan * quoted character. We need to move 180f32db406SSean Eric Fagan * the entire string down, from loc+1 181f32db406SSean Eric Fagan * to loc. 182f32db406SSean Eric Fagan */ 183f32db406SSean Eric Fagan size_t len = strlen(loc + 1) + 1; 184f32db406SSean Eric Fagan memmove(loc, loc + 1, len); 185f32db406SSean Eric Fagan found = 1; 186f32db406SSean Eric Fagan } 187f32db406SSean Eric Fagan } while (found != 0); 188f32db406SSean Eric Fagan } 189f32db406SSean Eric Fagan 190f32db406SSean Eric Fagan /* 19168bbf3adSDavid Nugent * arrayize() 1929a01d32bSJeroen Ruigrok van der Werven * Turn a simple string <str> separated by any of 19368bbf3adSDavid Nugent * the set of <chars> into an array. The last element 19468bbf3adSDavid Nugent * of the array will be NULL, as is proper. 19568bbf3adSDavid Nugent * Free using freearraystr() 19668bbf3adSDavid Nugent */ 19768bbf3adSDavid Nugent 198547fa0d9SMark Murray static const char ** 199547fa0d9SMark Murray arrayize(const char *str, const char *chars, int *size) 20068bbf3adSDavid Nugent { 20168bbf3adSDavid Nugent int i; 20205bcd1d0SPeter Wemm char *ptr; 20305bcd1d0SPeter Wemm const char *cptr; 204547fa0d9SMark Murray const char **res = NULL; 20568bbf3adSDavid Nugent 20656c04344SDavid Nugent /* count the sub-strings */ 20705bcd1d0SPeter Wemm for (i = 0, cptr = str; *cptr; i++) { 208f32db406SSean Eric Fagan int count = strcspn_quote(cptr, chars, NULL); 20905bcd1d0SPeter Wemm cptr += count; 21005bcd1d0SPeter Wemm if (*cptr) 21105bcd1d0SPeter Wemm ++cptr; 21268bbf3adSDavid Nugent } 21368bbf3adSDavid Nugent 21456c04344SDavid Nugent /* alloc the array */ 21556c04344SDavid Nugent if ((ptr = allocstr(str)) != NULL) { 21656c04344SDavid Nugent if ((res = allocarray(++i)) == NULL) 21705bcd1d0SPeter Wemm free((void *)(uintptr_t)(const void *)str); 21856c04344SDavid Nugent else { 21956c04344SDavid Nugent /* now split the string */ 2205f3a7367SDavid Nugent i = 0; 22156c04344SDavid Nugent while (*ptr) { 222f32db406SSean Eric Fagan int quoted = 0; 223f32db406SSean Eric Fagan int count = strcspn_quote(ptr, chars, "ed); 224f32db406SSean Eric Fagan char *base = ptr; 22556c04344SDavid Nugent res[i++] = ptr; 22668bbf3adSDavid Nugent ptr += count; 22768bbf3adSDavid Nugent if (*ptr) 22868bbf3adSDavid Nugent *ptr++ = '\0'; 229f32db406SSean Eric Fagan /* 230f32db406SSean Eric Fagan * If the string contains a quoted element, we 231f32db406SSean Eric Fagan * need to remove the quotes. 232f32db406SSean Eric Fagan */ 233f32db406SSean Eric Fagan if (quoted) { 234f32db406SSean Eric Fagan remove_quotes(base); 235f32db406SSean Eric Fagan } 236f32db406SSean Eric Fagan 23768bbf3adSDavid Nugent } 23856c04344SDavid Nugent res[i] = NULL; 23968bbf3adSDavid Nugent } 24056c04344SDavid Nugent } 24156c04344SDavid Nugent 24268bbf3adSDavid Nugent if (size) 24368bbf3adSDavid Nugent *size = i; 24456c04344SDavid Nugent 24568bbf3adSDavid Nugent return res; 24668bbf3adSDavid Nugent } 24768bbf3adSDavid Nugent 24856c04344SDavid Nugent 24968bbf3adSDavid Nugent /* 25068bbf3adSDavid Nugent * login_close() 25168bbf3adSDavid Nugent * Frees up all resources relating to a login class 25268bbf3adSDavid Nugent * 25368bbf3adSDavid Nugent */ 25468bbf3adSDavid Nugent 25568bbf3adSDavid Nugent void 25668bbf3adSDavid Nugent login_close(login_cap_t * lc) 25768bbf3adSDavid Nugent { 25868bbf3adSDavid Nugent if (lc) { 25968bbf3adSDavid Nugent free(lc->lc_style); 26068bbf3adSDavid Nugent free(lc->lc_class); 2613f81737fSTim Vanderhoek free(lc->lc_cap); 26268bbf3adSDavid Nugent free(lc); 26368bbf3adSDavid Nugent if (--lc_object_count == 0) { 26468bbf3adSDavid Nugent free(internal_string); 2652955fda4SDavid Nugent free(internal_array); 26668bbf3adSDavid Nugent internal_array = NULL; 26751706563SDavid Nugent internal_arraysz = 0; 26868bbf3adSDavid Nugent internal_string = NULL; 26951706563SDavid Nugent internal_stringsz = 0; 27068bbf3adSDavid Nugent cgetclose(); 27168bbf3adSDavid Nugent } 27268bbf3adSDavid Nugent } 27368bbf3adSDavid Nugent } 27468bbf3adSDavid Nugent 27568bbf3adSDavid Nugent 27668bbf3adSDavid Nugent /* 277a7429823SYaroslav Tykhiy * login_getclassbyname() 278a7429823SYaroslav Tykhiy * Get the login class by its name. 27968bbf3adSDavid Nugent * If the name given is NULL or empty, the default class 280a7429823SYaroslav Tykhiy * LOGIN_DEFCLASS (i.e., "default") is fetched. 281a7429823SYaroslav Tykhiy * If the name given is LOGIN_MECLASS and 28294cf9da0SDiomidis Spinellis * 'pwd' argument is non-NULL and contains an non-NULL 28394cf9da0SDiomidis Spinellis * dir entry, then the file _FILE_LOGIN_CONF is picked 28494cf9da0SDiomidis Spinellis * up from that directory and used before the system 285a7429823SYaroslav Tykhiy * login database. In that case the system login database 286a7429823SYaroslav Tykhiy * is looked up using LOGIN_MECLASS, too, which is a bug. 28768bbf3adSDavid Nugent * Return a filled-out login_cap_t structure, including 28868bbf3adSDavid Nugent * class name, and the capability record buffer. 28968bbf3adSDavid Nugent */ 29068bbf3adSDavid Nugent 29168bbf3adSDavid Nugent login_cap_t * 29256c04344SDavid Nugent login_getclassbyname(char const *name, const struct passwd *pwd) 29368bbf3adSDavid Nugent { 29456c04344SDavid Nugent login_cap_t *lc; 29568bbf3adSDavid Nugent 2969df529b8SXin LI if ((lc = calloc(1, sizeof(login_cap_t))) != NULL) { 297e36b245cSAndrey A. Chernov int r, me, i = 0; 2988a2deaa1SAndrey A. Chernov uid_t euid = 0; 2998a2deaa1SAndrey A. Chernov gid_t egid = 0; 30056c04344SDavid Nugent const char *msg = NULL; 301e36b245cSAndrey A. Chernov const char *dir; 30268bbf3adSDavid Nugent char userpath[MAXPATHLEN]; 30356c04344SDavid Nugent 30405bcd1d0SPeter Wemm static char *login_dbarray[] = { NULL, NULL, NULL }; 30568bbf3adSDavid Nugent 306e36b245cSAndrey A. Chernov me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); 307e36b245cSAndrey A. Chernov dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; 3088df8b73fSRobert Watson /* 3098df8b73fSRobert Watson * Switch to user mode before checking/reading its ~/.login_conf 3108df8b73fSRobert Watson * - some NFSes have root read access disabled. 3118df8b73fSRobert Watson * 3128df8b73fSRobert Watson * XXX: This fails to configure additional groups. 3138df8b73fSRobert Watson */ 3148a2deaa1SAndrey A. Chernov if (dir) { 315ae702574SAndrey A. Chernov euid = geteuid(); 316ae702574SAndrey A. Chernov egid = getegid(); 317ae702574SAndrey A. Chernov (void)setegid(pwd->pw_gid); 318ae702574SAndrey A. Chernov (void)seteuid(pwd->pw_uid); 3198a2deaa1SAndrey A. Chernov } 320ae702574SAndrey A. Chernov 32156c04344SDavid Nugent if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, 32256c04344SDavid Nugent _FILE_LOGIN_CONF) < MAXPATHLEN) { 32356c04344SDavid Nugent if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) 324b8a5cd86SDag-Erling Smørgrav login_dbarray[i++] = userpath; 32556c04344SDavid Nugent } 326a7429823SYaroslav Tykhiy /* 327a7429823SYaroslav Tykhiy * XXX: Why to add the system database if the class is `me'? 328a7429823SYaroslav Tykhiy */ 329b8a5cd86SDag-Erling Smørgrav if (_secure_path(path_login_conf, 0, 0) != -1) 330b8a5cd86SDag-Erling Smørgrav login_dbarray[i++] = path_login_conf; 33168bbf3adSDavid Nugent login_dbarray[i] = NULL; 33268bbf3adSDavid Nugent 33356c04344SDavid Nugent if (name == NULL || *name == '\0') 33456c04344SDavid Nugent name = LOGIN_DEFCLASS; 33568bbf3adSDavid Nugent 336547fa0d9SMark Murray switch (cgetent(&lc->lc_cap, login_dbarray, name)) { 33756c04344SDavid Nugent case -1: /* Failed, entry does not exist */ 338e36b245cSAndrey A. Chernov if (me) 33956c04344SDavid Nugent break; /* Don't retry default on 'me' */ 34056c04344SDavid Nugent if (i == 0) 34156c04344SDavid Nugent r = -1; 342d1d4d952SJilles Tjoelker else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) 34356c04344SDavid Nugent close(r); 34456c04344SDavid Nugent /* 34556c04344SDavid Nugent * If there's at least one login class database, 34656c04344SDavid Nugent * and we aren't searching for a default class 34756c04344SDavid Nugent * then complain about a non-existent class. 34856c04344SDavid Nugent */ 34956c04344SDavid Nugent if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0) 35056c04344SDavid Nugent syslog(LOG_ERR, "login_getclass: unknown class '%s'", name); 35156c04344SDavid Nugent /* fall-back to default class */ 35256c04344SDavid Nugent name = LOGIN_DEFCLASS; 35356c04344SDavid Nugent msg = "%s: no default/fallback class '%s'"; 354547fa0d9SMark Murray if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) 35556c04344SDavid Nugent break; 3567fed38d0SPhilippe Charnier /* FALLTHROUGH - just return system defaults */ 35756c04344SDavid Nugent case 0: /* success! */ 35856c04344SDavid Nugent if ((lc->lc_class = strdup(name)) != NULL) { 3598a2deaa1SAndrey A. Chernov if (dir) { 360ae702574SAndrey A. Chernov (void)seteuid(euid); 361ae702574SAndrey A. Chernov (void)setegid(egid); 3628a2deaa1SAndrey A. Chernov } 36356c04344SDavid Nugent ++lc_object_count; 36468bbf3adSDavid Nugent return lc; 36568bbf3adSDavid Nugent } 36656c04344SDavid Nugent msg = "%s: strdup: %m"; 36756c04344SDavid Nugent break; 36856c04344SDavid Nugent case -2: 36956c04344SDavid Nugent msg = "%s: retrieving class information: %m"; 37056c04344SDavid Nugent break; 37156c04344SDavid Nugent case -3: 37256c04344SDavid Nugent msg = "%s: 'tc=' reference loop '%s'"; 37356c04344SDavid Nugent break; 37456c04344SDavid Nugent case 1: 37556c04344SDavid Nugent msg = "couldn't resolve 'tc=' reference in '%s'"; 37656c04344SDavid Nugent break; 37756c04344SDavid Nugent default: 37856c04344SDavid Nugent msg = "%s: unexpected cgetent() error '%s': %m"; 37956c04344SDavid Nugent break; 38056c04344SDavid Nugent } 3818a2deaa1SAndrey A. Chernov if (dir) { 382ae702574SAndrey A. Chernov (void)seteuid(euid); 383ae702574SAndrey A. Chernov (void)setegid(egid); 3848a2deaa1SAndrey A. Chernov } 38556c04344SDavid Nugent if (msg != NULL) 38656c04344SDavid Nugent syslog(LOG_ERR, msg, "login_getclass", name); 38756c04344SDavid Nugent free(lc); 38856c04344SDavid Nugent } 38968bbf3adSDavid Nugent 39056c04344SDavid Nugent return NULL; 39156c04344SDavid Nugent } 39256c04344SDavid Nugent 39356c04344SDavid Nugent 39456c04344SDavid Nugent 39556c04344SDavid Nugent /* 39656c04344SDavid Nugent * login_getclass() 39756c04344SDavid Nugent * Get the login class for the system (only) login class database. 39856c04344SDavid Nugent * Return a filled-out login_cap_t structure, including 39956c04344SDavid Nugent * class name, and the capability record buffer. 40056c04344SDavid Nugent */ 40156c04344SDavid Nugent 40256c04344SDavid Nugent login_cap_t * 40356c04344SDavid Nugent login_getclass(const char *cls) 40456c04344SDavid Nugent { 40556c04344SDavid Nugent return login_getclassbyname(cls, NULL); 40656c04344SDavid Nugent } 40768bbf3adSDavid Nugent 40868bbf3adSDavid Nugent 40968bbf3adSDavid Nugent /* 410a7429823SYaroslav Tykhiy * login_getpwclass() 41168bbf3adSDavid Nugent * Get the login class for a given password entry from 41268bbf3adSDavid Nugent * the system (only) login class database. 41368bbf3adSDavid Nugent * If the password entry's class field is not set, or 41468bbf3adSDavid Nugent * the class specified does not exist, then use the 415a7429823SYaroslav Tykhiy * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged 416a7429823SYaroslav Tykhiy * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. 41768bbf3adSDavid Nugent * Return a filled-out login_cap_t structure, including 41868bbf3adSDavid Nugent * class name, and the capability record buffer. 41968bbf3adSDavid Nugent */ 42068bbf3adSDavid Nugent 42168bbf3adSDavid Nugent login_cap_t * 42256c04344SDavid Nugent login_getpwclass(const struct passwd *pwd) 42368bbf3adSDavid Nugent { 42456c04344SDavid Nugent const char *cls = NULL; 42556c04344SDavid Nugent 4261c594de5SDavid Nugent if (pwd != NULL) { 42756c04344SDavid Nugent cls = pwd->pw_class; 42856c04344SDavid Nugent if (cls == NULL || *cls == '\0') 42956c04344SDavid Nugent cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; 4302dc7d862SDavid Nugent } 431a7429823SYaroslav Tykhiy /* 432a7429823SYaroslav Tykhiy * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', 433a7429823SYaroslav Tykhiy * so NULL can be passed instead of pwd for more safety. 434a7429823SYaroslav Tykhiy */ 43556c04344SDavid Nugent return login_getclassbyname(cls, pwd); 43668bbf3adSDavid Nugent } 43768bbf3adSDavid Nugent 43868bbf3adSDavid Nugent 43968bbf3adSDavid Nugent /* 44068bbf3adSDavid Nugent * login_getuserclass() 441a7429823SYaroslav Tykhiy * Get the `me' login class, allowing user overrides via ~/.login_conf. 442a7429823SYaroslav Tykhiy * Note that user overrides are allowed only in the `me' class. 44368bbf3adSDavid Nugent */ 44468bbf3adSDavid Nugent 44568bbf3adSDavid Nugent login_cap_t * 44668bbf3adSDavid Nugent login_getuserclass(const struct passwd *pwd) 44768bbf3adSDavid Nugent { 44856c04344SDavid Nugent return login_getclassbyname(LOGIN_MECLASS, pwd); 44968bbf3adSDavid Nugent } 45068bbf3adSDavid Nugent 45168bbf3adSDavid Nugent 45268bbf3adSDavid Nugent /* 45368bbf3adSDavid Nugent * login_getcapstr() 45468bbf3adSDavid Nugent * Given a login_cap entry, and a capability name, return the 455043d661dSTom Rhodes * value defined for that capability, a default if not found, or 45668bbf3adSDavid Nugent * an error string on error. 45768bbf3adSDavid Nugent */ 45868bbf3adSDavid Nugent 459b00ba4ccSRuslan Ermilov const char * 460b00ba4ccSRuslan Ermilov login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) 46168bbf3adSDavid Nugent { 46268bbf3adSDavid Nugent char *res; 46368bbf3adSDavid Nugent int ret; 46468bbf3adSDavid Nugent 46568bbf3adSDavid Nugent if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') 46668bbf3adSDavid Nugent return def; 46768bbf3adSDavid Nugent 468547fa0d9SMark Murray if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) 46968bbf3adSDavid Nugent return def; 47056c04344SDavid Nugent return (ret >= 0) ? res : error; 47168bbf3adSDavid Nugent } 47268bbf3adSDavid Nugent 47368bbf3adSDavid Nugent 47468bbf3adSDavid Nugent /* 47568bbf3adSDavid Nugent * login_getcaplist() 47668bbf3adSDavid Nugent * Given a login_cap entry, and a capability name, return the 47768bbf3adSDavid Nugent * value defined for that capability split into an array of 47868bbf3adSDavid Nugent * strings. 47968bbf3adSDavid Nugent */ 48068bbf3adSDavid Nugent 481547fa0d9SMark Murray const char ** 48268bbf3adSDavid Nugent login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) 48368bbf3adSDavid Nugent { 484547fa0d9SMark Murray const char *lstring; 48568bbf3adSDavid Nugent 48668bbf3adSDavid Nugent if (chars == NULL) 487f01e3989SDavid Nugent chars = ", \t"; 488547fa0d9SMark Murray if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) 48968bbf3adSDavid Nugent return arrayize(lstring, chars, NULL); 49068bbf3adSDavid Nugent return NULL; 49168bbf3adSDavid Nugent } 49268bbf3adSDavid Nugent 49368bbf3adSDavid Nugent 49468bbf3adSDavid Nugent /* 49568bbf3adSDavid Nugent * login_getpath() 49668bbf3adSDavid Nugent * From the login_cap_t <lc>, get the capability <cap> which is 49768bbf3adSDavid Nugent * formatted as either a space or comma delimited list of paths 49868bbf3adSDavid Nugent * and append them all into a string and separate by semicolons. 49968bbf3adSDavid Nugent * If there is an error of any kind, return <error>. 50068bbf3adSDavid Nugent */ 50168bbf3adSDavid Nugent 502b00ba4ccSRuslan Ermilov const char * 503b00ba4ccSRuslan Ermilov login_getpath(login_cap_t *lc, const char *cap, const char *error) 50468bbf3adSDavid Nugent { 505b00ba4ccSRuslan Ermilov const char *str; 506547fa0d9SMark Murray char *ptr; 507547fa0d9SMark Murray int count; 50868bbf3adSDavid Nugent 509547fa0d9SMark Murray str = login_getcapstr(lc, cap, NULL, NULL); 510547fa0d9SMark Murray if (str == NULL) 511547fa0d9SMark Murray return error; 512547fa0d9SMark Murray ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ 51368bbf3adSDavid Nugent while (*ptr) { 514547fa0d9SMark Murray count = strcspn(ptr, ", \t"); 51568bbf3adSDavid Nugent ptr += count; 51668bbf3adSDavid Nugent if (*ptr) 51768bbf3adSDavid Nugent *ptr++ = ':'; 51868bbf3adSDavid Nugent } 51968bbf3adSDavid Nugent return str; 52068bbf3adSDavid Nugent } 52168bbf3adSDavid Nugent 52268bbf3adSDavid Nugent 52356c04344SDavid Nugent static int 52456c04344SDavid Nugent isinfinite(const char *s) 52556c04344SDavid Nugent { 52656c04344SDavid Nugent static const char *infs[] = { 52756c04344SDavid Nugent "infinity", 52856c04344SDavid Nugent "inf", 52956c04344SDavid Nugent "unlimited", 53056c04344SDavid Nugent "unlimit", 53156c04344SDavid Nugent "-1", 53256c04344SDavid Nugent NULL 53356c04344SDavid Nugent }; 53456c04344SDavid Nugent const char **i = &infs[0]; 53556c04344SDavid Nugent 53656c04344SDavid Nugent while (*i != NULL) { 53756c04344SDavid Nugent if (strcasecmp(s, *i) == 0) 53856c04344SDavid Nugent return 1; 53956c04344SDavid Nugent ++i; 54056c04344SDavid Nugent } 54156c04344SDavid Nugent return 0; 54256c04344SDavid Nugent } 54356c04344SDavid Nugent 54456c04344SDavid Nugent 54556c04344SDavid Nugent static u_quad_t 54656c04344SDavid Nugent rmultiply(u_quad_t n1, u_quad_t n2) 54756c04344SDavid Nugent { 54856c04344SDavid Nugent u_quad_t m, r; 54956c04344SDavid Nugent int b1, b2; 55056c04344SDavid Nugent 55156c04344SDavid Nugent static int bpw = 0; 55256c04344SDavid Nugent 55356c04344SDavid Nugent /* Handle simple cases */ 55456c04344SDavid Nugent if (n1 == 0 || n2 == 0) 55556c04344SDavid Nugent return 0; 55656c04344SDavid Nugent if (n1 == 1) 55756c04344SDavid Nugent return n2; 55856c04344SDavid Nugent if (n2 == 1) 55956c04344SDavid Nugent return n1; 56056c04344SDavid Nugent 56156c04344SDavid Nugent /* 56256c04344SDavid Nugent * sizeof() returns number of bytes needed for storage. 56356c04344SDavid Nugent * This may be different from the actual number of useful bits. 56456c04344SDavid Nugent */ 56556c04344SDavid Nugent if (!bpw) { 56656c04344SDavid Nugent bpw = sizeof(u_quad_t) * 8; 56756c04344SDavid Nugent while (((u_quad_t)1 << (bpw-1)) == 0) 56856c04344SDavid Nugent --bpw; 56956c04344SDavid Nugent } 57056c04344SDavid Nugent 57156c04344SDavid Nugent /* 57256c04344SDavid Nugent * First check the magnitude of each number. If the sum of the 57356c04344SDavid Nugent * magnatude is way to high, reject the number. (If this test 57456c04344SDavid Nugent * is not done then the first multiply below may overflow.) 57556c04344SDavid Nugent */ 57656c04344SDavid Nugent for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 57756c04344SDavid Nugent ; 57856c04344SDavid Nugent for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 57956c04344SDavid Nugent ; 58056c04344SDavid Nugent if (b1 + b2 - 2 > bpw) { 58156c04344SDavid Nugent errno = ERANGE; 58256c04344SDavid Nugent return (UQUAD_MAX); 58356c04344SDavid Nugent } 58456c04344SDavid Nugent 58556c04344SDavid Nugent /* 58656c04344SDavid Nugent * Decompose the multiplication to be: 58756c04344SDavid Nugent * h1 = n1 & ~1 58856c04344SDavid Nugent * h2 = n2 & ~1 58956c04344SDavid Nugent * l1 = n1 & 1 59056c04344SDavid Nugent * l2 = n2 & 1 59156c04344SDavid Nugent * (h1 + l1) * (h2 + l2) 59256c04344SDavid Nugent * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 59356c04344SDavid Nugent * 59456c04344SDavid Nugent * Since h1 && h2 do not have the low bit set, we can then say: 59556c04344SDavid Nugent * 59656c04344SDavid Nugent * (h1>>1 * h2>>1 * 4) + ... 59756c04344SDavid Nugent * 59856c04344SDavid Nugent * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 59956c04344SDavid Nugent * overflow. 60056c04344SDavid Nugent * 60156c04344SDavid Nugent * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 60256c04344SDavid Nugent * then adding in residual amout will cause an overflow. 60356c04344SDavid Nugent */ 60456c04344SDavid Nugent 60556c04344SDavid Nugent m = (n1 >> 1) * (n2 >> 1); 60656c04344SDavid Nugent if (m >= ((u_quad_t)1 << (bpw-2))) { 60756c04344SDavid Nugent errno = ERANGE; 60856c04344SDavid Nugent return (UQUAD_MAX); 60956c04344SDavid Nugent } 61056c04344SDavid Nugent m *= 4; 61156c04344SDavid Nugent 61256c04344SDavid Nugent r = (n1 & n2 & 1) 61356c04344SDavid Nugent + (n2 & 1) * (n1 & ~(u_quad_t)1) 61456c04344SDavid Nugent + (n1 & 1) * (n2 & ~(u_quad_t)1); 61556c04344SDavid Nugent 61656c04344SDavid Nugent if ((u_quad_t)(m + r) < m) { 61756c04344SDavid Nugent errno = ERANGE; 61856c04344SDavid Nugent return (UQUAD_MAX); 61956c04344SDavid Nugent } 62056c04344SDavid Nugent m += r; 62156c04344SDavid Nugent 62256c04344SDavid Nugent return (m); 62356c04344SDavid Nugent } 62456c04344SDavid Nugent 62556c04344SDavid Nugent 62668bbf3adSDavid Nugent /* 62768bbf3adSDavid Nugent * login_getcaptime() 62868bbf3adSDavid Nugent * From the login_cap_t <lc>, get the capability <cap>, which is 62968bbf3adSDavid Nugent * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not 63068bbf3adSDavid Nugent * present in <lc>, return <def>; if there is an error of some kind, 63168bbf3adSDavid Nugent * return <error>. 63268bbf3adSDavid Nugent */ 63368bbf3adSDavid Nugent 63468bbf3adSDavid Nugent rlim_t 63568bbf3adSDavid Nugent login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 63668bbf3adSDavid Nugent { 63756c04344SDavid Nugent char *res, *ep, *oval; 63856c04344SDavid Nugent int r; 63951706563SDavid Nugent rlim_t tot; 64068bbf3adSDavid Nugent 64168bbf3adSDavid Nugent errno = 0; 64268bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL) 64368bbf3adSDavid Nugent return def; 64468bbf3adSDavid Nugent 64568bbf3adSDavid Nugent /* 64668bbf3adSDavid Nugent * Look for <cap> in lc_cap. 64768bbf3adSDavid Nugent * If it's not there (-1), return <def>. 64868bbf3adSDavid Nugent * If there's an error, return <error>. 64968bbf3adSDavid Nugent */ 65068bbf3adSDavid Nugent 651547fa0d9SMark Murray if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 65268bbf3adSDavid Nugent return def; 653*b8c1aadeSOlivier Certner else if (r < 0) 65468bbf3adSDavid Nugent return error; 65568bbf3adSDavid Nugent 65656c04344SDavid Nugent /* "inf" and "infinity" are special cases */ 65756c04344SDavid Nugent if (isinfinite(res)) 65868bbf3adSDavid Nugent return RLIM_INFINITY; 65968bbf3adSDavid Nugent 66068bbf3adSDavid Nugent /* 66168bbf3adSDavid Nugent * Now go through the string, turning something like 1h2m3s into 66268bbf3adSDavid Nugent * an integral value. Whee. 66368bbf3adSDavid Nugent */ 66468bbf3adSDavid Nugent 66568bbf3adSDavid Nugent errno = 0; 66651706563SDavid Nugent tot = 0; 66756c04344SDavid Nugent oval = res; 66868bbf3adSDavid Nugent while (*res) { 66956c04344SDavid Nugent rlim_t tim = strtoq(res, &ep, 0); 67056c04344SDavid Nugent rlim_t mult = 1; 67156c04344SDavid Nugent 67256c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) { 67356c04344SDavid Nugent invalid: 67456c04344SDavid Nugent syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s", 67556c04344SDavid Nugent lc->lc_class, cap, oval); 67656c04344SDavid Nugent errno = ERANGE; 67768bbf3adSDavid Nugent return error; 67868bbf3adSDavid Nugent } 67968bbf3adSDavid Nugent /* Look for suffixes */ 68068bbf3adSDavid Nugent switch (*ep++) { 68168bbf3adSDavid Nugent case 0: 68256c04344SDavid Nugent ep--; 68356c04344SDavid Nugent break; /* end of string */ 68468bbf3adSDavid Nugent case 's': case 'S': /* seconds */ 68568bbf3adSDavid Nugent break; 68668bbf3adSDavid Nugent case 'm': case 'M': /* minutes */ 68756c04344SDavid Nugent mult = 60; 68868bbf3adSDavid Nugent break; 68968bbf3adSDavid Nugent case 'h': case 'H': /* hours */ 69056c04344SDavid Nugent mult = 60L * 60L; 69168bbf3adSDavid Nugent break; 69268bbf3adSDavid Nugent case 'd': case 'D': /* days */ 69356c04344SDavid Nugent mult = 60L * 60L * 24L; 69468bbf3adSDavid Nugent break; 69568bbf3adSDavid Nugent case 'w': case 'W': /* weeks */ 69656c04344SDavid Nugent mult = 60L * 60L * 24L * 7L; 697c2043f40SDavid Nugent break; 69856c04344SDavid Nugent case 'y': case 'Y': /* 365-day years */ 69956c04344SDavid Nugent mult = 60L * 60L * 24L * 365L; 700c2043f40SDavid Nugent break; 70168bbf3adSDavid Nugent default: 70256c04344SDavid Nugent goto invalid; 70368bbf3adSDavid Nugent } 70468bbf3adSDavid Nugent res = ep; 70556c04344SDavid Nugent tot += rmultiply(tim, mult); 70656c04344SDavid Nugent if (errno) 70756c04344SDavid Nugent goto invalid; 70868bbf3adSDavid Nugent } 70956c04344SDavid Nugent 71068bbf3adSDavid Nugent return tot; 71168bbf3adSDavid Nugent } 71268bbf3adSDavid Nugent 71368bbf3adSDavid Nugent 71468bbf3adSDavid Nugent /* 71568bbf3adSDavid Nugent * login_getcapnum() 71668bbf3adSDavid Nugent * From the login_cap_t <lc>, extract the numerical value <cap>. 71768bbf3adSDavid Nugent * If it is not present, return <def> for a default, and return 71868bbf3adSDavid Nugent * <error> if there is an error. 71968bbf3adSDavid Nugent * Like login_getcaptime(), only it only converts to a number, not 72068bbf3adSDavid Nugent * to a time; "infinity" and "inf" are 'special.' 72168bbf3adSDavid Nugent */ 72268bbf3adSDavid Nugent 72368bbf3adSDavid Nugent rlim_t 72468bbf3adSDavid Nugent login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 72568bbf3adSDavid Nugent { 72668bbf3adSDavid Nugent char *ep, *res; 72756c04344SDavid Nugent int r; 72868bbf3adSDavid Nugent rlim_t val; 72968bbf3adSDavid Nugent 73068bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL) 73168bbf3adSDavid Nugent return def; 73268bbf3adSDavid Nugent 73368bbf3adSDavid Nugent /* 73468bbf3adSDavid Nugent * For BSDI compatibility, try for the tag=<val> first 73568bbf3adSDavid Nugent */ 736*b8c1aadeSOlivier Certner r = cgetstr(lc->lc_cap, cap, &res); 737*b8c1aadeSOlivier Certner if (r == -1) { 73868bbf3adSDavid Nugent long lval; 73956c04344SDavid Nugent /* string capability not present, so try for tag#<val> as numeric */ 740547fa0d9SMark Murray if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) 74168bbf3adSDavid Nugent return def; /* Not there, so return default */ 742*b8c1aadeSOlivier Certner else if (r < 0) 74356c04344SDavid Nugent return error; 744*b8c1aadeSOlivier Certner else 745*b8c1aadeSOlivier Certner return (rlim_t)lval; 746*b8c1aadeSOlivier Certner } else if (r < 0) 747*b8c1aadeSOlivier Certner return error; 74856c04344SDavid Nugent 74956c04344SDavid Nugent if (isinfinite(res)) 75068bbf3adSDavid Nugent return RLIM_INFINITY; 75168bbf3adSDavid Nugent 75268bbf3adSDavid Nugent errno = 0; 75356c04344SDavid Nugent val = strtoq(res, &ep, 0); 75456c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) { 75556c04344SDavid Nugent syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s", 75656c04344SDavid Nugent lc->lc_class, cap, res); 75756c04344SDavid Nugent errno = ERANGE; 75868bbf3adSDavid Nugent return error; 75956c04344SDavid Nugent } 76056c04344SDavid Nugent 76168bbf3adSDavid Nugent return val; 76268bbf3adSDavid Nugent } 76368bbf3adSDavid Nugent 76468bbf3adSDavid Nugent 76556c04344SDavid Nugent 76668bbf3adSDavid Nugent /* 76768bbf3adSDavid Nugent * login_getcapsize() 76868bbf3adSDavid Nugent * From the login_cap_t <lc>, extract the capability <cap>, which is 76968bbf3adSDavid Nugent * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". 77068bbf3adSDavid Nugent * If not present, return <def>, or <error> if there is an error of 77168bbf3adSDavid Nugent * some sort. 77268bbf3adSDavid Nugent */ 77368bbf3adSDavid Nugent 77468bbf3adSDavid Nugent rlim_t 77556c04344SDavid Nugent login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 77656c04344SDavid Nugent { 77756c04344SDavid Nugent char *ep, *res, *oval; 77856c04344SDavid Nugent int r; 77956c04344SDavid Nugent rlim_t tot; 78068bbf3adSDavid Nugent 78168bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL) 78268bbf3adSDavid Nugent return def; 78368bbf3adSDavid Nugent 784547fa0d9SMark Murray if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 78568bbf3adSDavid Nugent return def; 786*b8c1aadeSOlivier Certner else if (r < 0) 78768bbf3adSDavid Nugent return error; 78868bbf3adSDavid Nugent 78956c04344SDavid Nugent if (isinfinite(res)) 79065f50b7fSAndrey A. Chernov return RLIM_INFINITY; 79165f50b7fSAndrey A. Chernov 79268bbf3adSDavid Nugent errno = 0; 79351706563SDavid Nugent tot = 0; 79456c04344SDavid Nugent oval = res; 79551706563SDavid Nugent while (*res) { 79656c04344SDavid Nugent rlim_t siz = strtoq(res, &ep, 0); 79756c04344SDavid Nugent rlim_t mult = 1; 79856c04344SDavid Nugent 79956c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) { 80056c04344SDavid Nugent invalid: 80156c04344SDavid Nugent syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s", 80256c04344SDavid Nugent lc->lc_class, cap, oval); 80356c04344SDavid Nugent errno = ERANGE; 80468bbf3adSDavid Nugent return error; 80556c04344SDavid Nugent } 806f9074e29SDavid Nugent switch (*ep++) { 80768bbf3adSDavid Nugent case 0: /* end of string */ 80851706563SDavid Nugent ep--; 80951706563SDavid Nugent break; 81068bbf3adSDavid Nugent case 'b': case 'B': /* 512-byte blocks */ 81156c04344SDavid Nugent mult = 512; 81256c04344SDavid Nugent break; 81368bbf3adSDavid Nugent case 'k': case 'K': /* 1024-byte Kilobytes */ 81456c04344SDavid Nugent mult = 1024; 81556c04344SDavid Nugent break; 81668bbf3adSDavid Nugent case 'm': case 'M': /* 1024-k kbytes */ 81756c04344SDavid Nugent mult = 1024 * 1024; 81856c04344SDavid Nugent break; 81968bbf3adSDavid Nugent case 'g': case 'G': /* 1Gbyte */ 82056c04344SDavid Nugent mult = 1024 * 1024 * 1024; 82156c04344SDavid Nugent break; 82268bbf3adSDavid Nugent case 't': case 'T': /* 1TBte */ 82356c04344SDavid Nugent mult = 1024LL * 1024LL * 1024LL * 1024LL; 82456c04344SDavid Nugent break; 82568bbf3adSDavid Nugent default: 82656c04344SDavid Nugent goto invalid; 82768bbf3adSDavid Nugent } 828f9074e29SDavid Nugent res = ep; 82956c04344SDavid Nugent tot += rmultiply(siz, mult); 83056c04344SDavid Nugent if (errno) 83156c04344SDavid Nugent goto invalid; 83251706563SDavid Nugent } 83356c04344SDavid Nugent 83451706563SDavid Nugent return tot; 83568bbf3adSDavid Nugent } 83668bbf3adSDavid Nugent 83768bbf3adSDavid Nugent 83868bbf3adSDavid Nugent /* 83968bbf3adSDavid Nugent * login_getcapbool() 840872a3a62SPedro F. Giffuni * From the login_cap_t <lc>, check for the existence of the capability 84168bbf3adSDavid Nugent * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return 84268bbf3adSDavid Nugent * the whether or not <cap> exists there. 84368bbf3adSDavid Nugent */ 84468bbf3adSDavid Nugent 84568bbf3adSDavid Nugent int 84668bbf3adSDavid Nugent login_getcapbool(login_cap_t *lc, const char *cap, int def) 84768bbf3adSDavid Nugent { 84868bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL) 84968bbf3adSDavid Nugent return def; 850547fa0d9SMark Murray return (cgetcap(lc->lc_cap, cap, ':') != NULL); 85168bbf3adSDavid Nugent } 85268bbf3adSDavid Nugent 85368bbf3adSDavid Nugent 85468bbf3adSDavid Nugent /* 85568bbf3adSDavid Nugent * login_getstyle() 85668bbf3adSDavid Nugent * Given a login_cap entry <lc>, and optionally a type of auth <auth>, 85768bbf3adSDavid Nugent * and optionally a style <style>, find the style that best suits these 85868bbf3adSDavid Nugent * rules: 85968bbf3adSDavid Nugent * 1. If <auth> is non-null, look for an "auth-<auth>=" string 86068bbf3adSDavid Nugent * in the capability; if not present, default to "auth=". 86168bbf3adSDavid Nugent * 2. If there is no auth list found from (1), default to 86268bbf3adSDavid Nugent * "passwd" as an authorization list. 86368bbf3adSDavid Nugent * 3. If <style> is non-null, look for <style> in the list of 86468bbf3adSDavid Nugent * authorization methods found from (2); if <style> is NULL, default 86568bbf3adSDavid Nugent * to LOGIN_DEFSTYLE ("passwd"). 86668bbf3adSDavid Nugent * 4. If the chosen style is found in the chosen list of authorization 86768bbf3adSDavid Nugent * methods, return that; otherwise, return NULL. 86868bbf3adSDavid Nugent * E.g.: 86968bbf3adSDavid Nugent * login_getstyle(lc, NULL, "ftp"); 87068bbf3adSDavid Nugent * login_getstyle(lc, "login", NULL); 87168bbf3adSDavid Nugent * login_getstyle(lc, "skey", "network"); 87268bbf3adSDavid Nugent */ 87368bbf3adSDavid Nugent 874b00ba4ccSRuslan Ermilov const char * 875b00ba4ccSRuslan Ermilov login_getstyle(login_cap_t *lc, const char *style, const char *auth) 87668bbf3adSDavid Nugent { 87768bbf3adSDavid Nugent int i; 878547fa0d9SMark Murray const char **authtypes = NULL; 87968bbf3adSDavid Nugent char *auths= NULL; 88068bbf3adSDavid Nugent char realauth[64]; 88168bbf3adSDavid Nugent 882547fa0d9SMark Murray static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; 88368bbf3adSDavid Nugent 88456c04344SDavid Nugent if (auth != NULL && *auth != '\0') { 885547fa0d9SMark Murray if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) 88668bbf3adSDavid Nugent authtypes = login_getcaplist(lc, realauth, NULL); 88756c04344SDavid Nugent } 88868bbf3adSDavid Nugent 88968bbf3adSDavid Nugent if (authtypes == NULL) 89068bbf3adSDavid Nugent authtypes = login_getcaplist(lc, "auth", NULL); 89168bbf3adSDavid Nugent 89268bbf3adSDavid Nugent if (authtypes == NULL) 89368bbf3adSDavid Nugent authtypes = defauthtypes; 89468bbf3adSDavid Nugent 89568bbf3adSDavid Nugent /* 8969a01d32bSJeroen Ruigrok van der Werven * We have at least one authtype now; auths is a comma-separated 89768bbf3adSDavid Nugent * (or space-separated) list of authentication types. We have to 89868bbf3adSDavid Nugent * convert from this to an array of char*'s; authtypes then gets this. 89968bbf3adSDavid Nugent */ 90068bbf3adSDavid Nugent i = 0; 90168bbf3adSDavid Nugent if (style != NULL && *style != '\0') { 90268bbf3adSDavid Nugent while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) 90368bbf3adSDavid Nugent i++; 90468bbf3adSDavid Nugent } 90556c04344SDavid Nugent 90668bbf3adSDavid Nugent lc->lc_style = NULL; 90768bbf3adSDavid Nugent if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) 90868bbf3adSDavid Nugent lc->lc_style = auths; 90968bbf3adSDavid Nugent 91056c04344SDavid Nugent if (lc->lc_style != NULL) 91156c04344SDavid Nugent lc->lc_style = strdup(lc->lc_style); 91256c04344SDavid Nugent 91368bbf3adSDavid Nugent return lc->lc_style; 91468bbf3adSDavid Nugent } 915