Blob Blame History Raw
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <selinux/selinux.h>
#include <selinux/context.h>
#include "selinux_internal.h"

/* Process line from seusers.conf and split into its fields.
   Returns 0 on success, -1 on comments, and -2 on error. */
static int process_seusers(const char *buffer, 
			   char **luserp, 
			   char **seuserp, 
			   char **levelp,
			   int mls_enabled)
{
	char *newbuf = strdup(buffer);
	char *luser = NULL, *seuser = NULL, *level = NULL;
	char *start, *end;

	if (!newbuf)
		goto err;

	start = newbuf;
	while (isspace(*start))
		start++;
	if (*start == '#' || *start == 0) {
		free(newbuf);
		return -1; /* Comment or empty line, skip over */
	}
	end = strchr(start, ':');
	if (!end)
		goto err;
	*end = 0;
	
	luser = strdup(start);
	if (!luser)
		goto err;

	start = end+1;
	end = strchr(start, ':');
	if (!end) {
		if (mls_enabled)
			goto err; /* no MLS level and MLS is enabled */
		/* MLS is disabled, so :level suffix not required. */
		end = start;
		while (*end && !isspace(*end))
			end++;
	}
	*end = 0;
	
	seuser = strdup(start);
	if (!seuser)
		goto err;

	if (!mls_enabled)
		goto out; /* skip any MLS level */

	start = ++end;
	while (*end && !isspace(*end))
		end++;
	*end = 0;

	level = strdup(start);
	if (!level)
		goto err;

out:
	free(newbuf);
	*luserp = luser;
	*seuserp = seuser;
	*levelp = level;
	return 0;
err:
	free(newbuf);
	free(luser);
	free(seuser);
	free(level);
	return -2; /* error */
}

int require_seusers hidden = 0;

int getseuserbyname(const char *name, char **r_seuser, char **r_level) {
	FILE *cfg=NULL;
	size_t size=0;
	char *buffer=NULL;
	int rc;
	unsigned long lineno = 0;
	int mls_enabled = is_selinux_mls_enabled();

	char *username=NULL;
        char *seuser=NULL;
        char *level=NULL;
        char *defaultseuser=NULL;
        char *defaultlevel=NULL;

	cfg = fopen(selinux_usersconf_path(), "r");
	if (!cfg)
		goto nomatch;

	while (getline(&buffer, &size, cfg) > 0) {
		++lineno;
		rc = process_seusers(buffer, &username, &seuser, &level, mls_enabled);
		if (rc == -1)
			continue; /* comment, skip */
		if (rc == -2) {
			fprintf(stderr, "%s:  error on line %lu, skipping...\n",
				selinux_usersconf_path(), lineno);
			continue;
		}

		if (!strcmp(username, name))
			break;

		if (!defaultseuser && !strcmp(username,"default")) {
			free(username);
			defaultseuser = seuser;
			defaultlevel = level;
		} else {
			free(username);
			free(seuser);
			free(level);
		}
		seuser=NULL;
	}

	if (buffer) 
		free(buffer);
	fclose(cfg);

	if (seuser) {
		free(username);
		free(defaultseuser);
		free(defaultlevel);
		*r_seuser = seuser;
		*r_level = level;
		return 0;
	}

	if (defaultseuser) {
		*r_seuser = defaultseuser;
		*r_level = defaultlevel;
		return 0;
	}

nomatch:
	if (require_seusers)
		return -1;

	/* Fall back to the Linux username and no level. */
	*r_seuser = strdup(name);
	if (!(*r_seuser))
		return -1;
	*r_level = NULL;
	return 0;
}