xref: /illumos-gate/usr/src/lib/pam_modules/list/list.c (revision d362b749)
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