#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;
}