xref: /freebsd/usr.sbin/ppp/exec.c (revision fb11a9c23d3da57e67bc474faa1ba0e55899d7b8)
15d9e6103SBrian Somers /*-
25d9e6103SBrian Somers  * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
35d9e6103SBrian Somers  * All rights reserved.
45d9e6103SBrian Somers  *
55d9e6103SBrian Somers  * Redistribution and use in source and binary forms, with or without
65d9e6103SBrian Somers  * modification, are permitted provided that the following conditions
75d9e6103SBrian Somers  * are met:
85d9e6103SBrian Somers  * 1. Redistributions of source code must retain the above copyright
95d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer.
105d9e6103SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
115d9e6103SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
125d9e6103SBrian Somers  *    documentation and/or other materials provided with the distribution.
135d9e6103SBrian Somers  *
145d9e6103SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155d9e6103SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165d9e6103SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175d9e6103SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185d9e6103SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195d9e6103SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205d9e6103SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215d9e6103SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225d9e6103SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235d9e6103SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245d9e6103SBrian Somers  * SUCH DAMAGE.
255d9e6103SBrian Somers  *
2697d92980SPeter Wemm  * $FreeBSD$
275d9e6103SBrian Somers  */
285d9e6103SBrian Somers 
295d9e6103SBrian Somers #include <sys/param.h>
305d9e6103SBrian Somers #include <sys/socket.h>
315d9e6103SBrian Somers #include <sys/un.h>
325d9e6103SBrian Somers 
335d9e6103SBrian Somers #include <errno.h>
345d9e6103SBrian Somers #include <fcntl.h>
355d9e6103SBrian Somers #include <stdio.h>
365d9e6103SBrian Somers #include <stdlib.h>
375d9e6103SBrian Somers #include <string.h>
385d9e6103SBrian Somers #include <sys/wait.h>
39f5a99677SBrian Somers #include <sys/uio.h>
405d9e6103SBrian Somers #include <termios.h>
415d9e6103SBrian Somers #include <unistd.h>
425d9e6103SBrian Somers 
435d9e6103SBrian Somers #include "layer.h"
445d9e6103SBrian Somers #include "defs.h"
455d9e6103SBrian Somers #include "mbuf.h"
465d9e6103SBrian Somers #include "log.h"
475d9e6103SBrian Somers #include "timer.h"
485d9e6103SBrian Somers #include "lqr.h"
495d9e6103SBrian Somers #include "hdlc.h"
505d9e6103SBrian Somers #include "throughput.h"
515d9e6103SBrian Somers #include "fsm.h"
525d9e6103SBrian Somers #include "lcp.h"
535d9e6103SBrian Somers #include "ccp.h"
545d9e6103SBrian Somers #include "link.h"
555d9e6103SBrian Somers #include "async.h"
565d9e6103SBrian Somers #include "descriptor.h"
575d9e6103SBrian Somers #include "physical.h"
585d9e6103SBrian Somers #include "mp.h"
595d9e6103SBrian Somers #include "chat.h"
605d9e6103SBrian Somers #include "command.h"
615d9e6103SBrian Somers #include "auth.h"
625d9e6103SBrian Somers #include "chap.h"
635d9e6103SBrian Somers #include "cbcp.h"
645d9e6103SBrian Somers #include "datalink.h"
65e7d008b4SBrian Somers #include "id.h"
665d9e6103SBrian Somers #include "exec.h"
675d9e6103SBrian Somers 
686815097bSBrian Somers static struct device execdevice = {
696815097bSBrian Somers   EXEC_DEVICE,
706815097bSBrian Somers   "exec",
71c8b9fb53SBrian Somers   0,
72fdc29d54SBrian Somers   { CD_NOTREQUIRED, 0 },
736815097bSBrian Somers   NULL,
746815097bSBrian Somers   NULL,
756815097bSBrian Somers   NULL,
766815097bSBrian Somers   NULL,
776815097bSBrian Somers   NULL,
786815097bSBrian Somers   NULL,
796815097bSBrian Somers   NULL,
806815097bSBrian Somers   NULL,
816815097bSBrian Somers   NULL,
82eb6e5e05SBrian Somers   NULL,
8387c3786eSBrian Somers   NULL,
84fb11a9c2SBrian Somers   NULL,
856815097bSBrian Somers   NULL
866815097bSBrian Somers };
876815097bSBrian Somers 
886815097bSBrian Somers struct device *
896815097bSBrian Somers exec_iov2device(int type, struct physical *p, struct iovec *iov,
9087c3786eSBrian Somers                 int *niov, int maxiov, int *auxfd, int *nauxfd)
915d9e6103SBrian Somers {
92acbd1f00SBrian Somers   if (type == EXEC_DEVICE) {
93f5a99677SBrian Somers     free(iov[(*niov)++].iov_base);
94a1bc3dccSBrian Somers     physical_SetupStack(p, execdevice.name, PHYSICAL_NOFORCE);
956815097bSBrian Somers     return &execdevice;
96acbd1f00SBrian Somers   }
976815097bSBrian Somers 
986815097bSBrian Somers   return NULL;
996815097bSBrian Somers }
1006815097bSBrian Somers 
1016815097bSBrian Somers struct device *
1026815097bSBrian Somers exec_Create(struct physical *p)
1036815097bSBrian Somers {
1046815097bSBrian Somers   if (p->fd < 0 && *p->name.full == '!') {
105d9626e94SBrian Somers     int fids[2], type;
1065d9e6103SBrian Somers 
10787c3786eSBrian Somers     p->fd--;	/* We own the device but maybe can't use it - change fd */
108d9626e94SBrian Somers     type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM;
10987c3786eSBrian Somers 
110d9626e94SBrian Somers     if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0)
1115d9e6103SBrian Somers       log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
1125d9e6103SBrian Somers                  strerror(errno));
1135d9e6103SBrian Somers     else {
11407e4efadSBrian Somers       static int child_status;		/* This variable is abused ! */
115d9626e94SBrian Somers       int stat, argc, i, ret, wret, pidpipe[2];
1168fb106c6SBrian Somers       pid_t pid, realpid;
1175d9e6103SBrian Somers       char *argv[MAXARGS];
1185d9e6103SBrian Somers 
1195d9e6103SBrian Somers       stat = fcntl(fids[0], F_GETFL, 0);
1205d9e6103SBrian Somers       if (stat > 0) {
1215d9e6103SBrian Somers         stat |= O_NONBLOCK;
1225d9e6103SBrian Somers         fcntl(fids[0], F_SETFL, stat);
1235d9e6103SBrian Somers       }
1248fb106c6SBrian Somers       realpid = getpid();
125d9626e94SBrian Somers       if (pipe(pidpipe) == -1) {
126d9626e94SBrian Somers         log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n",
1275d9e6103SBrian Somers                    strerror(errno));
1283ce91245SBrian Somers         close(fids[1]);
129d9626e94SBrian Somers       } else switch ((pid = fork())) {
130d9626e94SBrian Somers         case -1:
131d9626e94SBrian Somers           log_Printf(LogPHASE, "Unable to fork for line exec: %s\n",
132d9626e94SBrian Somers                      strerror(errno));
133d9626e94SBrian Somers           close(pidpipe[0]);
134d9626e94SBrian Somers           close(pidpipe[1]);
135d9626e94SBrian Somers           close(fids[1]);
1365d9e6103SBrian Somers           break;
1375d9e6103SBrian Somers 
1385d9e6103SBrian Somers         case  0:
139d9626e94SBrian Somers           close(pidpipe[0]);
1405d9e6103SBrian Somers           close(fids[0]);
1415d9e6103SBrian Somers           timer_TermService();
14268602c3eSBrian Somers #ifndef NOSUID
143a19a5c02SBrian Somers           setuid(ID0realuid());
14468602c3eSBrian Somers #endif
1455d9e6103SBrian Somers 
1463ce91245SBrian Somers           child_status = 0;
147d9626e94SBrian Somers           switch ((pid = vfork())) {
1485d9e6103SBrian Somers             case 0:
149d9626e94SBrian Somers               close(pidpipe[1]);
1505d9e6103SBrian Somers               break;
1515d9e6103SBrian Somers 
1525d9e6103SBrian Somers             case -1:
1533ce91245SBrian Somers               ret = errno;
154d9626e94SBrian Somers               log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n",
1555d9e6103SBrian Somers                          strerror(errno));
156d9626e94SBrian Somers               close(pidpipe[1]);
1573ce91245SBrian Somers               _exit(ret);
1583ce91245SBrian Somers 
1595d9e6103SBrian Somers             default:
160d9626e94SBrian Somers               write(pidpipe[1], &pid, sizeof pid);
161d9626e94SBrian Somers               close(pidpipe[1]);
1623ce91245SBrian Somers               _exit(child_status);	/* The error from exec() ! */
1635d9e6103SBrian Somers           }
1645d9e6103SBrian Somers 
16544e73c12SBrian Somers           log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
16644e73c12SBrian Somers 
1675b78bdf8SBrian Somers           if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
1685b78bdf8SBrian Somers                                PARSE_REDUCE|PARSE_NOHASH)) < 0) {
169c39aa54eSBrian Somers             log_Printf(LogWARN, "Syntax error in exec command\n");
1703ce91245SBrian Somers             _exit(ESRCH);
171c39aa54eSBrian Somers           }
172c39aa54eSBrian Somers 
173c39aa54eSBrian Somers           command_Expand(argv, argc, (char const *const *)argv,
174c39aa54eSBrian Somers                          p->dl->bundle, 0, realpid);
175c39aa54eSBrian Somers 
1765d9e6103SBrian Somers           dup2(fids[1], STDIN_FILENO);
1775d9e6103SBrian Somers           dup2(fids[1], STDOUT_FILENO);
1785d9e6103SBrian Somers           dup2(fids[1], STDERR_FILENO);
17944e73c12SBrian Somers           for (i = getdtablesize(); i > STDERR_FILENO; i--)
18044e73c12SBrian Somers             fcntl(i, F_SETFD, 1);
1815d9e6103SBrian Somers 
1825d9e6103SBrian Somers           execvp(*argv, argv);
1833ce91245SBrian Somers           child_status = errno;		/* Only works for vfork() */
1843ce91245SBrian Somers           printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
1853ce91245SBrian Somers           _exit(child_status);
1865d9e6103SBrian Somers           break;
1875d9e6103SBrian Somers 
1885d9e6103SBrian Somers         default:
189d9626e94SBrian Somers           close(pidpipe[1]);
1905d9e6103SBrian Somers           close(fids[1]);
191d9626e94SBrian Somers           if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) !=
192d9626e94SBrian Somers               sizeof p->session_owner)
193d9626e94SBrian Somers             p->session_owner = (pid_t)-1;
194d9626e94SBrian Somers           close(pidpipe[0]);
1953ce91245SBrian Somers           while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
1963ce91245SBrian Somers             ;
1973ce91245SBrian Somers           if (wret == -1) {
1983ce91245SBrian Somers             log_Printf(LogWARN, "Waiting for child process: %s\n",
1993ce91245SBrian Somers                        strerror(errno));
2003ce91245SBrian Somers             close(fids[0]);
201d9626e94SBrian Somers             p->session_owner = (pid_t)-1;
2023ce91245SBrian Somers             break;
2033ce91245SBrian Somers           } else if (WIFSIGNALED(stat)) {
2043ce91245SBrian Somers             log_Printf(LogWARN, "Child process received sig %d !\n",
2053ce91245SBrian Somers                        WTERMSIG(stat));
2063ce91245SBrian Somers             close(fids[0]);
207d9626e94SBrian Somers             p->session_owner = (pid_t)-1;
2083ce91245SBrian Somers             break;
2093ce91245SBrian Somers           } else if (WIFSTOPPED(stat)) {
2103ce91245SBrian Somers             log_Printf(LogWARN, "Child process received stop sig %d !\n",
2113ce91245SBrian Somers                        WSTOPSIG(stat));
2123ce91245SBrian Somers             /* I guess that's ok.... */
2133ce91245SBrian Somers           } else if ((ret = WEXITSTATUS(stat))) {
2143ce91245SBrian Somers             log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
2153ce91245SBrian Somers                        strerror(ret));
2163ce91245SBrian Somers             close(fids[0]);
217d9626e94SBrian Somers             p->session_owner = (pid_t)-1;
2183ce91245SBrian Somers             break;
2193ce91245SBrian Somers           }
2205d9e6103SBrian Somers           p->fd = fids[0];
2218e7bd08eSBrian Somers           log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
222d9626e94SBrian Somers           physical_SetupStack(p, execdevice.name, PHYSICAL_NOFORCE);
223fdc29d54SBrian Somers           if (p->cfg.cd.necessity != CD_DEFAULT)
224fdc29d54SBrian Somers             log_Printf(LogWARN, "Carrier settings ignored\n");
2256815097bSBrian Somers           return &execdevice;
2265d9e6103SBrian Somers       }
2273ce91245SBrian Somers       close(fids[0]);
2285d9e6103SBrian Somers     }
2295d9e6103SBrian Somers   }
2305d9e6103SBrian Somers 
2316815097bSBrian Somers   return NULL;
2325d9e6103SBrian Somers }
233