exec.c revision 78410
1235783Skib/*-
2235783Skib * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
3235783Skib * All rights reserved.
4235783Skib *
5235783Skib * Redistribution and use in source and binary forms, with or without
6235783Skib * modification, are permitted provided that the following conditions
7235783Skib * are met:
8235783Skib * 1. Redistributions of source code must retain the above copyright
9235783Skib *    notice, this list of conditions and the following disclaimer.
10235783Skib * 2. Redistributions in binary form must reproduce the above copyright
11235783Skib *    notice, this list of conditions and the following disclaimer in the
12235783Skib *    documentation and/or other materials provided with the distribution.
13235783Skib *
14235783Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235783Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235783Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235783Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235783Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235783Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235783Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235783Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235783Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235783Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235783Skib * SUCH DAMAGE.
25235783Skib *
26235783Skib * $FreeBSD: head/usr.sbin/ppp/exec.c 78410 2001-06-18 14:59:36Z brian $
27235783Skib */
28235783Skib
29235783Skib#include <sys/param.h>
30235783Skib#include <sys/socket.h>
31235783Skib#include <sys/un.h>
32235783Skib
33235783Skib#include <errno.h>
34235783Skib#include <fcntl.h>
35235783Skib#include <stdio.h>
36235783Skib#include <stdlib.h>
37235783Skib#include <string.h>
38235783Skib#include <sys/wait.h>
39235783Skib#include <sys/uio.h>
40235783Skib#include <termios.h>
41235783Skib#include <unistd.h>
42235783Skib
43235783Skib#include "layer.h"
44235783Skib#include "defs.h"
45235783Skib#include "mbuf.h"
46235783Skib#include "log.h"
47235783Skib#include "timer.h"
48235783Skib#include "lqr.h"
49235783Skib#include "hdlc.h"
50235783Skib#include "throughput.h"
51235783Skib#include "fsm.h"
52235783Skib#include "lcp.h"
53235783Skib#include "ccp.h"
54235783Skib#include "link.h"
55235783Skib#include "async.h"
56235783Skib#include "descriptor.h"
57235783Skib#include "physical.h"
58235783Skib#include "mp.h"
59235783Skib#include "chat.h"
60235783Skib#include "command.h"
61235783Skib#include "auth.h"
62235783Skib#include "chap.h"
63235783Skib#include "cbcp.h"
64235783Skib#include "datalink.h"
65235783Skib#include "id.h"
66235783Skib#include "exec.h"
67235783Skib
68235783Skibstatic struct device execdevice = {
69235783Skib  EXEC_DEVICE,
70235783Skib  "exec",
71235783Skib  0,
72235783Skib  { CD_NOTREQUIRED, 0 },
73235783Skib  NULL,
74235783Skib  NULL,
75235783Skib  NULL,
76235783Skib  NULL,
77235783Skib  NULL,
78235783Skib  NULL,
79235783Skib  NULL,
80235783Skib  NULL,
81235783Skib  NULL,
82235783Skib  NULL,
83235783Skib  NULL,
84235783Skib  NULL
85235783Skib};
86235783Skib
87235783Skibstruct device *
88235783Skibexec_iov2device(int type, struct physical *p, struct iovec *iov,
89235783Skib                int *niov, int maxiov, int *auxfd, int *nauxfd)
90235783Skib{
91235783Skib  if (type == EXEC_DEVICE) {
92235783Skib    free(iov[(*niov)++].iov_base);
93235783Skib    physical_SetupStack(p, execdevice.name, PHYSICAL_NOFORCE);
94235783Skib    return &execdevice;
95235783Skib  }
96235783Skib
97235783Skib  return NULL;
98235783Skib}
99235783Skib
100235783Skibstruct device *
101235783Skibexec_Create(struct physical *p)
102235783Skib{
103235783Skib  if (p->fd < 0 && *p->name.full == '!') {
104235783Skib    int fids[2], type;
105235783Skib
106235783Skib    p->fd--;	/* We own the device but maybe can't use it - change fd */
107235783Skib    type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM;
108235783Skib
109235783Skib    if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0)
110235783Skib      log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
111235783Skib                 strerror(errno));
112235783Skib    else {
113235783Skib      static int child_status;		/* This variable is abused ! */
114235783Skib      int stat, argc, i, ret, wret, pidpipe[2];
115235783Skib      pid_t pid, realpid;
116235783Skib      char *argv[MAXARGS];
117235783Skib
118235783Skib      stat = fcntl(fids[0], F_GETFL, 0);
119235783Skib      if (stat > 0) {
120235783Skib        stat |= O_NONBLOCK;
121235783Skib        fcntl(fids[0], F_SETFL, stat);
122235783Skib      }
123235783Skib      realpid = getpid();
124235783Skib      if (pipe(pidpipe) == -1) {
125235783Skib        log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n",
126235783Skib                   strerror(errno));
127235783Skib        close(fids[1]);
128235783Skib      } else switch ((pid = fork())) {
129235783Skib        case -1:
130271816Sdumbbell          log_Printf(LogPHASE, "Unable to fork for line exec: %s\n",
131271816Sdumbbell                     strerror(errno));
132271816Sdumbbell          close(pidpipe[0]);
133271816Sdumbbell          close(pidpipe[1]);
134271816Sdumbbell          close(fids[1]);
135271816Sdumbbell          break;
136271816Sdumbbell
137271816Sdumbbell        case  0:
138271816Sdumbbell          close(pidpipe[0]);
139271816Sdumbbell          close(fids[0]);
140271816Sdumbbell          timer_TermService();
141271816Sdumbbell#ifndef NOSUID
142271816Sdumbbell          setuid(ID0realuid());
143271816Sdumbbell#endif
144271816Sdumbbell
145271816Sdumbbell          child_status = 0;
146271816Sdumbbell          switch ((pid = vfork())) {
147271816Sdumbbell            case 0:
148235783Skib              close(pidpipe[1]);
149235783Skib              break;
150235783Skib
151235783Skib            case -1:
152235783Skib              ret = errno;
153235783Skib              log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n",
154282199Sdumbbell                         strerror(errno));
155235783Skib              close(pidpipe[1]);
156254838Sdumbbell              _exit(ret);
157254838Sdumbbell
158254838Sdumbbell            default:
159235783Skib              write(pidpipe[1], &pid, sizeof pid);
160235783Skib              close(pidpipe[1]);
161235783Skib              _exit(child_status);	/* The error from exec() ! */
162235783Skib          }
163282199Sdumbbell
164235783Skib          log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
165235783Skib
166235783Skib          if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
167235783Skib                               PARSE_REDUCE|PARSE_NOHASH)) < 0) {
168235783Skib            log_Printf(LogWARN, "Syntax error in exec command\n");
169235783Skib            _exit(ESRCH);
170235783Skib          }
171235783Skib
172235783Skib          command_Expand(argv, argc, (char const *const *)argv,
173235783Skib                         p->dl->bundle, 0, realpid);
174235783Skib
175235783Skib          dup2(fids[1], STDIN_FILENO);
176235783Skib          dup2(fids[1], STDOUT_FILENO);
177235783Skib          dup2(fids[1], STDERR_FILENO);
178235783Skib          for (i = getdtablesize(); i > STDERR_FILENO; i--)
179235783Skib            fcntl(i, F_SETFD, 1);
180235783Skib
181235783Skib          execvp(*argv, argv);
182235783Skib          child_status = errno;		/* Only works for vfork() */
183235783Skib          printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
184235783Skib          _exit(child_status);
185235783Skib          break;
186235783Skib
187235783Skib        default:
188235783Skib          close(pidpipe[1]);
189235783Skib          close(fids[1]);
190235783Skib          if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) !=
191235783Skib              sizeof p->session_owner)
192235783Skib            p->session_owner = (pid_t)-1;
193235783Skib          close(pidpipe[0]);
194235783Skib          while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
195235783Skib            ;
196235783Skib          if (wret == -1) {
197235783Skib            log_Printf(LogWARN, "Waiting for child process: %s\n",
198235783Skib                       strerror(errno));
199235783Skib            close(fids[0]);
200235783Skib            p->session_owner = (pid_t)-1;
201235783Skib            break;
202235783Skib          } else if (WIFSIGNALED(stat)) {
203235783Skib            log_Printf(LogWARN, "Child process received sig %d !\n",
204235783Skib                       WTERMSIG(stat));
205235783Skib            close(fids[0]);
206235783Skib            p->session_owner = (pid_t)-1;
207235783Skib            break;
208235783Skib          } else if (WIFSTOPPED(stat)) {
209235783Skib            log_Printf(LogWARN, "Child process received stop sig %d !\n",
210235783Skib                       WSTOPSIG(stat));
211235783Skib            /* I guess that's ok.... */
212235783Skib          } else if ((ret = WEXITSTATUS(stat))) {
213235783Skib            log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
214235783Skib                       strerror(ret));
215235783Skib            close(fids[0]);
216235783Skib            p->session_owner = (pid_t)-1;
217235783Skib            break;
218235783Skib          }
219235783Skib          p->fd = fids[0];
220235783Skib          log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
221235783Skib          physical_SetupStack(p, execdevice.name, PHYSICAL_NOFORCE);
222235783Skib          if (p->cfg.cd.necessity != CD_DEFAULT)
223235783Skib            log_Printf(LogWARN, "Carrier settings ignored\n");
224235783Skib          return &execdevice;
225235783Skib      }
226235783Skib      close(fids[0]);
227235783Skib    }
228235783Skib  }
229235783Skib
230  return NULL;
231}
232