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