int mac_selinux_apply(const char *path, const char *label) { #ifdef HAVE_SELINUX if (!mac_selinux_use()) return 0; assert(path); assert(label); if (setfilecon(path, label) < 0) { log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path); if (security_getenforce() > 0) return -errno; } #endif return 0; }
int chcon_main(int argc, char **argv) { int rc, i; if (argc < 3) { fprintf(stderr, "usage: %s context path...\n", argv[0]); exit(1); } for (i = 2; i < argc; i++) { rc = setfilecon(argv[i], argv[1]); if (rc < 0) { fprintf(stderr, "%s: Could not label %s with %s: %s\n", argv[0], argv[i], argv[1], strerror(errno)); exit(2); } } exit(0); }
// Copy security info from "from_file" to "to_file". void mch_copy_sec(char_u *from_file, char_u *to_file) { if (from_file == NULL) return; if (selinux_enabled == -1) selinux_enabled = is_selinux_enabled(); if (selinux_enabled > 0) { security_context_t from_context = NULL; security_context_t to_context = NULL; if (getfilecon((char *)from_file, &from_context) < 0) { // If the filesystem doesn't support extended attributes, // the original had no special security context and the // target cannot have one either. if (errno == EOPNOTSUPP) { return; } MSG_PUTS(_("\nCould not get security context for ")); msg_outtrans(from_file); msg_putchar('\n'); return; } if (getfilecon((char *)to_file, &to_context) < 0) { MSG_PUTS(_("\nCould not get security context for ")); msg_outtrans(to_file); msg_putchar('\n'); freecon (from_context); return; } if (strcmp(from_context, to_context) != 0) { if (setfilecon((char *)to_file, from_context) < 0) { MSG_PUTS(_("\nCould not set security context for ")); msg_outtrans(to_file); msg_putchar('\n'); } } freecon(to_context); freecon(from_context); } }
int label_fix(const char *path, bool ignore_enoent) { int r = 0; #ifdef HAVE_SELINUX struct stat st; security_context_t fcon; if (!use_selinux() || !label_hnd) return 0; r = lstat(path, &st); if (r == 0) { r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); /* If there's no label to set, then exit without warning */ if (r < 0 && errno == ENOENT) return 0; if (r == 0) { r = setfilecon(path, fcon); freecon(fcon); /* If the FS doesn't support labels, then exit without warning */ if (r < 0 && errno == ENOTSUP) return 0; } } if (r < 0) { /* Ignore ENOENT in some cases */ if (ignore_enoent && errno == ENOENT) return 0; log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, "Unable to fix label of %s: %m", path); r = security_getenforce() == 1 ? -errno : 0; } #endif return r; }
static void initselinux(char *username, char *full_tty, security_context_t *user_sid) { security_context_t old_tty_sid, new_tty_sid; if (!is_selinux_enabled()) return; if (get_default_context(username, NULL, user_sid)) { bb_error_msg_and_die("can't get SID for %s", username); } if (getfilecon(full_tty, &old_tty_sid) < 0) { bb_perror_msg_and_die("getfilecon(%s) failed", full_tty); } if (security_compute_relabel(*user_sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0) { bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty); } if (setfilecon(full_tty, new_tty_sid) != 0) { bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid); } }
/* * Function: setFileCon * Purpose: set the security context of a file object * Parameters: * path: the location of the file system object * context: the new security context of the file system object * Returns: true on success, false on error * Exception: NullPointerException is thrown if either path or context strign are NULL */ static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) { if (isSELinuxDisabled) { return false; } ScopedUtfChars path(env, pathStr); if (path.c_str() == NULL) { return false; } ScopedUtfChars context(env, contextStr); if (context.c_str() == NULL) { return false; } // GetStringUTFChars returns const char * yet setfilecon needs char * char *tmp = const_cast<char *>(context.c_str()); int ret = setfilecon(path.c_str(), tmp); ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret); return (ret == 0) ? true : false; }
/* Set the TTY context for the specified user */ void ssh_selinux_setup_pty(char *pwname, const char *tty) { security_context_t new_tty_ctx = NULL; security_context_t user_ctx = NULL; security_context_t old_tty_ctx = NULL; if (!ssh_selinux_enabled()) return; debug3("%s: setting TTY context on %s", __func__, tty); user_ctx = ssh_selinux_getctxbyname(pwname); /* XXX: should these calls fatal() upon failure in enforcing mode? */ if (getfilecon(tty, &old_tty_ctx) == -1) { error("%s: getfilecon: %s", __func__, strerror(errno)); goto out; } if (security_compute_relabel(user_ctx, old_tty_ctx, SECCLASS_CHR_FILE, &new_tty_ctx) != 0) { error("%s: security_compute_relabel: %s", __func__, strerror(errno)); goto out; } if (setfilecon(tty, new_tty_ctx) != 0) error("%s: setfilecon: %s", __func__, strerror(errno)); out: if (new_tty_ctx != NULL) freecon(new_tty_ctx); if (old_tty_ctx != NULL) freecon(old_tty_ctx); if (user_ctx != NULL) freecon(user_ctx); debug3("%s: done", __func__); }
m_spriteram2.set_target(reinterpret_cast<UINT16 *>(memregion("gfx5")->base()), 0x20000); aerofgt_register_state_globals(); } VIDEO_START_MEMBER(aerofgt_state,turbofrc) { m_bg1_tilemap = &machine().tilemap().create(tilemap_get_info_delegate(FUNC(aerofgt_state::get_bg1_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 64); m_bg2_tilemap = &machine().tilemap().create(tilemap_get_info_delegate(FUNC(aerofgt_state::get_bg2_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 64); m_bg2_tilemap->set_transparent_pen(15); m_spritepalettebank = 0; m_sprite_gfx = 2; aerofgt_register_state_globals(); } /* new hw type */ UINT32 aerofgt_state::aerofgt_tile_callback( UINT32 code ) { return m_spriteram1[code&0x7fff]; } /* old hw type */ UINT32 aerofgt_state::aerofgt_old_tile_callback( UINT32 code ) {
static void pw_write(void) { char tmp[FILENAMELEN + 4]; sprintf(tmp, "%s%s", orig_file, ".OLD"); unlink(tmp); if (link(orig_file, tmp)) warn(_("%s: create a link to %s failed"), orig_file, tmp); #ifdef HAVE_LIBSELINUX if (is_selinux_enabled() > 0) { security_context_t passwd_context = NULL; int ret = 0; if (getfilecon(orig_file, &passwd_context) < 0) { warnx(_("Can't get context for %s"), orig_file); pw_error(orig_file, 1, 1); } ret = setfilecon(tmp_file, passwd_context); freecon(passwd_context); if (ret != 0) { warnx(_("Can't set context for %s"), tmp_file); pw_error(tmp_file, 1, 1); } } #endif if (rename(tmp_file, orig_file) == -1) { int errsv = errno; errx(EXIT_FAILURE, ("cannot write %s: %s (your changes are still in %s)"), orig_file, strerror(errsv), tmp_file); } unlink(tmp_file); free(tmp_file); }
static void security_restorelabel_tty(const pam_handle_t *pamh, const char *tty, security_context_t context) { char ttybuf[PATH_MAX]; const char *ptr; if (context==NULL) return; if(strncmp("/dev/", tty, 5)) { snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty); ptr = ttybuf; } else ptr = tty; if (setfilecon(ptr, context) && errno != ENOENT) { pam_syslog(pamh, LOG_NOTICE, "Warning! Could not relabel %s with %s, not relabeling: %m", ptr, context); } }
/* Return: * -1 error, copy not made * 0 copy is made or user answered "no" in interactive mode * (failures to preserve mode/owner/times are not reported in exit code) */ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) { /* This is a recursive function, try to minimize stack usage */ /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; smallint retval = 0; smallint dest_exists = 0; smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { /* This may be a dangling symlink. * Making [sym]links to dangling symlinks works, so... */ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) goto make_links; bb_perror_msg("can't stat '%s'", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("can't stat '%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino ) { bb_error_msg("'%s' and '%s' are the same file", source, dest); return -1; } dest_exists = 1; } #if ENABLE_SELINUX if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) { security_context_t con; if (lgetfilecon(source, &con) >= 0) { if (setfscreatecon(con) < 0) { bb_perror_msg("can't set setfscreatecon %s", con); freecon(con); return -1; } } else if (errno == ENOTSUP || errno == ENODATA) { setfscreatecon_or_die(NULL); } else { bb_perror_msg("can't lgetfilecon %s", source); return -1; } } #endif if (S_ISDIR(source_stat.st_mode)) { DIR *dp; const char *tp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("omitting directory '%s'", source); return -1; } /* Did we ever create source ourself before? */ tp = is_in_ino_dev_hashtable(&source_stat); if (tp) { /* We did! it's a recursion! man the lifeboats... */ bb_error_msg("recursion detected, omitting directory '%s'", source); return -1; } if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); return -1; } /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { /* Create DEST */ mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; /* Allow owner to access new dir (at least for now) */ mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("can't create directory '%s'", dest); return -1; } umask(saved_umask); /* need stat info for add_to_ino_dev_hashtable */ if (lstat(dest, &dest_stat) < 0) { bb_perror_msg("can't stat '%s'", dest); return -1; } } /* remember (dev,inode) of each created dir. * NULL: name is not remembered */ add_to_ino_dev_hashtable(&dest_stat, NULL); /* Recursively copy files in SOURCE */ dp = opendir(source); if (dp == NULL) { retval = -1; goto preserve_mode_ugid_time; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if (new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0) retval = -1; free(new_source); free(new_dest); } closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 ) { bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); /* retval = -1; - WRONG! copy *WAS* made */ } goto preserve_mode_ugid_time; } if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { int (*lf)(const char *oldpath, const char *newpath); make_links: /* Hmm... maybe * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? * (but realpath returns NULL on dangling symlinks...) */ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; if (lf(source, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (lf(source, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } /* _Not_ jumping to preserve_mode_ugid_time: * (sym)links don't have those */ return 0; } if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */ !(flags & FILEUTILS_RECUR) /* "cp [-opts] regular_file thing2" */ || S_ISREG(source_stat.st_mode) /* DEREF uses stat, which never returns S_ISLNK() == true. * So the below is never true: */ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ ) { int src_fd; int dst_fd; mode_t new_mode; if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) { /* "cp -d symlink dst": create a link */ goto dont_cat; } if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { const char *link_target; link_target = is_in_ino_dev_hashtable(&source_stat); if (link_target) { if (link(link_target, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (link(link_target, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } return 0; } add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open_or_warn(source, O_RDONLY); if (src_fd < 0) return -1; /* Do not try to open with weird mode fields */ new_mode = source_stat.st_mode; if (!S_ISREG(source_stat.st_mode)) new_mode = 0666; // POSIX way is a security problem versus (sym)link attacks if (!ENABLE_FEATURE_NON_POSIX_CP) { dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); } else { /* safe way: */ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); } if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) { close(src_fd); return ovr; } /* It shouldn't exist. If it exists, do not open (symlink attack?) */ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); if (dst_fd < 0) { close(src_fd); return -1; } } #if ENABLE_SELINUX if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT)) && is_selinux_enabled() > 0 ) { security_context_t con; if (getfscreatecon(&con) == -1) { bb_perror_msg("getfscreatecon"); return -1; } if (con) { if (setfilecon(dest, con) == -1) { bb_perror_msg("setfilecon:%s,%s", dest, con); freecon(con); return -1; } freecon(con); } } #endif if (bb_copyfd_eof(src_fd, dst_fd) == -1) retval = -1; /* Careful with writing... */ if (close(dst_fd) < 0) { bb_perror_msg("error writing to '%s'", dest); retval = -1; } /* ...but read size is already checked by bb_copyfd_eof */ close(src_fd); /* "cp /dev/something new_file" should not * copy mode of /dev/something */ if (!S_ISREG(source_stat.st_mode)) return retval; goto preserve_mode_ugid_time; } dont_cat: /* Source is a symlink or a special file */ /* We are lazy here, a bit lax with races... */ if (dest_exists) { errno = EEXIST; ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; } if (S_ISLNK(source_stat.st_mode)) { char *lpath = xmalloc_readlink_or_warn(source); if (lpath) { int r = symlink(lpath, dest); free(lpath); if (r < 0) { bb_perror_msg("can't create symlink '%s'", dest); return -1; } if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } /* _Not_ jumping to preserve_mode_ugid_time: * symlinks don't have those */ return 0; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ) { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("can't create '%s'", dest); return -1; } } else { bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); return -1; } preserve_mode_ugid_time: if (flags & FILEUTILS_PRESERVE_STATUS /* Cannot happen: */ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ ) { struct timeval times[2]; times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime; times[1].tv_usec = times[0].tv_usec = 0; /* BTW, utimes sets usec-precision time - just FYI */ if (utimes(dest, times) < 0) bb_perror_msg("can't preserve %s of '%s'", "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } #if ENABLE_XATTR /* Preserve extended attributes. We must copy it after chown() * because it resets capabilities. */ if (copy_file_attr(source, dest) == -1) bb_perror_msg("can't preserve %s of '%s'", "extended attributes", dest); #endif if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } return retval; }
static int change_file_context(const char *file, unsigned long opts) { security_context_t file_context = NULL; security_context_t context_string; context_t context; int errors = 0; int status = 0; if (opts & OPT_CHCON_NODEREFERENCE) { status = lgetfilecon(file, &file_context); } else { status = getfilecon(file, &file_context); } if (status < 0 && errno != ENODATA) { if ((opts & OPT_CHCON_QUIET) == 0) fprintf(stderr, "could not obtain security context: %s\n", file); return 1; } if (file_context == NULL && specified_context == NULL) { fprintf(stderr, "can't apply partial context to unlabeled file %s", file); return 1; } if (specified_context == NULL) { context = compute_context_from_mask(file_context, opts); if (!context) { fprintf(stderr, "couldn't compute security context from %s", file_context); return 1; } } else { context = context_new(specified_context); if (!context) { fprintf(stderr, "invalid context: %s", specified_context); return 1; } } context_string = context_str(context); if (file_context == NULL || strcmp(context_string, file_context)!=0) { int fail = 0; if (opts & OPT_CHCON_NODEREFERENCE) { fail = lsetfilecon (file, context_string); } else { fail = setfilecon (file, context_string); } if ((opts & OPT_CHCON_VERBOSE) || ((opts & OPT_CHCON_CHANHES) && !fail)) { printf(!fail ? "context of %s changed to %s\n" : "failed to change context of %s to %s\n", file, context_string); } if (fail) { errors = 1; if ((opts & OPT_CHCON_QUIET) == 0) fprintf(stderr, "failed to change context of %s to %s\n", file, context_string); } } else if (opts & OPT_CHCON_VERBOSE) { printf("context of %s retained as %s\n", file, context_string); } context_free(context); freecon(file_context); if (opts & OPT_CHCON_RECURSIVE) { struct stat file_stats; if (lstat(file, &file_stats) == 0 && S_ISDIR(file_stats.st_mode)) errors |= change_dir_context(file, opts); } return errors; }
/** * Copy a file * * @param src_path Source * @param dst_path Destination * @param st File attributes * * @return 0 for success, negative value in case of an error */ static int copy_file(const char * property, const char *src_path, const char *dst_path, struct stat *st, security_context_t con, off64_t * done, const off64_t * total) { char buffer[MAX_PATH_LENGTH], buff[PROPERTY_VALUE_MAX]; int n = 0, m = 0, ret = -1; int fd_src, fd_dst; struct utimbuf time; double total_d = *total; fd_src = open(src_path, O_RDONLY); if (fd_src < 0) { LOGE("open %s failed\n", src_path); return fd_src; } fd_dst = open(dst_path, O_CREAT | O_WRONLY, st->st_mode); if (fd_dst < 0) { LOGE("open %s failed\n", dst_path); close(fd_src); return fd_dst; } do { n = read(fd_src, buffer, sizeof(buffer)); if (n < 0) { LOGE("Error reading from file\n"); close(fd_src); close(fd_dst); return n; } if (n == 0) break; m = write(fd_dst, buffer, n); if (m != n) { close(fd_src); close(fd_dst); return -1; } *done += m; // check if update is required if ((*done - m) / total_d * 100 != *done / total_d * 100) { memset(buff, 0, sizeof(buff)); snprintf(buff, sizeof(buff), "%llu", (off64_t)(*done / total_d * 100)); ret = property_set(property, buff); if (ret < 0) { LOGE("property_set"); } } } while (n); close(fd_src); close(fd_dst); ret = setfilecon(dst_path, con); if (ret < 0) { LOGE("setfilecon %s fail\n", dst_path); return ret; } ret = chown(dst_path, st->st_uid, st->st_gid); if (ret < 0) { LOGE("chown %s fail\n", dst_path); return ret; } /* Save access times */ time.actime = st->st_atime; time.modtime = st->st_mtime; ret = utime(dst_path, &time); if (ret != 0) { LOGE("utime on %s failed", dst_path); return -1; } return 0; }
/** * Create directory infrastructure and store it on disk * Used in context with copy file or copy directory * @param dir_list Linked list with directories names and attributes * @param src_path Source path * @param dst_path Destination path * * @return 0 on success, negative value on error */ static int create_dirs(file_info ** dir_list, const char *src_path, const char *dst_path) { file_info *iter = *dir_list; char *path; int len; int ret = -1; struct utimbuf time; if (!iter) return 0; len = strlen(dst_path) + strlen(iter->path) - strlen(src_path) + 1; if (len > MAX_PATH_LENGTH || strlen(dst_path) > MAX_PATH_LENGTH || strlen(src_path) > MAX_PATH_LENGTH) { LOGE("Can't copy %s", iter->path); return -1; } path = (char *)malloc(MAX_PATH_LENGTH + 1); if (!path) { LOGE("insufficient memory\n"); exit(EXIT_FAILURE); } memset(path, 0, MAX_PATH_LENGTH + 1); strcpy(path, dst_path); *(path + strlen(dst_path)) = '/'; strcpy(path + strlen(dst_path) + 1, iter->path + strlen(src_path)); /* The "list" is a stack; recurency will restore FIFO order */ if (!iter->next) { ret = mkdir(path, iter->st.st_mode); if (ret < 0) { LOGE("mkdir %s fail\n", path); free(path); return ret; } ret = setfilecon(path, iter->con); if (ret < 0) { LOGE("setfilecon %s fail\n", path); free(path); return ret; } ret = chown(path, iter->st.st_uid, iter->st.st_gid); if (ret < 0) { LOGE("chown %s fail\n", path); free(path); return ret; } time.actime = iter->st.st_atime; time.modtime = iter->st.st_mtime; ret = utime(path, &time); if (ret != 0) { LOGE("utime on %s failed", path); free(path); return -1; } return 0; } ret = create_dirs(&iter->next, src_path, dst_path); if (ret < 0) { free(path); return ret; }; ret = mkdir(path, iter->st.st_mode); if (ret < 0) { LOGE("mkdir %s fail", path); free(path); return ret; } ret = setfilecon(path, iter->con); if (ret < 0) { LOGE("setfilecon %s fail\n", path); free(path); return ret; } ret = chown(path, iter->st.st_uid, iter->st.st_gid); if (ret < 0) { LOGE("chown %s fail\n", path); free(path); return ret; } time.actime = iter->st.st_atime; time.modtime = iter->st.st_mtime; ret = utime(path, &time); if (ret != 0) { LOGE("utime on %s failed", path); free(path); return -1; } free(path); return 0; }
int login_main(int argc, char **argv) { char tty[BUFSIZ]; char full_tty[200]; char fromhost[512]; char username[USERNAME_SIZE]; const char *tmp; int amroot; int flag; int failed; int count=0; struct passwd *pw, pw_copy; #ifdef CONFIG_WHEEL_GROUP struct group *grp; #endif int opt_preserve = 0; int opt_fflag = 0; char *opt_host = 0; int alarmstarted = 0; #ifdef CONFIG_SELINUX security_context_t stat_sid = NULL, sid = NULL, old_tty_sid=NULL, new_tty_sid=NULL; #endif username[0]=0; amroot = ( getuid ( ) == 0 ); signal ( SIGALRM, alarm_handler ); alarm ( TIMEOUT ); alarmstarted = 1; while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) { switch ( flag ) { case 'p': opt_preserve = 1; break; case 'f': /* * username must be a separate token * (-f root, *NOT* -froot). --marekm */ if ( optarg != argv[optind-1] ) bb_show_usage( ); if ( !amroot ) /* Auth bypass only if real UID is zero */ bb_error_msg_and_die ( "-f permission denied" ); safe_strncpy(username, optarg, USERNAME_SIZE); opt_fflag = 1; break; case 'h': opt_host = optarg; break; default: bb_show_usage( ); } } if (optind < argc) // user from command line (getty) safe_strncpy(username, argv[optind], USERNAME_SIZE); if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 )) return EXIT_FAILURE; /* Must be a terminal */ #ifdef CONFIG_FEATURE_UTMP checkutmp ( !amroot ); #endif tmp = ttyname ( 0 ); if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 )) safe_strncpy ( tty, tmp + 5, sizeof( tty )); else if ( tmp && *tmp == '/' ) safe_strncpy ( tty, tmp, sizeof( tty )); else safe_strncpy ( tty, "UNKNOWN", sizeof( tty )); #ifdef CONFIG_FEATURE_UTMP if ( amroot ) memset ( utent.ut_host, 0, sizeof utent.ut_host ); #endif if ( opt_host ) { #ifdef CONFIG_FEATURE_UTMP safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host )); #endif snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host ); } else snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty ); setpgrp(); openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH ); while ( 1 ) { failed = 0; if ( !username[0] ) if(!login_prompt ( username )) return EXIT_FAILURE; if ( !alarmstarted && ( TIMEOUT > 0 )) { alarm ( TIMEOUT ); alarmstarted = 1; } if (!( pw = getpwnam ( username ))) { pw_copy.pw_name = "UNKNOWN"; pw_copy.pw_passwd = "!"; opt_fflag = 0; failed = 1; } else pw_copy = *pw; pw = &pw_copy; if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' )) failed = 1; if ( opt_fflag ) { opt_fflag = 0; goto auth_ok; } if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty ))) failed = 1; /* Don't check the password if password entry is empty (!) */ if ( !pw-> pw_passwd[0] ) goto auth_ok; /* authorization takes place here */ if ( correct_password ( pw )) goto auth_ok; failed = 1; auth_ok: if ( !failed) break; bb_do_delay(FAIL_DELAY); puts("Login incorrect"); username[0] = 0; if ( ++count == 3 ) { syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost); return EXIT_FAILURE; } } alarm ( 0 ); if ( check_nologin ( pw-> pw_uid == 0 )) return EXIT_FAILURE; #ifdef CONFIG_FEATURE_UTMP setutmp ( username, tty ); #endif if ( *tty != '/' ) snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty); else safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 ); #ifdef CONFIG_SELINUX if (is_selinux_enabled()) { struct stat st; int rc; if (get_default_context(username, NULL, &sid)) { fprintf(stderr, "Unable to get SID for %s\n", username); exit(1); } rc = getfilecon(full_tty,&stat_sid); freecon(stat_sid); if ((rc<0) || (stat(full_tty, &st)<0)) { fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", full_tty, strerror(errno)); return EXIT_FAILURE; } if (security_compute_relabel (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0) { fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno)); return EXIT_FAILURE; } if(setfilecon(full_tty, new_tty_sid) != 0) { fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno)); return EXIT_FAILURE; } freecon(sid); freecon(old_tty_sid); freecon(new_tty_sid); } #endif if ( !is_my_tty ( full_tty )) syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty ); /* Try these, but don't complain if they fail * (for example when the root fs is read only) */ chown ( full_tty, pw-> pw_uid, pw-> pw_gid ); chmod ( full_tty, 0600 ); change_identity ( pw ); tmp = pw-> pw_shell; if(!tmp || !*tmp) tmp = DEFAULT_SHELL; setup_environment ( tmp, 1, !opt_preserve, pw ); motd ( ); signal ( SIGALRM, SIG_DFL ); /* default alarm signal */ if ( pw-> pw_uid == 0 ) syslog ( LOG_INFO, "root login %s\n", fromhost ); #ifdef CONFIG_SELINUX set_current_security_context(sid); #endif run_shell ( tmp, 1, 0, 0); /* exec the shell finally. */ return EXIT_FAILURE; }
int fsetfilecon(int fd, security_context_t con) { return setfilecon("", con); }
int lsetfilecon(const char *path, security_context_t con) { return setfilecon(path, con); }
static int change_filedir_context(const char *fname, struct stat *stbuf, void *userData, int depth) { context_t context = NULL; security_context_t file_context = NULL; security_context_t context_string; int rc = FALSE; int status = 0; if (option_mask32 & OPT_NODEREFERENCE) { status = lgetfilecon(fname, &file_context); } else { status = getfilecon(fname, &file_context); } if (status < 0 && errno != ENODATA) { if ((option_mask32 & OPT_QUIET) == 0) bb_error_msg("cannot obtain security context: %s", fname); goto skip; } if (file_context == NULL && specified_context == NULL) { bb_error_msg("cannot apply partial context to unlabeled file %s", fname); goto skip; } if (specified_context == NULL) { context = set_security_context_component(file_context, user, role, type, range); if (!context) { bb_error_msg("cannot compute security context from %s", file_context); goto skip; } } else { context = context_new(specified_context); if (!context) { bb_error_msg("invalid context: %s", specified_context); goto skip; } } context_string = context_str(context); if (!context_string) { bb_error_msg("cannot obtain security context in text expression"); goto skip; } if (file_context == NULL || strcmp(context_string, file_context) != 0) { int fail; if (option_mask32 & OPT_NODEREFERENCE) { fail = lsetfilecon(fname, context_string); } else { fail = setfilecon(fname, context_string); } if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) { printf(!fail ? "context of %s changed to %s\n" : "failed to change context of %s to %s\n", fname, context_string); } if (!fail) { rc = TRUE; } else if ((option_mask32 & OPT_QUIET) == 0) { bb_error_msg("failed to change context of %s to %s", fname, context_string); } } else if (option_mask32 & OPT_VERBOSE) { printf("context of %s retained as %s\n", fname, context_string); rc = TRUE; } skip: context_free(context); freecon(file_context); return rc; }