CVE-2022-3437 third_party/heimdal: Don't pass NULL pointers to memcpy() in DES unwrap
[Samba.git] / source3 / printing / samba-bgqd.c
blob59ed0cc40dbaa73e8b5e301693758fd3b7c6b8e5
1 /*
2 * Printing background queue helper
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "replace.h"
19 #include "system/filesys.h"
20 #include "lib/util/server_id.h"
21 #include "source3/locking/share_mode_lock.h"
22 #include "source3/param/loadparm.h"
23 #include "source3/param/param_proto.h"
24 #include "lib/cmdline/cmdline.h"
25 #include "lib/cmdline/closefrom_except.h"
26 #include "lib/util/talloc_stack.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/signal.h"
29 #include "lib/util/fault.h"
30 #include "lib/util/become_daemon.h"
31 #include "lib/util/charset/charset.h"
32 #include "lib/util/samba_util.h"
33 #include "lib/util/sys_rw.h"
34 #include "lib/util/pidfile.h"
35 #include "lib/async_req/async_sock.h"
36 #include "dynconfig/dynconfig.h"
37 #include "source3/lib/global_contexts.h"
38 #include "messages.h"
39 #include "nsswitch/winbind_client.h"
40 #include "source3/include/auth.h"
41 #include "source3/lib/util_procid.h"
42 #include "source3/auth/proto.h"
43 #include "source3/printing/queue_process.h"
44 #include "source3/lib/substitute.h"
46 static void watch_handler(struct tevent_req *req)
48 bool *pdone = tevent_req_callback_data_void(req);
49 *pdone = true;
52 static void bgqd_sig_term_handler(
53 struct tevent_context *ev,
54 struct tevent_signal *se,
55 int signum,
56 int count,
57 void *siginfo,
58 void *private_data)
60 bool *pdone = private_data;
61 *pdone = true;
64 static bool ready_signal_filter(
65 struct messaging_rec *rec, void *private_data)
67 pid_t pid = getpid();
68 ssize_t written;
70 if (rec->msg_type != MSG_DAEMON_READY_FD) {
71 return false;
73 if (rec->num_fds != 1) {
74 return false;
77 written = sys_write(rec->fds[0], &pid, sizeof(pid));
78 if (written != sizeof(pid)) {
79 DBG_ERR("Could not write pid: %s\n", strerror(errno));
82 return false;
85 static int samba_bgqd_pidfile_create(
86 struct messaging_context *msg_ctx,
87 const char *progname,
88 int ready_signal_fd)
90 const char *piddir = lp_pid_directory();
91 size_t len = strlen(piddir) + strlen(progname) + 6;
92 char pidFile[len];
93 pid_t existing_pid;
94 int fd, ret;
96 snprintf(pidFile,
97 sizeof(pidFile),
98 "%s/%s.pid",
99 piddir, progname);
101 ret = pidfile_path_create(pidFile, &fd, &existing_pid);
102 if (ret == 0) {
103 struct tevent_req *ready_signal_req = NULL;
106 * Listen for fd's sent via MSG_DAEMON_READY_FD:
107 * Multiple instances of this process might have raced
108 * for creating the pidfile. Make sure the parent does
109 * not suffer from this race, reply on behalf of the
110 * loser of this race.
113 ready_signal_req = messaging_filtered_read_send(
114 msg_ctx,
115 messaging_tevent_context(msg_ctx),
116 msg_ctx,
117 ready_signal_filter,
118 NULL);
119 if (ready_signal_req == NULL) {
120 DBG_DEBUG("messaging_filtered_read_send failed\n");
121 pidfile_unlink(piddir, progname);
122 pidfile_fd_close(fd);
123 return ENOMEM;
126 /* leak fd */
127 return 0;
130 if (ret != EAGAIN) {
131 DBG_DEBUG("pidfile_path_create() failed: %s\n",
132 strerror(ret));
133 return ret;
136 DBG_DEBUG("%s pid %d exists\n", progname, (int)existing_pid);
138 if (ready_signal_fd != -1) {
140 * We lost the race for the pidfile, but someone else
141 * can report readiness on our behalf.
143 NTSTATUS status = messaging_send_iov(
144 msg_ctx,
145 pid_to_procid(existing_pid),
146 MSG_DAEMON_READY_FD,
147 NULL,
149 &ready_signal_fd,
151 if (!NT_STATUS_IS_OK(status)) {
152 DBG_DEBUG("Could not send ready_signal_fd: %s\n",
153 nt_errstr(status));
157 return EAGAIN;
160 int main(int argc, const char *argv[])
162 struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
163 const struct loadparm_substitution *lp_sub =
164 loadparm_s3_global_substitution();
165 const char *progname = getprogname();
166 TALLOC_CTX *frame = NULL;
167 poptContext pc;
168 struct messaging_context *msg_ctx = NULL;
169 struct tevent_context *ev = NULL;
170 struct tevent_req *watch_req = NULL;
171 struct tevent_signal *sigterm_handler = NULL;
172 struct bq_state *bq = NULL;
173 int log_stdout = 0;
174 int ready_signal_fd = -1;
175 int watch_fd = -1;
176 NTSTATUS status;
177 int ret;
178 bool ok;
179 bool done = false;
180 int exitcode = 1;
182 struct poptOption long_options[] = {
183 POPT_AUTOHELP
184 POPT_COMMON_SAMBA
185 POPT_COMMON_DAEMON
188 * File descriptor to write the PID of the helper
189 * process to
192 .longName = "ready-signal-fd",
193 .argInfo = POPT_ARG_INT,
194 .arg = &ready_signal_fd,
195 .descrip = "Fd to signal readiness to" ,
199 * Read end of a pipe held open by the parent
200 * smbd. Exit this process when it becomes readable.
203 .longName = "parent-watch-fd",
204 .argInfo = POPT_ARG_INT,
205 .arg = &watch_fd,
206 .descrip = "Fd to watch for exiting",
208 POPT_TABLEEND
212 const char *fd_params[] = {
213 "ready-signal-fd", "parent-watch-fd",
216 closefrom_except_fd_params(
217 3, ARRAY_SIZE(fd_params), fd_params, argc, argv);
220 talloc_enable_null_tracking();
221 frame = talloc_stackframe();
222 umask(0);
223 set_remote_machine_name("smbd-bgqd", true);
225 ok = samba_cmdline_init(frame,
226 SAMBA_CMDLINE_CONFIG_SERVER,
227 true /* require_smbconf */);
228 if (!ok) {
229 DBG_ERR("Failed to setup cmdline parser!\n");
230 exit(ENOMEM);
233 cmdline_daemon_cfg = samba_cmdline_get_daemon_cfg();
235 pc = samba_popt_get_context(progname,
236 argc,
237 argv,
238 long_options,
240 if (pc == NULL) {
241 DBG_ERR("Failed to get popt context!\n");
242 exit(ENOMEM);
245 ret = poptGetNextOpt(pc);
246 if (ret < -1) {
247 fprintf(stderr, "invalid options: %s\n", poptStrerror(ret));
248 goto done;
251 poptFreeContext(pc);
253 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
255 /* main process will notify systemd */
256 daemon_sd_notifications(false);
258 if (!cmdline_daemon_cfg->fork) {
259 daemon_status(progname, "Starting process ... ");
260 } else {
261 become_daemon(true,
262 cmdline_daemon_cfg->no_process_group,
263 log_stdout);
266 BlockSignals(true, SIGPIPE);
268 smb_init_locale();
269 dump_core_setup(progname, lp_logfile(frame, lp_sub));
271 msg_ctx = global_messaging_context();
272 if (msg_ctx == NULL) {
273 DBG_ERR("messaging_init() failed\n");
274 goto done;
276 ev = messaging_tevent_context(msg_ctx);
278 ret = samba_bgqd_pidfile_create(msg_ctx, progname, ready_signal_fd);
279 if (ret != 0) {
280 goto done;
283 if (watch_fd != -1) {
284 watch_req = wait_for_read_send(ev, ev, watch_fd, true);
285 if (watch_req == NULL) {
286 fprintf(stderr, "tevent_add_fd failed\n");
287 goto done;
289 tevent_req_set_callback(watch_req, watch_handler, &done);
292 (void)winbind_off();
293 ok = init_guest_session_info(frame);
294 (void)winbind_on();
295 if (!ok) {
296 DBG_ERR("init_guest_session_info failed\n");
297 goto done;
300 (void)winbind_off();
301 status = init_system_session_info(frame);
302 (void)winbind_on();
303 if (!NT_STATUS_IS_OK(status)) {
304 DBG_ERR("init_system_session_info failed: %s\n",
305 nt_errstr(status));
306 goto done;
309 sigterm_handler = tevent_add_signal(
310 ev, frame, SIGTERM, 0, bgqd_sig_term_handler, &done);
311 if (sigterm_handler == NULL) {
312 DBG_ERR("Could not install SIGTERM handler\n");
313 goto done;
316 bq = register_printing_bq_handlers(frame, msg_ctx);
317 if (bq == NULL) {
318 DBG_ERR("Could not register bq handlers\n");
319 goto done;
322 ok = locking_init();
323 if (!ok) {
324 DBG_ERR("locking_init failed\n");
325 goto done;
328 if (ready_signal_fd != -1) {
329 pid_t pid = getpid();
330 ssize_t written;
332 written = sys_write(ready_signal_fd, &pid, sizeof(pid));
333 if (written != sizeof(pid)) {
334 DBG_ERR("Reporting readiness failed\n");
335 goto done;
337 close(ready_signal_fd);
338 ready_signal_fd = -1;
341 while (!done) {
342 TALLOC_CTX *tmp = talloc_stackframe();
343 ret = tevent_loop_once(ev);
344 TALLOC_FREE(tmp);
345 if (ret != 0) {
346 DBG_ERR("tevent_loop_once failed\n");
347 break;
351 exitcode = 0;
352 done:
353 TALLOC_FREE(watch_req);
354 TALLOC_FREE(bq);
355 TALLOC_FREE(sigterm_handler);
356 global_messaging_context_free();
357 TALLOC_FREE(frame);
358 return exitcode;