1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <syslog.h> 34 #include <netdb.h> 35 #include <malloc.h> 36 #include <unistd.h> 37 #include <errno.h> 38 #include <security/pam_appl.h> 39 #include <security/pam_modules.h> 40 #include <security/pam_impl.h> 41 42 /*ARGSUSED*/ 43 int 44 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) 45 { 46 FILE *fd; 47 const char *allowdeny_filename = PF_PATH; 48 char buf[BUFSIZ]; 49 char hostname[MAXHOSTNAMELEN]; 50 char *username = NULL; 51 char *bufp; 52 char *rhost; 53 char *limit; 54 int userok = 0; 55 int hostok = 0; 56 int i; 57 int allow_deny_test = 0; 58 boolean_t debug = B_FALSE; 59 boolean_t plus_check = B_TRUE; 60 boolean_t allow = B_FALSE; 61 boolean_t matched = B_FALSE; 62 boolean_t check_user = B_TRUE; 63 boolean_t check_host = B_FALSE; 64 boolean_t check_exact = B_FALSE; 65 66 for (i = 0; i < argc; ++i) { 67 if (strncasecmp(argv[i], "debug", sizeof ("debug")) == 0) { 68 debug = B_TRUE; 69 } else if (strncasecmp(argv[i], "user", sizeof ("user")) == 0) { 70 check_user = B_TRUE; 71 } else if (strncasecmp(argv[i], "nouser", 72 sizeof ("nouser")) == 0) { 73 check_user = B_FALSE; 74 } else if (strncasecmp(argv[i], "host", sizeof ("host")) == 0) { 75 check_host = B_TRUE; 76 } else if (strncasecmp(argv[i], "nohost", 77 sizeof ("nohost")) == 0) { 78 check_host = B_FALSE; 79 } else if (strncasecmp(argv[i], "user_host_exact", 80 sizeof ("user_host_exact")) == 0) { 81 check_exact = B_TRUE; 82 } else if (strncasecmp(argv[i], "allow=", 83 sizeof ("allow=") - 1) == 0) { 84 allowdeny_filename = argv[i] + sizeof ("allow=") - 1; 85 allow = B_TRUE; 86 plus_check = B_FALSE; 87 allow_deny_test++; 88 } else if (strncasecmp(argv[i], "deny=", 89 sizeof ("deny=") - 1) == 0) { 90 allowdeny_filename = argv[i] + sizeof ("deny=") - 1; 91 allow = B_FALSE; 92 plus_check = B_FALSE; 93 allow_deny_test++; 94 } else { 95 __pam_log(LOG_AUTH | LOG_ERR, 96 "pam_list: illegal option %s", argv[i]); 97 return (PAM_SERVICE_ERR); 98 } 99 } 100 101 if (((check_user || check_host || check_exact) == B_FALSE) || 102 (allow_deny_test > 1)) { 103 __pam_log(LOG_AUTH | LOG_ERR, 104 "pam_list: illegal combination of options"); 105 return (PAM_SERVICE_ERR); 106 } 107 108 if (debug) { 109 __pam_log(LOG_AUTH | LOG_DEBUG, 110 "pam_list: check_user = %d, check_host = %d," 111 "check_exact = %d\n", 112 check_user, check_host, check_exact); 113 114 __pam_log(LOG_AUTH | LOG_DEBUG, 115 "pam_list: auth_file: %s, %s\n", allowdeny_filename, 116 allow ? "allow file" : "deny file"); 117 } 118 119 (void) pam_get_item(pamh, PAM_USER, (void**)&username); 120 121 if ((check_user || check_exact) && ((username == NULL) || 122 (*username == '\0'))) { 123 __pam_log(LOG_AUTH | LOG_ERR, 124 "pam_list: username not supplied, critical error"); 125 return (PAM_USER_UNKNOWN); 126 } 127 128 (void) pam_get_item(pamh, PAM_RHOST, (void**)&rhost); 129 130 if ((check_host || check_exact) && ((rhost == NULL) || 131 (*rhost == '\0'))) { 132 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { 133 rhost = hostname; 134 } else { 135 __pam_log(LOG_AUTH | LOG_ERR, 136 "pam_list: error by gethostname - %m"); 137 return (PAM_SERVICE_ERR); 138 } 139 } 140 141 if (debug) { 142 __pam_log(LOG_AUTH | LOG_DEBUG, 143 "pam_list:pam_sm_acct_mgmt for (%s,%s,)\n", 144 (rhost != NULL) ? rhost : "", username); 145 } 146 147 if ((fd = fopen(allowdeny_filename, "rF")) == NULL) { 148 return (PAM_SERVICE_ERR); 149 } 150 151 while (fgets(buf, BUFSIZ, fd) != NULL) { 152 /* lines longer than BUFSIZ-1 */ 153 if ((strlen(buf) == (BUFSIZ - 1)) && 154 (buf[BUFSIZ - 2] != '\n')) { 155 while ((fgetc(fd) != '\n') && (!feof(fd))) { 156 continue; 157 } 158 __pam_log(LOG_AUTH | LOG_DEBUG, 159 "pam_list: long line in file," 160 "more than %d chars, the rest ignored", BUFSIZ - 1); 161 } 162 163 /* remove unneeded colons if necessary */ 164 if ((limit = strpbrk(buf, ":\n")) != NULL) { 165 *limit = '\0'; 166 } 167 168 /* ignore free values */ 169 if (buf[0] == '\0') { 170 continue; 171 } 172 173 174 bufp = buf; 175 /* test for interesting lines = +/- in /etc/passwd */ 176 if (plus_check) { 177 if (((buf[0] != '+') && (buf[0] != '-')) || 178 (buf[1] == '\0')) { 179 continue; 180 } 181 182 if (buf[0] == '+') { 183 allow = B_TRUE; 184 } else { 185 allow = B_FALSE; 186 } 187 bufp++; 188 } 189 190 /* 191 * if -> netgroup line 192 * else -> user line 193 */ 194 if ((bufp[0] == '@') && (bufp[1] != '\0')) { 195 bufp++; 196 197 if (check_exact) { 198 if (innetgr(bufp, rhost, username, 199 NULL) == 1) { 200 matched = B_TRUE; 201 break; 202 } 203 } else { 204 if (check_user) { 205 userok = innetgr(bufp, NULL, username, 206 NULL); 207 } else { 208 userok = 1; 209 } 210 if (check_host) { 211 hostok = innetgr(bufp, rhost, NULL, 212 NULL); 213 } else { 214 hostok = 1; 215 } 216 if (userok && hostok) { 217 matched = B_TRUE; 218 break; 219 } 220 } 221 } else { 222 if (check_user) { 223 if (strcmp(bufp, username) == 0) { 224 matched = B_TRUE; 225 break; 226 } 227 } 228 } 229 } 230 (void) fclose(fd); 231 if (matched) { 232 return (allow ? PAM_SUCCESS : PAM_PERM_DENIED); 233 } 234 /* for compatibility with passwd_compat mode */ 235 if (plus_check) { 236 return (PAM_IGNORE); 237 } 238 return (allow ? PAM_PERM_DENIED : PAM_SUCCESS); 239 } 240