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