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. */ 15static 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 91int require_seusers hidden = 0; 92 93#include <pwd.h> 94#include <grp.h> 95 96static 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 113static 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 169int 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(), "r"); 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 268int 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, "r"); 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