xref: /netbsd/usr.bin/mail/mime_child.c (revision 517295dd)
1*517295ddSchristos /*	$NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $	*/
28207b28aSchristos 
38207b28aSchristos /*-
48207b28aSchristos  * Copyright (c) 2006 The NetBSD Foundation, Inc.
58207b28aSchristos  * All rights reserved.
68207b28aSchristos  *
78207b28aSchristos  * This code is derived from software contributed to The NetBSD Foundation
88207b28aSchristos  * by Anon Ymous.
98207b28aSchristos  *
108207b28aSchristos  * Redistribution and use in source and binary forms, with or without
118207b28aSchristos  * modification, are permitted provided that the following conditions
128207b28aSchristos  * are met:
138207b28aSchristos  * 1. Redistributions of source code must retain the above copyright
148207b28aSchristos  *    notice, this list of conditions and the following disclaimer.
158207b28aSchristos  * 2. Redistributions in binary form must reproduce the above copyright
168207b28aSchristos  *    notice, this list of conditions and the following disclaimer in the
178207b28aSchristos  *    documentation and/or other materials provided with the distribution.
188207b28aSchristos  *
198207b28aSchristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208207b28aSchristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218207b28aSchristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228207b28aSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238207b28aSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248207b28aSchristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258207b28aSchristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268207b28aSchristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278207b28aSchristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288207b28aSchristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298207b28aSchristos  * POSSIBILITY OF SUCH DAMAGE.
308207b28aSchristos  */
318207b28aSchristos 
328207b28aSchristos 
338207b28aSchristos #ifdef MIME_SUPPORT
348207b28aSchristos 
358207b28aSchristos #include <sys/cdefs.h>
368207b28aSchristos #ifndef __lint__
37*517295ddSchristos __RCSID("$NetBSD: mime_child.c,v 1.10 2019/12/14 20:21:43 christos Exp $");
388207b28aSchristos #endif /* not __lint__ */
398207b28aSchristos 
408207b28aSchristos #include <assert.h>
418207b28aSchristos #include <fcntl.h>
428207b28aSchristos #include <signal.h>
438207b28aSchristos #include <stdio.h>
448207b28aSchristos #include <stdlib.h>
458207b28aSchristos #include <unistd.h>
468207b28aSchristos 
478207b28aSchristos #include "def.h"
488207b28aSchristos #include "extern.h"
498207b28aSchristos 
508207b28aSchristos #ifdef MIME_SUPPORT
518207b28aSchristos #include "mime.h"
528207b28aSchristos #include "mime_child.h"
538207b28aSchristos #endif
548207b28aSchristos 
558207b28aSchristos /*
568207b28aSchristos  * This module contains the core routines used by mime modules that
578207b28aSchristos  * need to fork children.  Nothing else in the mime modules should be
588207b28aSchristos  * doing a pipe(), fork(), or a call to any popen functions that do.
598207b28aSchristos  * These routines are tied to the file registry in popen.c and hence
608207b28aSchristos  * share much of popen code.
618207b28aSchristos  */
628207b28aSchristos 
638207b28aSchristos #define READ 0
648207b28aSchristos #define WRITE 1
658207b28aSchristos 
668207b28aSchristos static int
get_cmd_flags(const char * cmd,const char ** cmd_start)678207b28aSchristos get_cmd_flags(const char *cmd, const char **cmd_start)
688207b28aSchristos {
698207b28aSchristos 	const char *cp;
708207b28aSchristos 	int flags;
718207b28aSchristos 
728207b28aSchristos 	flags = 0;
738207b28aSchristos 	for (cp = cmd; cp && *cp; cp++)
748207b28aSchristos 		switch (*cp) {
758207b28aSchristos 		case '+':
768207b28aSchristos 			flags |= CMD_FLAG_ALTERNATIVE;
778207b28aSchristos 			break;
788207b28aSchristos 		case '-':
798207b28aSchristos 			flags |= CMD_FLAG_NO_DECODE;
808207b28aSchristos 			break;
818207b28aSchristos 		case '!':
828207b28aSchristos 			flags |= CMD_FLAG_SHELLCMD;
838207b28aSchristos 			break;
848207b28aSchristos 		default:
858207b28aSchristos 			goto done;
868207b28aSchristos 		}
878207b28aSchristos  done:
888207b28aSchristos 	if (cmd_start)
898207b28aSchristos 		*cmd_start = cp;
908207b28aSchristos 
918207b28aSchristos 	return flags;
928207b28aSchristos }
938207b28aSchristos 
948207b28aSchristos 
958207b28aSchristos static int
prepare_pipe(sigset_t * nset,int p[2])968207b28aSchristos prepare_pipe(sigset_t *nset, int p[2])
978207b28aSchristos {
98674e12d2Schristos 	if (pipe2(p, O_CLOEXEC) == -1)
998207b28aSchristos 		return -1;
1008207b28aSchristos 
1018207b28aSchristos 	/*
1028207b28aSchristos 	 * We _must_ ignore SIGINT and SIGPIPE or the child
1038207b28aSchristos 	 * will end up in our earlier handlers.
1048207b28aSchristos 	 */
105c77cd738Schristos 	(void)sigemptyset(nset);
106c77cd738Schristos 	(void)sigaddset(nset, SIGINT);
107c77cd738Schristos 	(void)sigaddset(nset, SIGPIPE);
10875df0a78Schristos 	(void)sigaddset(nset, SIGHUP);
10975df0a78Schristos 	(void)sigaddset(nset, SIGTSTP);
11075df0a78Schristos 	(void)sigaddset(nset, SIGTTOU);
11175df0a78Schristos 	(void)sigaddset(nset, SIGTTIN);
11275df0a78Schristos 
1138207b28aSchristos 	return 0;
1148207b28aSchristos }
1158207b28aSchristos 
1168207b28aSchristos 
1178207b28aSchristos PUBLIC int
mime_run_command(const char * cmd,FILE * fo)1188207b28aSchristos mime_run_command(const char *cmd, FILE *fo)
1198207b28aSchristos {
1208207b28aSchristos 	sigset_t nset;
1218207b28aSchristos 	FILE *nfo;
1228207b28aSchristos 	pid_t pid;
1238207b28aSchristos 	int p[2];
1248207b28aSchristos 	int flags;
1258207b28aSchristos 
1268207b28aSchristos 	if (cmd == NULL)
1278207b28aSchristos 		return 0;
1288207b28aSchristos 
1298207b28aSchristos 	flags = get_cmd_flags(cmd, &cmd);
1308207b28aSchristos 	if (fo == NULL)		/* no output file, just return the flags! */
1318207b28aSchristos 		return flags;
1328207b28aSchristos 
1338207b28aSchristos 	if ((flags & CMD_FLAG_SHELLCMD) != 0) {	/* run command under the shell */
1348207b28aSchristos 		char *cp;
1358207b28aSchristos 		char *shellcmd;
136f3098750Schristos 		if ((shellcmd = value(ENAME_SHELL)) == NULL)
1378207b28aSchristos 			shellcmd = __UNCONST(_PATH_CSHELL);
138f3098750Schristos 		(void)sasprintf(&cp, "%s -c '%s'", shellcmd, cmd);
139f3098750Schristos 		cmd = cp;
1408207b28aSchristos 	}
1418207b28aSchristos 	if (prepare_pipe(&nset, p) != 0) {
1428207b28aSchristos 		warn("mime_run_command: prepare_pipe");
1438207b28aSchristos 		return flags;	/* XXX - this or -1? */
1448207b28aSchristos 	}
1458207b28aSchristos 	flush_files(fo, 0); /* flush fo, all registered files, and stdout */
1468207b28aSchristos 
1478207b28aSchristos 	switch (pid = start_command(cmd, &nset, p[READ], fileno(fo), NULL)) {
1488207b28aSchristos 	case -1:	/* error */
1498207b28aSchristos 		/* start_command already did a warn(). */
1508207b28aSchristos 		warnx("mime_run_command: %s", cmd); /* tell a bit more */
1518207b28aSchristos 		(void)close(p[READ]);
1528207b28aSchristos 		(void)close(p[WRITE]);
1538207b28aSchristos 		return flags;			/* XXX - this or -1? */
1548207b28aSchristos 
1558207b28aSchristos 	case 0:		/* child */
1568207b28aSchristos 		assert(/*CONSTCOND*/ 0);	/* a real coding error! */
1578207b28aSchristos 		/* NOTREACHED */
1588207b28aSchristos 
1598207b28aSchristos 	default:	/* parent */
1608207b28aSchristos 		(void)close(p[READ]);
1618207b28aSchristos 
162*517295ddSchristos 		nfo = fdopen(p[WRITE], "we");
1638207b28aSchristos 		if (nfo == NULL) {
1648207b28aSchristos 			warn("mime_run_command: fdopen");
1658207b28aSchristos 			(void)close(p[WRITE]);
1668207b28aSchristos 			warn("fdopen");
1678207b28aSchristos 			return flags;
1688207b28aSchristos 		}
1698207b28aSchristos 		register_file(nfo, 1, pid);
1708207b28aSchristos 		return flags;
1718207b28aSchristos 	}
1728207b28aSchristos }
1738207b28aSchristos 
1748207b28aSchristos 
1758207b28aSchristos PUBLIC void
mime_run_function(void (* fn)(FILE *,FILE *,void *),FILE * fo,void * cookie)1768207b28aSchristos mime_run_function(void (*fn)(FILE *, FILE *, void *), FILE *fo, void *cookie)
1778207b28aSchristos {
1788207b28aSchristos 	sigset_t nset;
1798207b28aSchristos 	FILE *nfo;
1808207b28aSchristos 	pid_t pid;
1818207b28aSchristos 	int p[2];
1828207b28aSchristos 
1838207b28aSchristos 	if (prepare_pipe(&nset, p) != 0) {
1848207b28aSchristos 		warn("mime_run_function: pipe");
1858207b28aSchristos 		return;
1868207b28aSchristos 	}
1878207b28aSchristos 	flush_files(fo, 0); /* flush fo, all registered files, and stdout */
1888207b28aSchristos 
1898207b28aSchristos 	switch (pid = fork()) {
1908207b28aSchristos 	case -1:	/* error */
1918207b28aSchristos 		warn("mime_run_function: fork");
1928207b28aSchristos 		(void)close(p[READ]);
1938207b28aSchristos 		(void)close(p[WRITE]);
1948207b28aSchristos 		return;
1958207b28aSchristos 
1968207b28aSchristos 	case 0:		/* child */
1978207b28aSchristos 		(void)close(p[WRITE]);
1988207b28aSchristos 		prepare_child(&nset, p[READ], fileno(fo));
1998207b28aSchristos 		fn(stdin, stdout, cookie);
2008207b28aSchristos 		(void)fflush(stdout);
2018207b28aSchristos 		_exit(0);
2028207b28aSchristos 		/* NOTREACHED */
2038207b28aSchristos 
2048207b28aSchristos 	default:	/* parent */
2058207b28aSchristos 		(void)close(p[READ]);
206*517295ddSchristos 		nfo = fdopen(p[WRITE], "we");
2078207b28aSchristos 		if (nfo == NULL) {
2088207b28aSchristos 			warn("run_function: fdopen");
2098207b28aSchristos 			(void)close(p[WRITE]);
2108207b28aSchristos 			return;
2118207b28aSchristos 		}
2128207b28aSchristos 		register_file(nfo, 1, pid);
2138207b28aSchristos 		return;
2148207b28aSchristos 	}
2158207b28aSchristos }
2168207b28aSchristos 
2178207b28aSchristos #endif /* MIME_SUPPORT */
218