Bug Summary

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