+static
+int child_run_as(void *_data)
+{
+ struct run_as_data *data = _data;
+ size_t writelen, writeleft, index;
+ union {
+ int i;
+ char c[sizeof(int)];
+ } sendret;
+ int ret;
+
+ /*
+ * Child: it is safe to drop egid and euid while sharing the
+ * file descriptors with the parent process, since we do not
+ * drop "uid": therefore, the user we are dropping egid/euid to
+ * cannot attach to this process with, e.g. ptrace, nor map this
+ * process memory.
+ */
+ ret = setegid(data->gid);
+ if (ret < 0) {
+ perror("setegid");
+ exit(EXIT_FAILURE);
+ }
+ ret = seteuid(data->uid);
+ if (ret < 0) {
+ perror("seteuid");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * Also set umask to 0 for mkdir executable bit.
+ */
+ umask(0);
+ sendret.i = (*data->cmd)(data->data);
+ /* send back return value */
+ writeleft = sizeof(sendret);
+ index = 0;
+ do {
+ writelen = write(data->retval_pipe, &sendret.c[index],
+ writeleft);
+ if (writelen < 0) {
+ perror("write");
+ exit(EXIT_FAILURE);
+ }
+ writeleft -= writelen;
+ index += writelen;
+ } while (writeleft > 0);
+
+ exit(EXIT_SUCCESS);
+}
+