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