xref: /freebsd/lib/libutil/login_cap.c (revision b8c1aadef9d80786daf731300c33d3a001261422)
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, &quoted);
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