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
2968bbf3adSDavid Nugent #include <sys/types.h>
3068bbf3adSDavid Nugent #include <sys/time.h>
3168bbf3adSDavid Nugent #include <sys/resource.h>
3268bbf3adSDavid Nugent #include <sys/param.h>
330ebec5d3SMark Murray #include <errno.h>
340ebec5d3SMark Murray #include <fcntl.h>
3556c04344SDavid Nugent #include <libutil.h>
3668bbf3adSDavid Nugent #include <login_cap.h>
370ebec5d3SMark Murray #include <pwd.h>
380ebec5d3SMark Murray #include <stdio.h>
390ebec5d3SMark Murray #include <stdlib.h>
400ebec5d3SMark Murray #include <string.h>
410ebec5d3SMark Murray #include <syslog.h>
420ebec5d3SMark Murray #include <unistd.h>
4368bbf3adSDavid Nugent
4456c04344SDavid Nugent /*
4556c04344SDavid Nugent * allocstr()
4656c04344SDavid Nugent * Manage a single static pointer for handling a local char* buffer,
4756c04344SDavid Nugent * resizing as necessary to contain the string.
4856c04344SDavid Nugent *
4956c04344SDavid Nugent * allocarray()
5056c04344SDavid Nugent * Manage a static array for handling a group of strings, resizing
5156c04344SDavid Nugent * when necessary.
5256c04344SDavid Nugent */
5368bbf3adSDavid Nugent
5468bbf3adSDavid Nugent static int lc_object_count = 0;
5568bbf3adSDavid Nugent
5668bbf3adSDavid Nugent static size_t internal_stringsz = 0;
5768bbf3adSDavid Nugent static char * internal_string = NULL;
5868bbf3adSDavid Nugent static size_t internal_arraysz = 0;
59547fa0d9SMark Murray static const char ** internal_array = NULL;
6068bbf3adSDavid Nugent
61b8a5cd86SDag-Erling Smørgrav static char path_login_conf[] = _PATH_LOGIN_CONF;
62b8a5cd86SDag-Erling Smørgrav
6368bbf3adSDavid Nugent static char *
allocstr(const char * str)64547fa0d9SMark Murray allocstr(const char *str)
6568bbf3adSDavid Nugent {
6668bbf3adSDavid Nugent char *p;
6756c04344SDavid Nugent
6868bbf3adSDavid Nugent size_t sz = strlen(str) + 1; /* realloc() only if necessary */
6968bbf3adSDavid Nugent if (sz <= internal_stringsz)
701c594de5SDavid Nugent p = strcpy(internal_string, str);
7168bbf3adSDavid Nugent else if ((p = realloc(internal_string, sz)) != NULL) {
7268bbf3adSDavid Nugent internal_stringsz = sz;
7368bbf3adSDavid Nugent internal_string = strcpy(p, str);
7468bbf3adSDavid Nugent }
7568bbf3adSDavid Nugent return p;
7668bbf3adSDavid Nugent }
7768bbf3adSDavid Nugent
7856c04344SDavid Nugent
79547fa0d9SMark Murray static const char **
allocarray(size_t sz)8068bbf3adSDavid Nugent allocarray(size_t sz)
8168bbf3adSDavid Nugent {
82547fa0d9SMark Murray static const char **p;
8356c04344SDavid Nugent
8468bbf3adSDavid Nugent if (sz <= internal_arraysz)
8568bbf3adSDavid Nugent p = internal_array;
86efa8af7cSPedro F. Giffuni else if ((p = reallocarray(internal_array, sz, sizeof(char*))) != NULL) {
8768bbf3adSDavid Nugent internal_arraysz = sz;
8868bbf3adSDavid Nugent internal_array = p;
8968bbf3adSDavid Nugent }
9068bbf3adSDavid Nugent return p;
9168bbf3adSDavid Nugent }
9268bbf3adSDavid Nugent
9368bbf3adSDavid Nugent
9468bbf3adSDavid Nugent /*
95f32db406SSean Eric Fagan * This is a variant of strcspn, which checks for quoted
96f32db406SSean Eric Fagan * strings. That is,:
97f32db406SSean Eric Fagan * strcspn_quote("how 'now, brown' cow", ",", NULL);
98f32db406SSean Eric Fagan * will return the index for the nul, rather than the comma, because
99f32db406SSean Eric Fagan * the string is quoted. It does not handle escaped characters
100f32db406SSean Eric Fagan * at this time.
101f32db406SSean Eric Fagan */
102f32db406SSean Eric Fagan static size_t
strcspn_quote(const char * str,const char * exclude,int * is_quoted)103f32db406SSean Eric Fagan strcspn_quote(const char *str, const char *exclude, int *is_quoted)
104f32db406SSean Eric Fagan {
105f32db406SSean Eric Fagan size_t indx = 0;
106f32db406SSean Eric Fagan char quote = 0;
107f32db406SSean Eric Fagan
108f32db406SSean Eric Fagan if (str == NULL)
109f32db406SSean Eric Fagan return 0;
110f32db406SSean Eric Fagan
111f32db406SSean Eric Fagan if (is_quoted)
112f32db406SSean Eric Fagan *is_quoted = 0;
113f32db406SSean Eric Fagan
114f32db406SSean Eric Fagan for (indx = 0; str[indx] != 0; indx++) {
115f32db406SSean Eric Fagan if (quote && str[indx] == quote) {
116f32db406SSean Eric Fagan if (is_quoted)
117f32db406SSean Eric Fagan *is_quoted = 1;
118f32db406SSean Eric Fagan quote = 0;
119f32db406SSean Eric Fagan continue;
120f32db406SSean Eric Fagan }
121f32db406SSean Eric Fagan if (quote == 0 &&
122f32db406SSean Eric Fagan (str[indx] == '\'' || str[indx] == '"')) {
123f32db406SSean Eric Fagan quote = str[indx];
124f32db406SSean Eric Fagan continue;
125f32db406SSean Eric Fagan }
126f32db406SSean Eric Fagan if (quote == 0 &&
127f32db406SSean Eric Fagan strchr(exclude, str[indx]) != NULL)
128f32db406SSean Eric Fagan return indx;
129f32db406SSean Eric Fagan }
130f32db406SSean Eric Fagan return indx;
131f32db406SSean Eric Fagan }
132f32db406SSean Eric Fagan
133f32db406SSean Eric Fagan /*
134f32db406SSean Eric Fagan * Remove quotes from the given string.
135f32db406SSean Eric Fagan * It's a very simplistic approach: the first
136f32db406SSean Eric Fagan * single or double quote it finds, it looks for
137f32db406SSean Eric Fagan * the next one, and if it finds it, moves the
138f32db406SSean Eric Fagan * entire string backwards in two chunks
139f32db406SSean Eric Fagan * (first quote + 1 to first quote, length
140f32db406SSean Eric Fagan * rest of string, and then second quote + 1
141f32db406SSean Eric Fagan * to second quote, length rest of the string).
142f32db406SSean Eric Fagan */
143f32db406SSean Eric Fagan static void
remove_quotes(char * str)144f32db406SSean Eric Fagan remove_quotes(char *str)
145f32db406SSean Eric Fagan {
146f32db406SSean Eric Fagan static const char *quote_chars = "'\"";
147f32db406SSean Eric Fagan char qc = 0;
148f32db406SSean Eric Fagan int found = 0;
149f32db406SSean Eric Fagan
150f32db406SSean Eric Fagan do {
151f32db406SSean Eric Fagan char *loc = NULL;
152f32db406SSean Eric Fagan
153f32db406SSean Eric Fagan found = 0;
154f32db406SSean Eric Fagan /*
155f32db406SSean Eric Fagan * If qc is 0, then we haven't found
156f32db406SSean Eric Fagan * a quote yet, so do a strcspn search.
157f32db406SSean Eric Fagan */
158f32db406SSean Eric Fagan if (qc == 0) {
159f32db406SSean Eric Fagan size_t indx;
160f32db406SSean Eric Fagan indx = strcspn(str, quote_chars);
161f32db406SSean Eric Fagan if (str[indx] == '\0')
162f32db406SSean Eric Fagan return; /* We're done */
163f32db406SSean Eric Fagan loc = str + indx;
164f32db406SSean Eric Fagan qc = str[indx];
165f32db406SSean Eric Fagan } else {
166f32db406SSean Eric Fagan /*
167f32db406SSean Eric Fagan * We've found a quote character,
168f32db406SSean Eric Fagan * so use strchr to find the next one.
169f32db406SSean Eric Fagan */
170f32db406SSean Eric Fagan loc = strchr(str, qc);
171f32db406SSean Eric Fagan if (loc == NULL)
172f32db406SSean Eric Fagan return;
173f32db406SSean Eric Fagan qc = 0;
174f32db406SSean Eric Fagan }
175f32db406SSean Eric Fagan if (loc) {
176f32db406SSean Eric Fagan /*
177f32db406SSean Eric Fagan * This gives us the location of the
178f32db406SSean Eric Fagan * quoted character. We need to move
179f32db406SSean Eric Fagan * the entire string down, from loc+1
180f32db406SSean Eric Fagan * to loc.
181f32db406SSean Eric Fagan */
182f32db406SSean Eric Fagan size_t len = strlen(loc + 1) + 1;
183f32db406SSean Eric Fagan memmove(loc, loc + 1, len);
184f32db406SSean Eric Fagan found = 1;
185f32db406SSean Eric Fagan }
186f32db406SSean Eric Fagan } while (found != 0);
187f32db406SSean Eric Fagan }
188f32db406SSean Eric Fagan
189f32db406SSean Eric Fagan /*
19068bbf3adSDavid Nugent * arrayize()
1919a01d32bSJeroen Ruigrok van der Werven * Turn a simple string <str> separated by any of
19268bbf3adSDavid Nugent * the set of <chars> into an array. The last element
19368bbf3adSDavid Nugent * of the array will be NULL, as is proper.
19468bbf3adSDavid Nugent * Free using freearraystr()
19568bbf3adSDavid Nugent */
19668bbf3adSDavid Nugent
197547fa0d9SMark Murray static const char **
arrayize(const char * str,const char * chars,int * size)198547fa0d9SMark Murray arrayize(const char *str, const char *chars, int *size)
19968bbf3adSDavid Nugent {
20068bbf3adSDavid Nugent int i;
20105bcd1d0SPeter Wemm char *ptr;
20205bcd1d0SPeter Wemm const char *cptr;
203547fa0d9SMark Murray const char **res = NULL;
20468bbf3adSDavid Nugent
20556c04344SDavid Nugent /* count the sub-strings */
20605bcd1d0SPeter Wemm for (i = 0, cptr = str; *cptr; i++) {
207f32db406SSean Eric Fagan int count = strcspn_quote(cptr, chars, NULL);
20805bcd1d0SPeter Wemm cptr += count;
20905bcd1d0SPeter Wemm if (*cptr)
21005bcd1d0SPeter Wemm ++cptr;
21168bbf3adSDavid Nugent }
21268bbf3adSDavid Nugent
21356c04344SDavid Nugent /* alloc the array */
21456c04344SDavid Nugent if ((ptr = allocstr(str)) != NULL) {
21556c04344SDavid Nugent if ((res = allocarray(++i)) == NULL)
21605bcd1d0SPeter Wemm free((void *)(uintptr_t)(const void *)str);
21756c04344SDavid Nugent else {
21856c04344SDavid Nugent /* now split the string */
2195f3a7367SDavid Nugent i = 0;
22056c04344SDavid Nugent while (*ptr) {
221f32db406SSean Eric Fagan int quoted = 0;
222f32db406SSean Eric Fagan int count = strcspn_quote(ptr, chars, "ed);
223f32db406SSean Eric Fagan char *base = ptr;
22456c04344SDavid Nugent res[i++] = ptr;
22568bbf3adSDavid Nugent ptr += count;
22668bbf3adSDavid Nugent if (*ptr)
22768bbf3adSDavid Nugent *ptr++ = '\0';
228f32db406SSean Eric Fagan /*
229f32db406SSean Eric Fagan * If the string contains a quoted element, we
230f32db406SSean Eric Fagan * need to remove the quotes.
231f32db406SSean Eric Fagan */
232f32db406SSean Eric Fagan if (quoted) {
233f32db406SSean Eric Fagan remove_quotes(base);
234f32db406SSean Eric Fagan }
235f32db406SSean Eric Fagan
23668bbf3adSDavid Nugent }
23756c04344SDavid Nugent res[i] = NULL;
23868bbf3adSDavid Nugent }
23956c04344SDavid Nugent }
24056c04344SDavid Nugent
24168bbf3adSDavid Nugent if (size)
24268bbf3adSDavid Nugent *size = i;
24356c04344SDavid Nugent
24468bbf3adSDavid Nugent return res;
24568bbf3adSDavid Nugent }
24668bbf3adSDavid Nugent
24756c04344SDavid Nugent
24868bbf3adSDavid Nugent /*
24968bbf3adSDavid Nugent * login_close()
25068bbf3adSDavid Nugent * Frees up all resources relating to a login class
25168bbf3adSDavid Nugent *
25268bbf3adSDavid Nugent */
25368bbf3adSDavid Nugent
25468bbf3adSDavid Nugent void
login_close(login_cap_t * lc)25568bbf3adSDavid Nugent login_close(login_cap_t * lc)
25668bbf3adSDavid Nugent {
25768bbf3adSDavid Nugent if (lc) {
25868bbf3adSDavid Nugent free(lc->lc_style);
25968bbf3adSDavid Nugent free(lc->lc_class);
2603f81737fSTim Vanderhoek free(lc->lc_cap);
26168bbf3adSDavid Nugent free(lc);
26268bbf3adSDavid Nugent if (--lc_object_count == 0) {
26368bbf3adSDavid Nugent free(internal_string);
2642955fda4SDavid Nugent free(internal_array);
26568bbf3adSDavid Nugent internal_array = NULL;
26651706563SDavid Nugent internal_arraysz = 0;
26768bbf3adSDavid Nugent internal_string = NULL;
26851706563SDavid Nugent internal_stringsz = 0;
26968bbf3adSDavid Nugent cgetclose();
27068bbf3adSDavid Nugent }
27168bbf3adSDavid Nugent }
27268bbf3adSDavid Nugent }
27368bbf3adSDavid Nugent
27468bbf3adSDavid Nugent
27568bbf3adSDavid Nugent /*
276a7429823SYaroslav Tykhiy * login_getclassbyname()
277a7429823SYaroslav Tykhiy * Get the login class by its name.
27868bbf3adSDavid Nugent * If the name given is NULL or empty, the default class
279a7429823SYaroslav Tykhiy * LOGIN_DEFCLASS (i.e., "default") is fetched.
280a7429823SYaroslav Tykhiy * If the name given is LOGIN_MECLASS and
28194cf9da0SDiomidis Spinellis * 'pwd' argument is non-NULL and contains an non-NULL
28294cf9da0SDiomidis Spinellis * dir entry, then the file _FILE_LOGIN_CONF is picked
28394cf9da0SDiomidis Spinellis * up from that directory and used before the system
284a7429823SYaroslav Tykhiy * login database. In that case the system login database
285a7429823SYaroslav Tykhiy * is looked up using LOGIN_MECLASS, too, which is a bug.
28668bbf3adSDavid Nugent * Return a filled-out login_cap_t structure, including
28768bbf3adSDavid Nugent * class name, and the capability record buffer.
28868bbf3adSDavid Nugent */
28968bbf3adSDavid Nugent
29068bbf3adSDavid Nugent login_cap_t *
login_getclassbyname(char const * name,const struct passwd * pwd)29156c04344SDavid Nugent login_getclassbyname(char const *name, const struct passwd *pwd)
29268bbf3adSDavid Nugent {
29356c04344SDavid Nugent login_cap_t *lc;
29468bbf3adSDavid Nugent
2959df529b8SXin LI if ((lc = calloc(1, sizeof(login_cap_t))) != NULL) {
296e36b245cSAndrey A. Chernov int r, me, i = 0;
2978a2deaa1SAndrey A. Chernov uid_t euid = 0;
2988a2deaa1SAndrey A. Chernov gid_t egid = 0;
29956c04344SDavid Nugent const char *msg = NULL;
300e36b245cSAndrey A. Chernov const char *dir;
30168bbf3adSDavid Nugent char userpath[MAXPATHLEN];
30256c04344SDavid Nugent
30305bcd1d0SPeter Wemm static char *login_dbarray[] = { NULL, NULL, NULL };
30468bbf3adSDavid Nugent
305e36b245cSAndrey A. Chernov me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0);
306e36b245cSAndrey A. Chernov dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir;
3078df8b73fSRobert Watson /*
3088df8b73fSRobert Watson * Switch to user mode before checking/reading its ~/.login_conf
3098df8b73fSRobert Watson * - some NFSes have root read access disabled.
3108df8b73fSRobert Watson *
3118df8b73fSRobert Watson * XXX: This fails to configure additional groups.
3128df8b73fSRobert Watson */
3138a2deaa1SAndrey A. Chernov if (dir) {
314ae702574SAndrey A. Chernov euid = geteuid();
315ae702574SAndrey A. Chernov egid = getegid();
316ae702574SAndrey A. Chernov (void)setegid(pwd->pw_gid);
317ae702574SAndrey A. Chernov (void)seteuid(pwd->pw_uid);
3188a2deaa1SAndrey A. Chernov }
319ae702574SAndrey A. Chernov
32056c04344SDavid Nugent if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
32156c04344SDavid Nugent _FILE_LOGIN_CONF) < MAXPATHLEN) {
32256c04344SDavid Nugent if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
323b8a5cd86SDag-Erling Smørgrav login_dbarray[i++] = userpath;
32456c04344SDavid Nugent }
325a7429823SYaroslav Tykhiy /*
326a7429823SYaroslav Tykhiy * XXX: Why to add the system database if the class is `me'?
327a7429823SYaroslav Tykhiy */
328b8a5cd86SDag-Erling Smørgrav if (_secure_path(path_login_conf, 0, 0) != -1)
329b8a5cd86SDag-Erling Smørgrav login_dbarray[i++] = path_login_conf;
33068bbf3adSDavid Nugent login_dbarray[i] = NULL;
33168bbf3adSDavid Nugent
33256c04344SDavid Nugent if (name == NULL || *name == '\0')
33356c04344SDavid Nugent name = LOGIN_DEFCLASS;
33468bbf3adSDavid Nugent
335547fa0d9SMark Murray switch (cgetent(&lc->lc_cap, login_dbarray, name)) {
33656c04344SDavid Nugent case -1: /* Failed, entry does not exist */
337e36b245cSAndrey A. Chernov if (me)
33856c04344SDavid Nugent break; /* Don't retry default on 'me' */
33956c04344SDavid Nugent if (i == 0)
34056c04344SDavid Nugent r = -1;
341d1d4d952SJilles Tjoelker else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0)
34256c04344SDavid Nugent close(r);
34356c04344SDavid Nugent /*
34456c04344SDavid Nugent * If there's at least one login class database,
34556c04344SDavid Nugent * and we aren't searching for a default class
34656c04344SDavid Nugent * then complain about a non-existent class.
34756c04344SDavid Nugent */
34856c04344SDavid Nugent if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
34956c04344SDavid Nugent syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
35056c04344SDavid Nugent /* fall-back to default class */
35156c04344SDavid Nugent name = LOGIN_DEFCLASS;
35256c04344SDavid Nugent msg = "%s: no default/fallback class '%s'";
353547fa0d9SMark Murray if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0)
35456c04344SDavid Nugent break;
3557fed38d0SPhilippe Charnier /* FALLTHROUGH - just return system defaults */
35656c04344SDavid Nugent case 0: /* success! */
35756c04344SDavid Nugent if ((lc->lc_class = strdup(name)) != NULL) {
3588a2deaa1SAndrey A. Chernov if (dir) {
359ae702574SAndrey A. Chernov (void)seteuid(euid);
360ae702574SAndrey A. Chernov (void)setegid(egid);
3618a2deaa1SAndrey A. Chernov }
36256c04344SDavid Nugent ++lc_object_count;
36368bbf3adSDavid Nugent return lc;
36468bbf3adSDavid Nugent }
36556c04344SDavid Nugent msg = "%s: strdup: %m";
36656c04344SDavid Nugent break;
36756c04344SDavid Nugent case -2:
36856c04344SDavid Nugent msg = "%s: retrieving class information: %m";
36956c04344SDavid Nugent break;
37056c04344SDavid Nugent case -3:
37156c04344SDavid Nugent msg = "%s: 'tc=' reference loop '%s'";
37256c04344SDavid Nugent break;
37356c04344SDavid Nugent case 1:
37456c04344SDavid Nugent msg = "couldn't resolve 'tc=' reference in '%s'";
37556c04344SDavid Nugent break;
37656c04344SDavid Nugent default:
37756c04344SDavid Nugent msg = "%s: unexpected cgetent() error '%s': %m";
37856c04344SDavid Nugent break;
37956c04344SDavid Nugent }
3808a2deaa1SAndrey A. Chernov if (dir) {
381ae702574SAndrey A. Chernov (void)seteuid(euid);
382ae702574SAndrey A. Chernov (void)setegid(egid);
3838a2deaa1SAndrey A. Chernov }
38456c04344SDavid Nugent if (msg != NULL)
38556c04344SDavid Nugent syslog(LOG_ERR, msg, "login_getclass", name);
38656c04344SDavid Nugent free(lc);
38756c04344SDavid Nugent }
38868bbf3adSDavid Nugent
38956c04344SDavid Nugent return NULL;
39056c04344SDavid Nugent }
39156c04344SDavid Nugent
39256c04344SDavid Nugent
39356c04344SDavid Nugent
39456c04344SDavid Nugent /*
39556c04344SDavid Nugent * login_getclass()
39656c04344SDavid Nugent * Get the login class for the system (only) login class database.
39756c04344SDavid Nugent * Return a filled-out login_cap_t structure, including
39856c04344SDavid Nugent * class name, and the capability record buffer.
39956c04344SDavid Nugent */
40056c04344SDavid Nugent
40156c04344SDavid Nugent login_cap_t *
login_getclass(const char * cls)40256c04344SDavid Nugent login_getclass(const char *cls)
40356c04344SDavid Nugent {
40456c04344SDavid Nugent return login_getclassbyname(cls, NULL);
40556c04344SDavid Nugent }
40668bbf3adSDavid Nugent
40768bbf3adSDavid Nugent
40868bbf3adSDavid Nugent /*
409a7429823SYaroslav Tykhiy * login_getpwclass()
41068bbf3adSDavid Nugent * Get the login class for a given password entry from
41168bbf3adSDavid Nugent * the system (only) login class database.
41268bbf3adSDavid Nugent * If the password entry's class field is not set, or
41368bbf3adSDavid Nugent * the class specified does not exist, then use the
414a7429823SYaroslav Tykhiy * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged
415a7429823SYaroslav Tykhiy * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user.
41668bbf3adSDavid Nugent * Return a filled-out login_cap_t structure, including
41768bbf3adSDavid Nugent * class name, and the capability record buffer.
41868bbf3adSDavid Nugent */
41968bbf3adSDavid Nugent
42068bbf3adSDavid Nugent login_cap_t *
login_getpwclass(const struct passwd * pwd)42156c04344SDavid Nugent login_getpwclass(const struct passwd *pwd)
42268bbf3adSDavid Nugent {
42356c04344SDavid Nugent const char *cls = NULL;
42456c04344SDavid Nugent
4251c594de5SDavid Nugent if (pwd != NULL) {
42656c04344SDavid Nugent cls = pwd->pw_class;
42756c04344SDavid Nugent if (cls == NULL || *cls == '\0')
42856c04344SDavid Nugent cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
4292dc7d862SDavid Nugent }
430a7429823SYaroslav Tykhiy /*
431a7429823SYaroslav Tykhiy * XXX: pwd should be unused by login_getclassbyname() unless cls is `me',
432a7429823SYaroslav Tykhiy * so NULL can be passed instead of pwd for more safety.
433a7429823SYaroslav Tykhiy */
43456c04344SDavid Nugent return login_getclassbyname(cls, pwd);
43568bbf3adSDavid Nugent }
43668bbf3adSDavid Nugent
43768bbf3adSDavid Nugent
43868bbf3adSDavid Nugent /*
43968bbf3adSDavid Nugent * login_getuserclass()
440a7429823SYaroslav Tykhiy * Get the `me' login class, allowing user overrides via ~/.login_conf.
441a7429823SYaroslav Tykhiy * Note that user overrides are allowed only in the `me' class.
44268bbf3adSDavid Nugent */
44368bbf3adSDavid Nugent
44468bbf3adSDavid Nugent login_cap_t *
login_getuserclass(const struct passwd * pwd)44568bbf3adSDavid Nugent login_getuserclass(const struct passwd *pwd)
44668bbf3adSDavid Nugent {
44756c04344SDavid Nugent return login_getclassbyname(LOGIN_MECLASS, pwd);
44868bbf3adSDavid Nugent }
44968bbf3adSDavid Nugent
45068bbf3adSDavid Nugent
45168bbf3adSDavid Nugent /*
45268bbf3adSDavid Nugent * login_getcapstr()
45368bbf3adSDavid Nugent * Given a login_cap entry, and a capability name, return the
454043d661dSTom Rhodes * value defined for that capability, a default if not found, or
45568bbf3adSDavid Nugent * an error string on error.
45668bbf3adSDavid Nugent */
45768bbf3adSDavid Nugent
458b00ba4ccSRuslan Ermilov const char *
login_getcapstr(login_cap_t * lc,const char * cap,const char * def,const char * error)459b00ba4ccSRuslan Ermilov login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error)
46068bbf3adSDavid Nugent {
46168bbf3adSDavid Nugent char *res;
46268bbf3adSDavid Nugent int ret;
46368bbf3adSDavid Nugent
46468bbf3adSDavid Nugent if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
46568bbf3adSDavid Nugent return def;
46668bbf3adSDavid Nugent
467547fa0d9SMark Murray if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1)
46868bbf3adSDavid Nugent return def;
46956c04344SDavid Nugent return (ret >= 0) ? res : error;
47068bbf3adSDavid Nugent }
47168bbf3adSDavid Nugent
47268bbf3adSDavid Nugent
47368bbf3adSDavid Nugent /*
47468bbf3adSDavid Nugent * login_getcaplist()
47568bbf3adSDavid Nugent * Given a login_cap entry, and a capability name, return the
47668bbf3adSDavid Nugent * value defined for that capability split into an array of
47768bbf3adSDavid Nugent * strings.
47868bbf3adSDavid Nugent */
47968bbf3adSDavid Nugent
480547fa0d9SMark Murray const char **
login_getcaplist(login_cap_t * lc,const char * cap,const char * chars)48168bbf3adSDavid Nugent login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
48268bbf3adSDavid Nugent {
483547fa0d9SMark Murray const char *lstring;
48468bbf3adSDavid Nugent
48568bbf3adSDavid Nugent if (chars == NULL)
486f01e3989SDavid Nugent chars = ", \t";
487547fa0d9SMark Murray if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL)
48868bbf3adSDavid Nugent return arrayize(lstring, chars, NULL);
48968bbf3adSDavid Nugent return NULL;
49068bbf3adSDavid Nugent }
49168bbf3adSDavid Nugent
49268bbf3adSDavid Nugent
49368bbf3adSDavid Nugent /*
49468bbf3adSDavid Nugent * login_getpath()
49568bbf3adSDavid Nugent * From the login_cap_t <lc>, get the capability <cap> which is
49668bbf3adSDavid Nugent * formatted as either a space or comma delimited list of paths
49768bbf3adSDavid Nugent * and append them all into a string and separate by semicolons.
49868bbf3adSDavid Nugent * If there is an error of any kind, return <error>.
49968bbf3adSDavid Nugent */
50068bbf3adSDavid Nugent
501b00ba4ccSRuslan Ermilov const char *
login_getpath(login_cap_t * lc,const char * cap,const char * error)502b00ba4ccSRuslan Ermilov login_getpath(login_cap_t *lc, const char *cap, const char *error)
50368bbf3adSDavid Nugent {
504b00ba4ccSRuslan Ermilov const char *str;
505547fa0d9SMark Murray char *ptr;
506547fa0d9SMark Murray int count;
50768bbf3adSDavid Nugent
508547fa0d9SMark Murray str = login_getcapstr(lc, cap, NULL, NULL);
509547fa0d9SMark Murray if (str == NULL)
510547fa0d9SMark Murray return error;
511547fa0d9SMark Murray ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */
51268bbf3adSDavid Nugent while (*ptr) {
513547fa0d9SMark Murray count = strcspn(ptr, ", \t");
51468bbf3adSDavid Nugent ptr += count;
51568bbf3adSDavid Nugent if (*ptr)
51668bbf3adSDavid Nugent *ptr++ = ':';
51768bbf3adSDavid Nugent }
51868bbf3adSDavid Nugent return str;
51968bbf3adSDavid Nugent }
52068bbf3adSDavid Nugent
52168bbf3adSDavid Nugent
52256c04344SDavid Nugent static int
isinfinite(const char * s)52356c04344SDavid Nugent isinfinite(const char *s)
52456c04344SDavid Nugent {
52556c04344SDavid Nugent static const char *infs[] = {
52656c04344SDavid Nugent "infinity",
52756c04344SDavid Nugent "inf",
52856c04344SDavid Nugent "unlimited",
52956c04344SDavid Nugent "unlimit",
53056c04344SDavid Nugent "-1",
53156c04344SDavid Nugent NULL
53256c04344SDavid Nugent };
53356c04344SDavid Nugent const char **i = &infs[0];
53456c04344SDavid Nugent
53556c04344SDavid Nugent while (*i != NULL) {
53656c04344SDavid Nugent if (strcasecmp(s, *i) == 0)
53756c04344SDavid Nugent return 1;
53856c04344SDavid Nugent ++i;
53956c04344SDavid Nugent }
54056c04344SDavid Nugent return 0;
54156c04344SDavid Nugent }
54256c04344SDavid Nugent
54356c04344SDavid Nugent
54456c04344SDavid Nugent static u_quad_t
rmultiply(u_quad_t n1,u_quad_t n2)54556c04344SDavid Nugent rmultiply(u_quad_t n1, u_quad_t n2)
54656c04344SDavid Nugent {
54756c04344SDavid Nugent u_quad_t m, r;
54856c04344SDavid Nugent int b1, b2;
54956c04344SDavid Nugent
55056c04344SDavid Nugent static int bpw = 0;
55156c04344SDavid Nugent
55256c04344SDavid Nugent /* Handle simple cases */
55356c04344SDavid Nugent if (n1 == 0 || n2 == 0)
55456c04344SDavid Nugent return 0;
55556c04344SDavid Nugent if (n1 == 1)
55656c04344SDavid Nugent return n2;
55756c04344SDavid Nugent if (n2 == 1)
55856c04344SDavid Nugent return n1;
55956c04344SDavid Nugent
56056c04344SDavid Nugent /*
56156c04344SDavid Nugent * sizeof() returns number of bytes needed for storage.
56256c04344SDavid Nugent * This may be different from the actual number of useful bits.
56356c04344SDavid Nugent */
56456c04344SDavid Nugent if (!bpw) {
56556c04344SDavid Nugent bpw = sizeof(u_quad_t) * 8;
56656c04344SDavid Nugent while (((u_quad_t)1 << (bpw-1)) == 0)
56756c04344SDavid Nugent --bpw;
56856c04344SDavid Nugent }
56956c04344SDavid Nugent
57056c04344SDavid Nugent /*
57156c04344SDavid Nugent * First check the magnitude of each number. If the sum of the
57256c04344SDavid Nugent * magnatude is way to high, reject the number. (If this test
57356c04344SDavid Nugent * is not done then the first multiply below may overflow.)
57456c04344SDavid Nugent */
57556c04344SDavid Nugent for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
57656c04344SDavid Nugent ;
57756c04344SDavid Nugent for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
57856c04344SDavid Nugent ;
57956c04344SDavid Nugent if (b1 + b2 - 2 > bpw) {
58056c04344SDavid Nugent errno = ERANGE;
58156c04344SDavid Nugent return (UQUAD_MAX);
58256c04344SDavid Nugent }
58356c04344SDavid Nugent
58456c04344SDavid Nugent /*
58556c04344SDavid Nugent * Decompose the multiplication to be:
58656c04344SDavid Nugent * h1 = n1 & ~1
58756c04344SDavid Nugent * h2 = n2 & ~1
58856c04344SDavid Nugent * l1 = n1 & 1
58956c04344SDavid Nugent * l2 = n2 & 1
59056c04344SDavid Nugent * (h1 + l1) * (h2 + l2)
59156c04344SDavid Nugent * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
59256c04344SDavid Nugent *
59356c04344SDavid Nugent * Since h1 && h2 do not have the low bit set, we can then say:
59456c04344SDavid Nugent *
59556c04344SDavid Nugent * (h1>>1 * h2>>1 * 4) + ...
59656c04344SDavid Nugent *
59756c04344SDavid Nugent * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
59856c04344SDavid Nugent * overflow.
59956c04344SDavid Nugent *
60056c04344SDavid Nugent * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
60156c04344SDavid Nugent * then adding in residual amout will cause an overflow.
60256c04344SDavid Nugent */
60356c04344SDavid Nugent
60456c04344SDavid Nugent m = (n1 >> 1) * (n2 >> 1);
60556c04344SDavid Nugent if (m >= ((u_quad_t)1 << (bpw-2))) {
60656c04344SDavid Nugent errno = ERANGE;
60756c04344SDavid Nugent return (UQUAD_MAX);
60856c04344SDavid Nugent }
60956c04344SDavid Nugent m *= 4;
61056c04344SDavid Nugent
61156c04344SDavid Nugent r = (n1 & n2 & 1)
61256c04344SDavid Nugent + (n2 & 1) * (n1 & ~(u_quad_t)1)
61356c04344SDavid Nugent + (n1 & 1) * (n2 & ~(u_quad_t)1);
61456c04344SDavid Nugent
61556c04344SDavid Nugent if ((u_quad_t)(m + r) < m) {
61656c04344SDavid Nugent errno = ERANGE;
61756c04344SDavid Nugent return (UQUAD_MAX);
61856c04344SDavid Nugent }
61956c04344SDavid Nugent m += r;
62056c04344SDavid Nugent
62156c04344SDavid Nugent return (m);
62256c04344SDavid Nugent }
62356c04344SDavid Nugent
62456c04344SDavid Nugent
62568bbf3adSDavid Nugent /*
62668bbf3adSDavid Nugent * login_getcaptime()
62768bbf3adSDavid Nugent * From the login_cap_t <lc>, get the capability <cap>, which is
62868bbf3adSDavid Nugent * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
62968bbf3adSDavid Nugent * present in <lc>, return <def>; if there is an error of some kind,
63068bbf3adSDavid Nugent * return <error>.
63168bbf3adSDavid Nugent */
63268bbf3adSDavid Nugent
63368bbf3adSDavid Nugent rlim_t
login_getcaptime(login_cap_t * lc,const char * cap,rlim_t def,rlim_t error)63468bbf3adSDavid Nugent login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
63568bbf3adSDavid Nugent {
63656c04344SDavid Nugent char *res, *ep, *oval;
63756c04344SDavid Nugent int r;
63851706563SDavid Nugent rlim_t tot;
63968bbf3adSDavid Nugent
64068bbf3adSDavid Nugent errno = 0;
64168bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL)
64268bbf3adSDavid Nugent return def;
64368bbf3adSDavid Nugent
64468bbf3adSDavid Nugent /*
64568bbf3adSDavid Nugent * Look for <cap> in lc_cap.
64668bbf3adSDavid Nugent * If it's not there (-1), return <def>.
64768bbf3adSDavid Nugent * If there's an error, return <error>.
64868bbf3adSDavid Nugent */
64968bbf3adSDavid Nugent
650547fa0d9SMark Murray if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
65168bbf3adSDavid Nugent return def;
652b8c1aadeSOlivier Certner else if (r < 0)
65368bbf3adSDavid Nugent return error;
65468bbf3adSDavid Nugent
65556c04344SDavid Nugent /* "inf" and "infinity" are special cases */
65656c04344SDavid Nugent if (isinfinite(res))
65768bbf3adSDavid Nugent return RLIM_INFINITY;
65868bbf3adSDavid Nugent
65968bbf3adSDavid Nugent /*
66068bbf3adSDavid Nugent * Now go through the string, turning something like 1h2m3s into
66168bbf3adSDavid Nugent * an integral value. Whee.
66268bbf3adSDavid Nugent */
66368bbf3adSDavid Nugent
66468bbf3adSDavid Nugent errno = 0;
66551706563SDavid Nugent tot = 0;
66656c04344SDavid Nugent oval = res;
66768bbf3adSDavid Nugent while (*res) {
66856c04344SDavid Nugent rlim_t tim = strtoq(res, &ep, 0);
66956c04344SDavid Nugent rlim_t mult = 1;
67056c04344SDavid Nugent
67156c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) {
67256c04344SDavid Nugent invalid:
67356c04344SDavid Nugent syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
67456c04344SDavid Nugent lc->lc_class, cap, oval);
67556c04344SDavid Nugent errno = ERANGE;
67668bbf3adSDavid Nugent return error;
67768bbf3adSDavid Nugent }
67868bbf3adSDavid Nugent /* Look for suffixes */
67968bbf3adSDavid Nugent switch (*ep++) {
68068bbf3adSDavid Nugent case 0:
68156c04344SDavid Nugent ep--;
68256c04344SDavid Nugent break; /* end of string */
68368bbf3adSDavid Nugent case 's': case 'S': /* seconds */
68468bbf3adSDavid Nugent break;
68568bbf3adSDavid Nugent case 'm': case 'M': /* minutes */
68656c04344SDavid Nugent mult = 60;
68768bbf3adSDavid Nugent break;
68868bbf3adSDavid Nugent case 'h': case 'H': /* hours */
68956c04344SDavid Nugent mult = 60L * 60L;
69068bbf3adSDavid Nugent break;
69168bbf3adSDavid Nugent case 'd': case 'D': /* days */
69256c04344SDavid Nugent mult = 60L * 60L * 24L;
69368bbf3adSDavid Nugent break;
69468bbf3adSDavid Nugent case 'w': case 'W': /* weeks */
69556c04344SDavid Nugent mult = 60L * 60L * 24L * 7L;
696c2043f40SDavid Nugent break;
69756c04344SDavid Nugent case 'y': case 'Y': /* 365-day years */
69856c04344SDavid Nugent mult = 60L * 60L * 24L * 365L;
699c2043f40SDavid Nugent break;
70068bbf3adSDavid Nugent default:
70156c04344SDavid Nugent goto invalid;
70268bbf3adSDavid Nugent }
70368bbf3adSDavid Nugent res = ep;
70456c04344SDavid Nugent tot += rmultiply(tim, mult);
70556c04344SDavid Nugent if (errno)
70656c04344SDavid Nugent goto invalid;
70768bbf3adSDavid Nugent }
70856c04344SDavid Nugent
70968bbf3adSDavid Nugent return tot;
71068bbf3adSDavid Nugent }
71168bbf3adSDavid Nugent
71268bbf3adSDavid Nugent
71368bbf3adSDavid Nugent /*
71468bbf3adSDavid Nugent * login_getcapnum()
71568bbf3adSDavid Nugent * From the login_cap_t <lc>, extract the numerical value <cap>.
71668bbf3adSDavid Nugent * If it is not present, return <def> for a default, and return
71768bbf3adSDavid Nugent * <error> if there is an error.
71868bbf3adSDavid Nugent * Like login_getcaptime(), only it only converts to a number, not
71968bbf3adSDavid Nugent * to a time; "infinity" and "inf" are 'special.'
72068bbf3adSDavid Nugent */
72168bbf3adSDavid Nugent
72268bbf3adSDavid Nugent rlim_t
login_getcapnum(login_cap_t * lc,const char * cap,rlim_t def,rlim_t error)72368bbf3adSDavid Nugent login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
72468bbf3adSDavid Nugent {
72568bbf3adSDavid Nugent char *ep, *res;
72656c04344SDavid Nugent int r;
72768bbf3adSDavid Nugent rlim_t val;
72868bbf3adSDavid Nugent
72968bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL)
73068bbf3adSDavid Nugent return def;
73168bbf3adSDavid Nugent
73268bbf3adSDavid Nugent /*
73368bbf3adSDavid Nugent * For BSDI compatibility, try for the tag=<val> first
73468bbf3adSDavid Nugent */
735b8c1aadeSOlivier Certner r = cgetstr(lc->lc_cap, cap, &res);
736b8c1aadeSOlivier Certner if (r == -1) {
73768bbf3adSDavid Nugent long lval;
73856c04344SDavid Nugent /* string capability not present, so try for tag#<val> as numeric */
739547fa0d9SMark Murray if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1)
74068bbf3adSDavid Nugent return def; /* Not there, so return default */
741b8c1aadeSOlivier Certner else if (r < 0)
74256c04344SDavid Nugent return error;
743b8c1aadeSOlivier Certner else
744b8c1aadeSOlivier Certner return (rlim_t)lval;
745b8c1aadeSOlivier Certner } else if (r < 0)
746b8c1aadeSOlivier Certner return error;
74756c04344SDavid Nugent
74856c04344SDavid Nugent if (isinfinite(res))
74968bbf3adSDavid Nugent return RLIM_INFINITY;
75068bbf3adSDavid Nugent
75168bbf3adSDavid Nugent errno = 0;
75256c04344SDavid Nugent val = strtoq(res, &ep, 0);
75356c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) {
75456c04344SDavid Nugent syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
75556c04344SDavid Nugent lc->lc_class, cap, res);
75656c04344SDavid Nugent errno = ERANGE;
75768bbf3adSDavid Nugent return error;
75856c04344SDavid Nugent }
75956c04344SDavid Nugent
76068bbf3adSDavid Nugent return val;
76168bbf3adSDavid Nugent }
76268bbf3adSDavid Nugent
763*90e914cdSOlivier Certner /*
764*90e914cdSOlivier Certner * Extract a string capability expected to hold a specific value from a list.
765*90e914cdSOlivier Certner *
766*90e914cdSOlivier Certner * 'values' must be a NULL-terminated array of strings listing the possible
767*90e914cdSOlivier Certner * values.
768*90e914cdSOlivier Certner *
769*90e914cdSOlivier Certner * A non-negative return code indicates success, and is the index of the value
770*90e914cdSOlivier Certner * in 'values' the capability is set to.
771*90e914cdSOlivier Certner *
772*90e914cdSOlivier Certner * Negative return codes indicate an error:
773*90e914cdSOlivier Certner * -4: 'lc' or 'cap' insufficiently initialized or not valid.
774*90e914cdSOlivier Certner * -3: System error (allocation failure).
775*90e914cdSOlivier Certner * -2: Capability not found or not a string.
776*90e914cdSOlivier Certner * -1: Capability has a string value, but not one listed in 'values'.
777*90e914cdSOlivier Certner */
778*90e914cdSOlivier Certner int
login_getcapenum(login_cap_t * lc,const char * cap,const char * const * values)779*90e914cdSOlivier Certner login_getcapenum(login_cap_t *lc, const char *cap, const char * const *values)
780*90e914cdSOlivier Certner {
781*90e914cdSOlivier Certner int ret, i;
782*90e914cdSOlivier Certner char *cand;
783*90e914cdSOlivier Certner const char * const *val;
784*90e914cdSOlivier Certner
785*90e914cdSOlivier Certner if (lc == NULL || lc->lc_cap == NULL || cap == NULL || *cap == '\0')
786*90e914cdSOlivier Certner return (-4);
787*90e914cdSOlivier Certner
788*90e914cdSOlivier Certner ret = cgetstr(lc->lc_cap, cap, &cand);
789*90e914cdSOlivier Certner
790*90e914cdSOlivier Certner if (ret == -1)
791*90e914cdSOlivier Certner /* Cap not found. */
792*90e914cdSOlivier Certner return (-2);
793*90e914cdSOlivier Certner else if (ret < 0)
794*90e914cdSOlivier Certner /* System error (normally, allocation failure). */
795*90e914cdSOlivier Certner return (-3);
796*90e914cdSOlivier Certner
797*90e914cdSOlivier Certner ret = -1;
798*90e914cdSOlivier Certner
799*90e914cdSOlivier Certner for (i = 0, val = values; *val != NULL; val++)
800*90e914cdSOlivier Certner if (strcmp(cand, *val) == 0) {
801*90e914cdSOlivier Certner ret = i;
802*90e914cdSOlivier Certner break;
803*90e914cdSOlivier Certner }
804*90e914cdSOlivier Certner
805*90e914cdSOlivier Certner free(cand);
806*90e914cdSOlivier Certner return (ret);
807*90e914cdSOlivier Certner }
808*90e914cdSOlivier Certner
80968bbf3adSDavid Nugent
81056c04344SDavid Nugent
81168bbf3adSDavid Nugent /*
81268bbf3adSDavid Nugent * login_getcapsize()
81368bbf3adSDavid Nugent * From the login_cap_t <lc>, extract the capability <cap>, which is
81468bbf3adSDavid Nugent * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
81568bbf3adSDavid Nugent * If not present, return <def>, or <error> if there is an error of
81668bbf3adSDavid Nugent * some sort.
81768bbf3adSDavid Nugent */
81868bbf3adSDavid Nugent
81968bbf3adSDavid Nugent rlim_t
login_getcapsize(login_cap_t * lc,const char * cap,rlim_t def,rlim_t error)82056c04344SDavid Nugent login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
82156c04344SDavid Nugent {
82256c04344SDavid Nugent char *ep, *res, *oval;
82356c04344SDavid Nugent int r;
82456c04344SDavid Nugent rlim_t tot;
82568bbf3adSDavid Nugent
82668bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL)
82768bbf3adSDavid Nugent return def;
82868bbf3adSDavid Nugent
829547fa0d9SMark Murray if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
83068bbf3adSDavid Nugent return def;
831b8c1aadeSOlivier Certner else if (r < 0)
83268bbf3adSDavid Nugent return error;
83368bbf3adSDavid Nugent
83456c04344SDavid Nugent if (isinfinite(res))
83565f50b7fSAndrey A. Chernov return RLIM_INFINITY;
83665f50b7fSAndrey A. Chernov
83768bbf3adSDavid Nugent errno = 0;
83851706563SDavid Nugent tot = 0;
83956c04344SDavid Nugent oval = res;
84051706563SDavid Nugent while (*res) {
84156c04344SDavid Nugent rlim_t siz = strtoq(res, &ep, 0);
84256c04344SDavid Nugent rlim_t mult = 1;
84356c04344SDavid Nugent
84456c04344SDavid Nugent if (ep == NULL || ep == res || errno != 0) {
84556c04344SDavid Nugent invalid:
84656c04344SDavid Nugent syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
84756c04344SDavid Nugent lc->lc_class, cap, oval);
84856c04344SDavid Nugent errno = ERANGE;
84968bbf3adSDavid Nugent return error;
85056c04344SDavid Nugent }
851f9074e29SDavid Nugent switch (*ep++) {
85268bbf3adSDavid Nugent case 0: /* end of string */
85351706563SDavid Nugent ep--;
85451706563SDavid Nugent break;
85568bbf3adSDavid Nugent case 'b': case 'B': /* 512-byte blocks */
85656c04344SDavid Nugent mult = 512;
85756c04344SDavid Nugent break;
85868bbf3adSDavid Nugent case 'k': case 'K': /* 1024-byte Kilobytes */
85956c04344SDavid Nugent mult = 1024;
86056c04344SDavid Nugent break;
86168bbf3adSDavid Nugent case 'm': case 'M': /* 1024-k kbytes */
86256c04344SDavid Nugent mult = 1024 * 1024;
86356c04344SDavid Nugent break;
86468bbf3adSDavid Nugent case 'g': case 'G': /* 1Gbyte */
86556c04344SDavid Nugent mult = 1024 * 1024 * 1024;
86656c04344SDavid Nugent break;
86768bbf3adSDavid Nugent case 't': case 'T': /* 1TBte */
86856c04344SDavid Nugent mult = 1024LL * 1024LL * 1024LL * 1024LL;
86956c04344SDavid Nugent break;
87068bbf3adSDavid Nugent default:
87156c04344SDavid Nugent goto invalid;
87268bbf3adSDavid Nugent }
873f9074e29SDavid Nugent res = ep;
87456c04344SDavid Nugent tot += rmultiply(siz, mult);
87556c04344SDavid Nugent if (errno)
87656c04344SDavid Nugent goto invalid;
87751706563SDavid Nugent }
87856c04344SDavid Nugent
87951706563SDavid Nugent return tot;
88068bbf3adSDavid Nugent }
88168bbf3adSDavid Nugent
88268bbf3adSDavid Nugent
88368bbf3adSDavid Nugent /*
88468bbf3adSDavid Nugent * login_getcapbool()
885872a3a62SPedro F. Giffuni * From the login_cap_t <lc>, check for the existence of the capability
88668bbf3adSDavid Nugent * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
88768bbf3adSDavid Nugent * the whether or not <cap> exists there.
88868bbf3adSDavid Nugent */
88968bbf3adSDavid Nugent
89068bbf3adSDavid Nugent int
login_getcapbool(login_cap_t * lc,const char * cap,int def)89168bbf3adSDavid Nugent login_getcapbool(login_cap_t *lc, const char *cap, int def)
89268bbf3adSDavid Nugent {
89368bbf3adSDavid Nugent if (lc == NULL || lc->lc_cap == NULL)
89468bbf3adSDavid Nugent return def;
895547fa0d9SMark Murray return (cgetcap(lc->lc_cap, cap, ':') != NULL);
89668bbf3adSDavid Nugent }
89768bbf3adSDavid Nugent
89868bbf3adSDavid Nugent
89968bbf3adSDavid Nugent /*
90068bbf3adSDavid Nugent * login_getstyle()
90168bbf3adSDavid Nugent * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
90268bbf3adSDavid Nugent * and optionally a style <style>, find the style that best suits these
90368bbf3adSDavid Nugent * rules:
90468bbf3adSDavid Nugent * 1. If <auth> is non-null, look for an "auth-<auth>=" string
90568bbf3adSDavid Nugent * in the capability; if not present, default to "auth=".
90668bbf3adSDavid Nugent * 2. If there is no auth list found from (1), default to
90768bbf3adSDavid Nugent * "passwd" as an authorization list.
90868bbf3adSDavid Nugent * 3. If <style> is non-null, look for <style> in the list of
90968bbf3adSDavid Nugent * authorization methods found from (2); if <style> is NULL, default
91068bbf3adSDavid Nugent * to LOGIN_DEFSTYLE ("passwd").
91168bbf3adSDavid Nugent * 4. If the chosen style is found in the chosen list of authorization
91268bbf3adSDavid Nugent * methods, return that; otherwise, return NULL.
91368bbf3adSDavid Nugent * E.g.:
91468bbf3adSDavid Nugent * login_getstyle(lc, NULL, "ftp");
91568bbf3adSDavid Nugent * login_getstyle(lc, "login", NULL);
91668bbf3adSDavid Nugent * login_getstyle(lc, "skey", "network");
91768bbf3adSDavid Nugent */
91868bbf3adSDavid Nugent
919b00ba4ccSRuslan Ermilov const char *
login_getstyle(login_cap_t * lc,const char * style,const char * auth)920b00ba4ccSRuslan Ermilov login_getstyle(login_cap_t *lc, const char *style, const char *auth)
92168bbf3adSDavid Nugent {
92268bbf3adSDavid Nugent int i;
923547fa0d9SMark Murray const char **authtypes = NULL;
92468bbf3adSDavid Nugent char *auths= NULL;
92568bbf3adSDavid Nugent char realauth[64];
92668bbf3adSDavid Nugent
927547fa0d9SMark Murray static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
92868bbf3adSDavid Nugent
92956c04344SDavid Nugent if (auth != NULL && *auth != '\0') {
930547fa0d9SMark Murray if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth))
93168bbf3adSDavid Nugent authtypes = login_getcaplist(lc, realauth, NULL);
93256c04344SDavid Nugent }
93368bbf3adSDavid Nugent
93468bbf3adSDavid Nugent if (authtypes == NULL)
93568bbf3adSDavid Nugent authtypes = login_getcaplist(lc, "auth", NULL);
93668bbf3adSDavid Nugent
93768bbf3adSDavid Nugent if (authtypes == NULL)
93868bbf3adSDavid Nugent authtypes = defauthtypes;
93968bbf3adSDavid Nugent
94068bbf3adSDavid Nugent /*
9419a01d32bSJeroen Ruigrok van der Werven * We have at least one authtype now; auths is a comma-separated
94268bbf3adSDavid Nugent * (or space-separated) list of authentication types. We have to
94368bbf3adSDavid Nugent * convert from this to an array of char*'s; authtypes then gets this.
94468bbf3adSDavid Nugent */
94568bbf3adSDavid Nugent i = 0;
94668bbf3adSDavid Nugent if (style != NULL && *style != '\0') {
94768bbf3adSDavid Nugent while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
94868bbf3adSDavid Nugent i++;
94968bbf3adSDavid Nugent }
95056c04344SDavid Nugent
95168bbf3adSDavid Nugent lc->lc_style = NULL;
95268bbf3adSDavid Nugent if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
95368bbf3adSDavid Nugent lc->lc_style = auths;
95468bbf3adSDavid Nugent
95556c04344SDavid Nugent if (lc->lc_style != NULL)
95656c04344SDavid Nugent lc->lc_style = strdup(lc->lc_style);
95756c04344SDavid Nugent
95868bbf3adSDavid Nugent return lc->lc_style;
95968bbf3adSDavid Nugent }
960