16cd6a6acSopenharmony_ci#include <unistd.h> 26cd6a6acSopenharmony_ci#include <fcntl.h> 36cd6a6acSopenharmony_ci#include <stdlib.h> 46cd6a6acSopenharmony_ci#include <string.h> 56cd6a6acSopenharmony_ci#include <stdio.h> 66cd6a6acSopenharmony_ci#include <stdio_ext.h> 76cd6a6acSopenharmony_ci#include <ctype.h> 86cd6a6acSopenharmony_ci#include <errno.h> 96cd6a6acSopenharmony_ci#include <selinux/selinux.h> 106cd6a6acSopenharmony_ci#include <selinux/context.h> 116cd6a6acSopenharmony_ci#include "selinux_internal.h" 126cd6a6acSopenharmony_ci 136cd6a6acSopenharmony_ci/* Process line from seusers.conf and split into its fields. 146cd6a6acSopenharmony_ci Returns 0 on success, -1 on comments, and -2 on error. */ 156cd6a6acSopenharmony_cistatic int process_seusers(const char *buffer, 166cd6a6acSopenharmony_ci char **luserp, 176cd6a6acSopenharmony_ci char **seuserp, char **levelp, int mls_enabled) 186cd6a6acSopenharmony_ci{ 196cd6a6acSopenharmony_ci char *newbuf = strdup(buffer); 206cd6a6acSopenharmony_ci char *luser = NULL, *seuser = NULL, *level = NULL; 216cd6a6acSopenharmony_ci char *start, *end; 226cd6a6acSopenharmony_ci int mls_found = 1; 236cd6a6acSopenharmony_ci 246cd6a6acSopenharmony_ci if (!newbuf) 256cd6a6acSopenharmony_ci goto err; 266cd6a6acSopenharmony_ci 276cd6a6acSopenharmony_ci start = newbuf; 286cd6a6acSopenharmony_ci while (isspace(*start)) 296cd6a6acSopenharmony_ci start++; 306cd6a6acSopenharmony_ci if (*start == '#' || *start == 0) { 316cd6a6acSopenharmony_ci free(newbuf); 326cd6a6acSopenharmony_ci return -1; /* Comment or empty line, skip over */ 336cd6a6acSopenharmony_ci } 346cd6a6acSopenharmony_ci end = strchr(start, ':'); 356cd6a6acSopenharmony_ci if (!end) 366cd6a6acSopenharmony_ci goto err; 376cd6a6acSopenharmony_ci *end = 0; 386cd6a6acSopenharmony_ci 396cd6a6acSopenharmony_ci luser = strdup(start); 406cd6a6acSopenharmony_ci if (!luser) 416cd6a6acSopenharmony_ci goto err; 426cd6a6acSopenharmony_ci 436cd6a6acSopenharmony_ci start = end + 1; 446cd6a6acSopenharmony_ci end = strchr(start, ':'); 456cd6a6acSopenharmony_ci if (!end) { 466cd6a6acSopenharmony_ci mls_found = 0; 476cd6a6acSopenharmony_ci 486cd6a6acSopenharmony_ci end = start; 496cd6a6acSopenharmony_ci while (*end && !isspace(*end)) 506cd6a6acSopenharmony_ci end++; 516cd6a6acSopenharmony_ci } 526cd6a6acSopenharmony_ci *end = 0; 536cd6a6acSopenharmony_ci 546cd6a6acSopenharmony_ci seuser = strdup(start); 556cd6a6acSopenharmony_ci if (!seuser) 566cd6a6acSopenharmony_ci goto err; 576cd6a6acSopenharmony_ci 586cd6a6acSopenharmony_ci if (!strcmp(seuser, "")) 596cd6a6acSopenharmony_ci goto err; 606cd6a6acSopenharmony_ci 616cd6a6acSopenharmony_ci /* Skip MLS if disabled, or missing. */ 626cd6a6acSopenharmony_ci if (!mls_enabled || !mls_found) 636cd6a6acSopenharmony_ci goto out; 646cd6a6acSopenharmony_ci 656cd6a6acSopenharmony_ci start = ++end; 666cd6a6acSopenharmony_ci while (*end && !isspace(*end)) 676cd6a6acSopenharmony_ci end++; 686cd6a6acSopenharmony_ci *end = 0; 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_ci level = strdup(start); 716cd6a6acSopenharmony_ci if (!level) 726cd6a6acSopenharmony_ci goto err; 736cd6a6acSopenharmony_ci 746cd6a6acSopenharmony_ci if (!strcmp(level, "")) 756cd6a6acSopenharmony_ci goto err; 766cd6a6acSopenharmony_ci 776cd6a6acSopenharmony_ci out: 786cd6a6acSopenharmony_ci free(newbuf); 796cd6a6acSopenharmony_ci *luserp = luser; 806cd6a6acSopenharmony_ci *seuserp = seuser; 816cd6a6acSopenharmony_ci *levelp = level; 826cd6a6acSopenharmony_ci return 0; 836cd6a6acSopenharmony_ci err: 846cd6a6acSopenharmony_ci free(newbuf); 856cd6a6acSopenharmony_ci free(luser); 866cd6a6acSopenharmony_ci free(seuser); 876cd6a6acSopenharmony_ci free(level); 886cd6a6acSopenharmony_ci return -2; /* error */ 896cd6a6acSopenharmony_ci} 906cd6a6acSopenharmony_ci 916cd6a6acSopenharmony_ciint require_seusers = 0; 926cd6a6acSopenharmony_ci 936cd6a6acSopenharmony_ci#include <pwd.h> 946cd6a6acSopenharmony_ci#include <grp.h> 956cd6a6acSopenharmony_ci 966cd6a6acSopenharmony_cistatic gid_t get_default_gid(const char *name) { 976cd6a6acSopenharmony_ci struct passwd pwstorage, *pwent = NULL; 986cd6a6acSopenharmony_ci gid_t gid = -1; 996cd6a6acSopenharmony_ci /* Allocate space for the getpwnam_r buffer */ 1006cd6a6acSopenharmony_ci long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); 1016cd6a6acSopenharmony_ci if (rbuflen <= 0) return -1; 1026cd6a6acSopenharmony_ci char *rbuf = malloc(rbuflen); 1036cd6a6acSopenharmony_ci if (rbuf == NULL) return -1; 1046cd6a6acSopenharmony_ci 1056cd6a6acSopenharmony_ci int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent); 1066cd6a6acSopenharmony_ci if (retval == 0 && pwent) { 1076cd6a6acSopenharmony_ci gid = pwent->pw_gid; 1086cd6a6acSopenharmony_ci } 1096cd6a6acSopenharmony_ci free(rbuf); 1106cd6a6acSopenharmony_ci return gid; 1116cd6a6acSopenharmony_ci} 1126cd6a6acSopenharmony_ci 1136cd6a6acSopenharmony_cistatic int check_group(const char *group, const char *name, const gid_t gid) { 1146cd6a6acSopenharmony_ci int match = 0; 1156cd6a6acSopenharmony_ci int i, ng = 0; 1166cd6a6acSopenharmony_ci gid_t *groups = NULL; 1176cd6a6acSopenharmony_ci struct group gbuf, *grent = NULL; 1186cd6a6acSopenharmony_ci 1196cd6a6acSopenharmony_ci long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); 1206cd6a6acSopenharmony_ci if (rbuflen <= 0) 1216cd6a6acSopenharmony_ci return 0; 1226cd6a6acSopenharmony_ci char *rbuf; 1236cd6a6acSopenharmony_ci 1246cd6a6acSopenharmony_ci while(1) { 1256cd6a6acSopenharmony_ci rbuf = malloc(rbuflen); 1266cd6a6acSopenharmony_ci if (rbuf == NULL) 1276cd6a6acSopenharmony_ci return 0; 1286cd6a6acSopenharmony_ci int retval = getgrnam_r(group, &gbuf, rbuf, 1296cd6a6acSopenharmony_ci rbuflen, &grent); 1306cd6a6acSopenharmony_ci if ( retval == ERANGE ) 1316cd6a6acSopenharmony_ci { 1326cd6a6acSopenharmony_ci free(rbuf); 1336cd6a6acSopenharmony_ci rbuflen = rbuflen * 2; 1346cd6a6acSopenharmony_ci } else if ( retval != 0 || grent == NULL ) 1356cd6a6acSopenharmony_ci { 1366cd6a6acSopenharmony_ci goto done; 1376cd6a6acSopenharmony_ci } else 1386cd6a6acSopenharmony_ci { 1396cd6a6acSopenharmony_ci break; 1406cd6a6acSopenharmony_ci } 1416cd6a6acSopenharmony_ci } 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_ci if (getgrouplist(name, gid, NULL, &ng) < 0) { 1446cd6a6acSopenharmony_ci if (ng == 0) 1456cd6a6acSopenharmony_ci goto done; 1466cd6a6acSopenharmony_ci groups = calloc(ng, sizeof(*groups)); 1476cd6a6acSopenharmony_ci if (!groups) 1486cd6a6acSopenharmony_ci goto done; 1496cd6a6acSopenharmony_ci if (getgrouplist(name, gid, groups, &ng) < 0) 1506cd6a6acSopenharmony_ci goto done; 1516cd6a6acSopenharmony_ci } else { 1526cd6a6acSopenharmony_ci /* WTF? ng was 0 and we didn't fail? Are we in 0 groups? */ 1536cd6a6acSopenharmony_ci goto done; 1546cd6a6acSopenharmony_ci } 1556cd6a6acSopenharmony_ci 1566cd6a6acSopenharmony_ci for (i = 0; i < ng; i++) { 1576cd6a6acSopenharmony_ci if (grent->gr_gid == groups[i]) { 1586cd6a6acSopenharmony_ci match = 1; 1596cd6a6acSopenharmony_ci goto done; 1606cd6a6acSopenharmony_ci } 1616cd6a6acSopenharmony_ci } 1626cd6a6acSopenharmony_ci 1636cd6a6acSopenharmony_ci done: 1646cd6a6acSopenharmony_ci free(groups); 1656cd6a6acSopenharmony_ci free(rbuf); 1666cd6a6acSopenharmony_ci return match; 1676cd6a6acSopenharmony_ci} 1686cd6a6acSopenharmony_ci 1696cd6a6acSopenharmony_ciint getseuserbyname(const char *name, char **r_seuser, char **r_level) 1706cd6a6acSopenharmony_ci{ 1716cd6a6acSopenharmony_ci FILE *cfg = NULL; 1726cd6a6acSopenharmony_ci size_t size = 0; 1736cd6a6acSopenharmony_ci char *buffer = NULL; 1746cd6a6acSopenharmony_ci int rc; 1756cd6a6acSopenharmony_ci unsigned long lineno = 0; 1766cd6a6acSopenharmony_ci int mls_enabled = is_selinux_mls_enabled(); 1776cd6a6acSopenharmony_ci 1786cd6a6acSopenharmony_ci char *username = NULL; 1796cd6a6acSopenharmony_ci char *seuser = NULL; 1806cd6a6acSopenharmony_ci char *level = NULL; 1816cd6a6acSopenharmony_ci char *groupseuser = NULL; 1826cd6a6acSopenharmony_ci char *grouplevel = NULL; 1836cd6a6acSopenharmony_ci char *defaultseuser = NULL; 1846cd6a6acSopenharmony_ci char *defaultlevel = NULL; 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci gid_t gid = get_default_gid(name); 1876cd6a6acSopenharmony_ci 1886cd6a6acSopenharmony_ci cfg = fopen(selinux_usersconf_path(), "re"); 1896cd6a6acSopenharmony_ci if (!cfg) 1906cd6a6acSopenharmony_ci goto nomatch; 1916cd6a6acSopenharmony_ci 1926cd6a6acSopenharmony_ci __fsetlocking(cfg, FSETLOCKING_BYCALLER); 1936cd6a6acSopenharmony_ci while (getline(&buffer, &size, cfg) > 0) { 1946cd6a6acSopenharmony_ci ++lineno; 1956cd6a6acSopenharmony_ci rc = process_seusers(buffer, &username, &seuser, &level, 1966cd6a6acSopenharmony_ci mls_enabled); 1976cd6a6acSopenharmony_ci if (rc == -1) 1986cd6a6acSopenharmony_ci continue; /* comment, skip */ 1996cd6a6acSopenharmony_ci if (rc == -2) { 2006cd6a6acSopenharmony_ci fprintf(stderr, "%s: error on line %lu, skipping...\n", 2016cd6a6acSopenharmony_ci selinux_usersconf_path(), lineno); 2026cd6a6acSopenharmony_ci continue; 2036cd6a6acSopenharmony_ci } 2046cd6a6acSopenharmony_ci 2056cd6a6acSopenharmony_ci if (!strcmp(username, name)) 2066cd6a6acSopenharmony_ci break; 2076cd6a6acSopenharmony_ci 2086cd6a6acSopenharmony_ci if (username[0] == '%' && 2096cd6a6acSopenharmony_ci !groupseuser && 2106cd6a6acSopenharmony_ci check_group(&username[1], name, gid)) { 2116cd6a6acSopenharmony_ci groupseuser = seuser; 2126cd6a6acSopenharmony_ci grouplevel = level; 2136cd6a6acSopenharmony_ci } else { 2146cd6a6acSopenharmony_ci if (!defaultseuser && 2156cd6a6acSopenharmony_ci !strcmp(username, "__default__")) { 2166cd6a6acSopenharmony_ci defaultseuser = seuser; 2176cd6a6acSopenharmony_ci defaultlevel = level; 2186cd6a6acSopenharmony_ci } else { 2196cd6a6acSopenharmony_ci free(seuser); 2206cd6a6acSopenharmony_ci free(level); 2216cd6a6acSopenharmony_ci } 2226cd6a6acSopenharmony_ci } 2236cd6a6acSopenharmony_ci free(username); 2246cd6a6acSopenharmony_ci username = NULL; 2256cd6a6acSopenharmony_ci seuser = NULL; 2266cd6a6acSopenharmony_ci } 2276cd6a6acSopenharmony_ci 2286cd6a6acSopenharmony_ci free(buffer); 2296cd6a6acSopenharmony_ci fclose(cfg); 2306cd6a6acSopenharmony_ci 2316cd6a6acSopenharmony_ci if (seuser) { 2326cd6a6acSopenharmony_ci free(username); 2336cd6a6acSopenharmony_ci free(defaultseuser); 2346cd6a6acSopenharmony_ci free(defaultlevel); 2356cd6a6acSopenharmony_ci free(groupseuser); 2366cd6a6acSopenharmony_ci free(grouplevel); 2376cd6a6acSopenharmony_ci *r_seuser = seuser; 2386cd6a6acSopenharmony_ci *r_level = level; 2396cd6a6acSopenharmony_ci return 0; 2406cd6a6acSopenharmony_ci } 2416cd6a6acSopenharmony_ci 2426cd6a6acSopenharmony_ci if (groupseuser) { 2436cd6a6acSopenharmony_ci free(defaultseuser); 2446cd6a6acSopenharmony_ci free(defaultlevel); 2456cd6a6acSopenharmony_ci *r_seuser = groupseuser; 2466cd6a6acSopenharmony_ci *r_level = grouplevel; 2476cd6a6acSopenharmony_ci return 0; 2486cd6a6acSopenharmony_ci } 2496cd6a6acSopenharmony_ci 2506cd6a6acSopenharmony_ci if (defaultseuser) { 2516cd6a6acSopenharmony_ci *r_seuser = defaultseuser; 2526cd6a6acSopenharmony_ci *r_level = defaultlevel; 2536cd6a6acSopenharmony_ci return 0; 2546cd6a6acSopenharmony_ci } 2556cd6a6acSopenharmony_ci 2566cd6a6acSopenharmony_ci nomatch: 2576cd6a6acSopenharmony_ci if (require_seusers) 2586cd6a6acSopenharmony_ci return -1; 2596cd6a6acSopenharmony_ci 2606cd6a6acSopenharmony_ci /* Fall back to the Linux username and no level. */ 2616cd6a6acSopenharmony_ci *r_seuser = strdup(name); 2626cd6a6acSopenharmony_ci if (!(*r_seuser)) 2636cd6a6acSopenharmony_ci return -1; 2646cd6a6acSopenharmony_ci *r_level = NULL; 2656cd6a6acSopenharmony_ci return 0; 2666cd6a6acSopenharmony_ci} 2676cd6a6acSopenharmony_ci 2686cd6a6acSopenharmony_ciint getseuser(const char *username, const char *service, 2696cd6a6acSopenharmony_ci char **r_seuser, char **r_level) { 2706cd6a6acSopenharmony_ci int ret = -1; 2716cd6a6acSopenharmony_ci int len = 0; 2726cd6a6acSopenharmony_ci char *seuser = NULL; 2736cd6a6acSopenharmony_ci char *level = NULL; 2746cd6a6acSopenharmony_ci char *buffer = NULL; 2756cd6a6acSopenharmony_ci size_t size = 0; 2766cd6a6acSopenharmony_ci char *rec = NULL; 2776cd6a6acSopenharmony_ci char *path = NULL; 2786cd6a6acSopenharmony_ci FILE *fp = NULL; 2796cd6a6acSopenharmony_ci if (asprintf(&path,"%s/logins/%s", selinux_policy_root(), username) < 0) 2806cd6a6acSopenharmony_ci goto err; 2816cd6a6acSopenharmony_ci fp = fopen(path, "re"); 2826cd6a6acSopenharmony_ci free(path); 2836cd6a6acSopenharmony_ci if (fp == NULL) goto err; 2846cd6a6acSopenharmony_ci __fsetlocking(fp, FSETLOCKING_BYCALLER); 2856cd6a6acSopenharmony_ci while (getline(&buffer, &size, fp) > 0) { 2866cd6a6acSopenharmony_ci if (strncmp(buffer, "*:", 2) == 0) { 2876cd6a6acSopenharmony_ci free(rec); 2886cd6a6acSopenharmony_ci rec = strdup(buffer); 2896cd6a6acSopenharmony_ci continue; 2906cd6a6acSopenharmony_ci } 2916cd6a6acSopenharmony_ci if (!service) 2926cd6a6acSopenharmony_ci continue; 2936cd6a6acSopenharmony_ci len = strlen(service); 2946cd6a6acSopenharmony_ci if ((strncmp(buffer, service, len) == 0) && 2956cd6a6acSopenharmony_ci (buffer[len] == ':')) { 2966cd6a6acSopenharmony_ci free(rec); 2976cd6a6acSopenharmony_ci rec = strdup(buffer); 2986cd6a6acSopenharmony_ci break; 2996cd6a6acSopenharmony_ci } 3006cd6a6acSopenharmony_ci } 3016cd6a6acSopenharmony_ci 3026cd6a6acSopenharmony_ci if (! rec) goto err; 3036cd6a6acSopenharmony_ci seuser = strchr(rec, ':'); 3046cd6a6acSopenharmony_ci if (! seuser) goto err; 3056cd6a6acSopenharmony_ci 3066cd6a6acSopenharmony_ci seuser++; 3076cd6a6acSopenharmony_ci level = strchr(seuser, ':'); 3086cd6a6acSopenharmony_ci if (! level) goto err; 3096cd6a6acSopenharmony_ci *level = 0; 3106cd6a6acSopenharmony_ci level++; 3116cd6a6acSopenharmony_ci *r_seuser = strdup(seuser); 3126cd6a6acSopenharmony_ci if (! *r_seuser) goto err; 3136cd6a6acSopenharmony_ci 3146cd6a6acSopenharmony_ci len = strlen(level); 3156cd6a6acSopenharmony_ci if (len && level[len-1] == '\n') 3166cd6a6acSopenharmony_ci level[len-1] = 0; 3176cd6a6acSopenharmony_ci 3186cd6a6acSopenharmony_ci *r_level = strdup(level); 3196cd6a6acSopenharmony_ci if (! *r_level) { 3206cd6a6acSopenharmony_ci free(*r_seuser); 3216cd6a6acSopenharmony_ci goto err; 3226cd6a6acSopenharmony_ci } 3236cd6a6acSopenharmony_ci ret = 0; 3246cd6a6acSopenharmony_ci 3256cd6a6acSopenharmony_ci err: 3266cd6a6acSopenharmony_ci free(buffer); 3276cd6a6acSopenharmony_ci if (fp) fclose(fp); 3286cd6a6acSopenharmony_ci free(rec); 3296cd6a6acSopenharmony_ci 3306cd6a6acSopenharmony_ci return (ret ? getseuserbyname(username, r_seuser, r_level) : ret); 3316cd6a6acSopenharmony_ci} 332