48 !pipe(pd) && !pipe(sd) &&
50 !!(fp = fdopen(pd[0],
"r")) &&
52 (pid = fork()) != (pid_t)-1) ) {
53 int err = (errno ? errno : ENOSYS);
55 fclose(fp); close(pd[1]);
57 else if (pd[0] >= 0) {
58 close(pd[0]); close(pd[1]);
61 close(sd[0]); close(sd[1]);
71 for (i = 0; i <= pd[1] || i <= sd[1]; i++) {
72 if (i == pd[1] || i == sd[1])
76 int open_max = sysconf(_SC_OPEN_MAX);
77#ifdef HAVE_CLOSE_RANGE
78 if (close_range(i, open_max - 1, 0))
83 for (
int failed = 0; i < open_max && failed < 1024; i++)
84 failed = (!close(i) ? 0 : failed + 1);
90 open(
"/dev/null", O_RDWR) == 0 &&
91 dup(0) == 1 && dup(0) == 2 &&
93 !fcntl(pd[1], F_SETFD, FD_CLOEXEC) &&
94 !fcntl(sd[1], F_SETFD, FD_CLOEXEC) &&
96 (!gid || (!setgid(gid) && !setgroups(1, &gid))) &&
97 (!uid || !setuid(uid)) &&
99 !!(fc = popen(
cmd, mode)) )) {
100 err = (errno ? errno : ENOSYS);
104 if (write(sd[1], &err,
sizeof(err)) != (int)
sizeof(err))
112 while (!err && (c = getc(fc)) != EOF) {
114 if (write(pd[1], &cb, 1) != 1)
119 int status = pclose(fc);
120 if (WIFSIGNALED(status))
121 kill(getpid(), WTERMSIG(status));
122 _exit(WIFEXITED(status) ? WEXITSTATUS(status) : 127);
126 close(pd[1]); close(sd[1]);
130 if (read(sd[0], &err,
sizeof(err)) != (
int)
sizeof(err))
155 pid_t pid;
int status;
158 while (pid == (pid_t)-1 && errno == EINTR);
161 if (pid == (pid_t)-1)
167 std::string & uname, std::string & gname )
170 int len = strlen(
s), n1 = -1, n2 = -1;
171 char un[64+1] =
"", gn[64+1] =
"";
172 if (!( sscanf(
s,
"%64[^ :]%n:%64[^ :]%n", un, &n1, gn, &n2) >= 1
173 && (n1 == len || n2 == len) )) {
174 return "Syntax error";
178 const struct passwd * pwd;
180 if (sscanf(un,
"%u%n", &u, (n1 = -1, &n1)) == 1 && n1 == (
int)strlen(un)) {
187 return "Unknown user name";
191 uname = pwd->pw_name;
193 const struct group * grp;
197 if (sscanf(gn,
"%u%n", &g, (n1 = -1, &n1)) == 1 && n1 == (
int)strlen(gn)) {
204 return "Unknown group name";
211 return "Unknown default group";
216 gname = grp->gr_name;
218 return (
const char *)0;
224int main(
int argc,
char **argv)
226 const char * user_group, *
cmd;
228 case 2: user_group = 0;
cmd = argv[1];
break;
229 case 3: user_group = argv[1];
cmd = argv[2];
break;
231 printf(
"Usage: %s [USER[:GROUP]] \"COMMAND ARG...\"\n", argv[0]);
235 int leak1 = open(
"/dev/null", O_RDONLY), leak2 = dup2(leak1, 1000);
239 uid_t uid; gid_t gid;
240 std::string uname =
"unknown", gname =
"unknown";
241 const char * err =
parse_ugid(user_group, uid, gid, uname, gname);
243 fprintf(stderr,
"Error: %s\n", err);
246 printf(
"popen_as_ugid(\"%s\", \"r\", %u(%s), %u(%s)):\n",
cmd,
247 (
unsigned)uid, uname.c_str(), (
unsigned)gid, gname.c_str());
251 printf(
"popen(\"%s\", \"r\"):\n",
cmd);
255 close(leak1); close(leak2);
263 for (cnt = 0; (c = getc(f)) != EOF; cnt++)
265 printf(
"[EOF]\nread %d bytes\n", cnt);
277 printf(
"pclose() = 0x%04x (exit = %d, sig = %d)\n",
278 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)