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 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 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 * 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 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 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 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 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 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