int sss_get_seuser(const char *linuxuser, char **selinuxuser, char **level) { int ret; semanage_handle_t *handle; handle = semanage_handle_create(); if (handle == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); return EIO; } semanage_msg_set_callback(handle, sss_semanage_error_callback, NULL); /* We only needed the handle for this call. Close the handle right * after it */ ret = sss_is_selinux_managed(handle); sss_semanage_close(handle); if (ret != EOK) { return ret; } return getseuserbyname(linuxuser, selinuxuser, level); }
static const security_context_t selinux_get_user_context(const char *name) { security_context_t user_context=NULL; char *role=NULL; int ret = -1; char *seuser=NULL; char *level=NULL; if (the_authctxt) role=the_authctxt->role; if (getseuserbyname(name, &seuser, &level)==0) { if (role != NULL && role[0]) ret=get_default_context_with_rolelevel(seuser, role, level,NULL, &user_context); else ret=get_default_context_with_level(seuser, level, NULL,&user_context); } if ( ret < 0 ) { if (security_getenforce() > 0) fatal("Failed to get default security context for %s.", name); else error("Failed to get default security context for %s." "Continuing in permissive mode", name); } return user_context; }
int main(int argc, char **argv) { char *seuser = NULL, *level = NULL; security_context_t *contextlist; int rc, n, i; if (argc != 3) { fprintf(stderr, "usage: %s linuxuser fromcon\n", argv[0]); exit(1); } rc = getseuserbyname(argv[1], &seuser, &level); if (rc) { fprintf(stderr, "getseuserbyname failed: %s\n", strerror(errno)); exit(2); } printf("seuser: %s, level %s\n", seuser, level); n = get_ordered_context_list_with_level(seuser, level, argv[2], &contextlist); if (n <= 0) { fprintf(stderr, "get_ordered_context_list_with_level failed: %s\n", strerror(errno)); exit(3); } free(seuser); free(level); for (i = 0; i < n; i++) printf("Context %d\t%s\n", i, contextlist[i]); freeconary(contextlist); exit(0); }
/* Return the default security context for the given username */ static security_context_t ssh_selinux_getctxbyname(char *pwname) { security_context_t sc = NULL; char *sename = NULL, *lvl = NULL; int r; #ifdef HAVE_GETSEUSERBYNAME if (getseuserbyname(pwname, &sename, &lvl) != 0) return NULL; #else sename = pwname; lvl = NULL; #endif #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL r = get_default_context_with_level(sename, lvl, NULL, &sc); #else r = get_default_context(sename, NULL, &sc); #endif if (r != 0) { switch (security_getenforce()) { case -1: fatal("%s: ssh_selinux_getctxbyname: " "security_getenforce() failed", __func__); case 0: error("%s: Failed to get default SELinux security " "context for %s", __func__, pwname); sc = NULL; break; default: fatal("%s: Failed to get default SELinux security " "context for %s (in enforcing mode)", __func__, pwname); } } #ifdef HAVE_GETSEUSERBYNAME if (sename != NULL) xfree(sename); if (lvl != NULL) xfree(lvl); #endif return sc; }
/* selinux_prepare_fork - Initialize context switching * * Returns * - 0 if everything is OK, * - +1 if the code should continue, even if SELinux wouldn't allow * (for instance due to permissive mode) * - -1 if the code should not continue */ int selinux_prepare_fork(char * name) { #ifndef SELINUX return 0; #else char * newcon = 0; char * curcon = 0; struct av_decision avd; int rc; int permissive = 0; int dom_permissive = 0; char * sename = 0; char * selevel = 0; /* * See if SELinux is enabled. * If not, then we can immediately tell the code * that everything is OK. */ rc = is_selinux_enabled(); if (rc == 0) { out(DEBUG, "SELinux is not enabled.\n"); return 0; } else if (rc == -1) { out(WARN, "Could not check SELinux state (is_selinux_enabled() failed)\n"); return 1; }; out(DEBUG, "SELinux is enabled.\n"); /* * See if SELinux is in enforcing mode * or permissive mode */ rc = security_getenforce(); if (rc == 0) { permissive = 1; } else if (rc == 1) { permissive = 0; } else { out(WARN, "Could not check SELinux mode (security_getenforce() failed)\n"); } out(DEBUG, "SELinux mode is %s\n", permissive ? "permissive" : "enforcing"); /* * Get the current SELinux context of the process. * Always interesting to log this for end users * trying to debug a possible issue. */ rc = getcon(&curcon); if (rc) { out(WARN, "Could not get current SELinux context (getcon() failed)\n"); if (permissive) return +1; else return -1; }; out(DEBUG, "Currently in SELinux context \"%s\"\n", (char *) curcon); /* * Get the SELinux user given the Linux user * name passed on to this function. */ rc = getseuserbyname(name, &sename, &selevel); if (rc) { out(WARN, "Could not find SELinux user for Linux user \"%s\" (getseuserbyname() failed)\n", name); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux user for Linux user \"%s\" is \"%s\"\n", name, sename); /* * Find out what the context is that this process should transition * to. */ rc = get_default_context(sename, NULL, &newcon); if (rc) { out(WARN, "Could not deduce default context for SELinux user \"%s\" given our current context (\"%s\")\n", sename, (char *) curcon); freecon(curcon); if (permissive) return +1; else return -1; }; out(DEBUG, "SELinux context to transition to is \"%s\"\n", (char *) newcon); /* * Now let's look if we are allowed to transition to the new context. * We currently only check the transition access for the process class. However, * transitioning is a bit more complex (execute rights on target context, * entrypoint of that context for the new domain, no constraints like target * domain not being a valid one, MLS constraints, etc.). */ rc = security_compute_av_flags(curcon, newcon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd); if (rc) { out(WARN, "Could not deduce rights for transitioning \"%s\" -> \"%s\" (security_compute_av_flags() failed)\n", (char *) curcon, (char *) newcon); freecon(curcon); freecon(newcon); if (permissive) return +1; else return -1; }; /* Validate the response * * We are interested in two things: * - Is the transition allowed, but also * - Is the permissive flag set * * If the permissive flag is set, then we * know the current domain is permissive * (even if the rest of the system is in * enforcing mode). */ if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) { out(DEBUG, "The SELINUX_AVD_FLAGS_PERMISSIVE flag is set, so domain is permissive.\n"); dom_permissive = 1; }; if (!(avd.allowed & PROCESS__TRANSITION)) { // The transition is denied if (permissive) { out(DEBUG, "Transition is not allowed by SELinux, but permissive mode is enabled. Continuing.\n"); }; if (dom_permissive) { out(DEBUG, "Transition is not allowed by SELinux, but domain is in permissive mode. Continuing.\n"); }; if ((permissive == 0) && (dom_permissive == 0)) { out(WARN, "The domain transition is not allowed and we are not in permissive mode.\n"); freecon(curcon); freecon(newcon); return -1; }; }; /* * Set the context for the fork (process execution). */ rc = setexeccon(newcon); if (rc) { out(WARN, "Could not set execution context (setexeccon() failed)\n"); freecon(curcon); freecon(newcon); if ((permissive) || (dom_permissive)) return +1; else return -1; }; freecon(newcon); freecon(curcon); return 0; #endif };
// sushell.cmt static void sushell(struct passwd *pwd) { char shell[128]; char home[128]; char *p; char *sushell; /* * Set directory and shell. */ (void)chdir(pwd->pw_dir); if ((p = getenv("SUSHELL")) != NULL) sushell = p; else if ((p = getenv("sushell")) != NULL) sushell = p; else { if (pwd->pw_shell[0]) sushell = pwd->pw_shell; else sushell = BINSH; } if ((p = strrchr(sushell, '/')) == NULL) p = sushell; else p++; snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p); /* * Set some important environment variables. */ getcwd(home, sizeof(home)); setenv("HOME", home, 1); setenv("LOGNAME", "root", 1); setenv("USER", "root", 1); if (!profile) setenv("SHLVL","0",1); /* * Try to execute a shell. */ setenv("SHELL", sushell, 1); signal(SIGINT, saved_sigint); signal(SIGTSTP, saved_sigtstp); signal(SIGQUIT, saved_sigquit); #ifdef WITH_SELINUX if (is_selinux_enabled() > 0) { security_context_t scon=NULL; char *seuser=NULL; char *level=NULL; if (getseuserbyname("root", &seuser, &level) == 0) if (get_default_context_with_level(seuser, level, 0, &scon) == 0) { if (setexeccon(scon) != 0) fprintf(stderr, "setexeccon faile\n"); freecon(scon); } free(seuser); free(level); } #endif execl(sushell, shell, NULL); perror(sushell); setenv("SHELL", BINSH, 1); execl(BINSH, profile ? "-sh" : "sh", NULL); perror(BINSH); /* Fall back to staticly linked shell if both the users shell and /bin/sh failed to execute. */ setenv("SHELL", STATICSH, 1); execl(STATICSH, STATICSH, NULL); perror(STATICSH); }
/* * Password was OK, execute a shell. */ static void sushell(struct passwd *pwd) { char shell[PATH_MAX]; char home[PATH_MAX]; char *p; char *su_shell; /* * Set directory and shell. */ if (chdir(pwd->pw_dir) != 0) { warn(_("%s: change directory failed"), pwd->pw_dir); printf(_("Logging in with home = \"/\".\n")); if (chdir("/") != 0) warn(_("change directory to system root failed")); } if ((p = getenv("SUSHELL")) != NULL) su_shell = p; else if ((p = getenv("sushell")) != NULL) su_shell = p; else { if (pwd->pw_shell[0]) su_shell = pwd->pw_shell; else su_shell = "/bin/sh"; } if ((p = strrchr(su_shell, '/')) == NULL) p = su_shell; else p++; snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p); /* * Set some important environment variables. */ if (getcwd(home, sizeof(home)) != NULL) setenv("HOME", home, 1); setenv("LOGNAME", "root", 1); setenv("USER", "root", 1); if (!profile) setenv("SHLVL","0",1); /* * Try to execute a shell. */ setenv("SHELL", su_shell, 1); unmask_signal(SIGINT, &saved_sigint); unmask_signal(SIGTSTP, &saved_sigtstp); unmask_signal(SIGQUIT, &saved_sigquit); #ifdef HAVE_LIBSELINUX if (is_selinux_enabled() > 0) { security_context_t scon=NULL; char *seuser=NULL; char *level=NULL; if (getseuserbyname("root", &seuser, &level) == 0) { if (get_default_context_with_level(seuser, level, 0, &scon) == 0) { if (setexeccon(scon) != 0) warnx(_("setexeccon failed")); freecon(scon); } } free(seuser); free(level); } #endif execl(su_shell, shell, NULL); warn(_("%s: exec failed"), su_shell); setenv("SHELL", "/bin/sh", 1); execl("/bin/sh", profile ? "-sh" : "sh", NULL); warn(_("%s: exec failed"), "/bin/sh"); }
int getseuser(const char *username, const char *service, char **r_seuser, char **r_level) { int ret = -1; int len = 0; char *seuser = NULL; char *level = NULL; char *buffer = NULL; size_t size = 0; char *rec = NULL; char *path = NULL; FILE *fp = NULL; if (asprintf(&path,"%s/logins/%s", selinux_policy_root(), username) < 0) goto err; fp = fopen(path, "re"); free(path); if (fp == NULL) goto err; __fsetlocking(fp, FSETLOCKING_BYCALLER); while (getline(&buffer, &size, fp) > 0) { if (strncmp(buffer, "*:", 2) == 0) { free(rec); rec = strdup(buffer); continue; } if (!service) continue; len = strlen(service); if ((strncmp(buffer, service, len) == 0) && (buffer[len] == ':')) { free(rec); rec = strdup(buffer); break; } } if (! rec) goto err; seuser = strchr(rec, ':'); if (! seuser) goto err; seuser++; level = strchr(seuser, ':'); if (! level) goto err; *level = 0; level++; *r_seuser = strdup(seuser); if (! *r_seuser) goto err; len = strlen(level); if (len && level[len-1] == '\n') level[len-1] = 0; *r_level = strdup(level); if (! *r_level) { free(*r_seuser); goto err; } ret = 0; err: free(buffer); if (fp) fclose(fp); free(rec); return (ret ? getseuserbyname(username, r_seuser, r_level) : ret); }
static int get_security_context(char *name, int crontab_fd, security_context_t *rcontext, char *tabname) { security_context_t *context_list = NULL; security_context_t current_con; int list_count = 0; security_context_t file_context=NULL; struct av_decision avd; int retval=0; char *seuser = NULL; char *level = NULL; int i; if (name != NULL) { if (getseuserbyname(name, &seuser, &level)) { log_it(name, getpid(), "getseuserbyname FAILED", tabname); return (security_getenforce() > 0); } } else { seuser = strdup("system_u"); } *rcontext = NULL; if(getcon(¤t_con)) { log_it(name, getpid(), "Can't get current context", tabname); return -1; } list_count = get_ordered_context_list_with_level(seuser, level, current_con, &context_list); freecon(current_con); free(seuser); free(level); if (list_count == -1) { if (security_getenforce() > 0) { log_it(name, getpid(), "No SELinux security context", tabname); return -1; } else { log_it(name, getpid(), "No security context but SELinux in permissive mode," " continuing", tabname); return 0; } } if (fgetfilecon(crontab_fd, &file_context) < OK) { if (security_getenforce() > 0) { log_it(name, getpid(), "getfilecon FAILED", tabname); freeconary(context_list); return -1; } else { log_it(name, getpid(), "getfilecon FAILED but SELinux in " "permissive mode, continuing", tabname); *rcontext = strdup(context_list[0]); freeconary(context_list); return 0; } } /* * Since crontab files are not directly executed, * crond must ensure that the crontab file has * a context that is appropriate for the context of * the user cron job. It performs an entrypoint * permission check for this purpose. */ for(i = 0; i < list_count; i++) { retval = security_compute_av(context_list[i], file_context, SECCLASS_FILE, FILE__ENTRYPOINT, &avd); if(!retval && ((FILE__ENTRYPOINT & avd.allowed) == FILE__ENTRYPOINT)) { *rcontext = strdup(context_list[i]); freecon(file_context); freeconary(context_list); return 0; } } freecon(file_context); if (security_getenforce() > 0) { log_it(name, getpid(), "ENTRYPOINT FAILED", tabname); freeconary(context_list); return -1; } else { log_it(name, getpid(), "ENTRYPOINT FAILED but SELinux in permissive mode, continuing", tabname); *rcontext = strdup(context_list[0]); freeconary(context_list); } return 0; }