xref: /freebsd/lib/libutil/login_cap.c (revision d1d4d95209e4ba5da75c16a5653bc46fca6418f8)
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>
308719c58fSMatthew Dillon __FBSDID("$FreeBSD$");
318719c58fSMatthew Dillon 
3268bbf3adSDavid Nugent #include <sys/types.h>
3368bbf3adSDavid Nugent #include <sys/time.h>
3468bbf3adSDavid Nugent #include <sys/resource.h>
3568bbf3adSDavid Nugent #include <sys/param.h>
360ebec5d3SMark Murray #include <errno.h>
370ebec5d3SMark Murray #include <fcntl.h>
3856c04344SDavid Nugent #include <libutil.h>
3968bbf3adSDavid Nugent #include <login_cap.h>
400ebec5d3SMark Murray #include <pwd.h>
410ebec5d3SMark Murray #include <stdio.h>
420ebec5d3SMark Murray #include <stdlib.h>
430ebec5d3SMark Murray #include <string.h>
440ebec5d3SMark Murray #include <syslog.h>
450ebec5d3SMark Murray #include <unistd.h>
4668bbf3adSDavid Nugent 
4756c04344SDavid Nugent /*
4856c04344SDavid Nugent  * allocstr()
4956c04344SDavid Nugent  * Manage a single static pointer for handling a local char* buffer,
5056c04344SDavid Nugent  * resizing as necessary to contain the string.
5156c04344SDavid Nugent  *
5256c04344SDavid Nugent  * allocarray()
5356c04344SDavid Nugent  * Manage a static array for handling a group of strings, resizing
5456c04344SDavid Nugent  * when necessary.
5556c04344SDavid Nugent  */
5668bbf3adSDavid Nugent 
5768bbf3adSDavid Nugent static int lc_object_count = 0;
5868bbf3adSDavid Nugent 
5968bbf3adSDavid Nugent static size_t internal_stringsz = 0;
6068bbf3adSDavid Nugent static char * internal_string = NULL;
6168bbf3adSDavid Nugent static size_t internal_arraysz = 0;
62547fa0d9SMark Murray static const char ** internal_array = NULL;
6368bbf3adSDavid Nugent 
64b8a5cd86SDag-Erling Smørgrav static char path_login_conf[] = _PATH_LOGIN_CONF;
65b8a5cd86SDag-Erling Smørgrav 
6668bbf3adSDavid Nugent static char *
67547fa0d9SMark Murray allocstr(const char *str)
6868bbf3adSDavid Nugent {
6968bbf3adSDavid Nugent     char    *p;
7056c04344SDavid Nugent 
7168bbf3adSDavid Nugent     size_t sz = strlen(str) + 1;	/* realloc() only if necessary */
7268bbf3adSDavid Nugent     if (sz <= internal_stringsz)
731c594de5SDavid Nugent 	p = strcpy(internal_string, str);
7468bbf3adSDavid Nugent     else if ((p = realloc(internal_string, sz)) != NULL) {
7568bbf3adSDavid Nugent 	internal_stringsz = sz;
7668bbf3adSDavid Nugent 	internal_string = strcpy(p, str);
7768bbf3adSDavid Nugent     }
7868bbf3adSDavid Nugent     return p;
7968bbf3adSDavid Nugent }
8068bbf3adSDavid Nugent 
8156c04344SDavid Nugent 
82547fa0d9SMark Murray static const char **
8368bbf3adSDavid Nugent allocarray(size_t sz)
8468bbf3adSDavid Nugent {
85547fa0d9SMark Murray     static const char    **p;
8656c04344SDavid Nugent 
8768bbf3adSDavid Nugent     if (sz <= internal_arraysz)
8868bbf3adSDavid Nugent 	p = internal_array;
8968bbf3adSDavid Nugent     else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
9068bbf3adSDavid Nugent 	internal_arraysz = sz;
9168bbf3adSDavid Nugent 	internal_array = p;
9268bbf3adSDavid Nugent     }
9368bbf3adSDavid Nugent     return p;
9468bbf3adSDavid Nugent }
9568bbf3adSDavid Nugent 
9668bbf3adSDavid Nugent 
9768bbf3adSDavid Nugent /*
9868bbf3adSDavid Nugent  * arrayize()
999a01d32bSJeroen Ruigrok van der Werven  * Turn a simple string <str> separated by any of
10068bbf3adSDavid Nugent  * the set of <chars> into an array.  The last element
10168bbf3adSDavid Nugent  * of the array will be NULL, as is proper.
10268bbf3adSDavid Nugent  * Free using freearraystr()
10368bbf3adSDavid Nugent  */
10468bbf3adSDavid Nugent 
105547fa0d9SMark Murray static const char **
106547fa0d9SMark Murray arrayize(const char *str, const char *chars, int *size)
10768bbf3adSDavid Nugent {
10868bbf3adSDavid Nugent     int	    i;
10905bcd1d0SPeter Wemm     char *ptr;
11005bcd1d0SPeter Wemm     const char *cptr;
111547fa0d9SMark Murray     const char **res = NULL;
11268bbf3adSDavid Nugent 
11356c04344SDavid Nugent     /* count the sub-strings */
11405bcd1d0SPeter Wemm     for (i = 0, cptr = str; *cptr; i++) {
11505bcd1d0SPeter Wemm 	int count = strcspn(cptr, chars);
11605bcd1d0SPeter Wemm 	cptr += count;
11705bcd1d0SPeter Wemm 	if (*cptr)
11805bcd1d0SPeter Wemm 	    ++cptr;
11968bbf3adSDavid Nugent     }
12068bbf3adSDavid Nugent 
12156c04344SDavid Nugent     /* alloc the array */
12256c04344SDavid Nugent     if ((ptr = allocstr(str)) != NULL) {
12356c04344SDavid Nugent 	if ((res = allocarray(++i)) == NULL)
12405bcd1d0SPeter Wemm 	    free((void *)(uintptr_t)(const void *)str);
12556c04344SDavid Nugent 	else {
12656c04344SDavid Nugent 	    /* now split the string */
1275f3a7367SDavid Nugent 	    i = 0;
12856c04344SDavid Nugent 	    while (*ptr) {
12968bbf3adSDavid Nugent 		int count = strcspn(ptr, chars);
13056c04344SDavid Nugent 		res[i++] = ptr;
13168bbf3adSDavid Nugent 		ptr += count;
13268bbf3adSDavid Nugent 		if (*ptr)
13368bbf3adSDavid Nugent 		    *ptr++ = '\0';
13468bbf3adSDavid Nugent 	    }
13556c04344SDavid Nugent 	    res[i] = NULL;
13668bbf3adSDavid Nugent 	}
13756c04344SDavid Nugent     }
13856c04344SDavid Nugent 
13968bbf3adSDavid Nugent     if (size)
14068bbf3adSDavid Nugent 	*size = i;
14156c04344SDavid Nugent 
14268bbf3adSDavid Nugent     return res;
14368bbf3adSDavid Nugent }
14468bbf3adSDavid Nugent 
14556c04344SDavid Nugent 
14668bbf3adSDavid Nugent /*
14768bbf3adSDavid Nugent  * login_close()
14868bbf3adSDavid Nugent  * Frees up all resources relating to a login class
14968bbf3adSDavid Nugent  *
15068bbf3adSDavid Nugent  */
15168bbf3adSDavid Nugent 
15268bbf3adSDavid Nugent void
15368bbf3adSDavid Nugent login_close(login_cap_t * lc)
15468bbf3adSDavid Nugent {
15568bbf3adSDavid Nugent     if (lc) {
15668bbf3adSDavid Nugent 	free(lc->lc_style);
15768bbf3adSDavid Nugent 	free(lc->lc_class);
1583f81737fSTim Vanderhoek 	free(lc->lc_cap);
15968bbf3adSDavid Nugent 	free(lc);
16068bbf3adSDavid Nugent 	if (--lc_object_count == 0) {
16168bbf3adSDavid Nugent 	    free(internal_string);
1622955fda4SDavid Nugent 	    free(internal_array);
16368bbf3adSDavid Nugent 	    internal_array = NULL;
16451706563SDavid Nugent 	    internal_arraysz = 0;
16568bbf3adSDavid Nugent 	    internal_string = NULL;
16651706563SDavid Nugent 	    internal_stringsz = 0;
16768bbf3adSDavid Nugent 	    cgetclose();
16868bbf3adSDavid Nugent 	}
16968bbf3adSDavid Nugent     }
17068bbf3adSDavid Nugent }
17168bbf3adSDavid Nugent 
17268bbf3adSDavid Nugent 
17368bbf3adSDavid Nugent /*
174a7429823SYaroslav Tykhiy  * login_getclassbyname()
175a7429823SYaroslav Tykhiy  * Get the login class by its name.
17668bbf3adSDavid Nugent  * If the name given is NULL or empty, the default class
177a7429823SYaroslav Tykhiy  * LOGIN_DEFCLASS (i.e., "default") is fetched.
178a7429823SYaroslav Tykhiy  * If the name given is LOGIN_MECLASS and
17994cf9da0SDiomidis Spinellis  * 'pwd' argument is non-NULL and contains an non-NULL
18094cf9da0SDiomidis Spinellis  * dir entry, then the file _FILE_LOGIN_CONF is picked
18194cf9da0SDiomidis Spinellis  * up from that directory and used before the system
182a7429823SYaroslav Tykhiy  * login database. In that case the system login database
183a7429823SYaroslav Tykhiy  * is looked up using LOGIN_MECLASS, too, which is a bug.
18468bbf3adSDavid Nugent  * Return a filled-out login_cap_t structure, including
18568bbf3adSDavid Nugent  * class name, and the capability record buffer.
18668bbf3adSDavid Nugent  */
18768bbf3adSDavid Nugent 
18868bbf3adSDavid Nugent login_cap_t *
18956c04344SDavid Nugent login_getclassbyname(char const *name, const struct passwd *pwd)
19068bbf3adSDavid Nugent {
19156c04344SDavid Nugent     login_cap_t	*lc;
19268bbf3adSDavid Nugent 
19356c04344SDavid Nugent     if ((lc = malloc(sizeof(login_cap_t))) != NULL) {
194e36b245cSAndrey A. Chernov 	int         r, me, i = 0;
1958a2deaa1SAndrey A. Chernov 	uid_t euid = 0;
1968a2deaa1SAndrey A. Chernov 	gid_t egid = 0;
19756c04344SDavid Nugent 	const char  *msg = NULL;
198e36b245cSAndrey A. Chernov 	const char  *dir;
19968bbf3adSDavid Nugent 	char	    userpath[MAXPATHLEN];
20056c04344SDavid Nugent 
20105bcd1d0SPeter Wemm 	static char *login_dbarray[] = { NULL, NULL, NULL };
20268bbf3adSDavid Nugent 
203e36b245cSAndrey A. Chernov 	me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0);
204e36b245cSAndrey A. Chernov 	dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir;
2058df8b73fSRobert Watson 	/*
2068df8b73fSRobert Watson 	 * Switch to user mode before checking/reading its ~/.login_conf
2078df8b73fSRobert Watson 	 * - some NFSes have root read access disabled.
2088df8b73fSRobert Watson 	 *
2098df8b73fSRobert Watson 	 * XXX: This fails to configure additional groups.
2108df8b73fSRobert Watson 	 */
2118a2deaa1SAndrey A. Chernov 	if (dir) {
212ae702574SAndrey A. Chernov 	    euid = geteuid();
213ae702574SAndrey A. Chernov 	    egid = getegid();
214ae702574SAndrey A. Chernov 	    (void)setegid(pwd->pw_gid);
215ae702574SAndrey A. Chernov 	    (void)seteuid(pwd->pw_uid);
2168a2deaa1SAndrey A. Chernov 	}
217ae702574SAndrey A. Chernov 
21856c04344SDavid Nugent 	if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
21956c04344SDavid Nugent 			    _FILE_LOGIN_CONF) < MAXPATHLEN) {
22056c04344SDavid Nugent 	    if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
221b8a5cd86SDag-Erling Smørgrav 		login_dbarray[i++] = userpath;
22256c04344SDavid Nugent 	}
223a7429823SYaroslav Tykhiy 	/*
224a7429823SYaroslav Tykhiy 	 * XXX: Why to add the system database if the class is `me'?
225a7429823SYaroslav Tykhiy 	 */
226b8a5cd86SDag-Erling Smørgrav 	if (_secure_path(path_login_conf, 0, 0) != -1)
227b8a5cd86SDag-Erling Smørgrav 	    login_dbarray[i++] = path_login_conf;
22868bbf3adSDavid Nugent 	login_dbarray[i] = NULL;
22968bbf3adSDavid Nugent 
23056c04344SDavid Nugent 	memset(lc, 0, sizeof(login_cap_t));
23168bbf3adSDavid Nugent 	lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
23268bbf3adSDavid Nugent 
23356c04344SDavid Nugent 	if (name == NULL || *name == '\0')
23456c04344SDavid Nugent 	    name = LOGIN_DEFCLASS;
23568bbf3adSDavid Nugent 
236547fa0d9SMark Murray 	switch (cgetent(&lc->lc_cap, login_dbarray, name)) {
23756c04344SDavid Nugent 	case -1:		/* Failed, entry does not exist */
238e36b245cSAndrey A. Chernov 	    if (me)
23956c04344SDavid Nugent 		break;	/* Don't retry default on 'me' */
24056c04344SDavid Nugent 	    if (i == 0)
24156c04344SDavid Nugent 	        r = -1;
242*d1d4d952SJilles Tjoelker 	    else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0)
24356c04344SDavid Nugent 	        close(r);
24456c04344SDavid Nugent 	    /*
24556c04344SDavid Nugent 	     * If there's at least one login class database,
24656c04344SDavid Nugent 	     * and we aren't searching for a default class
24756c04344SDavid Nugent 	     * then complain about a non-existent class.
24856c04344SDavid Nugent 	     */
24956c04344SDavid Nugent 	    if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
25056c04344SDavid Nugent 		syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
25156c04344SDavid Nugent 	    /* fall-back to default class */
25256c04344SDavid Nugent 	    name = LOGIN_DEFCLASS;
25356c04344SDavid Nugent 	    msg = "%s: no default/fallback class '%s'";
254547fa0d9SMark Murray 	    if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0)
25556c04344SDavid Nugent 		break;
2567fed38d0SPhilippe Charnier 	    /* FALLTHROUGH - just return system defaults */
25756c04344SDavid Nugent 	case 0:		/* success! */
25856c04344SDavid Nugent 	    if ((lc->lc_class = strdup(name)) != NULL) {
2598a2deaa1SAndrey A. Chernov 		if (dir) {
260ae702574SAndrey A. Chernov 		    (void)seteuid(euid);
261ae702574SAndrey A. Chernov 		    (void)setegid(egid);
2628a2deaa1SAndrey A. Chernov 		}
26356c04344SDavid Nugent 		++lc_object_count;
26468bbf3adSDavid Nugent 		return lc;
26568bbf3adSDavid Nugent 	    }
26656c04344SDavid Nugent 	    msg = "%s: strdup: %m";
26756c04344SDavid Nugent 	    break;
26856c04344SDavid Nugent 	case -2:
26956c04344SDavid Nugent 	    msg = "%s: retrieving class information: %m";
27056c04344SDavid Nugent 	    break;
27156c04344SDavid Nugent 	case -3:
27256c04344SDavid Nugent 	    msg = "%s: 'tc=' reference loop '%s'";
27356c04344SDavid Nugent 	    break;
27456c04344SDavid Nugent 	case 1:
27556c04344SDavid Nugent 	    msg = "couldn't resolve 'tc=' reference in '%s'";
27656c04344SDavid Nugent 	    break;
27756c04344SDavid Nugent 	default:
27856c04344SDavid Nugent 	    msg = "%s: unexpected cgetent() error '%s': %m";
27956c04344SDavid Nugent 	    break;
28056c04344SDavid Nugent 	}
2818a2deaa1SAndrey A. Chernov 	if (dir) {
282ae702574SAndrey A. Chernov 	    (void)seteuid(euid);
283ae702574SAndrey A. Chernov 	    (void)setegid(egid);
2848a2deaa1SAndrey A. Chernov 	}
28556c04344SDavid Nugent 	if (msg != NULL)
28656c04344SDavid Nugent 	    syslog(LOG_ERR, msg, "login_getclass", name);
28756c04344SDavid Nugent 	free(lc);
28856c04344SDavid Nugent     }
28968bbf3adSDavid Nugent 
29056c04344SDavid Nugent     return NULL;
29156c04344SDavid Nugent }
29256c04344SDavid Nugent 
29356c04344SDavid Nugent 
29456c04344SDavid Nugent 
29556c04344SDavid Nugent /*
29656c04344SDavid Nugent  * login_getclass()
29756c04344SDavid Nugent  * Get the login class for the system (only) login class database.
29856c04344SDavid Nugent  * Return a filled-out login_cap_t structure, including
29956c04344SDavid Nugent  * class name, and the capability record buffer.
30056c04344SDavid Nugent  */
30156c04344SDavid Nugent 
30256c04344SDavid Nugent login_cap_t *
30356c04344SDavid Nugent login_getclass(const char *cls)
30456c04344SDavid Nugent {
30556c04344SDavid Nugent     return login_getclassbyname(cls, NULL);
30656c04344SDavid Nugent }
30768bbf3adSDavid Nugent 
30868bbf3adSDavid Nugent 
30968bbf3adSDavid Nugent /*
310a7429823SYaroslav Tykhiy  * login_getpwclass()
31168bbf3adSDavid Nugent  * Get the login class for a given password entry from
31268bbf3adSDavid Nugent  * the system (only) login class database.
31368bbf3adSDavid Nugent  * If the password entry's class field is not set, or
31468bbf3adSDavid Nugent  * the class specified does not exist, then use the
315a7429823SYaroslav Tykhiy  * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged
316a7429823SYaroslav Tykhiy  * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user.
31768bbf3adSDavid Nugent  * Return a filled-out login_cap_t structure, including
31868bbf3adSDavid Nugent  * class name, and the capability record buffer.
31968bbf3adSDavid Nugent  */
32068bbf3adSDavid Nugent 
32168bbf3adSDavid Nugent login_cap_t *
32256c04344SDavid Nugent login_getpwclass(const struct passwd *pwd)
32368bbf3adSDavid Nugent {
32456c04344SDavid Nugent     const char	*cls = NULL;
32556c04344SDavid Nugent 
3261c594de5SDavid Nugent     if (pwd != NULL) {
32756c04344SDavid Nugent 	cls = pwd->pw_class;
32856c04344SDavid Nugent 	if (cls == NULL || *cls == '\0')
32956c04344SDavid Nugent 	    cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
3302dc7d862SDavid Nugent     }
331a7429823SYaroslav Tykhiy     /*
332a7429823SYaroslav Tykhiy      * XXX: pwd should be unused by login_getclassbyname() unless cls is `me',
333a7429823SYaroslav Tykhiy      *      so NULL can be passed instead of pwd for more safety.
334a7429823SYaroslav Tykhiy      */
33556c04344SDavid Nugent     return login_getclassbyname(cls, pwd);
33668bbf3adSDavid Nugent }
33768bbf3adSDavid Nugent 
33868bbf3adSDavid Nugent 
33968bbf3adSDavid Nugent /*
34068bbf3adSDavid Nugent  * login_getuserclass()
341a7429823SYaroslav Tykhiy  * Get the `me' login class, allowing user overrides via ~/.login_conf.
342a7429823SYaroslav Tykhiy  * Note that user overrides are allowed only in the `me' class.
34368bbf3adSDavid Nugent  */
34468bbf3adSDavid Nugent 
34568bbf3adSDavid Nugent login_cap_t *
34668bbf3adSDavid Nugent login_getuserclass(const struct passwd *pwd)
34768bbf3adSDavid Nugent {
34856c04344SDavid Nugent     return login_getclassbyname(LOGIN_MECLASS, pwd);
34968bbf3adSDavid Nugent }
35068bbf3adSDavid Nugent 
35168bbf3adSDavid Nugent 
35268bbf3adSDavid Nugent /*
35368bbf3adSDavid Nugent  * login_getcapstr()
35468bbf3adSDavid Nugent  * Given a login_cap entry, and a capability name, return the
355043d661dSTom Rhodes  * value defined for that capability, a default if not found, or
35668bbf3adSDavid Nugent  * an error string on error.
35768bbf3adSDavid Nugent  */
35868bbf3adSDavid Nugent 
359b00ba4ccSRuslan Ermilov const char *
360b00ba4ccSRuslan Ermilov login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error)
36168bbf3adSDavid Nugent {
36268bbf3adSDavid Nugent     char    *res;
36368bbf3adSDavid Nugent     int	    ret;
36468bbf3adSDavid Nugent 
36568bbf3adSDavid Nugent     if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
36668bbf3adSDavid Nugent 	return def;
36768bbf3adSDavid Nugent 
368547fa0d9SMark Murray     if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1)
36968bbf3adSDavid Nugent 	return def;
37056c04344SDavid Nugent     return (ret >= 0) ? res : error;
37168bbf3adSDavid Nugent }
37268bbf3adSDavid Nugent 
37368bbf3adSDavid Nugent 
37468bbf3adSDavid Nugent /*
37568bbf3adSDavid Nugent  * login_getcaplist()
37668bbf3adSDavid Nugent  * Given a login_cap entry, and a capability name, return the
37768bbf3adSDavid Nugent  * value defined for that capability split into an array of
37868bbf3adSDavid Nugent  * strings.
37968bbf3adSDavid Nugent  */
38068bbf3adSDavid Nugent 
381547fa0d9SMark Murray const char **
38268bbf3adSDavid Nugent login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
38368bbf3adSDavid Nugent {
384547fa0d9SMark Murray     const char *lstring;
38568bbf3adSDavid Nugent 
38668bbf3adSDavid Nugent     if (chars == NULL)
387f01e3989SDavid Nugent 	chars = ", \t";
388547fa0d9SMark Murray     if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL)
38968bbf3adSDavid Nugent 	return arrayize(lstring, chars, NULL);
39068bbf3adSDavid Nugent     return NULL;
39168bbf3adSDavid Nugent }
39268bbf3adSDavid Nugent 
39368bbf3adSDavid Nugent 
39468bbf3adSDavid Nugent /*
39568bbf3adSDavid Nugent  * login_getpath()
39668bbf3adSDavid Nugent  * From the login_cap_t <lc>, get the capability <cap> which is
39768bbf3adSDavid Nugent  * formatted as either a space or comma delimited list of paths
39868bbf3adSDavid Nugent  * and append them all into a string and separate by semicolons.
39968bbf3adSDavid Nugent  * If there is an error of any kind, return <error>.
40068bbf3adSDavid Nugent  */
40168bbf3adSDavid Nugent 
402b00ba4ccSRuslan Ermilov const char *
403b00ba4ccSRuslan Ermilov login_getpath(login_cap_t *lc, const char *cap, const char *error)
40468bbf3adSDavid Nugent {
405b00ba4ccSRuslan Ermilov     const char *str;
406547fa0d9SMark Murray     char *ptr;
407547fa0d9SMark Murray     int count;
40868bbf3adSDavid Nugent 
409547fa0d9SMark Murray     str = login_getcapstr(lc, cap, NULL, NULL);
410547fa0d9SMark Murray     if (str == NULL)
411547fa0d9SMark Murray 	return error;
412547fa0d9SMark Murray     ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */
41368bbf3adSDavid Nugent     while (*ptr) {
414547fa0d9SMark Murray 	count = strcspn(ptr, ", \t");
41568bbf3adSDavid Nugent 	ptr += count;
41668bbf3adSDavid Nugent 	if (*ptr)
41768bbf3adSDavid Nugent 	    *ptr++ = ':';
41868bbf3adSDavid Nugent     }
41968bbf3adSDavid Nugent     return str;
42068bbf3adSDavid Nugent }
42168bbf3adSDavid Nugent 
42268bbf3adSDavid Nugent 
42356c04344SDavid Nugent static int
42456c04344SDavid Nugent isinfinite(const char *s)
42556c04344SDavid Nugent {
42656c04344SDavid Nugent     static const char *infs[] = {
42756c04344SDavid Nugent 	"infinity",
42856c04344SDavid Nugent 	"inf",
42956c04344SDavid Nugent 	"unlimited",
43056c04344SDavid Nugent 	"unlimit",
43156c04344SDavid Nugent 	"-1",
43256c04344SDavid Nugent 	NULL
43356c04344SDavid Nugent     };
43456c04344SDavid Nugent     const char **i = &infs[0];
43556c04344SDavid Nugent 
43656c04344SDavid Nugent     while (*i != NULL) {
43756c04344SDavid Nugent 	if (strcasecmp(s, *i) == 0)
43856c04344SDavid Nugent 	    return 1;
43956c04344SDavid Nugent 	++i;
44056c04344SDavid Nugent     }
44156c04344SDavid Nugent     return 0;
44256c04344SDavid Nugent }
44356c04344SDavid Nugent 
44456c04344SDavid Nugent 
44556c04344SDavid Nugent static u_quad_t
44656c04344SDavid Nugent rmultiply(u_quad_t n1, u_quad_t n2)
44756c04344SDavid Nugent {
44856c04344SDavid Nugent     u_quad_t	m, r;
44956c04344SDavid Nugent     int		b1, b2;
45056c04344SDavid Nugent 
45156c04344SDavid Nugent     static int bpw = 0;
45256c04344SDavid Nugent 
45356c04344SDavid Nugent     /* Handle simple cases */
45456c04344SDavid Nugent     if (n1 == 0 || n2 == 0)
45556c04344SDavid Nugent 	return 0;
45656c04344SDavid Nugent     if (n1 == 1)
45756c04344SDavid Nugent 	return n2;
45856c04344SDavid Nugent     if (n2 == 1)
45956c04344SDavid Nugent 	return n1;
46056c04344SDavid Nugent 
46156c04344SDavid Nugent     /*
46256c04344SDavid Nugent      * sizeof() returns number of bytes needed for storage.
46356c04344SDavid Nugent      * This may be different from the actual number of useful bits.
46456c04344SDavid Nugent      */
46556c04344SDavid Nugent     if (!bpw) {
46656c04344SDavid Nugent 	bpw = sizeof(u_quad_t) * 8;
46756c04344SDavid Nugent 	while (((u_quad_t)1 << (bpw-1)) == 0)
46856c04344SDavid Nugent 	    --bpw;
46956c04344SDavid Nugent     }
47056c04344SDavid Nugent 
47156c04344SDavid Nugent     /*
47256c04344SDavid Nugent      * First check the magnitude of each number. If the sum of the
47356c04344SDavid Nugent      * magnatude is way to high, reject the number. (If this test
47456c04344SDavid Nugent      * is not done then the first multiply below may overflow.)
47556c04344SDavid Nugent      */
47656c04344SDavid Nugent     for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
47756c04344SDavid Nugent 	;
47856c04344SDavid Nugent     for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
47956c04344SDavid Nugent 	;
48056c04344SDavid Nugent     if (b1 + b2 - 2 > bpw) {
48156c04344SDavid Nugent 	errno = ERANGE;
48256c04344SDavid Nugent 	return (UQUAD_MAX);
48356c04344SDavid Nugent     }
48456c04344SDavid Nugent 
48556c04344SDavid Nugent     /*
48656c04344SDavid Nugent      * Decompose the multiplication to be:
48756c04344SDavid Nugent      * h1 = n1 & ~1
48856c04344SDavid Nugent      * h2 = n2 & ~1
48956c04344SDavid Nugent      * l1 = n1 & 1
49056c04344SDavid Nugent      * l2 = n2 & 1
49156c04344SDavid Nugent      * (h1 + l1) * (h2 + l2)
49256c04344SDavid Nugent      * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
49356c04344SDavid Nugent      *
49456c04344SDavid Nugent      * Since h1 && h2 do not have the low bit set, we can then say:
49556c04344SDavid Nugent      *
49656c04344SDavid Nugent      * (h1>>1 * h2>>1 * 4) + ...
49756c04344SDavid Nugent      *
49856c04344SDavid Nugent      * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
49956c04344SDavid Nugent      * overflow.
50056c04344SDavid Nugent      *
50156c04344SDavid Nugent      * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
50256c04344SDavid Nugent      * then adding in residual amout will cause an overflow.
50356c04344SDavid Nugent      */
50456c04344SDavid Nugent 
50556c04344SDavid Nugent     m = (n1 >> 1) * (n2 >> 1);
50656c04344SDavid Nugent     if (m >= ((u_quad_t)1 << (bpw-2))) {
50756c04344SDavid Nugent 	errno = ERANGE;
50856c04344SDavid Nugent 	return (UQUAD_MAX);
50956c04344SDavid Nugent     }
51056c04344SDavid Nugent     m *= 4;
51156c04344SDavid Nugent 
51256c04344SDavid Nugent     r = (n1 & n2 & 1)
51356c04344SDavid Nugent 	+ (n2 & 1) * (n1 & ~(u_quad_t)1)
51456c04344SDavid Nugent 	+ (n1 & 1) * (n2 & ~(u_quad_t)1);
51556c04344SDavid Nugent 
51656c04344SDavid Nugent     if ((u_quad_t)(m + r) < m) {
51756c04344SDavid Nugent 	errno = ERANGE;
51856c04344SDavid Nugent 	return (UQUAD_MAX);
51956c04344SDavid Nugent     }
52056c04344SDavid Nugent     m += r;
52156c04344SDavid Nugent 
52256c04344SDavid Nugent     return (m);
52356c04344SDavid Nugent }
52456c04344SDavid Nugent 
52556c04344SDavid Nugent 
52668bbf3adSDavid Nugent /*
52768bbf3adSDavid Nugent  * login_getcaptime()
52868bbf3adSDavid Nugent  * From the login_cap_t <lc>, get the capability <cap>, which is
52968bbf3adSDavid Nugent  * formatted as a time (e.g., "<cap>=10h3m2s").  If <cap> is not
53068bbf3adSDavid Nugent  * present in <lc>, return <def>; if there is an error of some kind,
53168bbf3adSDavid Nugent  * return <error>.
53268bbf3adSDavid Nugent  */
53368bbf3adSDavid Nugent 
53468bbf3adSDavid Nugent rlim_t
53568bbf3adSDavid Nugent login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
53668bbf3adSDavid Nugent {
53756c04344SDavid Nugent     char    *res, *ep, *oval;
53856c04344SDavid Nugent     int	    r;
53951706563SDavid Nugent     rlim_t  tot;
54068bbf3adSDavid Nugent 
54168bbf3adSDavid Nugent     errno = 0;
54268bbf3adSDavid Nugent     if (lc == NULL || lc->lc_cap == NULL)
54368bbf3adSDavid Nugent 	return def;
54468bbf3adSDavid Nugent 
54568bbf3adSDavid Nugent     /*
54668bbf3adSDavid Nugent      * Look for <cap> in lc_cap.
54768bbf3adSDavid Nugent      * If it's not there (-1), return <def>.
54868bbf3adSDavid Nugent      * If there's an error, return <error>.
54968bbf3adSDavid Nugent      */
55068bbf3adSDavid Nugent 
551547fa0d9SMark Murray     if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
55268bbf3adSDavid Nugent 	return def;
55356c04344SDavid Nugent     else if (r < 0) {
55456c04344SDavid Nugent 	errno = ERANGE;
55568bbf3adSDavid Nugent 	return error;
55656c04344SDavid Nugent     }
55768bbf3adSDavid Nugent 
55856c04344SDavid Nugent     /* "inf" and "infinity" are special cases */
55956c04344SDavid Nugent     if (isinfinite(res))
56068bbf3adSDavid Nugent 	return RLIM_INFINITY;
56168bbf3adSDavid Nugent 
56268bbf3adSDavid Nugent     /*
56368bbf3adSDavid Nugent      * Now go through the string, turning something like 1h2m3s into
56468bbf3adSDavid Nugent      * an integral value.  Whee.
56568bbf3adSDavid Nugent      */
56668bbf3adSDavid Nugent 
56768bbf3adSDavid Nugent     errno = 0;
56851706563SDavid Nugent     tot = 0;
56956c04344SDavid Nugent     oval = res;
57068bbf3adSDavid Nugent     while (*res) {
57156c04344SDavid Nugent 	rlim_t tim = strtoq(res, &ep, 0);
57256c04344SDavid Nugent 	rlim_t mult = 1;
57356c04344SDavid Nugent 
57456c04344SDavid Nugent 	if (ep == NULL || ep == res || errno != 0) {
57556c04344SDavid Nugent 	invalid:
57656c04344SDavid Nugent 	    syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
57756c04344SDavid Nugent 		   lc->lc_class, cap, oval);
57856c04344SDavid Nugent 	    errno = ERANGE;
57968bbf3adSDavid Nugent 	    return error;
58068bbf3adSDavid Nugent 	}
58168bbf3adSDavid Nugent 	/* Look for suffixes */
58268bbf3adSDavid Nugent 	switch (*ep++) {
58368bbf3adSDavid Nugent 	case 0:
58456c04344SDavid Nugent 	    ep--;
58556c04344SDavid Nugent 	    break;	/* end of string */
58668bbf3adSDavid Nugent 	case 's': case 'S':	/* seconds */
58768bbf3adSDavid Nugent 	    break;
58868bbf3adSDavid Nugent 	case 'm': case 'M':	/* minutes */
58956c04344SDavid Nugent 	    mult = 60;
59068bbf3adSDavid Nugent 	    break;
59168bbf3adSDavid Nugent 	case 'h': case 'H':	/* hours */
59256c04344SDavid Nugent 	    mult = 60L * 60L;
59368bbf3adSDavid Nugent 	    break;
59468bbf3adSDavid Nugent 	case 'd': case 'D':	/* days */
59556c04344SDavid Nugent 	    mult = 60L * 60L * 24L;
59668bbf3adSDavid Nugent 	    break;
59768bbf3adSDavid Nugent 	case 'w': case 'W':	/* weeks */
59856c04344SDavid Nugent 	    mult = 60L * 60L * 24L * 7L;
599c2043f40SDavid Nugent 	    break;
60056c04344SDavid Nugent 	case 'y': case 'Y':	/* 365-day years */
60156c04344SDavid Nugent 	    mult = 60L * 60L * 24L * 365L;
602c2043f40SDavid Nugent 	    break;
60368bbf3adSDavid Nugent 	default:
60456c04344SDavid Nugent 	    goto invalid;
60568bbf3adSDavid Nugent 	}
60668bbf3adSDavid Nugent 	res = ep;
60756c04344SDavid Nugent 	tot += rmultiply(tim, mult);
60856c04344SDavid Nugent 	if (errno)
60956c04344SDavid Nugent 	    goto invalid;
61068bbf3adSDavid Nugent     }
61156c04344SDavid Nugent 
61268bbf3adSDavid Nugent     return tot;
61368bbf3adSDavid Nugent }
61468bbf3adSDavid Nugent 
61568bbf3adSDavid Nugent 
61668bbf3adSDavid Nugent /*
61768bbf3adSDavid Nugent  * login_getcapnum()
61868bbf3adSDavid Nugent  * From the login_cap_t <lc>, extract the numerical value <cap>.
61968bbf3adSDavid Nugent  * If it is not present, return <def> for a default, and return
62068bbf3adSDavid Nugent  * <error> if there is an error.
62168bbf3adSDavid Nugent  * Like login_getcaptime(), only it only converts to a number, not
62268bbf3adSDavid Nugent  * to a time; "infinity" and "inf" are 'special.'
62368bbf3adSDavid Nugent  */
62468bbf3adSDavid Nugent 
62568bbf3adSDavid Nugent rlim_t
62668bbf3adSDavid Nugent login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
62768bbf3adSDavid Nugent {
62868bbf3adSDavid Nugent     char    *ep, *res;
62956c04344SDavid Nugent     int	    r;
63068bbf3adSDavid Nugent     rlim_t  val;
63168bbf3adSDavid Nugent 
63268bbf3adSDavid Nugent     if (lc == NULL || lc->lc_cap == NULL)
63368bbf3adSDavid Nugent 	return def;
63468bbf3adSDavid Nugent 
63568bbf3adSDavid Nugent     /*
63668bbf3adSDavid Nugent      * For BSDI compatibility, try for the tag=<val> first
63768bbf3adSDavid Nugent      */
638547fa0d9SMark Murray     if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) {
63968bbf3adSDavid Nugent 	long	lval;
64056c04344SDavid Nugent 	/* string capability not present, so try for tag#<val> as numeric */
641547fa0d9SMark Murray 	if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1)
64268bbf3adSDavid Nugent 	    return def; /* Not there, so return default */
64356c04344SDavid Nugent 	else if (r >= 0)
64468bbf3adSDavid Nugent 	    return (rlim_t)lval;
64568bbf3adSDavid Nugent     }
64668bbf3adSDavid Nugent 
64756c04344SDavid Nugent     if (r < 0) {
64856c04344SDavid Nugent 	errno = ERANGE;
64956c04344SDavid Nugent 	return error;
65056c04344SDavid Nugent     }
65156c04344SDavid Nugent 
65256c04344SDavid Nugent     if (isinfinite(res))
65368bbf3adSDavid Nugent 	return RLIM_INFINITY;
65468bbf3adSDavid Nugent 
65568bbf3adSDavid Nugent     errno = 0;
65656c04344SDavid Nugent     val = strtoq(res, &ep, 0);
65756c04344SDavid Nugent     if (ep == NULL || ep == res || errno != 0) {
65856c04344SDavid Nugent 	syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
65956c04344SDavid Nugent 	       lc->lc_class, cap, res);
66056c04344SDavid Nugent 	errno = ERANGE;
66168bbf3adSDavid Nugent 	return error;
66256c04344SDavid Nugent     }
66356c04344SDavid Nugent 
66468bbf3adSDavid Nugent     return val;
66568bbf3adSDavid Nugent }
66668bbf3adSDavid Nugent 
66768bbf3adSDavid Nugent 
66856c04344SDavid Nugent 
66968bbf3adSDavid Nugent /*
67068bbf3adSDavid Nugent  * login_getcapsize()
67168bbf3adSDavid Nugent  * From the login_cap_t <lc>, extract the capability <cap>, which is
67268bbf3adSDavid Nugent  * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
67368bbf3adSDavid Nugent  * If not present, return <def>, or <error> if there is an error of
67468bbf3adSDavid Nugent  * some sort.
67568bbf3adSDavid Nugent  */
67668bbf3adSDavid Nugent 
67768bbf3adSDavid Nugent rlim_t
67856c04344SDavid Nugent login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
67956c04344SDavid Nugent {
68056c04344SDavid Nugent     char    *ep, *res, *oval;
68156c04344SDavid Nugent     int	    r;
68256c04344SDavid Nugent     rlim_t  tot;
68368bbf3adSDavid Nugent 
68468bbf3adSDavid Nugent     if (lc == NULL || lc->lc_cap == NULL)
68568bbf3adSDavid Nugent 	return def;
68668bbf3adSDavid Nugent 
687547fa0d9SMark Murray     if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
68868bbf3adSDavid Nugent 	return def;
68956c04344SDavid Nugent     else if (r < 0) {
69056c04344SDavid Nugent 	errno = ERANGE;
69168bbf3adSDavid Nugent 	return error;
69256c04344SDavid Nugent     }
69368bbf3adSDavid Nugent 
69456c04344SDavid Nugent     if (isinfinite(res))
69565f50b7fSAndrey A. Chernov 	return RLIM_INFINITY;
69665f50b7fSAndrey A. Chernov 
69768bbf3adSDavid Nugent     errno = 0;
69851706563SDavid Nugent     tot = 0;
69956c04344SDavid Nugent     oval = res;
70051706563SDavid Nugent     while (*res) {
70156c04344SDavid Nugent 	rlim_t siz = strtoq(res, &ep, 0);
70256c04344SDavid Nugent 	rlim_t mult = 1;
70356c04344SDavid Nugent 
70456c04344SDavid Nugent 	if (ep == NULL || ep == res || errno != 0) {
70556c04344SDavid Nugent 	invalid:
70656c04344SDavid Nugent 	    syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
70756c04344SDavid Nugent 		   lc->lc_class, cap, oval);
70856c04344SDavid Nugent 	    errno = ERANGE;
70968bbf3adSDavid Nugent 	    return error;
71056c04344SDavid Nugent 	}
711f9074e29SDavid Nugent 	switch (*ep++) {
71268bbf3adSDavid Nugent 	case 0:	/* end of string */
71351706563SDavid Nugent 	    ep--;
71451706563SDavid Nugent 	    break;
71568bbf3adSDavid Nugent 	case 'b': case 'B':	/* 512-byte blocks */
71656c04344SDavid Nugent 	    mult = 512;
71756c04344SDavid Nugent 	    break;
71868bbf3adSDavid Nugent 	case 'k': case 'K':	/* 1024-byte Kilobytes */
71956c04344SDavid Nugent 	    mult = 1024;
72056c04344SDavid Nugent 	    break;
72168bbf3adSDavid Nugent 	case 'm': case 'M':	/* 1024-k kbytes */
72256c04344SDavid Nugent 	    mult = 1024 * 1024;
72356c04344SDavid Nugent 	    break;
72468bbf3adSDavid Nugent 	case 'g': case 'G':	/* 1Gbyte */
72556c04344SDavid Nugent 	    mult = 1024 * 1024 * 1024;
72656c04344SDavid Nugent 	    break;
72768bbf3adSDavid Nugent 	case 't': case 'T':	/* 1TBte */
72856c04344SDavid Nugent 	    mult = 1024LL * 1024LL * 1024LL * 1024LL;
72956c04344SDavid Nugent 	    break;
73068bbf3adSDavid Nugent 	default:
73156c04344SDavid Nugent 	    goto invalid;
73268bbf3adSDavid Nugent 	}
733f9074e29SDavid Nugent 	res = ep;
73456c04344SDavid Nugent 	tot += rmultiply(siz, mult);
73556c04344SDavid Nugent 	if (errno)
73656c04344SDavid Nugent 	    goto invalid;
73751706563SDavid Nugent     }
73856c04344SDavid Nugent 
73951706563SDavid Nugent     return tot;
74068bbf3adSDavid Nugent }
74168bbf3adSDavid Nugent 
74268bbf3adSDavid Nugent 
74368bbf3adSDavid Nugent /*
74468bbf3adSDavid Nugent  * login_getcapbool()
74568bbf3adSDavid Nugent  * From the login_cap_t <lc>, check for the existance of the capability
74668bbf3adSDavid Nugent  * of <cap>.  Return <def> if <lc>->lc_cap is NULL, otherwise return
74768bbf3adSDavid Nugent  * the whether or not <cap> exists there.
74868bbf3adSDavid Nugent  */
74968bbf3adSDavid Nugent 
75068bbf3adSDavid Nugent int
75168bbf3adSDavid Nugent login_getcapbool(login_cap_t *lc, const char *cap, int def)
75268bbf3adSDavid Nugent {
75368bbf3adSDavid Nugent     if (lc == NULL || lc->lc_cap == NULL)
75468bbf3adSDavid Nugent 	return def;
755547fa0d9SMark Murray     return (cgetcap(lc->lc_cap, cap, ':') != NULL);
75668bbf3adSDavid Nugent }
75768bbf3adSDavid Nugent 
75868bbf3adSDavid Nugent 
75968bbf3adSDavid Nugent /*
76068bbf3adSDavid Nugent  * login_getstyle()
76168bbf3adSDavid Nugent  * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
76268bbf3adSDavid Nugent  * and optionally a style <style>, find the style that best suits these
76368bbf3adSDavid Nugent  * rules:
76468bbf3adSDavid Nugent  *	1.  If <auth> is non-null, look for an "auth-<auth>=" string
76568bbf3adSDavid Nugent  *	in the capability; if not present, default to "auth=".
76668bbf3adSDavid Nugent  *	2.  If there is no auth list found from (1), default to
76768bbf3adSDavid Nugent  *	"passwd" as an authorization list.
76868bbf3adSDavid Nugent  *	3.  If <style> is non-null, look for <style> in the list of
76968bbf3adSDavid Nugent  *	authorization methods found from (2); if <style> is NULL, default
77068bbf3adSDavid Nugent  *	to LOGIN_DEFSTYLE ("passwd").
77168bbf3adSDavid Nugent  *	4.  If the chosen style is found in the chosen list of authorization
77268bbf3adSDavid Nugent  *	methods, return that; otherwise, return NULL.
77368bbf3adSDavid Nugent  * E.g.:
77468bbf3adSDavid Nugent  *     login_getstyle(lc, NULL, "ftp");
77568bbf3adSDavid Nugent  *     login_getstyle(lc, "login", NULL);
77668bbf3adSDavid Nugent  *     login_getstyle(lc, "skey", "network");
77768bbf3adSDavid Nugent  */
77868bbf3adSDavid Nugent 
779b00ba4ccSRuslan Ermilov const char *
780b00ba4ccSRuslan Ermilov login_getstyle(login_cap_t *lc, const char *style, const char *auth)
78168bbf3adSDavid Nugent {
78268bbf3adSDavid Nugent     int	    i;
783547fa0d9SMark Murray     const char **authtypes = NULL;
78468bbf3adSDavid Nugent     char    *auths= NULL;
78568bbf3adSDavid Nugent     char    realauth[64];
78668bbf3adSDavid Nugent 
787547fa0d9SMark Murray     static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
78868bbf3adSDavid Nugent 
78956c04344SDavid Nugent     if (auth != NULL && *auth != '\0') {
790547fa0d9SMark Murray 	if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth))
79168bbf3adSDavid Nugent 	    authtypes = login_getcaplist(lc, realauth, NULL);
79256c04344SDavid Nugent     }
79368bbf3adSDavid Nugent 
79468bbf3adSDavid Nugent     if (authtypes == NULL)
79568bbf3adSDavid Nugent 	authtypes = login_getcaplist(lc, "auth", NULL);
79668bbf3adSDavid Nugent 
79768bbf3adSDavid Nugent     if (authtypes == NULL)
79868bbf3adSDavid Nugent 	authtypes = defauthtypes;
79968bbf3adSDavid Nugent 
80068bbf3adSDavid Nugent     /*
8019a01d32bSJeroen Ruigrok van der Werven      * We have at least one authtype now; auths is a comma-separated
80268bbf3adSDavid Nugent      * (or space-separated) list of authentication types.  We have to
80368bbf3adSDavid Nugent      * convert from this to an array of char*'s; authtypes then gets this.
80468bbf3adSDavid Nugent      */
80568bbf3adSDavid Nugent     i = 0;
80668bbf3adSDavid Nugent     if (style != NULL && *style != '\0') {
80768bbf3adSDavid Nugent 	while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
80868bbf3adSDavid Nugent 	    i++;
80968bbf3adSDavid Nugent     }
81056c04344SDavid Nugent 
81168bbf3adSDavid Nugent     lc->lc_style = NULL;
81268bbf3adSDavid Nugent     if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
81368bbf3adSDavid Nugent 	lc->lc_style = auths;
81468bbf3adSDavid Nugent 
81556c04344SDavid Nugent     if (lc->lc_style != NULL)
81656c04344SDavid Nugent 	lc->lc_style = strdup(lc->lc_style);
81756c04344SDavid Nugent 
81868bbf3adSDavid Nugent     return lc->lc_style;
81968bbf3adSDavid Nugent }
820