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