seusers.c revision 532bd9a8926b4123c9444660041f4e9961543577
1#include <unistd.h>
2#include <fcntl.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6#include <stdio_ext.h>
7#include <ctype.h>
8#include <selinux/selinux.h>
9#include <selinux/context.h>
10#include "selinux_internal.h"
11
12/* Process line from seusers.conf and split into its fields.
13   Returns 0 on success, -1 on comments, and -2 on error. */
14static int process_seusers(const char *buffer,
15			   char **luserp,
16			   char **seuserp, char **levelp, int mls_enabled)
17{
18	char *newbuf = strdup(buffer);
19	char *luser = NULL, *seuser = NULL, *level = NULL;
20	char *start, *end;
21	int mls_found = 1;
22
23	if (!newbuf)
24		goto err;
25
26	start = newbuf;
27	while (isspace(*start))
28		start++;
29	if (*start == '#' || *start == 0) {
30		free(newbuf);
31		return -1;	/* Comment or empty line, skip over */
32	}
33	end = strchr(start, ':');
34	if (!end)
35		goto err;
36	*end = 0;
37
38	luser = strdup(start);
39	if (!luser)
40		goto err;
41
42	start = end + 1;
43	end = strchr(start, ':');
44	if (!end) {
45		mls_found = 0;
46
47		end = start;
48		while (*end && !isspace(*end))
49			end++;
50	}
51	*end = 0;
52
53	seuser = strdup(start);
54	if (!seuser)
55		goto err;
56
57	if (!strcmp(seuser, ""))
58		goto err;
59
60	/* Skip MLS if disabled, or missing. */
61	if (!mls_enabled || !mls_found)
62		goto out;
63
64	start = ++end;
65	while (*end && !isspace(*end))
66		end++;
67	*end = 0;
68
69	level = strdup(start);
70	if (!level)
71		goto err;
72
73	if (!strcmp(level, ""))
74		goto err;
75
76      out:
77	free(newbuf);
78	*luserp = luser;
79	*seuserp = seuser;
80	*levelp = level;
81	return 0;
82      err:
83	free(newbuf);
84	free(luser);
85	free(seuser);
86	free(level);
87	return -2;		/* error */
88}
89
90int require_seusers hidden = 0;
91
92#include <pwd.h>
93#include <grp.h>
94
95static gid_t get_default_gid(const char *name) {
96	struct passwd pwstorage, *pwent = NULL;
97	gid_t gid = -1;
98	/* Allocate space for the getpwnam_r buffer */
99	long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
100	if (rbuflen <= 0) return -1;
101	char *rbuf = malloc(rbuflen);
102	if (rbuf == NULL) return -1;
103
104	int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
105	if (retval == 0 && pwent) {
106		gid = pwent->pw_gid;
107	}
108	free(rbuf);
109	return gid;
110}
111
112static int check_group(const char *group, const char *name, const gid_t gid) {
113	int match = 0;
114	int i, ng = 0;
115	gid_t *groups = NULL;
116	struct group gbuf, *grent = NULL;
117
118	long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
119	if (rbuflen <= 0)
120		return 0;
121	char *rbuf = malloc(rbuflen);
122	if (rbuf == NULL)
123		return 0;
124
125	if (getgrnam_r(group, &gbuf, rbuf, rbuflen,
126		       &grent) != 0)
127		goto done;
128
129	if (getgrouplist(name, gid, NULL, &ng) < 0) {
130		groups = (gid_t *) malloc(sizeof (gid_t) * ng);
131		if (!groups) goto done;
132		if (getgrouplist(name, gid, groups, &ng) < 0) goto done;
133	}
134
135	for (i = 0; i < ng; i++) {
136		if (grent->gr_gid == groups[i]) {
137			match = 1;
138			goto done;
139		}
140	}
141
142 done:
143	free(groups);
144	free(rbuf);
145	return match;
146}
147
148int getseuserbyname(const char *name, char **r_seuser, char **r_level)
149{
150	FILE *cfg = NULL;
151	size_t size = 0;
152	char *buffer = NULL;
153	int rc;
154	unsigned long lineno = 0;
155	int mls_enabled = is_selinux_mls_enabled();
156
157	char *username = NULL;
158	char *seuser = NULL;
159	char *level = NULL;
160	char *groupseuser = NULL;
161	char *grouplevel = NULL;
162	char *defaultseuser = NULL;
163	char *defaultlevel = NULL;
164
165	gid_t gid = get_default_gid(name);
166
167	cfg = fopen(selinux_usersconf_path(), "r");
168	if (!cfg)
169		goto nomatch;
170
171	__fsetlocking(cfg, FSETLOCKING_BYCALLER);
172	while (getline(&buffer, &size, cfg) > 0) {
173		++lineno;
174		rc = process_seusers(buffer, &username, &seuser, &level,
175				     mls_enabled);
176		if (rc == -1)
177			continue;	/* comment, skip */
178		if (rc == -2) {
179			fprintf(stderr, "%s:  error on line %lu, skipping...\n",
180				selinux_usersconf_path(), lineno);
181			continue;
182		}
183
184		if (!strcmp(username, name))
185			break;
186
187		if (username[0] == '%' &&
188		    !groupseuser &&
189		    check_group(&username[1], name, gid)) {
190				groupseuser = seuser;
191				grouplevel = level;
192		} else {
193			if (!defaultseuser &&
194			    !strcmp(username, "__default__")) {
195				defaultseuser = seuser;
196				defaultlevel = level;
197			} else {
198				free(seuser);
199				free(level);
200			}
201		}
202		free(username);
203		username = NULL;
204		seuser = NULL;
205	}
206
207	free(buffer);
208	fclose(cfg);
209
210	if (seuser) {
211		free(username);
212		free(defaultseuser);
213		free(defaultlevel);
214		free(groupseuser);
215		free(grouplevel);
216		*r_seuser = seuser;
217		*r_level = level;
218		return 0;
219	}
220
221	if (groupseuser) {
222		free(defaultseuser);
223		free(defaultlevel);
224		*r_seuser = groupseuser;
225		*r_level = grouplevel;
226		return 0;
227	}
228
229	if (defaultseuser) {
230		*r_seuser = defaultseuser;
231		*r_level = defaultlevel;
232		return 0;
233	}
234
235      nomatch:
236	if (require_seusers)
237		return -1;
238
239	/* Fall back to the Linux username and no level. */
240	*r_seuser = strdup(name);
241	if (!(*r_seuser))
242		return -1;
243	*r_level = NULL;
244	return 0;
245}
246
247int getseuser(const char *username, const char *service,
248	      char **r_seuser, char **r_level) {
249	int ret = -1;
250	int len = 0;
251	char *seuser = NULL;
252	char *level = NULL;
253	char *buffer = NULL;
254	size_t size = 0;
255	size_t lineno = 0;
256	char *rec = NULL;
257	char *path=NULL;
258	if (asprintf(&path,"%s/logins/%s", selinux_policy_root(), username) <  0)
259		goto err;
260	FILE *fp = fopen(path, "r");
261	free(path);
262	if (fp == NULL) goto err;
263	__fsetlocking(fp, FSETLOCKING_BYCALLER);
264	while (getline(&buffer, &size, fp) > 0) {
265		++lineno;
266
267		if (strncmp(buffer, "*:", 2) == 0) {
268			free(rec);
269			rec = strdup(buffer);
270			continue;
271		}
272		len = strlen(service);
273		if ((strncmp(buffer, service, len) == 0) &&
274		    (buffer[len] == ':')) {
275			free(rec);
276			rec = strdup(buffer);
277			break;
278		}
279	}
280
281	if (! rec)  goto err;
282	seuser = strchr(rec, ':');
283	if (! seuser) goto err;
284
285	seuser++;
286	level = strchr(seuser, ':');
287	*level = 0;
288	level++;
289	*r_seuser = strdup(seuser);
290	if (! *r_seuser) goto err;
291
292	len = strlen(level);
293	if (len && level[len-1] == '\n')
294		level[len-1] = 0;
295
296	*r_level = strdup(level);
297	if (! *r_level) {
298		free(*r_seuser);
299		goto err;
300	}
301	ret = 0;
302
303	err:
304	free(buffer);
305	if (fp) fclose(fp);
306	free(rec);
307
308	return (ret ? getseuserbyname(username, r_seuser, r_level) : ret);
309}
310