masqmail-0.2

view src/peopen.c @ 23:4a3bc3a7afbe

refactoring: early exit instead of deep if levels
author meillo@marmaro.de
date Fri, 05 Dec 2008 11:32:26 +0100
parents 26e34ae9a3e3
children 3654c502a4df
line source
1 /* This a snippet I found in sourceforge. I just changed the identing
2 style to my own and deleted the main function. */
4 #include <errno.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sysexits.h>
12 #include "peopen.h"
13 #include "masqmail.h"
15 static void
16 destroy_argv(char **arr)
17 {
18 char *p = arr[0];
19 int i = 0;
21 while (p) {
22 free(p);
23 p = arr[i++];
24 }
25 free(arr);
26 }
28 static char**
29 create_argv(const char *cmd, int count)
30 {
31 char buf[strlen(cmd) + 1];
32 char **arr, *q;
33 const char *p;
34 int i = 0;
36 arr = (char **) malloc(sizeof(char *) * count);
37 /* FIXME: check return value of malloc() */
39 p = cmd;
40 while (*p && i < (count - 1)) {
41 while (*p && isspace(*p))
42 p++;
43 q = buf;
44 while (*p && !isspace(*p))
45 *q++ = *p++;
46 *q = '\0';
47 arr[i++] = strdup(buf);
48 while (*p && isspace(*p))
49 p++;
50 }
51 arr[i] = NULL;
53 return arr;
54 }
56 FILE*
57 peidopen(const char *command, const char *type, char *const envp[], int *ret_pid, uid_t uid, gid_t gid)
58 {
59 enum { Read, Write } mode;
60 int pipe_fd[2];
61 pid_t pid;
63 if (command == NULL || type == NULL) {
64 errno = EINVAL;
65 return NULL;
66 }
68 if (strcmp(type, "r")) {
69 if (strcmp(type, "w")) {
70 errno = EINVAL;
71 return NULL;
72 } else
73 mode = Write;
74 } else
75 mode = Read;
77 if (pipe(pipe_fd) == -1)
78 return NULL;
80 switch (pid = fork()) {
81 case 0: /* child thread */
83 {
84 int i, max_fd = sysconf(_SC_OPEN_MAX);
86 if (max_fd <= 0)
87 max_fd = 64;
88 for (i = 0; i < max_fd; i++)
89 if ((i != pipe_fd[0]) && (i != pipe_fd[1]))
90 close(i);
91 }
92 if (close(pipe_fd[mode == Read ? 0 : 1]) != -1 &&
93 dup2(pipe_fd[mode == Read ? 1 : 0],
94 mode == Read ? STDOUT_FILENO : STDIN_FILENO) != -1) {
95 // char *argv [] = { "/bin/sh", "-c", (char*) command, NULL };
96 char **argv = create_argv(command, 10);
97 int ret;
99 if (uid != (uid_t) - 1) {
100 if ((ret = seteuid(0)) != 0) {
101 exit(EX_NOPERM);
102 }
103 }
104 if (gid != (gid_t) - 1) {
105 if ((ret = setgid(gid)) != 0) {
106 exit(EX_NOPERM);
107 }
108 }
109 if (uid != (uid_t) - 1) {
110 if ((ret = setuid(uid)) != 0) {
111 exit(EX_NOPERM);
112 }
113 }
114 execve(*argv, argv, envp);
115 }
117 _exit(errno);
119 default: /* parent thread */
120 *ret_pid = pid;
121 close(pipe_fd[mode == Read ? 1 : 0]);
122 return fdopen(pipe_fd[mode == Read ? 0 : 1], type);
124 case -1:
125 close(pipe_fd[0]);
126 close(pipe_fd[1]);
127 return NULL;
128 }
129 }
131 FILE*
132 peopen(const char *command, const char *type, char *const envp[], int *ret_pid)
133 {
134 return peidopen(command, type, envp, ret_pid, -1, -1);
135 }