1/*-
2 * Copyright (c) 1996 by
3 * David Nugent <davidn@blaze.net.au>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, is permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice immediately at the beginning of the file, without modification,
11 *    this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. This work was done expressly for inclusion into FreeBSD.  Other use
16 *    is permitted provided this notation is included.
17 * 4. Absolutely no warranty of function or purpose is made by the authors.
18 * 5. Modifications may be freely made to this file providing the above
19 *    conditions are met.
20 *
21 * Support allow/deny lists in login class capabilities
22 */
23
24#include <sys/cdefs.h>
25__FBSDID("$FreeBSD$");
26
27#include <sys/types.h>
28#include <sys/time.h>
29#include <sys/resource.h>
30#include <sys/param.h>
31#include <errno.h>
32#include <fnmatch.h>
33#include <login_cap.h>
34#include <stdlib.h>
35#include <string.h>
36#include <ttyent.h>
37#include <unistd.h>
38
39
40/* -- support functions -- */
41
42/*
43 * login_strinlist()
44 * This function is intentionally public - reused by TAS.
45 * Returns TRUE (non-zero) if a string matches a pattern
46 * in a given array of patterns. 'flags' is passed directly
47 * to fnmatch(3).
48 */
49
50int
51login_strinlist(const char **list, char const *str, int flags)
52{
53    int rc = 0;
54
55    if (str != NULL && *str != '\0') {
56	int	i = 0;
57
58	while (rc == 0 && list[i] != NULL)
59	    rc = fnmatch(list[i++], str, flags) == 0;
60    }
61    return rc;
62}
63
64
65/*
66 * login_str2inlist()
67 * Locate either or two strings in a given list
68 */
69
70int
71login_str2inlist(const char **ttlst, const char *str1, const char *str2, int flags)
72{
73    int	    rc = 0;
74
75    if (login_strinlist(ttlst, str1, flags))
76	rc = 1;
77    else if (login_strinlist(ttlst, str2, flags))
78	rc = 1;
79    return rc;
80}
81
82
83/*
84 * login_timelist()
85 * This function is intentionally public - reused by TAS.
86 * Returns an allocated list of time periods given an array
87 * of time periods in ascii form.
88 */
89
90login_time_t *
91login_timelist(login_cap_t *lc, char const *cap, int *ltno,
92	       login_time_t **ltptr)
93{
94    int			j = 0;
95    struct login_time	*lt = NULL;
96    const char		**tl;
97
98    if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
99
100	while (tl[j++] != NULL)
101	    ;
102	if (*ltno >= j)
103	    lt = *ltptr;
104	else if ((lt = realloc(*ltptr, j * sizeof(struct login_time))) != NULL) {
105	    *ltno = j;
106	    *ltptr = lt;
107	}
108	if (lt != NULL) {
109	    int	    i = 0;
110
111	    for (--j; i < j; i++)
112		lt[i] = parse_lt(tl[i]);
113	    lt[i].lt_dow = LTM_NONE;
114	}
115    }
116    return lt;
117}
118
119
120/*
121 * login_ttyok()
122 * This function is a variation of auth_ttyok(), but it checks two
123 * arbitrary capability lists not necessarily related to access.
124 * This hook is provided for the accounted/exclude accounting lists.
125 */
126
127int
128login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap,
129	    const char *denycap)
130{
131    int	    rc = 1;
132
133    if (lc != NULL && tty != NULL && *tty != '\0') {
134	struct ttyent	*te;
135	char		*grp;
136	const char	**ttl;
137
138	te = getttynam(tty);  /* Need group name */
139	grp = te ? te->ty_group : NULL;
140	ttl = login_getcaplist(lc, allowcap, NULL);
141
142	if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0))
143	    rc = 0;	/* tty or ttygroup not in allow list */
144	else {
145
146	    ttl = login_getcaplist(lc, denycap, NULL);
147	    if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
148		rc = 0; /* tty or ttygroup in deny list */
149	}
150    }
151
152    return rc;
153}
154
155
156/*
157 * auth_ttyok()
158 * Determine whether or not login on a tty is accessible for
159 * a login class
160 */
161
162int
163auth_ttyok(login_cap_t *lc, const char * tty)
164{
165    return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
166}
167
168
169/*
170 * login_hostok()
171 * This function is a variation of auth_hostok(), but it checks two
172 * arbitrary capability lists not necessarily related to access.
173 * This hook is provided for the accounted/exclude accounting lists.
174 */
175
176int
177login_hostok(login_cap_t *lc, const char *host, const char *ip,
178	     const char *allowcap, const char *denycap)
179{
180    int	    rc = 1; /* Default is ok */
181
182    if (lc != NULL &&
183	((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) {
184	const char **hl;
185
186	hl = login_getcaplist(lc, allowcap, NULL);
187	if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD))
188	    rc = 0;	/* host or IP not in allow list */
189	else {
190
191	    hl = login_getcaplist(lc, denycap, NULL);
192	    if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
193		rc = 0; /* host or IP in deny list */
194	}
195    }
196
197    return rc;
198}
199
200
201/*
202 * auth_hostok()
203 * Determine whether or not login from a host is ok
204 */
205
206int
207auth_hostok(login_cap_t *lc, const char *host, const char *ip)
208{
209    return login_hostok(lc, host, ip, "host.allow", "host.deny");
210}
211
212
213/*
214 * auth_timeok()
215 * Determine whether or not login is ok at a given time
216 */
217
218int
219auth_timeok(login_cap_t *lc, time_t t)
220{
221    int	    rc = 1; /* Default is ok */
222
223    if (lc != NULL && t != (time_t)0 && t != (time_t)-1) {
224	struct tm	*tptr;
225
226	static int 	ltimesno = 0;
227	static struct login_time *ltimes = NULL;
228
229	if ((tptr = localtime(&t)) != NULL) {
230	    struct login_time	*lt;
231
232	  lt = login_timelist(lc, "times.allow", &ltimesno, &ltimes);
233	  if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
234	      rc = 0;	  /* not in allowed times list */
235	  else {
236
237	      lt = login_timelist(lc, "times.deny", &ltimesno, &ltimes);
238	      if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
239		  rc = 0; /* in deny times list */
240	  }
241	  if (ltimes) {
242	      free(ltimes);
243	      ltimes = NULL;
244	      ltimesno = 0;
245	  }
246	}
247    }
248
249    return rc;
250}
251