source: trunk/third/sysinfo/run.c @ 11115

Revision 11115, 8.0 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11114, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1992-1996 Michael A. Cooper.
3 * This software may be freely used and distributed provided it is not sold
4 * for profit or used for commercial gain and the author is credited
5 * appropriately.
6 */
7
8#ifndef lint
9static char *RCSid = "$Id: run.c,v 1.1.1.2 1998-02-12 21:32:01 ghudson Exp $";
10#endif
11
12/*
13 * Things related to running system commands.
14 */
15
16#include "defs.h"
17
18/*
19 * Need default environment for some OS's like HP-UX.
20 */
21static char                    *DefEnviron[] = {
22    "HOME=/dev/null",
23    NULL };
24extern char                   **Environ;
25uid_t                           SavedUserID;
26
27/*
28 * Set our User ID.
29 */
30int SetUserID(RealUID, EffectUID)
31    uid_t                       RealUID;
32    uid_t                       EffectUID;
33{
34    if (Debug) printf("SetUserID(%d, %d) current: ruid=%d euid=%d\n",
35                      RealUID, EffectUID, getuid(), geteuid());
36
37    if (setreuid(RealUID, EffectUID) == -1) {
38        if (Debug) Error("setreuid to %d, %d failed: %s",
39                         RealUID, EffectUID, SYSERR);
40        return(-1);
41    }
42
43    if (Debug) printf("SetUserID(%d, %d) new: ruid=%d euid=%d\n",
44                      RealUID, EffectUID, getuid(), geteuid());
45
46    return(0);
47}
48
49/*
50 * Set environment variable "Key" to be "Value".
51 */
52int SetEnv(Key, Value)
53    char                       *Key;
54    char                       *Value;
55{
56    static char                 Buff[BUFSIZ];
57
58    (void) sprintf(Buff, "%s=%s", Key, (Value) ? Value : "");
59    if (putenv(strdup(Buff)) != 0) {
60        if (Debug) Error("putenv(%s) failed.", Buff);
61        return(-1);
62    }
63
64    return(0);
65}
66
67/*
68 * Initialize environment before executing external command.
69 */
70int ExecInit(WithPrivs)
71    int                         WithPrivs;
72{
73    static int                  First = TRUE;
74    register char             **PtrPtr;
75
76    if (First) {
77        First = FALSE;
78        SavedUserID = (uid_t) -1;
79        /*
80         * Remove environment variables considered to be a security risk.
81         */
82        for (PtrPtr = Environ; PtrPtr && *PtrPtr; ++PtrPtr) {
83            if (EQN(*PtrPtr, "IFS=", 4)) {
84                if (SetEnv("IFS", NULL) < 0)
85                    return(-1);
86            } else if (EQN(*PtrPtr, "LD_", 3)) {
87                if (SetEnv(*PtrPtr, NULL) < 0)
88                    return(-1);
89            }
90        }
91    }
92
93    /*
94     * Only change user ID if we're setuid root (uid==0).
95     */
96    if (!WithPrivs && (geteuid() == 0) && ((SavedUserID = getuid()) != 0))
97        if (SetUserID(0, SavedUserID) == -1)
98            return(-1);
99
100    return(0);
101}
102
103/*
104 * Reset things after executing external command.
105 */
106int ExecEnd(WithPrivs)
107    int                         WithPrivs;
108{
109    if (SavedUserID != (uid_t)-1 && SetUserID(SavedUserID, 0) == -1)
110        return(-1);
111    return(0);
112}
113
114/*
115 * Run a list of commands (found in cmds) and return command output.
116 */
117extern char *RunCmds(Cmds, WithPrivs)
118    char                      **Cmds;
119    int                         WithPrivs;
120{
121    static char                 Buf[BUFSIZ];
122    int                         l;
123    int                         Done = 0;
124    FILE                       *pf;
125    register char              *p;
126    char                      **Cmd;
127
128    if (ExecInit(WithPrivs) != 0)
129            return((char *)NULL);
130
131    Buf[0] = C_NULL;
132    for (Cmd = Cmds; Cmd != NULL && *Cmd != NULL && !Done; ++Cmd) {
133        /*
134         * If this command has any args, nuke them for the access() test.
135         */
136        strcpy(Buf, *Cmd);
137        p = strchr(Buf, ' ');
138        if (p != NULL)
139            *p = C_NULL;
140
141        if (access(Buf, X_OK) != 0)
142            continue;
143
144        if (Debug) printf("RunCmd '%s' %s Privs\n",
145                          *Cmd, (WithPrivs) ? "With" : "Without");
146
147        if ((pf = popen(*Cmd, "r")) == NULL)
148            continue;
149        if (fgets(Buf, sizeof(Buf), pf) == NULL) {
150            pclose(pf);
151            continue;
152        }
153        pclose(pf);
154
155        l = strlen(Buf);
156        if (Buf[l-1] == '\n')
157            Buf[l-1] = C_NULL;
158
159        Done = TRUE;
160    }
161 
162    if (ExecEnd(WithPrivs) != 0)
163            return((char *)NULL);
164
165    return((Buf[0]) ? Buf : (char *)NULL);
166}
167
168/*
169 * Wait for a given process to exit and return
170 * that processes exit status.
171 */
172#if     WAIT_TYPE == WAIT_WAITPID
173int WaitForProc(ProcID)
174    pid_t                       ProcID;
175{
176    pid_t                       RetProcID;
177    waitarg_t                   ProcStatus;
178
179    RetProcID = waitpid(ProcID, &ProcStatus, 0);
180
181    if (RetProcID == ProcID)
182        if (WIFEXITED(ProcStatus))
183            return(WAITEXITSTATUS(ProcStatus));
184        else {
185            Error("waitpid(%d, , 0) failed and returned %d: %s.",
186                  ProcID, RetProcID, SYSERR);
187            return(-1);
188        }
189    else
190        return(-1);
191}
192#endif  /* WAIT_WAITPID */
193#if     WAIT_TYPE == WAIT_WAIT4
194int WaitForProc(ProcID)
195    pid_t                       ProcID;
196{
197    pid_t                       RetProcID;
198    waitarg_t                   ProcStatus;
199
200    RetProcID = wait4(ProcID, &ProcStatus, 0, NULL);
201
202    if (RetProcID == ProcID)
203        if (WIFEXITED(ProcStatus))
204            return(WAITEXITSTATUS(ProcStatus));
205        else {
206            Error("wait4(%d) failed and returned %d: %s.",
207                  ProcID, RetProcID, SYSERR);
208            return(-1);
209        }
210    else
211        return(-1);
212}
213#endif  /* WAIT_WAIT4 */
214
215/*
216 * Execute a command with given arguments.
217 */
218int Execute(Cmd, Argv, Env, WithPrivs, StdOut, StdErr)
219    char                       *Cmd;
220    char                      **Argv;
221    char                      **Env;
222    int                         WithPrivs;
223    int                         StdOut;
224    int                         StdErr;
225{
226    pid_t                       ProcID = 0;
227    int                         Status;
228    register char             **PtrPtr;
229
230    if (access(Cmd, X_OK) != 0)
231        return(-1);
232
233    if (!Env)
234        Env = DefEnviron;
235
236    if (Debug) {
237        printf("Execute '%s'", Cmd);
238        for (PtrPtr = Argv; PtrPtr && *PtrPtr; ++PtrPtr)
239            printf(" '%s'", *PtrPtr);
240        printf("\t%s Privs\n", (WithPrivs) ? "With" : "Without");
241    }
242
243    ProcID = fork();
244    if (ProcID < 0) {
245        Error("Fork failed: %s", SYSERR);
246        return(-1);
247    } else if (ProcID == 0) {
248        /*
249         * Child
250         */
251        if (StdOut >= 0)
252            if (dup2(StdOut, fileno(stdout)) < 0)
253                Error("dup2(%d, stdout) failed: %s.", StdOut);
254        if (StdErr >= 0)
255            if (dup2(StdErr, fileno(stderr)) < 0)
256                Error("dup2(%d, stderr) failed: %s.", StdErr);
257        ExecInit(WithPrivs);
258        execve(Cmd, Argv, Env);
259        Error("Execve \"%s\" failed: %s", Cmd, SYSERR);
260        exit(127);
261    } else {
262        /*
263         * Parent
264         */
265        Status = WaitForProc(ProcID);
266        if (Debug) printf("\tCommand '%s' exited %d.\n", Cmd, Status);
267        return(Status);
268    }
269    return(-1);
270}
271
272#if     defined(RUN_TEST_CMD)
273static char                    *RunTestCmd[] = RUN_TEST_CMD;
274#endif  /* RUN_TEST_CMD */
275
276/*
277 * Get the Argument Vector for the command to run.
278 */
279static char **GetRunArgv(Command)
280    char                       *Command;
281{
282    static char               **Argv = NULL;
283    char                       *Base;
284#if     defined(RUN_TEST_CMD)
285    register char             **ArgvPtr;
286    register char             **PtrPtr;
287    register int                Count;
288
289    for (Count = 0, PtrPtr = RunTestCmd; PtrPtr && *PtrPtr; ++PtrPtr, ++Count);
290
291    if (Argv)
292        (void) free(Argv);
293    ArgvPtr = Argv = (char **) xmalloc((Count+2) * sizeof(char *));
294
295    for (PtrPtr = RunTestCmd; PtrPtr && *PtrPtr; ++PtrPtr, ++ArgvPtr)
296        *ArgvPtr = *PtrPtr;
297    *ArgvPtr = Command;
298    *++ArgvPtr = NULL;
299#else   /* !RUN_TEST_CMD */
300    Base = strrchr(Command, '/');
301    if (Base)
302        ++Base;
303    else
304        Base = Command;
305    if (Argv)
306        (void) free(Argv);
307    Argv = (char **) xmalloc(4 * sizeof(char *));
308    Argv[0] = Command;
309    Argv[1] = Base;
310    Argv[2] = NULL;
311#endif  /* RUN_TEST_CMD */
312
313    return(Argv);
314}
315   
316
317/*
318 * Run a list of test files.  Each test file is run and if the
319 * exit status is 0, we return the basename of the command.
320 * e.g. If "/bin/vax" exists and returns status 0, return string "vax".
321 */
322extern char *RunTestFiles(Cmds)
323    char                      **Cmds;
324{
325    char                      **Cmd;
326    char                      **RunEnv;
327    char                      **Argv;
328    char                       *Name = NULL;
329    register char              *p;
330    static char                 Buf[BUFSIZ];
331    int                         StdOut = -1;
332    int                         StdErr = -1;
333
334    /*
335     * Setup stdout/stderr to go to /dev/null since we
336     * only care about the exit status of commands.
337     */
338    if (!Debug) {
339        StdOut = open(_PATH_NULL, O_WRONLY);
340        StdErr = open(_PATH_NULL, O_WRONLY);
341    }
342
343    for (Cmd = Cmds; Name == NULL && Cmd != NULL && *Cmd != NULL; ++Cmd) {
344        /*
345         * If this command has any args, nuke them for the access() test.
346         */
347        strcpy(Buf, *Cmd);
348        p = strchr(Buf, ' ');
349        if (p != NULL)
350            *p = C_NULL;
351
352        if (access(Buf, X_OK) != 0)
353            continue;
354
355        /*
356         * Execute the command with a NULL environment for security
357         * reasons.
358         */
359        Argv = GetRunArgv(*Cmd);
360        if (Execute(Argv[0], &Argv[1], (char **)NULL, 0, StdOut, StdErr) != 0)
361            continue;
362
363        /*
364         * The name of this architecture is the last part of the Cmd name.
365         */
366        strcpy(Buf, *Cmd);
367        p = strrchr(Buf, '/');
368        if (p != NULL)
369            ++p;
370        Name = p;
371    }
372
373    if (StdOut >= 0)
374        (void) close(StdOut);
375    if (StdErr >= 0)
376        (void) close(StdErr);
377
378    return(Name);
379}
Note: See TracBrowser for help on using the repository browser.