Bug Summary

File:src/usr.sbin/smtpd/smtpctl/../smtpctl.c
Warning:line 270, column 33
Null pointer passed as 1st argument to string length function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name smtpctl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/smtpd/smtpctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/smtpd/smtpctl/.. -D NO_IO -D CONFIG_MINIMUM -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/smtpd/smtpctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/smtpd/smtpctl/../smtpctl.c
1/* $OpenBSD: smtpctl.c,v 1.169 2021/06/14 17:58:16 eric Exp $ */
2
3/*
4 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5 * Copyright (c) 2006 Gilles Chehade <gilles@poolp.org>
6 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
7 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
8 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
9 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <sys/un.h>
25#include <sys/stat.h>
26
27#include <err.h>
28#include <errno(*__errno()).h>
29#include <fts.h>
30#include <inttypes.h>
31#include <pwd.h>
32#include <stdlib.h>
33#include <string.h>
34#include <syslog.h>
35#include <unistd.h>
36#include <vis.h>
37
38#include "smtpd.h"
39#include "parser.h"
40#include "log.h"
41
42#define PATH_GZCAT"/usr/bin/gzcat" "/usr/bin/gzcat"
43#define PATH_CAT"/bin/cat" "/bin/cat"
44#define PATH_QUEUE"/queue" "/queue"
45#define PATH_ENCRYPT"/usr/bin/encrypt" "/usr/bin/encrypt"
46
47int srv_connect(void);
48int srv_connected(void);
49
50void usage(void);
51static void show_queue_envelope(struct envelope *, int);
52static void getflag(uint *, int, char *, char *, size_t);
53static void display(const char *);
54static int str_to_trace(const char *);
55static int str_to_profile(const char *);
56static void show_offline_envelope(uint64_t);
57static int is_gzip_fp(FILE *);
58static int is_encrypted_fp(FILE *);
59static int is_encrypted_buffer(const char *);
60static int is_gzip_buffer(const char *);
61static FILE *offline_file(void);
62static void sendmail_compat(int, char **);
63
64extern int spfwalk(int, struct parameter *);
65
66extern char *__progname;
67int sendmail;
68struct smtpd *env;
69struct imsgbuf *ibuf;
70struct imsg imsg;
71char *rdata;
72size_t rlen;
73time_t now;
74
75struct queue_backend queue_backend_null;
76struct queue_backend queue_backend_proc;
77struct queue_backend queue_backend_ram;
78
79__dead__attribute__((__noreturn__)) void
80usage(void)
81{
82 if (sendmail)
83 fprintf(stderr(&__sF[2]), "usage: %s [-tv] [-f from] [-F name] to ...\n",
84 __progname);
85 else
86 fprintf(stderr(&__sF[2]), "usage: %s command [argument ...]\n",
87 __progname);
88 exit(1);
89}
90
91void stat_increment(const char *k, size_t v)
92{
93}
94
95void stat_decrement(const char *k, size_t v)
96{
97}
98
99int
100srv_connect(void)
101{
102 struct sockaddr_un s_un;
103 int ctl_sock, saved_errno;
104
105 /* connect to smtpd control socket */
106 if ((ctl_sock = socket(AF_UNIX1, SOCK_STREAM1, 0)) == -1)
107 err(1, "socket");
108
109 memset(&s_un, 0, sizeof(s_un));
110 s_un.sun_family = AF_UNIX1;
111 (void)strlcpy(s_un.sun_path, SMTPD_SOCKET"/var/run/smtpd.sock", sizeof(s_un.sun_path));
112 if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
113 saved_errno = errno(*__errno());
114 close(ctl_sock);
115 errno(*__errno()) = saved_errno;
116 return (0);
117 }
118
119 ibuf = xcalloc(1, sizeof(struct imsgbuf));
120 imsg_init(ibuf, ctl_sock);
121
122 return (1);
123}
124
125int
126srv_connected(void)
127{
128 return ibuf != NULL((void *)0) ? 1 : 0;
129}
130
131FILE *
132offline_file(void)
133{
134 char path[PATH_MAX1024];
135 int fd;
136 FILE *fp;
137
138 if (!bsnprintf(path, sizeof(path), "%s%s/%lld.XXXXXXXXXX", PATH_SPOOL"/var/spool/smtpd",
139 PATH_OFFLINE"/offline", (long long int) time(NULL((void *)0))))
140 err(EX_UNAVAILABLE69, "snprintf");
141
142 if ((fd = mkstemp(path)) == -1 || (fp = fdopen(fd, "w+")) == NULL((void *)0)) {
143 if (fd != -1)
144 unlink(path);
145 err(EX_UNAVAILABLE69, "cannot create temporary file %s", path);
146 }
147
148 if (fchmod(fd, 0600) == -1) {
149 unlink(path);
150 err(EX_SOFTWARE70, "fchmod");
151 }
152
153 return fp;
154}
155
156
157static void
158srv_flush(void)
159{
160 if (imsg_flush(ibuf) == -1)
161 err(1, "write error");
162}
163
164static void
165srv_send(int msg, const void *data, size_t len)
166{
167 if (ibuf == NULL((void *)0) && !srv_connect())
168 errx(1, "smtpd doesn't seem to be running");
169 imsg_compose(ibuf, msg, IMSG_VERSION16, 0, -1, data, len);
170}
171
172static void
173srv_recv(int type)
174{
175 ssize_t n;
176
177 srv_flush();
178
179 while (1) {
180 if ((n = imsg_get(ibuf, &imsg)) == -1)
181 errx(1, "imsg_get error");
182 if (n) {
183 if (imsg.hdr.type == IMSG_CTL_FAIL &&
184 imsg.hdr.peerid != 0 &&
185 imsg.hdr.peerid != IMSG_VERSION16)
186 errx(1, "incompatible smtpctl and smtpd");
187 if (type != -1 && type != (int)imsg.hdr.type)
188 errx(1, "bad message type");
189 rdata = imsg.data;
190 rlen = imsg.hdr.len - sizeof(imsg.hdr);
191 break;
192 }
193
194 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
195 errx(1, "imsg_read error");
196 if (n == 0)
197 errx(1, "pipe closed");
198 }
199}
200
201static void
202srv_read(void *dst, size_t sz)
203{
204 if (sz == 0)
205 return;
206 if (rlen < sz)
207 errx(1, "message too short");
208 if (dst)
209 memmove(dst, rdata, sz);
210 rlen -= sz;
211 rdata += sz;
212}
213
214static void
215srv_get_int(int *i)
216{
217 srv_read(i, sizeof(*i));
218}
219
220static void
221srv_get_time(time_t *t)
222{
223 srv_read(t, sizeof(*t));
224}
225
226static void
227srv_get_evpid(uint64_t *evpid)
228{
229 srv_read(evpid, sizeof(*evpid));
230}
231
232static void
233srv_get_string(const char **s)
234{
235 const char *end;
236 size_t len;
237
238 if (rlen == 0)
15
Assuming 'rlen' is not equal to 0
16
Taking false branch
239 errx(1, "message too short");
240
241 rlen -= 1;
242 if (*rdata++ == '\0') {
17
Assuming the condition is true
18
Taking true branch
243 *s = NULL((void *)0);
19
Null pointer value stored to 'str'
244 return;
245 }
246
247 if (rlen == 0)
248 errx(1, "bogus string");
249
250 end = memchr(rdata, 0, rlen);
251 if (end == NULL((void *)0))
252 errx(1, "unterminated string");
253
254 len = end + 1 - rdata;
255
256 *s = rdata;
257 rlen -= len;
258 rdata += len;
259}
260
261static void
262srv_get_envelope(struct envelope *evp)
263{
264 uint64_t evpid;
265 const char *str;
266
267 srv_get_evpid(&evpid);
268 srv_get_string(&str);
14
Calling 'srv_get_string'
20
Returning from 'srv_get_string'
269
270 envelope_load_buffer(evp, str, strlen(str));
21
Null pointer passed as 1st argument to string length function
271 evp->id = evpid;
272}
273
274static void
275srv_end(void)
276{
277 if (rlen)
278 errx(1, "bogus data");
279 imsg_free(&imsg);
280}
281
282static int
283srv_check_result(int verbose_)
284{
285 srv_recv(-1);
286 srv_end();
287
288 switch (imsg.hdr.type) {
289 case IMSG_CTL_OK:
290 if (verbose_)
291 printf("command succeeded\n");
292 return (0);
293 case IMSG_CTL_FAIL:
294 if (verbose_) {
295 if (rlen)
296 printf("command failed: %s\n", rdata);
297 else
298 printf("command failed\n");
299 }
300 return (1);
301 default:
302 errx(1, "wrong message in response: %u", imsg.hdr.type);
303 }
304 return (0);
305}
306
307static int
308srv_iter_messages(uint32_t *res)
309{
310 static uint32_t *msgids = NULL((void *)0), from = 0;
311 static size_t n, curr;
312 static int done = 0;
313
314 if (done)
315 return (0);
316
317 if (msgids == NULL((void *)0)) {
318 srv_send(IMSG_CTL_LIST_MESSAGES, &from, sizeof(from));
319 srv_recv(IMSG_CTL_LIST_MESSAGES);
320 if (rlen == 0) {
321 srv_end();
322 done = 1;
323 return (0);
324 }
325 msgids = malloc(rlen);
326 n = rlen / sizeof(*msgids);
327 srv_read(msgids, rlen);
328 srv_end();
329
330 curr = 0;
331 from = msgids[n - 1] + 1;
332 if (from == 0)
333 done = 1;
334 }
335
336 *res = msgids[curr++];
337 if (curr == n) {
338 free(msgids);
339 msgids = NULL((void *)0);
340 }
341
342 return (1);
343}
344
345static int
346srv_iter_envelopes(uint32_t msgid, struct envelope *evp)
347{
348 static uint32_t currmsgid = 0;
349 static uint64_t from = 0;
350 static int done = 0, need_send = 1, found;
351 int flags;
352 time_t nexttry;
353
354 if (currmsgid != msgid) {
7
Assuming 'currmsgid' is equal to 'msgid'
8
Taking false branch
355 if (currmsgid != 0 && !done)
356 errx(1, "must finish current iteration first");
357 currmsgid = msgid;
358 from = msgid_to_evpid(msgid);
359 done = 0;
360 found = 0;
361 need_send = 1;
362 }
363
364 if (done
8.1
'done' is 0
)
9
Taking false branch
365 return (0);
366
367 again:
368 if (need_send
9.1
'need_send' is 1
) {
10
Taking true branch
369 found = 0;
370 srv_send(IMSG_CTL_LIST_ENVELOPES, &from, sizeof(from));
371 }
372 need_send = 0;
373
374 srv_recv(IMSG_CTL_LIST_ENVELOPES);
375 if (rlen == 0) {
11
Assuming 'rlen' is not equal to 0
12
Taking false branch
376 srv_end();
377 if (!found || evpid_to_msgid(from) != msgid) {
378 done = 1;
379 return (0);
380 }
381 need_send = 1;
382 goto again;
383 }
384
385 srv_get_int(&flags);
386 srv_get_time(&nexttry);
387 srv_get_envelope(evp);
13
Calling 'srv_get_envelope'
388 srv_end();
389
390 evp->flags |= flags;
391 evp->nexttry = nexttry;
392
393 from = evp->id + 1;
394 found++;
395 return (1);
396}
397
398static int
399srv_iter_evpids(uint32_t msgid, uint64_t *evpid, int *offset)
400{
401 static uint64_t *evpids = NULL((void *)0), *tmp;
402 static int n, tmpalloc, alloc = 0;
403 struct envelope evp;
404
405 if (*offset == 0) {
406 n = 0;
407 while (srv_iter_envelopes(msgid, &evp)) {
408 if (n == alloc) {
409 tmpalloc = alloc ? (alloc * 2) : 128;
410 tmp = recallocarray(evpids, alloc, tmpalloc,
411 sizeof(*evpids));
412 if (tmp == NULL((void *)0))
413 err(1, "recallocarray");
414 evpids = tmp;
415 alloc = tmpalloc;
416 }
417 evpids[n++] = evp.id;
418 }
419 }
420
421 if (*offset >= n)
422 return (0);
423 *evpid = evpids[*offset];
424 *offset += 1;
425 return (1);
426}
427
428static void
429srv_foreach_envelope(struct parameter *argv, int ctl, size_t *total, size_t *ok)
430{
431 uint32_t msgid;
432 uint64_t evpid;
433 int i;
434
435 *total = 0;
436 *ok = 0;
437
438 if (argv == NULL((void *)0)) {
439 while (srv_iter_messages(&msgid)) {
440 i = 0;
441 while (srv_iter_evpids(msgid, &evpid, &i)) {
442 *total += 1;
443 srv_send(ctl, &evpid, sizeof(evpid));
444 if (srv_check_result(0) == 0)
445 *ok += 1;
446 }
447 }
448 } else if (argv->type == P_MSGID) {
449 i = 0;
450 while (srv_iter_evpids(argv->u.u_msgid, &evpid, &i)) {
451 srv_send(ctl, &evpid, sizeof(evpid));
452 if (srv_check_result(0) == 0)
453 *ok += 1;
454 }
455 } else {
456 *total += 1;
457 srv_send(ctl, &argv->u.u_evpid, sizeof(evpid));
458 if (srv_check_result(0) == 0)
459 *ok += 1;
460 }
461}
462
463static void
464srv_show_cmd(int cmd, const void *data, size_t len)
465{
466 int done = 0;
467
468 srv_send(cmd, data, len);
469
470 do {
471 srv_recv(cmd);
472 if (rlen) {
473 printf("%s\n", rdata);
474 srv_read(NULL((void *)0), rlen);
475 }
476 else
477 done = 1;
478 srv_end();
479 } while (!done);
480}
481
482static void
483droppriv(void)
484{
485 struct passwd *pw;
486
487 if (geteuid())
488 return;
489
490 if ((pw = getpwnam(SMTPD_USER"_smtpd")) == NULL((void *)0))
491 errx(1, "unknown user " SMTPD_USER"_smtpd");
492
493 if ((setgroups(1, &pw->pw_gid) ||
494 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
495 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)))
496 err(1, "cannot drop privileges");
497}
498
499static int
500do_permission_denied(int argc, struct parameter *argv)
501{
502 errx(1, "need root privileges");
503}
504
505static int
506do_log_brief(int argc, struct parameter *argv)
507{
508 int v = 0;
509
510 srv_send(IMSG_CTL_VERBOSE, &v, sizeof(v));
511 return srv_check_result(1);
512}
513
514static int
515do_log_verbose(int argc, struct parameter *argv)
516{
517 int v = TRACE_DEBUG0x0001;
518
519 srv_send(IMSG_CTL_VERBOSE, &v, sizeof(v));
520 return srv_check_result(1);
521}
522
523static int
524do_monitor(int argc, struct parameter *argv)
525{
526 struct stat_digest last, digest;
527 size_t count;
528
529 memset(&last, 0, sizeof(last));
530 count = 0;
531
532 while (1) {
533 srv_send(IMSG_CTL_GET_DIGEST, NULL((void *)0), 0);
534 srv_recv(IMSG_CTL_GET_DIGEST);
535 srv_read(&digest, sizeof(digest));
536 srv_end();
537
538 if (count % 25 == 0) {
539 if (count != 0)
540 printf("\n");
541 printf("--- client --- "
542 "-- envelope -- "
543 "---- relay/delivery --- "
544 "------- misc -------\n"
545 "curr conn disc "
546 "curr enq deq "
547 "ok tmpfail prmfail loop "
548 "expire remove bounce\n");
549 }
550 printf("%4zu %4zu %4zu "
551 "%4zu %4zu %4zu "
552 "%4zu %4zu %4zu %4zu "
553 "%4zu %4zu %4zu\n",
554 digest.clt_connect - digest.clt_disconnect,
555 digest.clt_connect - last.clt_connect,
556 digest.clt_disconnect - last.clt_disconnect,
557
558 digest.evp_enqueued - digest.evp_dequeued,
559 digest.evp_enqueued - last.evp_enqueued,
560 digest.evp_dequeued - last.evp_dequeued,
561
562 digest.dlv_ok - last.dlv_ok,
563 digest.dlv_tempfail - last.dlv_tempfail,
564 digest.dlv_permfail - last.dlv_permfail,
565 digest.dlv_loop - last.dlv_loop,
566
567 digest.evp_expired - last.evp_expired,
568 digest.evp_removed - last.evp_removed,
569 digest.evp_bounce - last.evp_bounce);
570
571 last = digest;
572 count++;
573 sleep(1);
574 }
575
576 return (0);
577}
578
579static int
580do_pause_envelope(int argc, struct parameter *argv)
581{
582 size_t total, ok;
583
584 srv_foreach_envelope(argv, IMSG_CTL_PAUSE_EVP, &total, &ok);
585 printf("%zu envelope%s paused\n", ok, (ok > 1) ? "s" : "");
586
587 return (0);
588}
589
590static int
591do_pause_mda(int argc, struct parameter *argv)
592{
593 srv_send(IMSG_CTL_PAUSE_MDA, NULL((void *)0), 0);
594 return srv_check_result(1);
595}
596
597static int
598do_pause_mta(int argc, struct parameter *argv)
599{
600 srv_send(IMSG_CTL_PAUSE_MTA, NULL((void *)0), 0);
601 return srv_check_result(1);
602}
603
604static int
605do_pause_smtp(int argc, struct parameter *argv)
606{
607 srv_send(IMSG_CTL_PAUSE_SMTP, NULL((void *)0), 0);
608 return srv_check_result(1);
609}
610
611static int
612do_profile(int argc, struct parameter *argv)
613{
614 int v;
615
616 v = str_to_profile(argv[0].u.u_str);
617
618 srv_send(IMSG_CTL_PROFILE_ENABLE, &v, sizeof(v));
619 return srv_check_result(1);
620}
621
622static int
623do_remove(int argc, struct parameter *argv)
624{
625 size_t total, ok;
626
627 srv_foreach_envelope(argv, IMSG_CTL_REMOVE, &total, &ok);
628 printf("%zu envelope%s removed\n", ok, (ok > 1) ? "s" : "");
629
630 return (0);
631}
632
633static int
634do_resume_envelope(int argc, struct parameter *argv)
635{
636 size_t total, ok;
637
638 srv_foreach_envelope(argv, IMSG_CTL_RESUME_EVP, &total, &ok);
639 printf("%zu envelope%s resumed\n", ok, (ok > 1) ? "s" : "");
640
641 return (0);
642}
643
644static int
645do_resume_mda(int argc, struct parameter *argv)
646{
647 srv_send(IMSG_CTL_RESUME_MDA, NULL((void *)0), 0);
648 return srv_check_result(1);
649}
650
651static int
652do_resume_mta(int argc, struct parameter *argv)
653{
654 srv_send(IMSG_CTL_RESUME_MTA, NULL((void *)0), 0);
655 return srv_check_result(1);
656}
657
658static int
659do_resume_route(int argc, struct parameter *argv)
660{
661 uint64_t v;
662
663 if (argc == 0)
664 v = 0;
665 else
666 v = argv[0].u.u_routeid;
667
668 srv_send(IMSG_CTL_RESUME_ROUTE, &v, sizeof(v));
669 return srv_check_result(1);
670}
671
672static int
673do_resume_smtp(int argc, struct parameter *argv)
674{
675 srv_send(IMSG_CTL_RESUME_SMTP, NULL((void *)0), 0);
676 return srv_check_result(1);
677}
678
679static int
680do_schedule(int argc, struct parameter *argv)
681{
682 size_t total, ok;
683
684 srv_foreach_envelope(argv, IMSG_CTL_SCHEDULE, &total, &ok);
685 printf("%zu envelope%s scheduled\n", ok, (ok > 1) ? "s" : "");
686
687 return (0);
688}
689
690static int
691do_show_envelope(int argc, struct parameter *argv)
692{
693 char buf[PATH_MAX1024];
694
695 if (!bsnprintf(buf, sizeof(buf), "%s%s/%02x/%08x/%016" PRIx64"llx",
696 PATH_SPOOL"/var/spool/smtpd",
697 PATH_QUEUE"/queue",
698 (evpid_to_msgid(argv[0].u.u_evpid) & 0xff000000) >> 24,
699 evpid_to_msgid(argv[0].u.u_evpid),
700 argv[0].u.u_evpid))
701 errx(1, "unable to retrieve envelope");
702
703 display(buf);
704
705 return (0);
706}
707
708static int
709do_show_hoststats(int argc, struct parameter *argv)
710{
711 srv_show_cmd(IMSG_CTL_MTA_SHOW_HOSTSTATS, NULL((void *)0), 0);
712
713 return (0);
714}
715
716static int
717do_show_message(int argc, struct parameter *argv)
718{
719 char buf[PATH_MAX1024];
720 uint32_t msgid;
721
722 if (argv[0].type == P_EVPID)
723 msgid = evpid_to_msgid(argv[0].u.u_evpid);
724 else
725 msgid = argv[0].u.u_msgid;
726
727 if (!bsnprintf(buf, sizeof(buf), "%s%s/%02x/%08x/message",
728 PATH_SPOOL"/var/spool/smtpd",
729 PATH_QUEUE"/queue",
730 (msgid & 0xff000000) >> 24,
731 msgid))
732 errx(1, "unable to retrieve message");
733
734 display(buf);
735
736 return (0);
737}
738
739static int
740do_show_queue(int argc, struct parameter *argv)
741{
742 struct envelope evp;
743 uint32_t msgid;
744 FTS *fts;
745 FTSENT *ftse;
746 char *qpath[] = {"/queue", NULL((void *)0)};
747 char *tmp;
748 uint64_t evpid;
749
750 now = time(NULL((void *)0));
751
752 if (!srv_connect()) {
1
Taking false branch
753 queue_init("fs", 0);
754 if (chroot(PATH_SPOOL"/var/spool/smtpd") == -1 || chdir("/") == -1)
755 err(1, "%s", PATH_SPOOL"/var/spool/smtpd");
756 fts = fts_open(qpath, FTS_PHYSICAL0x0010|FTS_NOCHDIR0x0004, NULL((void *)0));
757 if (fts == NULL((void *)0))
758 err(1, "%s/queue", PATH_SPOOL"/var/spool/smtpd");
759
760 while ((ftse = fts_read(fts)) != NULL((void *)0)) {
761 switch (ftse->fts_info) {
762 case FTS_DP6:
763 case FTS_DNR4:
764 break;
765 case FTS_F8:
766 tmp = NULL((void *)0);
767 evpid = strtoull(ftse->fts_name, &tmp, 16);
768 if (tmp && *tmp != '\0')
769 break;
770 show_offline_envelope(evpid);
771 }
772 }
773
774 fts_close(fts);
775 return (0);
776 }
777
778 if (argc == 0) {
2
Assuming 'argc' is not equal to 0
3
Taking false branch
779 msgid = 0;
780 while (srv_iter_messages(&msgid))
781 while (srv_iter_envelopes(msgid, &evp))
782 show_queue_envelope(&evp, 1);
783 } else if (argv[0].type == P_MSGID) {
4
Assuming field 'type' is equal to P_MSGID
5
Taking true branch
784 while (srv_iter_envelopes(argv[0].u.u_msgid, &evp))
6
Calling 'srv_iter_envelopes'
785 show_queue_envelope(&evp, 1);
786 }
787
788 return (0);
789}
790
791static int
792do_show_hosts(int argc, struct parameter *argv)
793{
794 srv_show_cmd(IMSG_CTL_MTA_SHOW_HOSTS, NULL((void *)0), 0);
795
796 return (0);
797}
798
799static int
800do_show_relays(int argc, struct parameter *argv)
801{
802 srv_show_cmd(IMSG_CTL_MTA_SHOW_RELAYS, NULL((void *)0), 0);
803
804 return (0);
805}
806
807static int
808do_show_routes(int argc, struct parameter *argv)
809{
810 srv_show_cmd(IMSG_CTL_MTA_SHOW_ROUTES, NULL((void *)0), 0);
811
812 return (0);
813}
814
815static int
816do_show_stats(int argc, struct parameter *argv)
817{
818 struct stat_kv kv;
819 time_t duration;
820
821 memset(&kv, 0, sizeof kv);
822
823 while (1) {
824 srv_send(IMSG_CTL_GET_STATS, &kv, sizeof kv);
825 srv_recv(IMSG_CTL_GET_STATS);
826 srv_read(&kv, sizeof(kv));
827 srv_end();
828
829 if (kv.iter == NULL((void *)0))
830 break;
831
832 if (strcmp(kv.key, "uptime") == 0) {
833 duration = time(NULL((void *)0)) - kv.val.u.counter;
834 printf("uptime=%lld\n", (long long)duration);
835 printf("uptime.human=%s\n",
836 duration_to_text(duration));
837 }
838 else {
839 switch (kv.val.type) {
840 case STAT_COUNTER:
841 printf("%s=%zd\n",
842 kv.key, kv.val.u.counter);
843 break;
844 case STAT_TIMESTAMP:
845 printf("%s=%" PRId64"lld" "\n",
846 kv.key, (int64_t)kv.val.u.timestamp);
847 break;
848 case STAT_TIMEVAL:
849 printf("%s=%lld.%lld\n",
850 kv.key, (long long)kv.val.u.tv.tv_sec,
851 (long long)kv.val.u.tv.tv_usec);
852 break;
853 case STAT_TIMESPEC:
854 printf("%s=%lld.%06ld\n",
855 kv.key,
856 (long long)kv.val.u.ts.tv_sec * 1000000 +
857 kv.val.u.ts.tv_nsec / 1000000,
858 kv.val.u.ts.tv_nsec % 1000000);
859 break;
860 }
861 }
862 }
863
864 return (0);
865}
866
867static int
868do_show_status(int argc, struct parameter *argv)
869{
870 uint32_t sc_flags;
871
872 srv_send(IMSG_CTL_SHOW_STATUS, NULL((void *)0), 0);
873 srv_recv(IMSG_CTL_SHOW_STATUS);
874 srv_read(&sc_flags, sizeof(sc_flags));
875 srv_end();
876 printf("MDA %s\n",
877 (sc_flags & SMTPD_MDA_PAUSED0x00000002) ? "paused" : "running");
878 printf("MTA %s\n",
879 (sc_flags & SMTPD_MTA_PAUSED0x00000004) ? "paused" : "running");
880 printf("SMTP %s\n",
881 (sc_flags & SMTPD_SMTP_PAUSED0x00000008) ? "paused" : "running");
882 return (0);
883}
884
885static int
886do_trace(int argc, struct parameter *argv)
887{
888 int v;
889
890 v = str_to_trace(argv[0].u.u_str);
891
892 srv_send(IMSG_CTL_TRACE_ENABLE, &v, sizeof(v));
893 return srv_check_result(1);
894}
895
896static int
897do_unprofile(int argc, struct parameter *argv)
898{
899 int v;
900
901 v = str_to_profile(argv[0].u.u_str);
902
903 srv_send(IMSG_CTL_PROFILE_DISABLE, &v, sizeof(v));
904 return srv_check_result(1);
905}
906
907static int
908do_untrace(int argc, struct parameter *argv)
909{
910 int v;
911
912 v = str_to_trace(argv[0].u.u_str);
913
914 srv_send(IMSG_CTL_TRACE_DISABLE, &v, sizeof(v));
915 return srv_check_result(1);
916}
917
918static int
919do_update_table(int argc, struct parameter *argv)
920{
921 const char *name = argv[0].u.u_str;
922
923 srv_send(IMSG_CTL_UPDATE_TABLE, name, strlen(name) + 1);
924 return srv_check_result(1);
925}
926
927static int
928do_encrypt(int argc, struct parameter *argv)
929{
930 const char *p = NULL((void *)0);
931
932 droppriv();
933
934 if (argv)
935 p = argv[0].u.u_str;
936 execl(PATH_ENCRYPT"/usr/bin/encrypt", "encrypt", "--", p, (char *)NULL((void *)0));
937 errx(1, "execl");
938}
939
940static int
941do_block_mta(int argc, struct parameter *argv)
942{
943 struct ibuf *m;
944
945 if (ibuf == NULL((void *)0) && !srv_connect())
946 errx(1, "smtpd doesn't seem to be running");
947 m = imsg_create(ibuf, IMSG_CTL_MTA_BLOCK, IMSG_VERSION16, 0,
948 sizeof(argv[0].u.u_ss) + strlen(argv[1].u.u_str) + 1);
949 if (imsg_add(m, &argv[0].u.u_ss, sizeof(argv[0].u.u_ss)) == -1)
950 errx(1, "imsg_add");
951 if (imsg_add(m, argv[1].u.u_str, strlen(argv[1].u.u_str) + 1) == -1)
952 errx(1, "imsg_add");
953 imsg_close(ibuf, m);
954
955 return srv_check_result(1);
956}
957
958static int
959do_unblock_mta(int argc, struct parameter *argv)
960{
961 struct ibuf *m;
962
963 if (ibuf == NULL((void *)0) && !srv_connect())
964 errx(1, "smtpd doesn't seem to be running");
965
966 m = imsg_create(ibuf, IMSG_CTL_MTA_UNBLOCK, IMSG_VERSION16, 0,
967 sizeof(argv[0].u.u_ss) + strlen(argv[1].u.u_str) + 1);
968 if (imsg_add(m, &argv[0].u.u_ss, sizeof(argv[0].u.u_ss)) == -1)
969 errx(1, "imsg_add");
970 if (imsg_add(m, argv[1].u.u_str, strlen(argv[1].u.u_str) + 1) == -1)
971 errx(1, "imsg_add");
972 imsg_close(ibuf, m);
973
974 return srv_check_result(1);
975}
976
977static int
978do_show_mta_block(int argc, struct parameter *argv)
979{
980 srv_show_cmd(IMSG_CTL_MTA_SHOW_BLOCK, NULL((void *)0), 0);
981
982 return (0);
983}
984
985static int
986do_discover(int argc, struct parameter *argv)
987{
988 uint64_t evpid;
989 uint32_t msgid;
990 size_t n_evp;
991
992 if (ibuf == NULL((void *)0) && !srv_connect())
993 errx(1, "smtpd doesn't seem to be running");
994
995 if (argv[0].type == P_EVPID) {
996 evpid = argv[0].u.u_evpid;
997 srv_send(IMSG_CTL_DISCOVER_EVPID, &evpid, sizeof evpid);
998 srv_recv(IMSG_CTL_DISCOVER_EVPID);
999 } else {
1000 msgid = argv[0].u.u_msgid;
1001 srv_send(IMSG_CTL_DISCOVER_MSGID, &msgid, sizeof msgid);
1002 srv_recv(IMSG_CTL_DISCOVER_MSGID);
1003 }
1004
1005 if (rlen == 0) {
1006 srv_end();
1007 return (0);
1008 } else {
1009 srv_read(&n_evp, sizeof n_evp);
1010 srv_end();
1011 }
1012
1013 printf("%zu envelope%s discovered\n", n_evp, (n_evp != 1) ? "s" : "");
1014 return (0);
1015}
1016
1017static int
1018do_spf_walk(int argc, struct parameter *argv)
1019{
1020 droppriv();
1021
1022 return spfwalk(argc, argv);
1023}
1024
1025#define cmd_install_priv(s, f)cmd_install((s), privileged ? (f) : do_permission_denied) \
1026 cmd_install((s), privileged ? (f) : do_permission_denied)
1027
1028int
1029main(int argc, char **argv)
1030{
1031 gid_t gid;
1032 int privileged;
1033 char *argv_mailq[] = { "show", "queue", NULL((void *)0) };
1034
1035 log_init(1, LOG_MAIL(2<<3));
1036
1037 sendmail_compat(argc, argv);
1038 privileged = geteuid() == 0;
1039
1040 gid = getgid();
1041 if (setresgid(gid, gid, gid) == -1)
1042 err(1, "setresgid");
1043
1044 /* Privileged commands */
1045 cmd_install_priv("discover <evpid>", do_discover)cmd_install(("discover <evpid>"), privileged ? (do_discover
) : do_permission_denied)
;
1046 cmd_install_priv("discover <msgid>", do_discover)cmd_install(("discover <msgid>"), privileged ? (do_discover
) : do_permission_denied)
;
1047 cmd_install_priv("pause mta from <addr> for <str>", do_block_mta)cmd_install(("pause mta from <addr> for <str>"), privileged
? (do_block_mta) : do_permission_denied)
;
1048 cmd_install_priv("resume mta from <addr> for <str>", do_unblock_mta)cmd_install(("resume mta from <addr> for <str>"),
privileged ? (do_unblock_mta) : do_permission_denied)
;
1049 cmd_install_priv("show mta paused", do_show_mta_block)cmd_install(("show mta paused"), privileged ? (do_show_mta_block
) : do_permission_denied)
;
1050 cmd_install_priv("log brief", do_log_brief)cmd_install(("log brief"), privileged ? (do_log_brief) : do_permission_denied
)
;
1051 cmd_install_priv("log verbose", do_log_verbose)cmd_install(("log verbose"), privileged ? (do_log_verbose) : do_permission_denied
)
;
1052 cmd_install_priv("monitor", do_monitor)cmd_install(("monitor"), privileged ? (do_monitor) : do_permission_denied
)
;
1053 cmd_install_priv("pause envelope <evpid>", do_pause_envelope)cmd_install(("pause envelope <evpid>"), privileged ? (do_pause_envelope
) : do_permission_denied)
;
1054 cmd_install_priv("pause envelope <msgid>", do_pause_envelope)cmd_install(("pause envelope <msgid>"), privileged ? (do_pause_envelope
) : do_permission_denied)
;
1055 cmd_install_priv("pause envelope all", do_pause_envelope)cmd_install(("pause envelope all"), privileged ? (do_pause_envelope
) : do_permission_denied)
;
1056 cmd_install_priv("pause mda", do_pause_mda)cmd_install(("pause mda"), privileged ? (do_pause_mda) : do_permission_denied
)
;
1057 cmd_install_priv("pause mta", do_pause_mta)cmd_install(("pause mta"), privileged ? (do_pause_mta) : do_permission_denied
)
;
1058 cmd_install_priv("pause smtp", do_pause_smtp)cmd_install(("pause smtp"), privileged ? (do_pause_smtp) : do_permission_denied
)
;
1059 cmd_install_priv("profile <str>", do_profile)cmd_install(("profile <str>"), privileged ? (do_profile
) : do_permission_denied)
;
1060 cmd_install_priv("remove <evpid>", do_remove)cmd_install(("remove <evpid>"), privileged ? (do_remove
) : do_permission_denied)
;
1061 cmd_install_priv("remove <msgid>", do_remove)cmd_install(("remove <msgid>"), privileged ? (do_remove
) : do_permission_denied)
;
1062 cmd_install_priv("remove all", do_remove)cmd_install(("remove all"), privileged ? (do_remove) : do_permission_denied
)
;
1063 cmd_install_priv("resume envelope <evpid>", do_resume_envelope)cmd_install(("resume envelope <evpid>"), privileged ? (
do_resume_envelope) : do_permission_denied)
;
1064 cmd_install_priv("resume envelope <msgid>", do_resume_envelope)cmd_install(("resume envelope <msgid>"), privileged ? (
do_resume_envelope) : do_permission_denied)
;
1065 cmd_install_priv("resume envelope all", do_resume_envelope)cmd_install(("resume envelope all"), privileged ? (do_resume_envelope
) : do_permission_denied)
;
1066 cmd_install_priv("resume mda", do_resume_mda)cmd_install(("resume mda"), privileged ? (do_resume_mda) : do_permission_denied
)
;
1067 cmd_install_priv("resume mta", do_resume_mta)cmd_install(("resume mta"), privileged ? (do_resume_mta) : do_permission_denied
)
;
1068 cmd_install_priv("resume route <routeid>", do_resume_route)cmd_install(("resume route <routeid>"), privileged ? (do_resume_route
) : do_permission_denied)
;
1069 cmd_install_priv("resume smtp", do_resume_smtp)cmd_install(("resume smtp"), privileged ? (do_resume_smtp) : do_permission_denied
)
;
1070 cmd_install_priv("schedule <msgid>", do_schedule)cmd_install(("schedule <msgid>"), privileged ? (do_schedule
) : do_permission_denied)
;
1071 cmd_install_priv("schedule <evpid>", do_schedule)cmd_install(("schedule <evpid>"), privileged ? (do_schedule
) : do_permission_denied)
;
1072 cmd_install_priv("schedule all", do_schedule)cmd_install(("schedule all"), privileged ? (do_schedule) : do_permission_denied
)
;
1073 cmd_install_priv("show envelope <evpid>", do_show_envelope)cmd_install(("show envelope <evpid>"), privileged ? (do_show_envelope
) : do_permission_denied)
;
1074 cmd_install_priv("show hoststats", do_show_hoststats)cmd_install(("show hoststats"), privileged ? (do_show_hoststats
) : do_permission_denied)
;
1075 cmd_install_priv("show message <msgid>", do_show_message)cmd_install(("show message <msgid>"), privileged ? (do_show_message
) : do_permission_denied)
;
1076 cmd_install_priv("show message <evpid>", do_show_message)cmd_install(("show message <evpid>"), privileged ? (do_show_message
) : do_permission_denied)
;
1077 cmd_install_priv("show queue", do_show_queue)cmd_install(("show queue"), privileged ? (do_show_queue) : do_permission_denied
)
;
1078 cmd_install_priv("show queue <msgid>", do_show_queue)cmd_install(("show queue <msgid>"), privileged ? (do_show_queue
) : do_permission_denied)
;
1079 cmd_install_priv("show hosts", do_show_hosts)cmd_install(("show hosts"), privileged ? (do_show_hosts) : do_permission_denied
)
;
1080 cmd_install_priv("show relays", do_show_relays)cmd_install(("show relays"), privileged ? (do_show_relays) : do_permission_denied
)
;
1081 cmd_install_priv("show routes", do_show_routes)cmd_install(("show routes"), privileged ? (do_show_routes) : do_permission_denied
)
;
1082 cmd_install_priv("show stats", do_show_stats)cmd_install(("show stats"), privileged ? (do_show_stats) : do_permission_denied
)
;
1083 cmd_install_priv("show status", do_show_status)cmd_install(("show status"), privileged ? (do_show_status) : do_permission_denied
)
;
1084 cmd_install_priv("trace <str>", do_trace)cmd_install(("trace <str>"), privileged ? (do_trace) : do_permission_denied
)
;
1085 cmd_install_priv("unprofile <str>", do_unprofile)cmd_install(("unprofile <str>"), privileged ? (do_unprofile
) : do_permission_denied)
;
1086 cmd_install_priv("untrace <str>", do_untrace)cmd_install(("untrace <str>"), privileged ? (do_untrace
) : do_permission_denied)
;
1087 cmd_install_priv("update table <str>", do_update_table)cmd_install(("update table <str>"), privileged ? (do_update_table
) : do_permission_denied)
;
1088
1089 /* Unprivileged commands */
1090 cmd_install("encrypt", do_encrypt);
1091 cmd_install("encrypt <str>", do_encrypt);
1092 cmd_install("spf walk", do_spf_walk);
1093
1094 if (strcmp(__progname, "mailq") == 0)
1095 return cmd_run(2, argv_mailq);
1096 if (strcmp(__progname, "smtpctl") == 0)
1097 return cmd_run(argc - 1, argv + 1);
1098
1099 errx(1, "unsupported mode");
1100 return (0);
1101}
1102
1103void
1104sendmail_compat(int argc, char **argv)
1105{
1106 FILE *offlinefp = NULL((void *)0);
1107 gid_t gid;
1108 int i, r;
1109
1110 if (strcmp(__progname, "sendmail") == 0 ||
1111 strcmp(__progname, "send-mail") == 0) {
1112 /*
1113 * determine whether we are called with flags
1114 * that should invoke makemap/newaliases.
1115 */
1116 for (i = 1; i < argc; i++)
1117 if (strncmp(argv[i], "-bi", 3) == 0)
1118 exit(makemap(P_SENDMAIL0, argc, argv));
1119
1120 if (!srv_connect())
1121 offlinefp = offline_file();
1122
1123 gid = getgid();
1124 if (setresgid(gid, gid, gid) == -1)
1125 err(1, "setresgid");
1126
1127 /* we'll reduce further down the road */
1128 if (pledge("stdio rpath wpath cpath tmppath flock "
1129 "dns getpw recvfd", NULL((void *)0)) == -1)
1130 err(1, "pledge");
1131
1132 sendmail = 1;
1133 exit(enqueue(argc, argv, offlinefp));
1134 } else if (strcmp(__progname, "makemap") == 0)
1135 exit(makemap(P_MAKEMAP2, argc, argv));
1136 else if (strcmp(__progname, "newaliases") == 0) {
1137 r = makemap(P_NEWALIASES1, argc, argv);
1138 /*
1139 * if server is available, notify of table update.
1140 * only makes sense for static tables AND if server is up.
1141 */
1142 if (srv_connect()) {
1143 srv_send(IMSG_CTL_UPDATE_TABLE, "aliases", strlen("aliases") + 1);
1144 srv_check_result(0);
1145 }
1146 exit(r);
1147 }
1148}
1149
1150static void
1151show_queue_envelope(struct envelope *e, int online)
1152{
1153 const char *src = "?", *agent = "?";
1154 char status[128], runstate[128], errline[LINE_MAX2048];
1155
1156 status[0] = '\0';
1157
1158 getflag(&e->flags, EF_BOUNCE, "bounce", status, sizeof(status));
1159 getflag(&e->flags, EF_AUTHENTICATED, "auth", status, sizeof(status));
1160 getflag(&e->flags, EF_INTERNAL, "internal", status, sizeof(status));
1161 getflag(&e->flags, EF_SUSPEND, "suspend", status, sizeof(status));
1162 getflag(&e->flags, EF_HOLD, "hold", status, sizeof(status));
1163
1164 if (online) {
1165 if (e->flags & EF_PENDING)
1166 (void)snprintf(runstate, sizeof runstate, "pending|%zd",
1167 (ssize_t)(e->nexttry - now));
1168 else if (e->flags & EF_INFLIGHT)
1169 (void)snprintf(runstate, sizeof runstate,
1170 "inflight|%zd", (ssize_t)(now - e->lasttry));
1171 else
1172 (void)snprintf(runstate, sizeof runstate, "invalid|");
1173 e->flags &= ~(EF_PENDING|EF_INFLIGHT);
1174 }
1175 else
1176 (void)strlcpy(runstate, "offline|", sizeof runstate);
1177
1178 if (e->flags)
1179 errx(1, "%016" PRIx64"llx" ": unexpected flags 0x%04x", e->id,
1180 e->flags);
1181
1182 if (status[0])
1183 status[strlen(status) - 1] = '\0';
1184
1185 if (e->type == D_MDA)
1186 agent = "mda";
1187 else if (e->type == D_MTA)
1188 agent = "mta";
1189 else if (e->type == D_BOUNCE)
1190 agent = "bounce";
1191
1192 if (e->ss.ss_family == AF_LOCAL1)
1193 src = "local";
1194 else if (e->ss.ss_family == AF_INET2)
1195 src = "inet4";
1196 else if (e->ss.ss_family == AF_INET624)
1197 src = "inet6";
1198
1199 strnvis(errline, e->errorline, sizeof(errline), 0);
1200
1201 printf("%016"PRIx64"llx"
1202 "|%s|%s|%s|%s@%s|%s@%s|%s@%s"
1203 "|%zu|%zu|%zu|%zu|%s|%s\n",
1204
1205 e->id,
1206
1207 src,
1208 agent,
1209 status,
1210 e->sender.user, e->sender.domain,
1211 e->rcpt.user, e->rcpt.domain,
1212 e->dest.user, e->dest.domain,
1213
1214 (size_t) e->creation,
1215 (size_t) (e->creation + e->ttl),
1216 (size_t) e->lasttry,
1217 (size_t) e->retry,
1218 runstate,
1219 errline);
1220}
1221
1222static void
1223getflag(uint *bitmap, int bit, char *bitstr, char *buf, size_t len)
1224{
1225 if (*bitmap & bit) {
1226 *bitmap &= ~bit;
1227 (void)strlcat(buf, bitstr, len);
1228 (void)strlcat(buf, ",", len);
1229 }
1230}
1231
1232static void
1233show_offline_envelope(uint64_t evpid)
1234{
1235 FILE *fp = NULL((void *)0);
1236 char pathname[PATH_MAX1024];
1237 size_t plen;
1238 char *p;
1239 size_t buflen;
1240 char buffer[sizeof(struct envelope)];
1241
1242 struct envelope evp;
1243
1244 if (!bsnprintf(pathname, sizeof pathname,
1245 "/queue/%02x/%08x/%016"PRIx64"llx",
1246 (evpid_to_msgid(evpid) & 0xff000000) >> 24,
1247 evpid_to_msgid(evpid), evpid))
1248 goto end;
1249 fp = fopen(pathname, "r");
1250 if (fp == NULL((void *)0))
1251 goto end;
1252
1253 buflen = fread(buffer, 1, sizeof (buffer) - 1, fp);
1254 p = buffer;
1255 plen = buflen;
1256 buffer[buflen] = '\0';
1257
1258 if (is_encrypted_buffer(p)) {
1259 warnx("offline encrypted queue is not supported yet");
1260 goto end;
1261 }
1262
1263 if (is_gzip_buffer(p)) {
1264 warnx("offline compressed queue is not supported yet");
1265 goto end;
1266 }
1267
1268 if (!envelope_load_buffer(&evp, p, plen))
1269 goto end;
1270 evp.id = evpid;
1271 show_queue_envelope(&evp, 0);
1272
1273end:
1274 if (fp)
1275 fclose(fp);
1276}
1277
1278static void
1279display(const char *s)
1280{
1281 FILE *fp;
1282 char *key;
1283 int gzipped;
1284 char *gzcat_argv0 = strrchr(PATH_GZCAT"/usr/bin/gzcat", '/') + 1;
1285
1286 if ((fp = fopen(s, "r")) == NULL((void *)0))
1287 err(1, "fopen");
1288
1289 if (is_encrypted_fp(fp)) {
1290 int i;
1291 FILE *ofp = NULL((void *)0);
1292
1293 if ((ofp = tmpfile()) == NULL((void *)0))
1294 err(1, "tmpfile");
1295
1296 for (i = 0; i < 3; i++) {
1297 key = getpass("key> ");
1298 if (crypto_setup(key, strlen(key)))
1299 break;
1300 }
1301 if (i == 3)
1302 errx(1, "crypto-setup: invalid key");
1303
1304 if (!crypto_decrypt_file(fp, ofp)) {
1305 printf("object is encrypted: %s\n", key);
1306 exit(1);
1307 }
1308
1309 fclose(fp);
1310 fp = ofp;
1311 fseek(fp, 0, SEEK_SET0);
1312 }
1313 gzipped = is_gzip_fp(fp);
1314
1315 lseek(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), 0, SEEK_SET0);
1316 (void)dup2(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), STDIN_FILENO0);
1317 if (gzipped)
1318 execl(PATH_GZCAT"/usr/bin/gzcat", gzcat_argv0, (char *)NULL((void *)0));
1319 else
1320 execl(PATH_CAT"/bin/cat", "cat", (char *)NULL((void *)0));
1321 err(1, "execl");
1322}
1323
1324static int
1325str_to_trace(const char *str)
1326{
1327 if (!strcmp(str, "imsg"))
1328 return TRACE_IMSG0x0002;
1329 if (!strcmp(str, "io"))
1330 return TRACE_IO0x0004;
1331 if (!strcmp(str, "smtp"))
1332 return TRACE_SMTP0x0008;
1333 if (!strcmp(str, "filters"))
1334 return TRACE_FILTERS0x0010;
1335 if (!strcmp(str, "mta"))
1336 return TRACE_MTA0x0020;
1337 if (!strcmp(str, "bounce"))
1338 return TRACE_BOUNCE0x0040;
1339 if (!strcmp(str, "scheduler"))
1340 return TRACE_SCHEDULER0x0080;
1341 if (!strcmp(str, "lookup"))
1342 return TRACE_LOOKUP0x0100;
1343 if (!strcmp(str, "stat"))
1344 return TRACE_STAT0x0200;
1345 if (!strcmp(str, "rules"))
1346 return TRACE_RULES0x0400;
1347 if (!strcmp(str, "mproc"))
1348 return TRACE_MPROC0x0800;
1349 if (!strcmp(str, "expand"))
1350 return TRACE_EXPAND0x1000;
1351 if (!strcmp(str, "all"))
1352 return ~TRACE_DEBUG0x0001;
1353 errx(1, "invalid trace keyword: %s", str);
1354 return (0);
1355}
1356
1357static int
1358str_to_profile(const char *str)
1359{
1360 if (!strcmp(str, "imsg"))
1361 return PROFILE_IMSG0x0002;
1362 if (!strcmp(str, "queue"))
1363 return PROFILE_QUEUE0x0004;
1364 errx(1, "invalid profile keyword: %s", str);
1365 return (0);
1366}
1367
1368static int
1369is_gzip_buffer(const char *buffer)
1370{
1371 uint16_t magic;
1372
1373 memcpy(&magic, buffer, sizeof magic);
1374#define GZIP_MAGIC0x8b1f 0x8b1f
1375 return (magic == GZIP_MAGIC0x8b1f);
1376}
1377
1378static int
1379is_gzip_fp(FILE *fp)
1380{
1381 uint8_t magic[2];
1382 int ret = 0;
1383
1384 if (fread(&magic, 1, sizeof magic, fp) != sizeof magic)
1385 goto end;
1386
1387 ret = is_gzip_buffer((const char *)&magic);
1388end:
1389 fseek(fp, 0, SEEK_SET0);
1390 return ret;
1391}
1392
1393
1394/* XXX */
1395/*
1396 * queue supports transparent encryption.
1397 * encrypted chunks are prefixed with an API version byte
1398 * which we ensure is unambiguous with gzipped / plain
1399 * objects.
1400 */
1401
1402static int
1403is_encrypted_buffer(const char *buffer)
1404{
1405 uint8_t magic;
1406
1407 magic = *buffer;
1408#define ENCRYPTION_MAGIC0x1 0x1
1409 return (magic == ENCRYPTION_MAGIC0x1);
1410}
1411
1412static int
1413is_encrypted_fp(FILE *fp)
1414{
1415 uint8_t magic;
1416 int ret = 0;
1417
1418 if (fread(&magic, 1, sizeof magic, fp) != sizeof magic)
1419 goto end;
1420
1421 ret = is_encrypted_buffer((const char *)&magic);
1422end:
1423 fseek(fp, 0, SEEK_SET0);
1424 return ret;
1425}