#include #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { char *user = NULL, *group = NULL, *capstr = NULL; int c; while ((c = getopt(argc, argv, "+u:g:c:")) >= 0) switch (c) { case 'u': user = optarg; break; case 'g': group = optarg; break; case 'c': capstr = optarg; break; default: return 1; } if (!(user && *user)) error(EXIT_FAILURE, 0, "user not specified"); if (!(group && *group)) error(EXIT_FAILURE, 0, "group not specified"); if (!(capstr && *capstr)) error(EXIT_FAILURE, 0, "capabilities not specified"); if (optind >= argc) error(EXIT_FAILURE, 0, "command not specified"); struct passwd *pw = getpwnam(user); if (!pw) error(EXIT_FAILURE, 0, "getpwnam: user \"%s\" unknown", user); uid_t uid = pw->pw_uid; struct group *gr = getgrnam(group); if (!gr) error(EXIT_FAILURE, 0, "getgrnam: group \"%s\" unknown", group); gid_t gid = gr->gr_gid; cap_t caps = cap_from_text(capstr); if (!caps) error(EXIT_FAILURE, 1, "cap_from_text: \"%s\"", capstr); char suidcapstr[strlen(capstr) + sizeof "cap_setuid,"]; strcpy(suidcapstr, "cap_setuid,"); strcat(suidcapstr, capstr); cap_t suidcaps = cap_from_text(suidcapstr); if (!suidcaps) error(EXIT_FAILURE, 1, "cap_from_text: \"%s\"", suidcapstr); if (setgroups(0, NULL) < 0) error(EXIT_FAILURE, 1, "setgroups"); if (setregid(gid, gid) < 0) error(EXIT_FAILURE, 1, "setregid"); if (prctl(PR_SET_KEEPCAPS, 1) < 0) error(EXIT_FAILURE, 1, "prctl"); if (cap_set_proc(suidcaps) < 0) error(EXIT_FAILURE, 1, "cap_set_proc"); if (setreuid(uid, uid) < 0) error(EXIT_FAILURE, 1, "setreuid"); if (cap_set_proc(caps) < 0) error(EXIT_FAILURE, 1, "cap_set_proc"); execvp(argv[optind], argv + optind); error(EXIT_FAILURE, 1, "execvp: %s", argv[optind]); return EXIT_FAILURE; }