1 /*
2 * scm_spawn.c
3 *
4 * (C)2000-2011 Marc Huber <Marc.Huber@web.de>
5 * All rights reserved.
6 *
7 */
8
9 #include "misc/sysconf.h"
10 #include "spawnd_headers.h"
11 #include <grp.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/uio.h>
16 #include <sys/un.h>
17 #include <unistd.h>
18 #include <sysexits.h>
19
20 static const char rcsid[] __attribute__ ((used)) = "$Id: spawnd_scm_spawn.c,v 1.27 2019/03/31 09:14:23 marc Exp marc $";
21
spawnd_cleanup_internal(struct spawnd_context * ctx,int fd)22 void spawnd_cleanup_internal(struct spawnd_context *ctx, int fd __attribute__ ((unused)))
23 {
24 DebugIn(DEBUG_PROC);
25
26 io_close(ctx->io, ctx->fn);
27
28 while (io_sched_pop(ctx->io, ctx));
29
30 if (ctx->is_listener)
31 spawnd_data.listeners_max--;
32 else {
33 int i;
34 common_data.users_cur -= ctx->use;
35 for (i = 0; i < common_data.servers_cur && ctx != spawnd_data.server_arr[i]; i++);
36 if (i < --common_data.servers_cur)
37 spawnd_data.server_arr[i] = spawnd_data.server_arr[common_data.servers_cur];
38 set_proctitle(ACCEPT);
39 }
40
41 free(ctx);
42
43 DebugOut(DEBUG_PROC);
44 }
45
spawnd_spawn_child(pid_t * pidp)46 int spawnd_spawn_child(pid_t * pidp)
47 {
48 int socks[2];
49 pid_t pid;
50 int flags;
51 int bufsize = spawnd_data.scm_bufsize;
52 int one = 1;
53 char *argv[10];
54 int i = 0;
55 char *deb = alloca(20);
56
57 memset(&argv, 0, sizeof(argv));
58
59 argv[i++] = spawnd_data.child_path;
60 if (common_data.version_only)
61 argv[i++] = "-v";
62 if (common_data.parse_only)
63 argv[i++] = "-P";
64 if (common_data.debug) {
65 argv[i++] = "-d";
66 snprintf(deb, 20, "%u", common_data.debug);
67 argv[i++] = deb;
68 }
69 argv[i++] = spawnd_data.child_config;
70 argv[i++] = spawnd_data.child_id;
71 argv[i++] = NULL;
72
73 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, socks)) {
74 logerr("socketpair (%s:%d)", __FILE__, __LINE__);
75 exit(EX_OSERR);
76 }
77
78 switch ((pid = fork())) {
79 case 0:
80 io_destroy(common_data.io, NULL);
81 close(socks[0]);
82 dup2(socks[1], 0);
83 close(socks[1]);
84 if (bufsize) {
85 setsockopt(0, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, (socklen_t) sizeof(bufsize));
86 setsockopt(0, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, (socklen_t) sizeof(bufsize));
87 }
88 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, (socklen_t) sizeof(one));
89
90 if (common_data.parse_only)
91 execv(spawnd_data.child_path, argv);
92 else {
93 if (spawnd_data.uid)
94 setgroups(0, NULL);
95
96 if (spawnd_data.gid && setgid(spawnd_data.gid))
97 logerr("Can't set group id to %d", (int) spawnd_data.gid);
98
99 if (spawnd_data.uid && setuid(spawnd_data.uid))
100 logerr("Can't set user id to %d", (int) spawnd_data.uid);
101
102 if (spawnd_data.cwd && chdir(spawnd_data.cwd))
103 logerr("Can't chdir to %s", spawnd_data.cwd);
104
105 execv(spawnd_data.child_path, argv);
106 }
107
108 logerr("execl (%s, ...) (%s:%d)", spawnd_data.child_path, __FILE__, __LINE__);
109 if (!strchr(spawnd_data.child_path, '/'))
110 logmsg("Try calling %s with its absolute path, and this " "problem will go away.", spawnd_data.child_path);
111 exit(EX_OSERR);
112 case -1:
113 logerr("fork (%s:%d)", __FILE__, __LINE__);
114 exit(EX_OSERR);
115 default:
116 close(socks[1]);
117 flags = fcntl(socks[0], F_GETFD, 0) | FD_CLOEXEC;
118 fcntl(socks[0], F_SETFD, flags);
119 if (bufsize) {
120 setsockopt(socks[0], SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, (socklen_t) sizeof(bufsize));
121 setsockopt(socks[0], SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, (socklen_t) sizeof(bufsize));
122 }
123 setsockopt(socks[0], SOL_SOCKET, SO_KEEPALIVE, (char *) &one, (socklen_t) sizeof(one));
124 if (pidp)
125 *pidp = pid;
126
127 return socks[0];
128 }
129 }
130
recv_childmsg(struct spawnd_context * ctx,int cur)131 static void recv_childmsg(struct spawnd_context *ctx, int cur)
132 {
133 int max = -1;
134 struct scm_data_accept sd;
135 int result = common_data.scm_recv_msg(cur, &sd, sizeof(sd), NULL);
136
137 if (result)
138 spawnd_cleanup_internal(ctx, cur);
139 else
140 switch (sd.type) {
141 case SCM_DONE:
142 common_data.users_cur--, ctx->use--;
143 if (spawnd_data.listeners_inactive) {
144 int i;
145 logmsg("resuming normal operation");
146 spawnd_data.listeners_inactive = 0;
147 switch (spawnd_data.overload) {
148 case S_queue:
149 for (i = 0; i < spawnd_data.listeners_max; i++) {
150 if (spawnd_data.listener_arr[i]->listen_backlog != spawnd_data.listener_arr[i]->overload_backlog)
151 listen(spawnd_data.listener_arr[i]->fn, spawnd_data.listener_arr[i]->listen_backlog);
152 io_set_i(ctx->io, spawnd_data.listener_arr[i]->fn);
153 }
154 break;
155 case S_reset:
156 for (i = 0; i < spawnd_data.listeners_max; i++)
157 spawnd_bind_listener(spawnd_data.listener_arr[i], spawnd_data.listener_arr[i]->fn);
158 break;
159 default:;
160 }
161 }
162 set_proctitle(ACCEPT);
163 break;
164 case SCM_BAD_CFG:
165 logmsg("Child reported fatal configuration problem. Exiting.");
166 exit(EX_CONFIG);
167 case SCM_DYING:
168 spawnd_cleanup_internal(ctx, cur);
169 break;
170 case SCM_MAX:
171 max = ((struct scm_data_max *) (&sd))->max;
172 if (common_data.users_max > max) {
173 common_data.users_max = max;
174 logmsg("child limits maximum number of users to %d", common_data.users_max);
175 set_proctitle(ACCEPT);
176 }
177 break;
178 case SCM_KEEPALIVE:
179 break;
180 default:
181 logmsg("Child used unknown message type %d", (int) sd.type);
182 }
183 }
184
spawnd_add_child()185 void spawnd_add_child()
186 {
187 if (common_data.servers_cur < common_data.servers_max) {
188 pid_t pid;
189 int cur = spawnd_spawn_child(&pid);
190 if (cur > -1) {
191 struct spawnd_context *ctx = spawnd_new_context(common_data.io);
192 ctx->pid = pid;
193 ctx->fn = cur;
194 ctx->tv = io_now;
195
196 io_register(common_data.io, cur, ctx);
197 io_set_cb_i(common_data.io, cur, (void *) recv_childmsg);
198 io_set_cb_h(common_data.io, cur, (void *) spawnd_cleanup_internal);
199 io_set_cb_e(common_data.io, cur, (void *) spawnd_cleanup_internal);
200 io_clr_cb_o(common_data.io, cur);
201 io_set_i(common_data.io, cur);
202 spawnd_data.server_arr[common_data.servers_cur++] = ctx;
203 }
204 }
205 }
206