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