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

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