121288Sdavidn/*-
221288Sdavidn * Copyright (c) 1996 by
321288Sdavidn * David Nugent <davidn@blaze.net.au>
421288Sdavidn * All rights reserved.
521288Sdavidn *
621288Sdavidn * Redistribution and use in source and binary forms, with or without
721288Sdavidn * modification, is permitted provided that the following conditions
821288Sdavidn * are met:
921288Sdavidn * 1. Redistributions of source code must retain the above copyright
1021288Sdavidn *    notice immediately at the beginning of the file, without modification,
1121288Sdavidn *    this list of conditions, and the following disclaimer.
1221288Sdavidn * 2. Redistributions in binary form must reproduce the above copyright
1321288Sdavidn *    notice, this list of conditions and the following disclaimer in the
1421288Sdavidn *    documentation and/or other materials provided with the distribution.
1521288Sdavidn * 3. This work was done expressly for inclusion into FreeBSD.  Other use
1621288Sdavidn *    is permitted provided this notation is included.
1721288Sdavidn * 4. Absolutely no warranty of function or purpose is made by the authors.
1821288Sdavidn * 5. Modifications may be freely made to this file providing the above
1921288Sdavidn *    conditions are met.
2021288Sdavidn *
2121288Sdavidn * Support allow/deny lists in login class capabilities
2221288Sdavidn */
2321288Sdavidn
2484225Sdillon#include <sys/cdefs.h>
2584225Sdillon__FBSDID("$FreeBSD$");
2684225Sdillon
2721288Sdavidn#include <sys/types.h>
2821288Sdavidn#include <sys/time.h>
2921288Sdavidn#include <sys/resource.h>
3021288Sdavidn#include <sys/param.h>
31116344Smarkm#include <errno.h>
32116344Smarkm#include <fnmatch.h>
3321288Sdavidn#include <login_cap.h>
34116344Smarkm#include <stdlib.h>
35116344Smarkm#include <string.h>
36116344Smarkm#include <ttyent.h>
37116344Smarkm#include <unistd.h>
3821288Sdavidn
3921288Sdavidn
4021288Sdavidn/* -- support functions -- */
4121288Sdavidn
4225670Sdavidn/*
4325670Sdavidn * login_strinlist()
4421288Sdavidn * This function is intentionally public - reused by TAS.
4521288Sdavidn * Returns TRUE (non-zero) if a string matches a pattern
4621288Sdavidn * in a given array of patterns. 'flags' is passed directly
4721288Sdavidn * to fnmatch(3).
4821288Sdavidn */
4921288Sdavidn
5021288Sdavidnint
51121193Smarkmlogin_strinlist(const char **list, char const *str, int flags)
5221288Sdavidn{
5325670Sdavidn    int rc = 0;
5421288Sdavidn
5525670Sdavidn    if (str != NULL && *str != '\0') {
5625670Sdavidn	int	i = 0;
5725670Sdavidn
5825670Sdavidn	while (rc == 0 && list[i] != NULL)
5926694Sdavidn	    rc = fnmatch(list[i++], str, flags) == 0;
6025670Sdavidn    }
6125670Sdavidn    return rc;
6221288Sdavidn}
6321288Sdavidn
6421288Sdavidn
6525670Sdavidn/*
6625670Sdavidn * login_str2inlist()
6721288Sdavidn * Locate either or two strings in a given list
6821288Sdavidn */
6921288Sdavidn
7021288Sdavidnint
71121193Smarkmlogin_str2inlist(const char **ttlst, const char *str1, const char *str2, int flags)
7221288Sdavidn{
7325670Sdavidn    int	    rc = 0;
7421288Sdavidn
7525670Sdavidn    if (login_strinlist(ttlst, str1, flags))
7625670Sdavidn	rc = 1;
7725670Sdavidn    else if (login_strinlist(ttlst, str2, flags))
7825670Sdavidn	rc = 1;
7925670Sdavidn    return rc;
8021288Sdavidn}
8121288Sdavidn
8221288Sdavidn
8325670Sdavidn/*
8425670Sdavidn * login_timelist()
85154414Srwatson * This function is intentionally public - reused by TAS.
8621288Sdavidn * Returns an allocated list of time periods given an array
8721288Sdavidn * of time periods in ascii form.
8821288Sdavidn */
8921288Sdavidn
9021288Sdavidnlogin_time_t *
9125670Sdavidnlogin_timelist(login_cap_t *lc, char const *cap, int *ltno,
9225670Sdavidn	       login_time_t **ltptr)
9321288Sdavidn{
9425670Sdavidn    int			j = 0;
9525670Sdavidn    struct login_time	*lt = NULL;
96121193Smarkm    const char		**tl;
9721288Sdavidn
9825670Sdavidn    if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
9925670Sdavidn
10025670Sdavidn	while (tl[j++] != NULL)
10125670Sdavidn	    ;
10225670Sdavidn	if (*ltno >= j)
10325670Sdavidn	    lt = *ltptr;
10470544Sghelmer	else if ((lt = realloc(*ltptr, j * sizeof(struct login_time))) != NULL) {
10525670Sdavidn	    *ltno = j;
10625670Sdavidn	    *ltptr = lt;
10725670Sdavidn	}
10825670Sdavidn	if (lt != NULL) {
10925670Sdavidn	    int	    i = 0;
11025670Sdavidn
11125670Sdavidn	    for (--j; i < j; i++)
11225670Sdavidn		lt[i] = parse_lt(tl[i]);
11325670Sdavidn	    lt[i].lt_dow = LTM_NONE;
11425670Sdavidn	}
11521288Sdavidn    }
11625670Sdavidn    return lt;
11721288Sdavidn}
11821288Sdavidn
11921288Sdavidn
12025670Sdavidn/*
12125670Sdavidn * login_ttyok()
12221288Sdavidn * This function is a variation of auth_ttyok(), but it checks two
12321288Sdavidn * arbitrary capability lists not necessarily related to access.
12421288Sdavidn * This hook is provided for the accounted/exclude accounting lists.
12521288Sdavidn */
12621288Sdavidn
12721288Sdavidnint
12825670Sdavidnlogin_ttyok(login_cap_t *lc, const char *tty, const char *allowcap,
12925670Sdavidn	    const char *denycap)
13021288Sdavidn{
13125670Sdavidn    int	    rc = 1;
13221288Sdavidn
13325670Sdavidn    if (lc != NULL && tty != NULL && *tty != '\0') {
13425670Sdavidn	struct ttyent	*te;
13525670Sdavidn	char		*grp;
136121193Smarkm	const char	**ttl;
13721288Sdavidn
13825670Sdavidn	te = getttynam(tty);  /* Need group name */
13925670Sdavidn	grp = te ? te->ty_group : NULL;
14025670Sdavidn	ttl = login_getcaplist(lc, allowcap, NULL);
14125670Sdavidn
14225670Sdavidn	if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0))
14325670Sdavidn	    rc = 0;	/* tty or ttygroup not in allow list */
14425670Sdavidn	else {
14525670Sdavidn
14625670Sdavidn	    ttl = login_getcaplist(lc, denycap, NULL);
14725670Sdavidn	    if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
14825670Sdavidn		rc = 0; /* tty or ttygroup in deny list */
14925670Sdavidn	}
15021288Sdavidn    }
15125670Sdavidn
15225670Sdavidn    return rc;
15321288Sdavidn}
15421288Sdavidn
15521288Sdavidn
15625670Sdavidn/*
15725670Sdavidn * auth_ttyok()
15821288Sdavidn * Determine whether or not login on a tty is accessible for
15921288Sdavidn * a login class
16021288Sdavidn */
16121288Sdavidn
16221288Sdavidnint
16321288Sdavidnauth_ttyok(login_cap_t *lc, const char * tty)
16421288Sdavidn{
16525670Sdavidn    return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
16621288Sdavidn}
16721288Sdavidn
16821288Sdavidn
16925670Sdavidn/*
17025670Sdavidn * login_hostok()
17121288Sdavidn * This function is a variation of auth_hostok(), but it checks two
17221288Sdavidn * arbitrary capability lists not necessarily related to access.
17321288Sdavidn * This hook is provided for the accounted/exclude accounting lists.
17421288Sdavidn */
17521288Sdavidn
17621288Sdavidnint
17725670Sdavidnlogin_hostok(login_cap_t *lc, const char *host, const char *ip,
17825670Sdavidn	     const char *allowcap, const char *denycap)
17921288Sdavidn{
18025670Sdavidn    int	    rc = 1; /* Default is ok */
18121288Sdavidn
18225670Sdavidn    if (lc != NULL &&
18325670Sdavidn	((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) {
184121193Smarkm	const char **hl;
18521288Sdavidn
18625670Sdavidn	hl = login_getcaplist(lc, allowcap, NULL);
18725670Sdavidn	if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD))
18825670Sdavidn	    rc = 0;	/* host or IP not in allow list */
18925670Sdavidn	else {
19025670Sdavidn
19170544Sghelmer	    hl = login_getcaplist(lc, denycap, NULL);
19225670Sdavidn	    if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
19325670Sdavidn		rc = 0; /* host or IP in deny list */
19425670Sdavidn	}
19521288Sdavidn    }
19625670Sdavidn
19725670Sdavidn    return rc;
19821288Sdavidn}
19921288Sdavidn
20021288Sdavidn
20125670Sdavidn/*
20225670Sdavidn * auth_hostok()
20321288Sdavidn * Determine whether or not login from a host is ok
20421288Sdavidn */
20521288Sdavidn
20621288Sdavidnint
20721288Sdavidnauth_hostok(login_cap_t *lc, const char *host, const char *ip)
20821288Sdavidn{
20925670Sdavidn    return login_hostok(lc, host, ip, "host.allow", "host.deny");
21021288Sdavidn}
21121288Sdavidn
21221288Sdavidn
21325670Sdavidn/*
21425670Sdavidn * auth_timeok()
21521288Sdavidn * Determine whether or not login is ok at a given time
21621288Sdavidn */
21721288Sdavidn
21821288Sdavidnint
21921288Sdavidnauth_timeok(login_cap_t *lc, time_t t)
22021288Sdavidn{
22125670Sdavidn    int	    rc = 1; /* Default is ok */
22221288Sdavidn
22325670Sdavidn    if (lc != NULL && t != (time_t)0 && t != (time_t)-1) {
22425670Sdavidn	struct tm	*tptr;
22521288Sdavidn
22625670Sdavidn	static int 	ltimesno = 0;
22725670Sdavidn	static struct login_time *ltimes = NULL;
22821288Sdavidn
22925670Sdavidn	if ((tptr = localtime(&t)) != NULL) {
23025670Sdavidn	    struct login_time	*lt;
23121288Sdavidn
23225670Sdavidn	  lt = login_timelist(lc, "times.allow", &ltimesno, &ltimes);
23325670Sdavidn	  if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
23425670Sdavidn	      rc = 0;	  /* not in allowed times list */
23525670Sdavidn	  else {
23621288Sdavidn
23725670Sdavidn	      lt = login_timelist(lc, "times.deny", &ltimesno, &ltimes);
23825670Sdavidn	      if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
23925670Sdavidn		  rc = 0; /* in deny times list */
24025670Sdavidn	  }
24125670Sdavidn	  if (ltimes) {
24225670Sdavidn	      free(ltimes);
24325670Sdavidn	      ltimes = NULL;
24425670Sdavidn	      ltimesno = 0;
24525670Sdavidn	  }
24625670Sdavidn	}
24721288Sdavidn    }
24825670Sdavidn
24925670Sdavidn    return rc;
25021288Sdavidn}
251