1/*-
2 * Copyright (c) 1996 by
3 * Sean Eric Fagan <sef@kithrup.com>
4 * David Nugent <davidn@blaze.net.au>
5 * All rights reserved.
6 *
7 * Portions copyright (c) 1995,1997
8 * Berkeley Software Design, Inc.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, is permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice immediately at the beginning of the file, without modification,
16 *    this list of conditions, and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. This work was done expressly for inclusion into FreeBSD.  Other use
21 *    is permitted provided this notation is included.
22 * 4. Absolutely no warranty of function or purpose is made by the authors.
23 * 5. Modifications may be freely made to this file providing the above
24 *    conditions are met.
25 *
26 * Low-level routines relating to the user capabilities database
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: src/lib/libutil/login_cap.c,v 1.33 2005/04/22 23:11:57 trhodes Exp $");
31
32#include <sys/types.h>
33#include <sys/time.h>
34#include <sys/resource.h>
35#include <sys/param.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <libutil.h>
39#include <login_cap.h>
40#include <pwd.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45#include <unistd.h>
46
47/*
48 * allocstr()
49 * Manage a single static pointer for handling a local char* buffer,
50 * resizing as necessary to contain the string.
51 *
52 * allocarray()
53 * Manage a static array for handling a group of strings, resizing
54 * when necessary.
55 */
56
57static int lc_object_count = 0;
58
59static size_t internal_stringsz = 0;
60static char * internal_string = NULL;
61static size_t internal_arraysz = 0;
62static const char ** internal_array = NULL;
63
64static char *
65allocstr(const char *str)
66{
67    char    *p;
68
69    size_t sz = strlen(str) + 1;	/* realloc() only if necessary */
70    if (sz <= internal_stringsz)
71	p = strcpy(internal_string, str);
72    else if ((p = realloc(internal_string, sz)) != NULL) {
73	internal_stringsz = sz;
74	internal_string = strcpy(p, str);
75    }
76    return p;
77}
78
79
80static const char **
81allocarray(size_t sz)
82{
83    static const char    **p;
84
85    if (sz <= internal_arraysz)
86	p = internal_array;
87    else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
88	internal_arraysz = sz;
89	internal_array = p;
90    }
91    return p;
92}
93
94
95/*
96 * arrayize()
97 * Turn a simple string <str> separated by any of
98 * the set of <chars> into an array.  The last element
99 * of the array will be NULL, as is proper.
100 * Free using freearraystr()
101 */
102
103static const char **
104arrayize(const char *str, const char *chars, int *size)
105{
106    int	    i;
107    char *ptr;
108    const char *cptr;
109    const char **res = NULL;
110
111    /* count the sub-strings */
112    for (i = 0, cptr = str; *cptr; i++) {
113	int count = strcspn(cptr, chars);
114	cptr += count;
115	if (*cptr)
116	    ++cptr;
117    }
118
119    /* alloc the array */
120    if ((ptr = allocstr(str)) != NULL) {
121	if ((res = allocarray(++i)) == NULL)
122	    free((void *)(uintptr_t)(const void *)str);
123	else {
124	    /* now split the string */
125	    i = 0;
126	    while (*ptr) {
127		int count = strcspn(ptr, chars);
128		res[i++] = ptr;
129		ptr += count;
130		if (*ptr)
131		    *ptr++ = '\0';
132	    }
133	    res[i] = NULL;
134	}
135    }
136
137    if (size)
138	*size = i;
139
140    return res;
141}
142
143
144/*
145 * login_close()
146 * Frees up all resources relating to a login class
147 *
148 */
149
150void
151login_close(login_cap_t * lc)
152{
153    if (lc) {
154	free(lc->lc_style);
155	free(lc->lc_class);
156	free(lc->lc_cap);
157	free(lc);
158	if (--lc_object_count == 0) {
159	    free(internal_string);
160	    free(internal_array);
161	    internal_array = NULL;
162	    internal_arraysz = 0;
163	    internal_string = NULL;
164	    internal_stringsz = 0;
165	    cgetclose();
166	}
167    }
168}
169
170
171/*
172 * login_getclassbyname() get the login class by its name.
173 * If the name given is NULL or empty, the default class
174 * LOGIN_DEFCLASS (ie. "default") is fetched. If the
175 * 'pwd' argument is non-NULL and contains an non-NULL
176 * dir entry, then the file _FILE_LOGIN_CONF is picked
177 * up from that directory and used before the system
178 * login database.
179 * Return a filled-out login_cap_t structure, including
180 * class name, and the capability record buffer.
181 */
182
183login_cap_t *
184login_getclassbyname(char const *name, const struct passwd *pwd)
185{
186    login_cap_t	*lc;
187
188    if ((lc = malloc(sizeof(login_cap_t))) != NULL) {
189	int         r, me, i = 0;
190	uid_t euid = 0;
191	gid_t egid = 0;
192	const char  *msg = NULL;
193	const char  *dir;
194	char	    userpath[MAXPATHLEN];
195
196	static char *login_dbarray[] = { NULL, NULL, NULL };
197
198	me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0);
199	dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir;
200	/*
201	 * Switch to user mode before checking/reading its ~/.login_conf
202	 * - some NFSes have root read access disabled.
203	 *
204	 * XXX: This fails to configure additional groups.
205	 */
206	if (dir) {
207	    euid = geteuid();
208	    egid = getegid();
209	    (void)setegid(pwd->pw_gid);
210	    (void)seteuid(pwd->pw_uid);
211	}
212
213	if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
214			    _FILE_LOGIN_CONF) < MAXPATHLEN) {
215	    login_dbarray[i] = userpath;
216	    if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
217		i++;		/* only use 'secure' data */
218	}
219	if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1)
220	    login_dbarray[i++] = _PATH_LOGIN_CONF;
221	login_dbarray[i] = NULL;
222
223	memset(lc, 0, sizeof(login_cap_t));
224	lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
225
226	if (name == NULL || *name == '\0')
227	    name = LOGIN_DEFCLASS;
228
229	switch (cgetent(&lc->lc_cap, login_dbarray, name)) {
230	case -1:		/* Failed, entry does not exist */
231	    if (me)
232		break;	/* Don't retry default on 'me' */
233	    if (i == 0)
234	        r = -1;
235	    else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0)
236	        close(r);
237	    /*
238	     * If there's at least one login class database,
239	     * and we aren't searching for a default class
240	     * then complain about a non-existent class.
241	     */
242	    if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
243		syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
244	    /* fall-back to default class */
245	    name = LOGIN_DEFCLASS;
246	    msg = "%s: no default/fallback class '%s'";
247	    if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0)
248		break;
249	    /* FALLTHROUGH - just return system defaults */
250	case 0:		/* success! */
251	    if ((lc->lc_class = strdup(name)) != NULL) {
252		if (dir) {
253		    (void)seteuid(euid);
254		    (void)setegid(egid);
255		}
256		++lc_object_count;
257		return lc;
258	    }
259	    msg = "%s: strdup: %m";
260	    break;
261	case -2:
262	    msg = "%s: retrieving class information: %m";
263	    break;
264	case -3:
265	    msg = "%s: 'tc=' reference loop '%s'";
266	    break;
267	case 1:
268	    msg = "couldn't resolve 'tc=' reference in '%s'";
269	    break;
270	default:
271	    msg = "%s: unexpected cgetent() error '%s': %m";
272	    break;
273	}
274	if (dir) {
275	    (void)seteuid(euid);
276	    (void)setegid(egid);
277	}
278	if (msg != NULL)
279	    syslog(LOG_ERR, msg, "login_getclass", name);
280	free(lc);
281    }
282
283    return NULL;
284}
285
286
287
288/*
289 * login_getclass()
290 * Get the login class for the system (only) login class database.
291 * Return a filled-out login_cap_t structure, including
292 * class name, and the capability record buffer.
293 */
294
295login_cap_t *
296login_getclass(const char *cls)
297{
298    return login_getclassbyname(cls, NULL);
299}
300
301
302/*
303 * login_getclass()
304 * Get the login class for a given password entry from
305 * the system (only) login class database.
306 * If the password entry's class field is not set, or
307 * the class specified does not exist, then use the
308 * default of LOGIN_DEFCLASS (ie. "default").
309 * Return a filled-out login_cap_t structure, including
310 * class name, and the capability record buffer.
311 */
312
313login_cap_t *
314login_getpwclass(const struct passwd *pwd)
315{
316    const char	*cls = NULL;
317
318    if (pwd != NULL) {
319	cls = pwd->pw_class;
320	if (cls == NULL || *cls == '\0')
321	    cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
322    }
323    return login_getclassbyname(cls, pwd);
324}
325
326
327/*
328 * login_getuserclass()
329 * Get the login class for a given password entry, allowing user
330 * overrides via ~/.login_conf.
331 */
332
333login_cap_t *
334login_getuserclass(const struct passwd *pwd)
335{
336    return login_getclassbyname(LOGIN_MECLASS, pwd);
337}
338
339
340
341/*
342 * login_getcapstr()
343 * Given a login_cap entry, and a capability name, return the
344 * value defined for that capability, a default if not found, or
345 * an error string on error.
346 */
347
348const char *
349login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error)
350{
351    char    *res;
352    int	    ret;
353
354    if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
355	return def;
356
357    if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1)
358	return def;
359    return (ret >= 0) ? res : error;
360}
361
362
363/*
364 * login_getcaplist()
365 * Given a login_cap entry, and a capability name, return the
366 * value defined for that capability split into an array of
367 * strings.
368 */
369
370const char **
371login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
372{
373    const char *lstring;
374
375    if (chars == NULL)
376	chars = ", \t";
377    if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL)
378	return arrayize(lstring, chars, NULL);
379    return NULL;
380}
381
382
383/*
384 * login_getpath()
385 * From the login_cap_t <lc>, get the capability <cap> which is
386 * formatted as either a space or comma delimited list of paths
387 * and append them all into a string and separate by semicolons.
388 * If there is an error of any kind, return <error>.
389 */
390
391const char *
392login_getpath(login_cap_t *lc, const char *cap, const char *error)
393{
394    const char *str;
395    char *ptr;
396    int count;
397
398    str = login_getcapstr(lc, cap, NULL, NULL);
399    if (str == NULL)
400	return error;
401    ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */
402    while (*ptr) {
403	count = strcspn(ptr, ", \t");
404	ptr += count;
405	if (*ptr)
406	    *ptr++ = ':';
407    }
408    return str;
409}
410
411
412static int
413isinfinite(const char *s)
414{
415    static const char *infs[] = {
416	"infinity",
417	"inf",
418	"unlimited",
419	"unlimit",
420	"-1",
421	NULL
422    };
423    const char **i = &infs[0];
424
425    while (*i != NULL) {
426	if (strcasecmp(s, *i) == 0)
427	    return 1;
428	++i;
429    }
430    return 0;
431}
432
433
434static u_quad_t
435rmultiply(u_quad_t n1, u_quad_t n2)
436{
437    u_quad_t	m, r;
438    int		b1, b2;
439
440    static int bpw = 0;
441
442    /* Handle simple cases */
443    if (n1 == 0 || n2 == 0)
444	return 0;
445    if (n1 == 1)
446	return n2;
447    if (n2 == 1)
448	return n1;
449
450    /*
451     * sizeof() returns number of bytes needed for storage.
452     * This may be different from the actual number of useful bits.
453     */
454    if (!bpw) {
455	bpw = sizeof(u_quad_t) * 8;
456	while (((u_quad_t)1 << (bpw-1)) == 0)
457	    --bpw;
458    }
459
460    /*
461     * First check the magnitude of each number. If the sum of the
462     * magnatude is way to high, reject the number. (If this test
463     * is not done then the first multiply below may overflow.)
464     */
465    for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
466	;
467    for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
468	;
469    if (b1 + b2 - 2 > bpw) {
470	errno = ERANGE;
471	return (UQUAD_MAX);
472    }
473
474    /*
475     * Decompose the multiplication to be:
476     * h1 = n1 & ~1
477     * h2 = n2 & ~1
478     * l1 = n1 & 1
479     * l2 = n2 & 1
480     * (h1 + l1) * (h2 + l2)
481     * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
482     *
483     * Since h1 && h2 do not have the low bit set, we can then say:
484     *
485     * (h1>>1 * h2>>1 * 4) + ...
486     *
487     * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
488     * overflow.
489     *
490     * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
491     * then adding in residual amout will cause an overflow.
492     */
493
494    m = (n1 >> 1) * (n2 >> 1);
495    if (m >= ((u_quad_t)1 << (bpw-2))) {
496	errno = ERANGE;
497	return (UQUAD_MAX);
498    }
499    m *= 4;
500
501    r = (n1 & n2 & 1)
502	+ (n2 & 1) * (n1 & ~(u_quad_t)1)
503	+ (n1 & 1) * (n2 & ~(u_quad_t)1);
504
505    if ((u_quad_t)(m + r) < m) {
506	errno = ERANGE;
507	return (UQUAD_MAX);
508    }
509    m += r;
510
511    return (m);
512}
513
514
515/*
516 * login_getcaptime()
517 * From the login_cap_t <lc>, get the capability <cap>, which is
518 * formatted as a time (e.g., "<cap>=10h3m2s").  If <cap> is not
519 * present in <lc>, return <def>; if there is an error of some kind,
520 * return <error>.
521 */
522
523rlim_t
524login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
525{
526    char    *res, *ep, *oval;
527    int	    r;
528    rlim_t  tot;
529
530    errno = 0;
531    if (lc == NULL || lc->lc_cap == NULL)
532	return def;
533
534    /*
535     * Look for <cap> in lc_cap.
536     * If it's not there (-1), return <def>.
537     * If there's an error, return <error>.
538     */
539
540    if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
541	return def;
542    else if (r < 0) {
543	errno = ERANGE;
544	return error;
545    }
546
547    /* "inf" and "infinity" are special cases */
548    if (isinfinite(res))
549	return RLIM_INFINITY;
550
551    /*
552     * Now go through the string, turning something like 1h2m3s into
553     * an integral value.  Whee.
554     */
555
556    errno = 0;
557    tot = 0;
558    oval = res;
559    while (*res) {
560	rlim_t tim = strtoq(res, &ep, 0);
561	rlim_t mult = 1;
562
563	if (ep == NULL || ep == res || errno != 0) {
564	invalid:
565	    syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
566		   lc->lc_class, cap, oval);
567	    errno = ERANGE;
568	    return error;
569	}
570	/* Look for suffixes */
571	switch (*ep++) {
572	case 0:
573	    ep--;
574	    break;	/* end of string */
575	case 's': case 'S':	/* seconds */
576	    break;
577	case 'm': case 'M':	/* minutes */
578	    mult = 60;
579	    break;
580	case 'h': case 'H':	/* hours */
581	    mult = 60L * 60L;
582	    break;
583	case 'd': case 'D':	/* days */
584	    mult = 60L * 60L * 24L;
585	    break;
586	case 'w': case 'W':	/* weeks */
587	    mult = 60L * 60L * 24L * 7L;
588	    break;
589	case 'y': case 'Y':	/* 365-day years */
590	    mult = 60L * 60L * 24L * 365L;
591	    break;
592	default:
593	    goto invalid;
594	}
595	res = ep;
596	tot += rmultiply(tim, mult);
597	if (errno)
598	    goto invalid;
599    }
600
601    return tot;
602}
603
604
605/*
606 * login_getcapnum()
607 * From the login_cap_t <lc>, extract the numerical value <cap>.
608 * If it is not present, return <def> for a default, and return
609 * <error> if there is an error.
610 * Like login_getcaptime(), only it only converts to a number, not
611 * to a time; "infinity" and "inf" are 'special.'
612 */
613
614rlim_t
615login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
616{
617    char    *ep, *res;
618    int	    r;
619    rlim_t  val;
620
621    if (lc == NULL || lc->lc_cap == NULL)
622	return def;
623
624    /*
625     * For BSDI compatibility, try for the tag=<val> first
626     */
627    if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) {
628	long	lval;
629	/* string capability not present, so try for tag#<val> as numeric */
630	if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1)
631	    return def; /* Not there, so return default */
632	else if (r >= 0)
633	    return (rlim_t)lval;
634    }
635
636    if (r < 0) {
637	errno = ERANGE;
638	return error;
639    }
640
641    if (isinfinite(res))
642	return RLIM_INFINITY;
643
644    errno = 0;
645    val = strtoq(res, &ep, 0);
646    if (ep == NULL || ep == res || errno != 0) {
647	syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
648	       lc->lc_class, cap, res);
649	errno = ERANGE;
650	return error;
651    }
652
653    return val;
654}
655
656
657
658/*
659 * login_getcapsize()
660 * From the login_cap_t <lc>, extract the capability <cap>, which is
661 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
662 * If not present, return <def>, or <error> if there is an error of
663 * some sort.
664 */
665
666rlim_t
667login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
668{
669    char    *ep, *res, *oval;
670    int	    r;
671    rlim_t  tot;
672
673    if (lc == NULL || lc->lc_cap == NULL)
674	return def;
675
676    if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
677	return def;
678    else if (r < 0) {
679	errno = ERANGE;
680	return error;
681    }
682
683    if (isinfinite(res))
684	return RLIM_INFINITY;
685
686    errno = 0;
687    tot = 0;
688    oval = res;
689    while (*res) {
690	rlim_t siz = strtoq(res, &ep, 0);
691	rlim_t mult = 1;
692
693	if (ep == NULL || ep == res || errno != 0) {
694	invalid:
695	    syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
696		   lc->lc_class, cap, oval);
697	    errno = ERANGE;
698	    return error;
699	}
700	switch (*ep++) {
701	case 0:	/* end of string */
702	    ep--;
703	    break;
704	case 'b': case 'B':	/* 512-byte blocks */
705	    mult = 512;
706	    break;
707	case 'k': case 'K':	/* 1024-byte Kilobytes */
708	    mult = 1024;
709	    break;
710	case 'm': case 'M':	/* 1024-k kbytes */
711	    mult = 1024 * 1024;
712	    break;
713	case 'g': case 'G':	/* 1Gbyte */
714	    mult = 1024 * 1024 * 1024;
715	    break;
716	case 't': case 'T':	/* 1TBte */
717	    mult = 1024LL * 1024LL * 1024LL * 1024LL;
718	    break;
719	default:
720	    goto invalid;
721	}
722	res = ep;
723	tot += rmultiply(siz, mult);
724	if (errno)
725	    goto invalid;
726    }
727
728    return tot;
729}
730
731
732/*
733 * login_getcapbool()
734 * From the login_cap_t <lc>, check for the existance of the capability
735 * of <cap>.  Return <def> if <lc>->lc_cap is NULL, otherwise return
736 * the whether or not <cap> exists there.
737 */
738
739int
740login_getcapbool(login_cap_t *lc, const char *cap, int def)
741{
742    if (lc == NULL || lc->lc_cap == NULL)
743	return def;
744    return (cgetcap(lc->lc_cap, cap, ':') != NULL);
745}
746
747
748/*
749 * login_getstyle()
750 * Given a login_cap entry <lc>, and optionally a type of auth <auth>,
751 * and optionally a style <style>, find the style that best suits these
752 * rules:
753 *	1.  If <auth> is non-null, look for an "auth-<auth>=" string
754 *	in the capability; if not present, default to "auth=".
755 *	2.  If there is no auth list found from (1), default to
756 *	"passwd" as an authorization list.
757 *	3.  If <style> is non-null, look for <style> in the list of
758 *	authorization methods found from (2); if <style> is NULL, default
759 *	to LOGIN_DEFSTYLE ("passwd").
760 *	4.  If the chosen style is found in the chosen list of authorization
761 *	methods, return that; otherwise, return NULL.
762 * E.g.:
763 *     login_getstyle(lc, NULL, "ftp");
764 *     login_getstyle(lc, "login", NULL);
765 *     login_getstyle(lc, "skey", "network");
766 */
767
768const char *
769login_getstyle(login_cap_t *lc, const char *style, const char *auth)
770{
771    int	    i;
772    const char **authtypes = NULL;
773    char    *auths= NULL;
774    char    realauth[64];
775
776    static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
777
778    if (auth != NULL && *auth != '\0') {
779	if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth))
780	    authtypes = login_getcaplist(lc, realauth, NULL);
781    }
782
783    if (authtypes == NULL)
784	authtypes = login_getcaplist(lc, "auth", NULL);
785
786    if (authtypes == NULL)
787	authtypes = defauthtypes;
788
789    /*
790     * We have at least one authtype now; auths is a comma-separated
791     * (or space-separated) list of authentication types.  We have to
792     * convert from this to an array of char*'s; authtypes then gets this.
793     */
794    i = 0;
795    if (style != NULL && *style != '\0') {
796	while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
797	    i++;
798    }
799
800    lc->lc_style = NULL;
801    if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
802	lc->lc_style = auths;
803
804    if (lc->lc_style != NULL)
805	lc->lc_style = strdup(lc->lc_style);
806
807    return lc->lc_style;
808}
809