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