1 /* Copyright (C) 2005 Red Hat, Inc. */ 2 3 struct semanage_seuser; 4 struct semanage_seuser_key; 5 typedef struct semanage_seuser_key record_key_t; 6 typedef struct semanage_seuser record_t; 7 #define DBASE_RECORD_DEFINED 8 9 #include <sepol/policydb.h> 10 #include <sepol/context.h> 11 #include <libaudit.h> 12 #include <errno.h> 13 #include "user_internal.h" 14 #include "seuser_internal.h" 15 #include "handle.h" 16 #include "database.h" 17 #include "debug.h" 18 #include "string.h" 19 #include <stdlib.h> 20 21 static char *semanage_user_roles(semanage_handle_t * handle, const char *sename) { 22 char *roles = NULL; 23 unsigned int num_roles; 24 size_t i; 25 size_t size = 0; 26 const char **roles_arr; 27 semanage_user_key_t *key = NULL; 28 semanage_user_t * user; 29 if (semanage_user_key_create(handle, sename, &key) >= 0) { 30 if (semanage_user_query(handle, key, &user) >= 0) { 31 if (semanage_user_get_roles(handle, 32 user, 33 &roles_arr, 34 &num_roles) >= 0) { 35 for (i = 0; i<num_roles; i++) { 36 size += (strlen(roles_arr[i]) + 1); 37 } 38 roles = malloc(size); 39 if (roles) { 40 strcpy(roles,roles_arr[0]); 41 for (i = 1; i<num_roles; i++) { 42 strcat(roles,","); 43 strcat(roles,roles_arr[i]); 44 } 45 } 46 } 47 semanage_user_free(user); 48 } 49 semanage_user_key_free(key); 50 } 51 return roles; 52 } 53 54 static int semanage_seuser_audit(semanage_handle_t * handle, 55 const semanage_seuser_t * seuser, 56 const semanage_seuser_t * previous, 57 int audit_type, 58 int success) { 59 const char *name = NULL; 60 const char *sename = NULL; 61 char *roles = NULL; 62 const char *mls = NULL; 63 const char *psename = NULL; 64 const char *pmls = NULL; 65 char *proles = NULL; 66 char msg[1024]; 67 const char *sep = "-"; 68 int rc = -1; 69 strcpy(msg, "login"); 70 if (seuser) { 71 name = semanage_seuser_get_name(seuser); 72 sename = semanage_seuser_get_sename(seuser); 73 mls = semanage_seuser_get_mlsrange(seuser); 74 roles = semanage_user_roles(handle, sename); 75 } 76 if (previous) { 77 psename = semanage_seuser_get_sename(previous); 78 pmls = semanage_seuser_get_mlsrange(previous); 79 proles = semanage_user_roles(handle, psename); 80 } 81 if (audit_type != AUDIT_ROLE_REMOVE) { 82 if (sename && (!psename || strcmp(psename, sename) != 0)) { 83 strcat(msg,sep); 84 strcat(msg,"sename"); 85 sep = ","; 86 } 87 if (roles && (!proles || strcmp(proles, roles) != 0)) { 88 strcat(msg,sep); 89 strcat(msg,"role"); 90 sep = ","; 91 } 92 if (mls && (!pmls || strcmp(pmls, mls) != 0)) { 93 strcat(msg,sep); 94 strcat(msg,"range"); 95 } 96 } 97 98 int fd = audit_open(); 99 if (fd < 0) 100 { 101 /* If kernel doesn't support audit, bail out */ 102 if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { 103 rc = 0; 104 goto err; 105 } 106 rc = fd; 107 goto err; 108 } 109 audit_log_semanage_message(fd, audit_type, NULL, msg, name, 0, sename, roles, mls, psename, proles, pmls, NULL, NULL,NULL, success); 110 rc = 0; 111 err: 112 audit_close(fd); 113 free(roles); 114 free(proles); 115 return rc; 116 } 117 118 int semanage_seuser_modify_local(semanage_handle_t * handle, 119 const semanage_seuser_key_t * key, 120 const semanage_seuser_t * data) 121 { 122 int rc; 123 void *callback = (void *) handle->msg_callback; 124 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 125 const char *sename = semanage_seuser_get_sename(data); 126 const char *mls_range = semanage_seuser_get_mlsrange(data); 127 semanage_seuser_t *previous = NULL; 128 semanage_seuser_t *new = NULL; 129 130 if (!sename) { 131 errno=EINVAL; 132 return -1; 133 } 134 rc = semanage_seuser_clone(handle, data, &new); 135 if (rc < 0) { 136 goto err; 137 } 138 139 if (!mls_range && semanage_mls_enabled(handle)) { 140 semanage_user_key_t *ukey = NULL; 141 semanage_user_t *u = NULL; 142 rc = semanage_user_key_create(handle, sename, &ukey); 143 if (rc < 0) 144 goto err; 145 146 rc = semanage_user_query(handle, ukey, &u); 147 semanage_user_key_free(ukey); 148 if (rc >= 0 ) { 149 mls_range = semanage_user_get_mlsrange(u); 150 rc = semanage_seuser_set_mlsrange(handle, new, mls_range); 151 semanage_user_free(u); 152 } 153 if (rc < 0) 154 goto err; 155 } 156 157 handle->msg_callback = NULL; 158 (void) semanage_seuser_query(handle, key, &previous); 159 handle->msg_callback = callback; 160 rc = dbase_modify(handle, dconfig, key, new); 161 if (semanage_seuser_audit(handle, new, previous, AUDIT_ROLE_ASSIGN, rc == 0) < 0) 162 rc = -1; 163 err: 164 if (previous) 165 semanage_seuser_free(previous); 166 semanage_seuser_free(new); 167 return rc; 168 } 169 170 int semanage_seuser_del_local(semanage_handle_t * handle, 171 const semanage_seuser_key_t * key) 172 { 173 int rc; 174 semanage_seuser_t *seuser = NULL; 175 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 176 rc = dbase_del(handle, dconfig, key); 177 semanage_seuser_query(handle, key, &seuser); 178 if (semanage_seuser_audit(handle, NULL, seuser, AUDIT_ROLE_REMOVE, rc == 0) < 0) 179 rc = -1; 180 if (seuser) 181 semanage_seuser_free(seuser); 182 return rc; 183 } 184 185 int semanage_seuser_query_local(semanage_handle_t * handle, 186 const semanage_seuser_key_t * key, 187 semanage_seuser_t ** response) 188 { 189 190 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 191 return dbase_query(handle, dconfig, key, response); 192 } 193 194 int semanage_seuser_exists_local(semanage_handle_t * handle, 195 const semanage_seuser_key_t * key, 196 int *response) 197 { 198 199 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 200 return dbase_exists(handle, dconfig, key, response); 201 } 202 203 int semanage_seuser_count_local(semanage_handle_t * handle, 204 unsigned int *response) 205 { 206 207 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 208 return dbase_count(handle, dconfig, response); 209 } 210 211 int semanage_seuser_iterate_local(semanage_handle_t * handle, 212 int (*handler) (const semanage_seuser_t * 213 record, void *varg), 214 void *handler_arg) 215 { 216 217 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 218 return dbase_iterate(handle, dconfig, handler, handler_arg); 219 } 220 221 hidden_def(semanage_seuser_iterate_local) 222 223 int semanage_seuser_list_local(semanage_handle_t * handle, 224 semanage_seuser_t *** records, 225 unsigned int *count) 226 { 227 228 dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); 229 return dbase_list(handle, dconfig, records, count); 230 } 231 232 struct validate_handler_arg { 233 semanage_handle_t *handle; 234 const sepol_policydb_t *policydb; 235 }; 236 237 static int validate_handler(const semanage_seuser_t * seuser, void *varg) 238 { 239 240 semanage_user_t *user = NULL; 241 semanage_user_key_t *key = NULL; 242 int exists, mls_ok; 243 244 /* Unpack varg */ 245 struct validate_handler_arg *arg = (struct validate_handler_arg *)varg; 246 semanage_handle_t *handle = arg->handle; 247 const sepol_policydb_t *policydb = arg->policydb; 248 249 /* Unpack seuser */ 250 const char *name = semanage_seuser_get_name(seuser); 251 const char *sename = semanage_seuser_get_sename(seuser); 252 const char *mls_range = semanage_seuser_get_mlsrange(seuser); 253 const char *user_mls_range; 254 255 /* Make sure the (SElinux) user exists */ 256 if (semanage_user_key_create(handle, sename, &key) < 0) 257 goto err; 258 if (semanage_user_exists(handle, key, &exists) < 0) 259 goto err; 260 if (!exists) { 261 ERR(handle, "selinux user %s does not exist", sename); 262 goto invalid; 263 } 264 265 /* Verify that the mls range is valid, and that it's contained 266 * within the (SELinux) user mls range. This range is optional */ 267 if (mls_range && sepol_policydb_mls_enabled(policydb)) { 268 269 if (semanage_user_query(handle, key, &user) < 0) 270 goto err; 271 user_mls_range = semanage_user_get_mlsrange(user); 272 273 if (sepol_mls_check(handle->sepolh, policydb, mls_range) < 0) 274 goto invalid; 275 if (sepol_mls_contains(handle->sepolh, policydb, 276 user_mls_range, mls_range, &mls_ok) < 0) 277 goto err; 278 279 if (!mls_ok) { 280 ERR(handle, "MLS range %s for Unix user %s " 281 "exceeds allowed range %s for SELinux user %s", 282 mls_range, name, user_mls_range, sename); 283 goto invalid; 284 } 285 286 } else if (mls_range) { 287 ERR(handle, "MLS is disabled, but MLS range %s " 288 "was found for Unix user %s", mls_range, name); 289 goto invalid; 290 } 291 292 semanage_user_key_free(key); 293 semanage_user_free(user); 294 return 0; 295 296 err: 297 ERR(handle, "could not check if seuser mapping for %s is valid", name); 298 semanage_user_key_free(key); 299 semanage_user_free(user); 300 return -1; 301 302 invalid: 303 if (mls_range) 304 ERR(handle, "seuser mapping [%s -> (%s, %s)] is invalid", 305 name, sename, mls_range); 306 else 307 ERR(handle, "seuser mapping [%s -> %s] is invalid", 308 name, sename); 309 semanage_user_key_free(key); 310 semanage_user_free(user); 311 return -1; 312 } 313 314 /* This function may not be called outside a transaction, or 315 * it will (1) deadlock, because iterate is not reentrant outside 316 * a transaction, and (2) be racy, because it makes multiple dbase calls */ 317 318 int hidden semanage_seuser_validate_local(semanage_handle_t * handle, 319 const sepol_policydb_t * policydb) 320 { 321 322 struct validate_handler_arg arg; 323 arg.handle = handle; 324 arg.policydb = policydb; 325 return semanage_seuser_iterate_local(handle, validate_handler, &arg); 326 } 327