50 !pipe(pd) && !pipe(sd) &&
52 !!(fp = fdopen(pd[0],
"r")) &&
54 (pid = fork()) != (pid_t)-1) ) {
55 int err = (errno ? errno : ENOSYS);
57 fclose(fp); close(pd[1]);
59 else if (pd[0] >= 0) {
60 close(pd[0]); close(pd[1]);
63 close(sd[0]); close(sd[1]);
73 for (i = 0; i <= pd[1] || i <= sd[1]; i++) {
74 if (i == pd[1] || i == sd[1])
78 int open_max = sysconf(_SC_OPEN_MAX);
79#ifdef HAVE_CLOSE_RANGE
80 if (close_range(i, open_max - 1, 0))
85 for (
int failed = 0; i < open_max && failed < 1024; i++)
86 failed = (!close(i) ? 0 : failed + 1);
92 open(
"/dev/null", O_RDWR) == 0 &&
93 dup(0) == 1 && dup(0) == 2 &&
95 !fcntl(pd[1], F_SETFD, FD_CLOEXEC) &&
96 !fcntl(sd[1], F_SETFD, FD_CLOEXEC) &&
98 (!gid || (!setgid(gid) && !setgroups(1, &gid))) &&
99 (!uid || !setuid(uid)) &&
101 !!(fc = popen(
cmd, mode)) )) {
102 err = (errno ? errno : ENOSYS);
106 if (write(sd[1], &err,
sizeof(err)) != (int)
sizeof(err))
114 while (!err && (c = getc(fc)) != EOF) {
116 if (write(pd[1], &cb, 1) != 1)
121 int status = pclose(fc);
122 if (WIFSIGNALED(status))
123 kill(getpid(), WTERMSIG(status));
124 _exit(WIFEXITED(status) ? WEXITSTATUS(status) : 127);
128 close(pd[1]); close(sd[1]);
132 if (read(sd[0], &err,
sizeof(err)) != (
int)
sizeof(err))
157 pid_t pid;
int status;
160 while (pid == (pid_t)-1 && errno == EINTR);
163 if (pid == (pid_t)-1)
169 std::string & uname, std::string & gname )
172 int len = strlen(
s), n1 = -1, n2 = -1;
173 char un[64+1] =
"", gn[64+1] =
"";
174 if (!( sscanf(
s,
"%64[^ :]%n:%64[^ :]%n", un, &n1, gn, &n2) >= 1
175 && (n1 == len || n2 == len) )) {
176 return "Syntax error";
180 const struct passwd * pwd;
182 if (sscanf(un,
"%u%n", &u, (n1 = -1, &n1)) == 1 && n1 == (
int)strlen(un)) {
189 return "Unknown user name";
193 uname = pwd->pw_name;
195 const struct group * grp;
199 if (sscanf(gn,
"%u%n", &g, (n1 = -1, &n1)) == 1 && n1 == (
int)strlen(gn)) {
206 return "Unknown group name";
213 return "Unknown default group";
218 gname = grp->gr_name;
220 return (
const char *)0;
226int main(
int argc,
char **argv)
228 const char * user_group, *
cmd;
230 case 2: user_group = 0;
cmd = argv[1];
break;
231 case 3: user_group = argv[1];
cmd = argv[2];
break;
233 printf(
"Usage: %s [USER[:GROUP]] \"COMMAND ARG...\"\n", argv[0]);
237 int leak1 = open(
"/dev/null", O_RDONLY), leak2 = dup2(leak1, 1000);
241 uid_t uid; gid_t gid;
242 std::string uname =
"unknown", gname =
"unknown";
243 const char * err =
parse_ugid(user_group, uid, gid, uname, gname);
245 fprintf(stderr,
"Error: %s\n", err);
248 printf(
"popen_as_ugid(\"%s\", \"r\", %u(%s), %u(%s)):\n",
cmd,
249 (
unsigned)uid, uname.c_str(), (
unsigned)gid, gname.c_str());
253 printf(
"popen(\"%s\", \"r\"):\n",
cmd);
257 close(leak1); close(leak2);
265 for (cnt = 0; (c = getc(f)) != EOF; cnt++)
267 printf(
"[EOF]\nread %d bytes\n", cnt);
279 printf(
"pclose() = 0x%04x (exit = %d, sig = %d)\n",
280 status, WEXITSTATUS(status), WTERMSIG(status));
FILE * popen_as_ugid(const char *cmd, const char *mode, uid_t uid, gid_t gid)
const char * popen_as_ugid_cvsid
static FILE * s_popen_file
int pclose_as_ugid(FILE *f)
const char * parse_ugid(const char *s, uid_t &uid, gid_t &gid, std::string &uname, std::string &gname)
#define POPEN_AS_UGID_H_CVSID
int main(int argc, char **argv)