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