1 /*
2 * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Nick Desaulniers
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <grp.h>
25 #include <pthread.h>
26 #include <pwd.h>
27 #include <signal.h>
28 #ifndef __linux__
29 #include <spawn.h>
30 #endif
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37 #if !defined(_SC_NPROCESSORS_ONLN)
38 #include <sys/sysctl.h>
39 #endif
40 #include "cloexec.h"
41 #include "h2o/memory.h"
42 #include "h2o/serverutil.h"
43 #include "h2o/socket.h"
44 #include "h2o/string_.h"
45
h2o_set_signal_handler(int signo,void (* cb)(int signo))46 void h2o_set_signal_handler(int signo, void (*cb)(int signo))
47 {
48 struct sigaction action;
49
50 memset(&action, 0, sizeof(action));
51 sigemptyset(&action.sa_mask);
52 action.sa_handler = cb;
53 sigaction(signo, &action, NULL);
54 }
55
h2o_setuidgid(const char * user)56 int h2o_setuidgid(const char *user)
57 {
58 struct passwd pwbuf, *pw;
59 char buf[65536]; /* should be large enough */
60
61 errno = 0;
62 if (getpwnam_r(user, &pwbuf, buf, sizeof(buf), &pw) != 0) {
63 h2o_perror("getpwnam_r");
64 return -1;
65 }
66 if (pw == NULL) {
67 h2o_error_printf("unknown user:%s\n", user);
68 return -1;
69 }
70 if (setgid(pw->pw_gid) != 0) {
71 h2o_error_printf("setgid(%d) failed:%s\n", (int)pw->pw_gid, strerror(errno));
72 return -1;
73 }
74 if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
75 h2o_error_printf("initgroups(%s, %d) failed:%s\n", pw->pw_name, (int)pw->pw_gid, strerror(errno));
76 return -1;
77 }
78 if (setuid(pw->pw_uid) != 0) {
79 h2o_error_printf("setuid(%d) failed:%s\n", (int)pw->pw_uid, strerror(errno));
80 return -1;
81 }
82
83 return 0;
84 }
85
h2o_server_starter_get_fds(int ** _fds)86 size_t h2o_server_starter_get_fds(int **_fds)
87 {
88 const char *ports_env, *start, *end, *eq;
89 size_t t;
90 H2O_VECTOR(int) fds = {NULL};
91
92 if ((ports_env = getenv(SERVER_STARTER_PORT)) == NULL)
93 return 0;
94 if (ports_env[0] == '\0') {
95 h2o_error_printf("$" SERVER_STARTER_PORT " is empty\n");
96 return SIZE_MAX;
97 }
98
99 /* ports_env example: 127.0.0.1:80=3;/tmp/sock=4 */
100 for (start = ports_env; *start != '\0'; start = *end == ';' ? end + 1 : end) {
101 if ((end = strchr(start, ';')) == NULL)
102 end = start + strlen(start);
103 if ((eq = memchr(start, '=', end - start)) == NULL) {
104 h2o_error_printf("invalid $" SERVER_STARTER_PORT ", an element without `=` in: %s\n", ports_env);
105 goto Error;
106 }
107 if ((t = h2o_strtosize(eq + 1, end - eq - 1)) == SIZE_MAX) {
108 h2o_error_printf("invalid file descriptor number in $" SERVER_STARTER_PORT ": %s\n", ports_env);
109 goto Error;
110 }
111 h2o_vector_reserve(NULL, &fds, fds.size + 1);
112 fds.entries[fds.size++] = (int)t;
113 }
114
115 *_fds = fds.entries;
116 return fds.size;
117 Error:
118 free(fds.entries);
119 return SIZE_MAX;
120 }
121
build_spawn_env(void)122 static char **build_spawn_env(void)
123 {
124 extern char **environ;
125 size_t num;
126
127 /* calculate number of envvars, as well as looking for H2O_ROOT= */
128 for (num = 0; environ[num] != NULL; ++num)
129 if (strncmp(environ[num], "H2O_ROOT=", sizeof("H2O_ROOT=") - 1) == 0)
130 return NULL;
131
132 /* not found */
133 char **newenv = h2o_mem_alloc(sizeof(*newenv) * (num + 2) + sizeof("H2O_ROOT=" H2O_TO_STR(H2O_ROOT)));
134 memcpy(newenv, environ, sizeof(*newenv) * num);
135 newenv[num] = (char *)(newenv + num + 2);
136 newenv[num + 1] = NULL;
137 strcpy(newenv[num], "H2O_ROOT=" H2O_TO_STR(H2O_ROOT));
138
139 return newenv;
140 }
141
h2o_spawnp(const char * cmd,char * const * argv,const int * mapped_fds,int cloexec_mutex_is_locked)142 pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked)
143 {
144 #if defined(__linux__)
145 #ifndef _GNU_SOURCE
146 extern int pipe2(int pipefd[2], int flags);
147 #endif
148
149 /* Before glibc 2.24, posix_spawnp of Linux does not return error if the executable does not exist, see
150 * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09
151 */
152 extern char **environ;
153 int pipefds[2] = {-1, -1}, errnum;
154 pid_t pid;
155
156 /* create pipe, used for sending error codes */
157 if (pipe2(pipefds, O_CLOEXEC) != 0)
158 goto Error;
159
160 /* fork */
161 if (!cloexec_mutex_is_locked)
162 pthread_mutex_lock(&cloexec_mutex);
163 if ((pid = fork()) == 0) {
164 /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */
165 if (mapped_fds != NULL) {
166 for (; *mapped_fds != -1; mapped_fds += 2) {
167 if (mapped_fds[0] != mapped_fds[1]) {
168 if (mapped_fds[1] != -1)
169 dup2(mapped_fds[0], mapped_fds[1]);
170 close(mapped_fds[0]);
171 }
172 }
173 }
174 char **env = build_spawn_env();
175 if (env != NULL)
176 environ = env;
177 execvp(cmd, argv);
178 errnum = errno;
179 write(pipefds[1], &errnum, sizeof(errnum));
180 _exit(EX_SOFTWARE);
181 }
182 if (!cloexec_mutex_is_locked)
183 pthread_mutex_unlock(&cloexec_mutex);
184 if (pid == -1)
185 goto Error;
186
187 /* parent process */
188 close(pipefds[1]);
189 pipefds[1] = -1;
190 ssize_t rret;
191 errnum = 0;
192 while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR)
193 ;
194 if (rret != 0) {
195 /* spawn failed */
196 while (waitpid(pid, NULL, 0) != pid)
197 ;
198 pid = -1;
199 errno = errnum;
200 goto Error;
201 }
202
203 /* spawn succeeded */
204 close(pipefds[0]);
205 return pid;
206
207 Error:
208 errnum = errno;
209 if (pipefds[0] != -1)
210 close(pipefds[0]);
211 if (pipefds[1] != -1)
212 close(pipefds[1]);
213 errno = errnum;
214 return -1;
215
216 #else
217
218 posix_spawn_file_actions_t file_actions;
219 pid_t pid;
220 extern char **environ;
221 char **env = build_spawn_env();
222 posix_spawn_file_actions_init(&file_actions);
223 if (mapped_fds != NULL) {
224 for (; *mapped_fds != -1; mapped_fds += 2) {
225 if (mapped_fds[1] != -1)
226 posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]);
227 posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]);
228 }
229 }
230 if (!cloexec_mutex_is_locked)
231 pthread_mutex_lock(&cloexec_mutex);
232 errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ);
233 if (!cloexec_mutex_is_locked)
234 pthread_mutex_unlock(&cloexec_mutex);
235 free(env);
236 posix_spawn_file_actions_destroy(&file_actions);
237 if (errno != 0)
238 return -1;
239
240 return pid;
241
242 #endif
243 }
244
h2o_read_command(const char * cmd,char ** argv,h2o_iovec_t std_in,h2o_buffer_t ** resp,int * child_status)245 int h2o_read_command(const char *cmd, char **argv, h2o_iovec_t std_in, h2o_buffer_t **resp, int *child_status)
246 {
247 int respfds[2] = {-1, -1}, inputfds[2] = {-1, -1};
248 pid_t pid = -1;
249 int mutex_locked = 0, ret = -1;
250
251 h2o_buffer_init(resp, &h2o_socket_buffer_prototype);
252
253 pthread_mutex_lock(&cloexec_mutex);
254 mutex_locked = 1;
255
256 /* create pipes for reading the result and for supplying input */
257 if (pipe(respfds) != 0)
258 goto Exit;
259 if (fcntl(respfds[0], F_SETFD, FD_CLOEXEC) < 0)
260 goto Exit;
261 if (pipe(inputfds) != 0)
262 goto Exit;
263 if (fcntl(inputfds[1], F_SETFD, FD_CLOEXEC) < 0)
264 goto Exit;
265
266 /* spawn */
267 int mapped_fds[] = {inputfds[0], 0, /* stdin of the child process is what is being provide as input */
268 respfds[1], 1, /* stdout of the child process is read from the pipe */
269 -1};
270 if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1)
271 goto Exit;
272 close(respfds[1]);
273 respfds[1] = -1;
274 close(inputfds[0]);
275 inputfds[0] = -1;
276
277 pthread_mutex_unlock(&cloexec_mutex);
278 mutex_locked = 0;
279
280 /* supply input */
281 for (size_t off = 0; off < std_in.len;) {
282 ssize_t r;
283 while ((r = write(inputfds[1], std_in.base + off, std_in.len - off)) == -1 && errno == EINTR)
284 ;
285 if (r < 0)
286 break;
287 off += r;
288 }
289 close(inputfds[1]);
290 inputfds[1] = -1;
291
292 /* read the response from pipe */
293 while (1) {
294 h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192);
295 ssize_t r;
296 while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR)
297 ;
298 if (r <= 0)
299 break;
300 (*resp)->size += r;
301 }
302
303 Exit:
304 if (mutex_locked)
305 pthread_mutex_unlock(&cloexec_mutex);
306 if (pid != -1) {
307 /* wait for the child to complete */
308 pid_t r;
309 while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR)
310 ;
311 if (r == pid) {
312 /* success */
313 ret = 0;
314 }
315 }
316 #define CLOSE_FD(x) \
317 do { \
318 if ((x) != -1) \
319 close(x); \
320 } while (0)
321 CLOSE_FD(respfds[0]);
322 CLOSE_FD(respfds[1]);
323 CLOSE_FD(inputfds[0]);
324 CLOSE_FD(inputfds[1]);
325 #undef CLOSE_FD
326 if (ret != 0)
327 h2o_buffer_dispose(resp);
328
329 return ret;
330 }
331
h2o_numproc(void)332 size_t h2o_numproc(void)
333 {
334 #if defined(_SC_NPROCESSORS_ONLN)
335 return (size_t)sysconf(_SC_NPROCESSORS_ONLN);
336 #elif defined(CTL_HW) && defined(HW_AVAILCPU)
337 int name[] = {CTL_HW, HW_AVAILCPU};
338 int ncpu;
339 size_t ncpu_sz = sizeof(ncpu);
340 if (sysctl(name, sizeof(name) / sizeof(name[0]), &ncpu, &ncpu_sz, NULL, 0) != 0 || sizeof(ncpu) != ncpu_sz) {
341 h2o_error_printf("[ERROR] failed to obtain number of CPU cores, assuming as one\n");
342 ncpu = 1;
343 }
344 return ncpu;
345 #else
346 return 1;
347 #endif
348 }
349