int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid, gid_t gid) { string cyName = rootDir + naming->encodePath(plaintextPath); rAssert(!cyName.empty()); VLOG(1) << "mkdir on " << cyName; // if uid or gid are set, then that should be the directory owner #if 0 int olduid = -1; int oldgid = -1; if (uid != 0) olduid = setfsuid(uid); if (gid != 0) oldgid = setfsgid(gid); #endif int res = unix::mkdir(cyName.c_str(), mode); #if 0 if (olduid >= 0) setfsuid(olduid); if (oldgid >= 0) setfsgid(oldgid); #endif if (res == -1) { int eno = errno; RLOG(WARNING) << "mkdir error on " << cyName << " mode " << mode << ": " << strerror(eno); res = -eno; } else res = 0; return res; }
Result<bool> ChangeFileOrDirOwnershipToUser(const std::string& path, const std::string& username) { std::lock_guard<std::mutex> lock(mPermissionsMutex); auto previuousuid = setfsuid(-1); auto previuousgid = setfsgid(-1); setfsuid(0); setfsgid(0); struct passwd* pwd = GetUserFromPasswordFile(username); auto returnVal = chown(path.c_str(), pwd->pw_uid, pwd->pw_gid); free(pwd); if (returnVal < 0) { std::string error{"Cannot chown dir/file: "}; error.append(path); error.append(" error number: "); error.append(std::to_string(errno)); error.append(" current fs permissions are for uid: "); error.append(std::to_string(setfsuid(-1))); setfsuid(previuousuid); setfsgid(previuousgid); return Result<bool>{false, error}; } setfsuid(previuousuid); setfsgid(previuousgid); return Result<bool>{true}; }
gid_t setgroup(gid_t gid) { gid_t orig_gid = setfsgid(gid); if (gid != setfsgid(gid)) LogCrit(COMPONENT_FSAL, "Could not set group identity"); return orig_gid; }
int main(int argc, char **argv) { int ret, verbose = 0, c, opt_index, bypass = 0, decimal = 0; char *file = NULL; setfsuid(getuid()); setfsgid(getgid()); if (argc == 1) help(); while ((c = getopt_long(argc, argv, short_options, long_options, &opt_index)) != EOF) { switch (c) { case 'h': help(); break; case 'v': version(); break; case 'V': verbose = 1; break; case 'D': decimal = 1; break; case 'b': bypass = 1; break; case 'd': bpf_dump_op_table(); die(); case 'i': file = xstrdup(optarg); break; case '?': switch (optopt) { case 'i': panic("Option -%c requires an argument!\n", optopt); default: if (isprint(optopt)) printf("Unknown option character `0x%X\'!\n", optopt); die(); } default: break; } } if (argc == 2) file = xstrdup(argv[1]); if (!file) panic("No Berkeley Packet Filter program specified!\n"); ret = compile_filter(file, verbose, bypass, decimal); xfree(file); return ret; }
static void restore_privs(void) { if (getuid() != 0) { setfsuid(oldfsuid); setfsgid(oldfsgid); } }
static void drop_privs(void) { if (getuid() != 0) { oldfsuid = setfsuid(getuid()); oldfsgid = setfsgid(getgid()); } }
static int drop_privs() { int res; struct __user_cap_header_struct head; struct __user_cap_data_struct newcaps; head.version = _LINUX_CAPABILITY_VERSION; head.pid = 0; res = capget(&head, &oldcaps); if(res == -1) { fprintf(stderr, "%s: failed to get capabilities: %s\n", progname, strerror(errno)); return -1; } oldfsuid = setfsuid(getuid()); oldfsgid = setfsgid(getgid()); newcaps = oldcaps; /* Keep CAP_SYS_ADMIN for mount */ newcaps.effective &= (1 << CAP_SYS_ADMIN); head.version = _LINUX_CAPABILITY_VERSION; head.pid = 0; res = capset(&head, &newcaps); if(res == -1) { fprintf(stderr, "%s: failed to set capabilities: %s\n", progname, strerror(errno)); return -1; } return 0; }
static void setfsids(uid_t cred_uid, gid_t cred_gid, gid_t * cred_gids, int cred_len) { setfsuid(cred_uid); setfsgid(cred_gid); /* First, set the user ID. */ if (auth_uid != cred_uid) { if (setfsuid(cred_uid) < 0) dbg_printf(__FILE__, __LINE__, L_ERROR, "Unable to setfsuid %d: %s\n", cred_uid, strerror(errno)); else auth_uid = cred_uid; } /* Next, the group ID. */ if (auth_gid != cred_gid) { if (setfsgid(cred_gid) < 0) dbg_printf(__FILE__, __LINE__, L_ERROR, "Unable to setfsgid %d: %s\n", cred_gid, strerror(errno)); else auth_gid = cred_gid; } #ifdef HAVE_SETGROUPS /* Finally, set the supplementary group IDs if possible. */ if (cred_len < 0 || cred_len > NGRPS) dbg_printf(__FILE__, __LINE__, L_ERROR, "Negative or huge cred_len: %d\n", cred_len); else if (cred_len != auth_gidlen || memcmp(cred_gids, auth_gids, auth_gidlen * sizeof(gid_t))) { if (setgroups(cred_len, cred_gids) < 0) dbg_printf(__FILE__, __LINE__, L_ERROR, "Unable to setgroups: %s\n", strerror(errno)); else { memcpy(auth_gids, cred_gids, cred_len * sizeof(gid_t)); auth_gidlen = cred_len; } } #endif /* HAVE_SETGROUPS */ }
void testValues() { f = 2; setfsgid(anyint()); //@ assert f == 2; //@ assert vacuous: \false; }
/* * When running as root, change the file system access to a user. */ void SetUserFileSystemAccess(const std::string& username) { struct passwd* pwd = GetUserFromPasswordFile(username); setfsuid(pwd->pw_uid); setfsgid(pwd->pw_gid); free(pwd); }
Result<std::string> ReadAsciiFileContentAsRoot(const std::string& filename) { std::lock_guard<std::mutex> lock(mPermissionsMutex); auto previuousuid = setfsuid(-1); auto previuousgid = setfsgid(-1); // RAII resource cleanup; de-escalate privileges from root to previous: std::shared_ptr<void> resetPreviousPermisions(nullptr, [&](void*) { setfsuid(previuousuid); setfsgid(previuousgid); }); setfsuid(0); setfsgid(0); auto result = ReadAsciiFileContent(filename); return result; }
static int mate_score_child(int infileno, int outfileno) { struct command cmd; gchar* level; gchar* realname; gint retval; #ifdef HAVE_SETFSGID gid_t gid; gid = getegid(); setgid(getgid()); setfsgid(gid); #endif realname = g_strdup(g_get_real_name()); if (strcmp(realname, "Unknown") == 0) { g_free(realname); realname = g_strdup(g_get_user_name()); } while (read(infileno, &cmd, sizeof cmd) == sizeof(cmd)) { level = g_new (char, cmd.level); if (read(infileno, level, cmd.level) != cmd.level) { g_free(realname); return EXIT_FAILURE; } if (!*level) { g_free(level); level = NULL; } retval = log_score(defgamename, level, realname, cmd.score, cmd.ordering); if (write(outfileno, &retval, sizeof retval) != sizeof retval) { g_free(realname); return EXIT_FAILURE; } g_free(level); } g_free(realname); return EXIT_SUCCESS; }
static void restore_privs(void) { if (getuid() != 0) { #ifdef HAVE_SET_FSID setfsuid(oldfsuid); setfsgid(oldfsgid); #else fprintf(stderr, "%s: Implement alternative setfsuid/gid \n", progname); #endif } }
static void drop_privs(void) { if (getuid() != 0) { #ifdef HAVE_SET_FSID oldfsuid = setfsuid(getuid()); oldfsgid = setfsgid(getgid()); #else fprintf(stderr, "%s: Implement alternative setfsuid/gid \n", progname); #endif } }
Result<bool> RemoveFileAsRoot(const std::string& filename) { std::lock_guard<std::mutex> lock(mPermissionsMutex); auto previuousuid = setfsuid(-1); auto previuousgid = setfsgid(-1); // RAII resource cleanup; de-escalate privileges from root to previous: std::shared_ptr<void> resetPreviousPermisions(nullptr, [&](void*) { setfsuid(previuousuid); setfsgid(previuousgid); }); setfsuid(0); setfsgid(0); int rc = unlink(filename.c_str()); if (rc == -1) { return Result<bool>{false, "Unable to unlink file"}; } return Result<bool>{true}; }
/** * Create a symbolic link pointing to "to" named "from" */ int encfs_symlink(const char *to, const char *from) { EncFS_Context *ctx = context(); if (isReadOnly(ctx)) return -EROFS; int res = -EIO; std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); if (!FSRoot) return res; try { string fromCName = FSRoot->cipherPath(from); // allow fully qualified names in symbolic links. string toCName = FSRoot->relativeCipherPath(to); VLOG(1) << "symlink " << fromCName << " -> " << toCName; // use setfsuid / setfsgid so that the new link will be owned by the // uid/gid provided by the fuse_context. int olduid = -1; int oldgid = -1; if (ctx->publicFilesystem) { fuse_context *context = fuse_get_context(); olduid = setfsuid(context->uid); oldgid = setfsgid(context->gid); } res = ::symlink(toCName.c_str(), fromCName.c_str()); if (olduid >= 0) setfsuid(olduid); if (oldgid >= 0) setfsgid(oldgid); if (res == -1) res = -errno; else res = ESUCCESS; } catch (encfs::Error &err) { RLOG(ERROR) << "error caught in symlink: " << err.what(); } return res; }
int main(int ac, char **av) { int lc; /* loop counter */ char *msg; /* message returned from parse_opts */ gid_t gid; /* parse standard options */ if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); } setup(); /* Check for looping state if -i option is given */ for (lc = 0; TEST_LOOPING(lc); lc++) { /* reset Tst_count in case we are looping */ Tst_count = 0; gid = 1; while (!getgrgid(gid)) { gid++; } TEST(setfsgid(gid)); if (TEST_RETURN == -1) { tst_resm(TFAIL, "call failed unexpectedly - errno %d", TEST_ERRNO); continue; } if (!STD_FUNCTIONAL_TEST) { tst_resm(TPASS, "call succeeded"); continue; } if (TEST_RETURN == gid) { tst_resm(TFAIL, "setfsgid() returned %ld, expected anything but %d", TEST_RETURN, gid); } else { tst_resm(TPASS, "setfsgid() returned expected value : " "%ld", TEST_RETURN); } } cleanup(); return EXIT_SUCCESS; }
static void restore_privs() { struct __user_cap_header_struct head; int res; head.version = _LINUX_CAPABILITY_VERSION; head.pid = 0; res = capset(&head, &oldcaps); if(res == -1) fprintf(stderr, "%s: failed to restore capabilities: %s\n", progname, strerror(errno)); setfsuid(oldfsuid); setfsgid(oldfsgid); }
int main(int ac, char **av) { int lc; /* loop counter */ char *msg; /* message returned from parse_opts */ gid_t gid; /* parse standard options */ if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){ tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg); } setup(); /* Check for looping state if -i option is given */ for (lc = 0; TEST_LOOPING(lc); lc++) { /* reset Tst_count in case we are looping */ Tst_count = 0; gid = getegid(); TEST(setfsgid(gid)); if (TEST_RETURN == -1) { tst_resm(TFAIL, "call failed unexpectedly - errno %d", TEST_ERRNO); continue; } if (!STD_FUNCTIONAL_TEST) { tst_resm(TPASS, "call succeeded"); continue; } if (TEST_RETURN != gid) { tst_resm(TFAIL, "setfsgid() returned %d, expeceted %d", TEST_RETURN, gid); } else { tst_resm(TPASS, "setfsgid() returned expected value : " "%d", gid); } } cleanup(); /*NOTREACHED*/ return(0); }
/* * from man 7 capabilities, section * Effect of User ID Changes on Capabilities: * 4. If the file system user ID is changed from 0 to nonzero (see setfsuid(2)) * then the following capabilities are cleared from the effective set: * CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, * CAP_LINUX_IMMUTABLE (since Linux 2.2.30), CAP_MAC_OVERRIDE, and CAP_MKNOD * (since Linux 2.2.30). If the file system UID is changed from nonzero to 0, * then any of these capabilities that are enabled in the permitted set * are enabled in the effective set. */ static int setfsugid(int uid, int gid) { /* * We still need DAC_OVERRIDE because we don't change * supplementary group ids, and hence may be subjected DAC rules */ cap_value_t cap_list[] = { CAP_DAC_OVERRIDE, }; setfsgid(gid); setfsuid(uid); if (uid != 0 || gid != 0) { return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0); } return 0; }
nix_uid_t nix_linux_setfsgid(nix_gid_t gid, nix_env_t *env) { #ifdef HAVE_SETFSGID int rv; errno = 0; rv = setfsgid((gid_t)gid); if (errno != 0) { nix_env_set_errno(env, errno); return (-1); } return (rv); #else nix_gid_t last = g_fsgid; g_fsgid = gid; return (last); #endif }
static void change_fsid (uid_t olduid, gid_t oldgid, uid_t uid, gid_t gid) { uid_t u; gid_t g; if (uid != olduid) { u = setfsuid (uid); if (u == -1) err ("setfsuid"); else if (u != olduid) msg ("setfsuid returned %d (wanted %d)", u, olduid); } if (gid != oldgid) { g = setfsgid (gid); if (g == -1) err ("setfsgid"); else if (g != oldgid) msg ("setfsgid returned %d (wanted %d)", g, oldgid); } if (!check_fsid (uid, gid)) msg_exit ("setfsuid/setfsgid failed"); msg ("fsid changed to %d:%d", uid, gid); }
void runSuccess() { setfsgid(anyint()); }
static void overlay_mknod(fuse_req_t req, struct inode_struct *pinode, struct name_struct *xname, struct call_info_struct *call_info, mode_t mode, dev_t rdev) { struct resource_struct *resource=call_info->object->resource; struct localfile_struct *localfile=(struct localfile_struct *) resource->data; struct pathinfo_struct *pathinfo=&call_info->pathinfo; unsigned int len0=pathinfo->len - call_info->relpath, len1=localfile->pathinfo.len; char path[len0 + len1 + 1]; struct entry_struct *entry=NULL, *parent=pinode->alias; struct inode_struct *inode; memcpy(path, localfile->pathinfo.path, len1); if (len0>0) { memcpy(path+len1, pathinfo->path + call_info->relpath, len0); len1+=len0; } path[len1]='\0'; entry=create_entry(parent, xname); inode=create_inode(); if (entry && inode) { struct entry_struct *result=NULL; unsigned int error=0; entry->inode=inode; inode->alias=entry; result=insert_entry(entry, &error, _ENTRY_FLAG_TEMP); if (result==entry) { uid_t uid_keep=setfsuid(call_info->uid); gid_t gid_keep=setfsgid(call_info->gid); mode_t umask_keep=umask(call_info->umask); mode = (mode & ~call_info->umask); if (mknod(path, mode, rdev)==0) { struct fuse_entry_param e; adjust_pathmax(call_info->pathinfo.len); add_inode_hashtable(inode, increase_inodes_workspace, (void *) call_info->workspace_mount); /* here complete the insert ?? */ inode->mode=mode; inode->nlink=1; inode->uid=call_info->uid; inode->gid=call_info->gid; inode->nlookup=1; inode->rdev=rdev; inode->size=0; get_current_time(&inode->mtim); memcpy(&inode->ctim, &inode->mtim, sizeof(struct timespec)); memset(&e, 0, sizeof(e)); e.ino = inode->ino; e.generation = 1; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_dev = 0; e.attr.st_uid=inode->uid; e.attr.st_gid=inode->gid; e.attr.st_size=inode->size; e.attr.st_rdev=inode->rdev; memcpy(&e.attr.st_mtim, &inode->mtim, sizeof(struct timespec)); memcpy(&e.attr.st_ctim, &inode->mtim, sizeof(struct timespec)); memcpy(&e.attr.st_atim, &inode->mtim, sizeof(struct timespec)); e.attr_timeout = fs_options.attr_timeout; e.entry_timeout = fs_options.entry_timeout; e.attr.st_blksize=4096; e.attr.st_blocks=0; fuse_reply_entry(req, &e); } else { unsigned int error_delete=0; error=errno; remove_entry(entry, &error_delete); destroy_entry(entry); entry=NULL; free(inode); inode=NULL; fuse_reply_err(req, error); } uid_keep=setfsuid(uid_keep); gid_keep=setfsgid(gid_keep); umask_keep=umask(umask_keep); } else { destroy_entry(entry); entry=NULL; free(inode); inode=NULL; if (error==0) error=EEXIST; fuse_reply_err(req, error); } } else { if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } fuse_reply_err(req, ENOMEM); } }
int main(int argc, char **argv) { int ret = 0, c, udp = 0, ipv4 = -1, daemon = 1, log = 1; char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias = NULL; enum working_mode wmode = MODE_UNKNOW; setfsuid(getuid()); setfsgid(getgid()); home = fetch_home_dir(); while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) { switch (c) { case 'h': help(); break; case 'v': version(); break; case 'D': daemon = 0; break; case 'N': log = 0; break; case 'C': wmode = MODE_DUMPC; break; case 'S': wmode = MODE_DUMPS; break; case 'c': wmode = MODE_CLIENT; if (optarg) { if (*optarg == '=') optarg++; alias = xstrdup(optarg); } break; case 'd': dev = xstrdup(optarg); break; case 'k': wmode = MODE_KEYGEN; break; case '4': ipv4 = 1; break; case '6': ipv4 = 0; break; case 'x': wmode = MODE_EXPORT; break; case 's': wmode = MODE_SERVER; break; case 'u': udp = 1; break; case 't': stun = xstrdup(optarg); break; case 'p': port = xstrdup(optarg); break; case '?': switch (optopt) { case 't': case 'd': case 'u': case 'p': panic("Option -%c requires an argument!\n", optopt); default: if (isprint(optopt)) printf("Unknown option character `0x%X\'!\n", optopt); die(); } default: break; } } if (argc < 2) help(); register_signal(SIGINT, signal_handler); register_signal(SIGHUP, signal_handler); register_signal(SIGTERM, signal_handler); register_signal(SIGPIPE, signal_handler); curve25519_selftest(); switch (wmode) { case MODE_KEYGEN: ret = main_keygen(home); break; case MODE_EXPORT: ret = main_export(home); break; case MODE_DUMPC: ret = main_dumpc(home); break; case MODE_DUMPS: ret = main_dumps(home); break; case MODE_CLIENT: ret = main_client(home, dev, alias, daemon); break; case MODE_SERVER: if (!port) panic("No port specified!\n"); if (stun) print_stun_probe(stun, 3478, strtoul(port, NULL, 10)); ret = main_server(home, dev, port, udp, ipv4, daemon, log); break; default: die(); } free(dev); free(stun); free(port); free(alias); return ret; }
int main(int argc, char **argv) { int ret, verbose = 0, c, opt_index, bypass = 0, format = 0; bool invoke_cpp = false; char *file = NULL; setfsuid(getuid()); setfsgid(getgid()); if (argc == 1) help(); while ((c = getopt_long(argc, argv, short_options, long_options, &opt_index)) != EOF) { switch (c) { case 'h': help(); break; case 'v': version(); break; case 'V': verbose = 1; break; case 'p': invoke_cpp = true; break; case 'f': if (!strncmp(optarg, "C", 1) || !strncmp(optarg, "netsniff-ng", 11)) format = 0; else if (!strncmp(optarg, "tcpdump", 7)) format = 2; else if (!strncmp(optarg, "xt_bpf", 6) || !strncmp(optarg, "tc", 2)) format = 1; else help(); break; case 'b': bypass = 1; break; case 'd': bpf_dump_op_table(); die(); case 'i': file = xstrdup(optarg); break; case '?': switch (optopt) { case 'i': case 'f': panic("Option -%c requires an argument!\n", optopt); default: if (isprint(optopt)) printf("Unknown option character `0x%X\'!\n", optopt); die(); } default: break; } } if (argc == 2) file = xstrdup(argv[1]); if (!file) panic("No Berkeley Packet Filter program specified!\n"); ret = compile_filter(file, verbose, bypass, format, invoke_cpp); xfree(file); return ret; }
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) { Lock _lock(mutex); int res; int olduid = -1; int oldgid = -1; if (gid != 0) { oldgid = setfsgid(gid); if (oldgid == -1) { int eno = errno; RLOG(DEBUG) << "setfsgid error: " << strerror(eno); return -EPERM; } } if (uid != 0) { olduid = setfsuid(uid); if (olduid == -1) { int eno = errno; RLOG(DEBUG) << "setfsuid error: " << strerror(eno); return -EPERM; } } /* * cf. xmp_mknod() in fusexmp.c * The regular file stuff could be stripped off if there * were a create method (advised to have) */ if (S_ISREG(mode)) { res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode); if (res >= 0) { res = ::close(res); } } else if (S_ISFIFO(mode)) { res = ::mkfifo(_cname.c_str(), mode); } else { res = ::mknod(_cname.c_str(), mode, rdev); } if (res == -1) { int eno = errno; VLOG(1) << "mknod error: " << strerror(eno); res = -eno; } if (olduid >= 0) { if(setfsuid(olduid) == -1) { int eno = errno; RLOG(DEBUG) << "setfsuid back error: " << strerror(eno); // does not return error here as initial setfsuid worked } } if (oldgid >= 0) { if(setfsgid(oldgid) == -1) { int eno = errno; RLOG(DEBUG) << "setfsgid back error: " << strerror(eno); // does not return error here as initial setfsgid worked } } return res; }
/* Note: it is possible for setfsuid/setfsgid to fail silently, * e.g. if user doesn't have CAP_SETUID/CAP_SETGID. * That should be checked at server startup. */ int np_setfsid (Npreq *req, Npuser *u, u32 gid_override) { Npwthread *wt = req->wthread; Npsrv *srv = req->conn->srv; int i, n, ret = -1; u32 gid; uid_t authuid; int dumpable = prctl (PR_GET_DUMPABLE, 0, 0, 0, 0); int dumpclrd = 0; if (np_conn_get_authuser(req->conn, &authuid) < 0) authuid = P9_NONUNAME; if ((srv->flags & SRV_FLAGS_SETFSID)) { /* gid_override must be one of user's suppl. groups unless * connection was originally authed as root (trusted). */ if (gid_override != -1 && u->uid != 0 && authuid != 0 && !(srv->flags & SRV_FLAGS_NOUSERDB)) { for (i = 0; i < u->nsg; i++) { if (u->sg[i] == gid_override) break; } if (i == u->nsg) { np_uerror (EPERM); np_logerr (srv, "np_setfsid(%s): gid_override " "%d not in user's sg list", u->uname, gid_override); goto done; } } gid = (gid_override == -1 ? u->gid : gid_override); if (wt->fsgid != gid) { dumpclrd = 1; if ((n = setfsgid (gid)) < 0) { np_uerror (errno); np_logerr (srv, "setfsgid(%s) gid=%d failed", u->uname, gid); wt->fsgid = P9_NONUNAME; goto done; } if (n != wt->fsgid) { np_uerror (errno); np_logerr (srv, "setfsgid(%s) gid=%d failed" "returned %d, expected %d", u->uname, gid, n, wt->fsgid); wt->fsgid = P9_NONUNAME; goto done; } wt->fsgid = gid; } if (wt->fsuid != u->uid) { dumpclrd = 1; if ((n = setfsuid (u->uid)) < 0) { np_uerror (errno); np_logerr (srv, "setfsuid(%s) uid=%d failed", u->uname, u->uid); wt->fsuid = P9_NONUNAME; goto done; } if (n != wt->fsuid) { np_uerror (EPERM); np_logerr (srv, "setfsuid(%s) uid=%d failed: " "returned %d, expected %d", u->uname, u->uid, n, wt->fsuid); wt->fsuid = P9_NONUNAME; goto done; } /* Track CAP side effects of setfsuid. */ if (u->uid == 0) wt->privcap = 1; /* transiton to 0 sets caps */ else if (wt->fsuid == 0) wt->privcap = 0; /* trans from 0 clears caps */ /* Suppl groups need to be part of cred for NFS * forwarding even with DAC_BYPASS. However only * do it if kernel treats sg's per-thread not process. * Addendum: late model glibc attempts to make this * per-process, so for now bypass glibc. See issue 53. */ if ((srv->flags & SRV_FLAGS_SETGROUPS)) { if (syscall(SYS_setgroups, u->nsg, u->sg) < 0) { np_uerror (errno); np_logerr (srv, "setgroups(%s) nsg=%d failed", u->uname, u->nsg); wt->fsuid = P9_NONUNAME; goto done; } } wt->fsuid = u->uid; } } #if HAVE_LIBCAP if ((srv->flags & SRV_FLAGS_DAC_BYPASS) && wt->fsuid != 0) { if (!wt->privcap && authuid == 0) { if (_chg_privcap (srv, CAP_SET) < 0) goto done; wt->privcap = 1; dumpclrd = 1; } else if (wt->privcap && authuid != 0) { if (_chg_privcap (srv, CAP_CLEAR) < 0) goto done; wt->privcap = 0; dumpclrd = 1; } } #endif ret = 0; done: if (dumpable && dumpclrd && prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) np_logerr (srv, "prctl PR_SET_DUMPABLE failed"); return ret; }
int main(int argc, char **argv) { int pid, s_p[2], f_p[2], r_p[3]; const __uid_t w_ruid = 1, w_euid = 2, w_suid = 3, w_fsuid = w_euid; const __uid_t w_rgid = 5, w_egid = 6, w_sgid = 7, w_fsgid = 8; __uid_t rid, eid, sid, fsid; char res = 'x'; test_init(argc, argv); pipe(s_p); pipe(f_p); pipe(r_p); pid = fork(); if (pid == 0) { close(s_p[0]); close(f_p[1]); close(r_p[0]); setresgid(w_rgid, w_egid, w_sgid); setfsgid(w_fsgid); setresuid(w_ruid, w_euid, w_suid); /* fsuid change is impossible after above */ close(s_p[1]); read(f_p[0], &res, 1); close(f_p[0]); #define CHECK_ID(__t, __w, __e) do { \ if (__t##id != w_##__t##__w##id) { \ res = __e; \ goto bad; \ } \ } while (0) rid = eid = sid = fsid = 0; getresuid(&rid, &eid, &sid); fsid = setfsuid(w_euid); CHECK_ID(r, u, '1'); CHECK_ID(e, u, '2'); CHECK_ID(s, u, '3'); CHECK_ID(s, u, '3'); CHECK_ID(fs, u, '4'); rid = eid = sid = fsid = 0; getresgid(&rid, &eid, &sid); fsid = setfsgid(w_fsgid); CHECK_ID(r, g, '5'); CHECK_ID(e, g, '6'); CHECK_ID(s, g, '7'); CHECK_ID(fs, g, '8'); res = '0'; bad: write(r_p[1], &res, 1); close(r_p[1]); _exit(0); } close(f_p[0]); close(s_p[1]); close(r_p[1]); read(s_p[0], &res, 1); close(s_p[0]); test_daemon(); test_waitsig(); close(f_p[1]); read(r_p[0], &res, 1); if (res == '0') pass(); else fail("Fail: %c", res); return 0; }
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { int opt_in = 1, i; struct passwd pwbuf, *findUser = &pwbuf; const char *currentUser; char randBufAscii[16] = {0}; uid_t oldUID; gid_t oldGID; char *CHAP, *RESP; char line[275]; FILE *tfa_file = NULL; char *tfa_filename = ""; struct stat tfa_stat; for( i = 0; i < argc; ++i ){ if( strcmp("debug", argv[i]) == 0 ) debug = 1; if( strcmp("noopt", argv[i]) == 0 ) opt_in = 0; } if(pam_get_user(pamh, ¤tUser, NULL) != PAM_SUCCESS || currentUser == NULL || strlen(currentUser) == 0) { pam_syslog(pamh, LOG_ERR, "Unable to determine target user."); clearParams(); return PAM_SYSTEM_ERR; } if(debug) pam_syslog(pamh, LOG_DEBUG, "TwoFactor for %s", currentUser); // gett pwentry if( getPwEntryByName(currentUser, findUser) != 0 ) { if( debug ) { pam_syslog(pamh, LOG_DEBUG, "Error while using getpwent"); } clearParams(); return PAM_SYSTEM_ERR; } /// now we have the correct user - allocate strlen pwdir, strlen tfa_config and 1 terminating null byte tfa_filename = (char*)malloc(strlen(findUser->pw_dir)+strlen(TFA_CONFIG)+1); if( !tfa_filename ) { pam_syslog(pamh, LOG_ERR, "Unable to alloc memory"); clearParams(); return PAM_SYSTEM_ERR; } *tfa_filename = 0; // set first byte to nil for favorable str* fn interaction // this should be okay, we used pw_dir to make the dest long // HOWEVER, we should probably figure out a 'safe' mechanism strcpy(tfa_filename, findUser->pw_dir); strcat(tfa_filename, TFA_CONFIG); /// if(0 != stat(tfa_filename, &tfa_stat) ) { release_pwbuf_structs(findUser); if( opt_in ) { pam_syslog(pamh, LOG_WARNING, "User '%s' not opted in for file '%s', allowing", currentUser, tfa_filename); free(tfa_filename); clearParams(); return PAM_SUCCESS; } //@todo: is it safe to print this name this way? I guess so since // the root user would have set this up... still... shiver? pam_syslog(pamh, LOG_ERR, "Unable to stat '%s'", tfa_filename); free(tfa_filename); clearParams(); return PAM_SYSTEM_ERR; } if( tfa_stat.st_mode & (S_IRWXG | S_IRWXO) ) { pam_syslog(pamh, LOG_ERR, "G/O are allowed to manipulate the secret seed on '%s'.", tfa_filename); request_random(pamh, PAM_ERROR_MSG, "G/O permissions on ~/.tfa_config are incorrect."); free(tfa_filename); // explicit denial here clearParams(); return PAM_PERM_DENIED; } oldUID = setfsuid(findUser->pw_uid); oldGID = setfsgid(findUser->pw_gid); release_pwbuf_structs(findUser); // give it up! tfa_file = fopen(tfa_filename, "r"); if( tfa_file == NULL ) { pam_syslog(pamh, LOG_ERR, "Unable to open '%s'", tfa_filename); free(tfa_filename); setfsgid(oldGID); setfsuid(oldUID); clearParams(); if( !opt_in ) return PAM_PERM_DENIED; // if we can stat but can't open for reading // there is some kind of hack afoot - explicit deny return PAM_SUCCESS; } if( debug ) pam_syslog(pamh, LOG_DEBUG, "Opened '%s' for reading.", tfa_filename); free(tfa_filename); while(fgets(line, sizeof(line), tfa_file) != NULL) { int iws = 0, iparam, found=0;; while(iws < sizeof(line) && (line[iws] == ' ' || line[iws] == '\r' || line[iws] == '\t')) ++iws; if( iws == sizeof(line) ) continue; if ( line[iws] == '#' || line[iws] == '\n' ) continue; for(iparam = 0; iparam < sizeof(file_params) / sizeof(file_params[0]); ++iparam) { if( strncmp(file_params[iparam].param_name, line+iws, strlen(file_params[iparam].param_name)) ) continue; found = 1; // skip more ws until = iws += strlen(file_params[iparam].param_name); while(line[iws] == ' ' || line[iws] == '\t') ++iws; if(iws == sizeof(line) || line[iws] != '=') { pam_syslog(pamh, LOG_ERR, "Invalid format for '%s'", file_params[iparam].param_name); fclose(tfa_file); setfsgid(oldGID); setfsuid(oldUID); clearParams(); return PAM_SYSTEM_ERR; } ++iws; while(line[iws] == ' ' || line[iws] == '\t') ++iws; if(iws == sizeof(line)) { pam_syslog(pamh, LOG_ERR, "Invalid format for '%s'", file_params[iparam].param_name); fclose(tfa_file); setfsgid(oldGID); setfsuid(oldUID); clearParams(); return PAM_SYSTEM_ERR; } strncpy(file_params[iparam].output_variable, line+iws, MIN(file_params[iparam].length_of_output, sizeof(line)-(iws))); file_params[iparam].output_variable[file_params[iparam].length_of_output-1] = 0; iws = 0; while( file_params[iparam].output_variable[iws] != ' ' && file_params[iparam].output_variable[iws] != '\t' && file_params[iparam].output_variable[iws] != '\r' && file_params[iparam].output_variable[iws] != '\n' ) iws++; file_params[iparam].output_variable[iws] = 0; // nuke any // trailing whitespace } if(!found) { pam_syslog(pamh, LOG_WARNING, "Unknown element '%s' is being ignored.", line+iws); } } fclose(tfa_file); // later memset(line, 0, sizeof(line)); if( debug ) { pam_syslog(pamh, LOG_DEBUG, "Email to: %s", emailToAddr); pam_syslog(pamh, LOG_DEBUG, "Email from: %s", emailFromAddr); pam_syslog(pamh, LOG_DEBUG, "Email server: %s", emailServer); pam_syslog(pamh, LOG_DEBUG, "Email port: %s", emailPort); pam_syslog(pamh, LOG_DEBUG, "Email username: %s", emailUser); } // get the random data as acii snprintf(randBufAscii, sizeof(randBufAscii), "%08x", getRandomInt32(pamh)); CHAP = base64_encode(randBufAscii, strlen(randBufAscii)); *(CHAP+8) = 0; if( publish_email(pamh, currentUser, CHAP) < 0 ) { pam_syslog(pamh, LOG_ERR, "Unable to send email!!"); free(CHAP); setfsgid(oldGID); setfsuid(oldUID); if( !strcmp(failPolicy, "pass") ) { clearParams(); return PAM_SUCCESS; } clearParams(); return PAM_PERM_DENIED; } if(debug) pam_syslog(pamh, LOG_DEBUG, "Sent email... awaiting response"); // RESP = request_random(pamh, PAM_PROMPT_ECHO_ON, "Challenge: "); if(debug) pam_syslog(pamh, LOG_DEBUG, "Response '%s' received, comparing with '%s'", RESP, CHAP); i = strcmp(RESP, CHAP); free(CHAP); free(RESP); setfsgid(oldGID); setfsuid(oldUID); clearParams(); if( i ) { //fputs("Failed - try again.", stdout); return PAM_PERM_DENIED; } return PAM_SUCCESS; }