source: trunk/athena/bin/athdir/athdir.c @ 10171

Revision 10171, 8.5 KB checked in by cfields, 27 years ago (diff)
Prevent constructs such as "../" from being used in ATHENA_SYS values (falling back to the compiled in default if necessary). This would only be an issue in a case such as a setuid root program running athdir to decide where to get a binary from, which should never happen in the ideal world.
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/param.h>          /* MAXPATHLEN */
5#include <sys/types.h>
6#include <sys/stat.h>
7
8#define NUMCONVENTIONS 5
9
10#ifdef ultrix
11#define HOSTTYPESET 1
12#define HOSTTYPE "decmips"
13#endif
14
15#ifdef _IBMR2
16#define HOSTTYPESET 1
17#define HOSTTYPE "rsaix"
18#endif
19
20#ifdef SOLARIS
21#define HOSTTYPESET 1
22#define HOSTTYPE "sun4"
23#endif
24
25#ifdef linux
26#define HOSTTYPESET 1
27#define HOSTTYPE "linux"
28#endif
29
30/*
31 * Don't define HOSTTYPE on platforms for which `machtype`bin was
32 * never widely used.
33 */
34
35/*
36 * This should be passed in as a compile flag.
37 */
38#ifndef ATHSYS
39#define ATHSYS "@sys"
40#endif
41
42char *athsys = ATHSYS;
43
44#ifdef HOSTTYPE
45int hosttypeset = 1;
46char *hosttype = HOSTTYPE;
47#else
48int hosttypeset = 0;
49char *hosttype = NULL;
50#endif
51
52char *progName;
53
54/*
55 * Definition of known conventions and what flavors they are.
56 */
57
58typedef struct {
59  char *name;
60  int flavor;
61} Convention;
62
63#define ARCHflavor (1<<0)
64#define MACHflavor (1<<1)
65#define PLAINflavor (1<<2)
66#define SYSflavor (1<<3)
67#define DEPENDENTflavor (1<<8)
68#define INDEPENDENTflavor (1<<9)
69
70Convention conventions[NUMCONVENTIONS] = {
71  { NULL,               ARCHflavor | MACHflavor | PLAINflavor |
72                        DEPENDENTflavor | INDEPENDENTflavor },
73  { "%p/arch/%s/%t",    ARCHflavor | DEPENDENTflavor },
74  { "%p/%s/%t",         SYSflavor | DEPENDENTflavor },
75  { "%p/%m%t",          MACHflavor | DEPENDENTflavor },
76  { "%p/%t",            PLAINflavor | INDEPENDENTflavor }
77};
78
79/*
80 * Editorial tagging for what conventions are acceptable or
81 * preferable for what types.
82 */
83
84typedef struct {
85  char *type;
86  int allowedFlavors;   /* searching parameters */
87  int preferredFlavor;  /* creating paramaters */
88} Editorial;
89
90Editorial editorials[] = {
91  { "bin",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
92  { "lib",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
93  { "etc",      ARCHflavor | SYSflavor | MACHflavor,    DEPENDENTflavor },
94  { "man",      ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
95  { "include",  ARCHflavor | PLAINflavor,               INDEPENDENTflavor },
96  { NULL,       ARCHflavor | PLAINflavor,               DEPENDENTflavor }
97};
98
99usage()
100{
101  fprintf(stderr, "usage: %s path [type]\n", progName);
102  fprintf(stderr,
103          "   or: %s [-t type] [-p path ...] [-e] [-c] [-l] [-d | -i]\n",
104          progName);
105  fprintf(stderr,
106          "       [-r recsep] [-f format] [-s sysname] [-m machtype]\n");
107  exit(1);
108}
109
110/*
111 * path = template(dir, type, sys, machine)
112 *      %p = path (dir)
113 *      %t = type
114 *      %s = sys
115 *      %m = machine
116 * %foo is inserted if the corresponding string is NULL.
117 * If this happens, expand returns 1 (not a valid path).
118 * Otherwise, expand returns 0.
119 */
120expand(path, template, dir, type, sys, machine)
121     char *path, *template, *dir, *type, *sys, *machine;
122{
123  char *src, *dst;
124  int somenull = 0;
125
126  src = template;
127  dst = path;
128  *dst = '\0';
129
130  while (*src != '\0')
131    {
132      if (*src != '%' && *src != '\0')
133        *dst++ = *src++;
134      else
135        {
136
137#define copystring(casec, cases, string)                        \
138        case casec:                                             \
139          src++;                                                \
140          if (string)                                           \
141            {                                                   \
142              strcpy(dst, string);                              \
143              dst += strlen(string);                            \
144            }                                                   \
145          else                                                  \
146            {                                                   \
147              strcpy(dst, cases);                               \
148              dst += 2;                                         \
149              somenull = 1;                                     \
150            }                                                   \
151          break;
152
153          src++;
154          switch(*src)
155            {
156              copystring('p', "%p", dir);
157              copystring('t', "%t", type);
158              copystring('s', "%s", sys);
159              copystring('m', "%m", machine);
160
161#undef copystring
162
163            case '\0':
164              break;
165
166            default:
167              *dst++ = '%';
168              *dst++ = *src++;
169              break;
170            }
171        }
172    }
173
174  *dst = '\0';
175  return somenull;
176}
177
178main(argc, argv)
179     int argc;
180     char **argv;
181{
182  int numPaths = 0, eflag = 0, cflag = 0, lflag = 0, tflag = 0,
183    sflag = 0, mflag = 0, dflag = 0, iflag = 0;
184  int preferredFlavor = 0;
185  char **pathList, *type = NULL, *tmp;
186  char *recsep = NULL;
187  char path[MAXPATHLEN];
188  struct stat statbuf;
189  int i, j, t;
190  int complete;
191  int failed, status = 0, first = 1;
192
193  progName = strrchr(argv[0], '/');
194  if (progName != NULL)
195    progName++;
196  else
197    progName = argv[0];
198
199  if (argc == 1)
200    usage();
201
202  if (argc)
203    pathList = malloc((argc + 1) * sizeof(char *));
204
205  /*
206   * ATHENA_SYS environment variable overrides hard-coded
207   * value.
208   */
209  tmp = getenv("ATHENA_SYS");
210  if (tmp != NULL && strchr(tmp, '/') == NULL)
211    athsys = tmp;
212
213  if (argv[1][0] != '-')
214    {
215      if (argc > 3)
216        usage();
217
218      pathList[numPaths++] = argv[1];
219
220      if (argv[2])
221        {
222          if (argv[2][0] == '-')
223            usage();
224
225          type = argv[2];
226        }
227      else
228        type = "bin";
229    }
230  else
231    {
232      argv++;
233
234      while (*argv)
235        {
236          if (**argv != '-' || (*argv)[2] != '\0')
237            {
238              fprintf(stderr, "%s: unknown option: %s\n", progName, *argv);
239              usage();
240            }
241
242          switch((*argv)[1])
243            {
244
245#define repeatflag                                                      \
246                {                                                       \
247                  fprintf(stderr, "%s: %s already specified.\n",        \
248                          progName, *argv);                             \
249                  usage();                                              \
250                }
251
252            case 't':
253              if (tflag)
254                repeatflag;
255              argv++;
256              if (*argv == NULL)
257                usage();
258              type = *argv++;
259              tflag++;
260              break;
261
262            case 'p':
263              if (numPaths != 0)
264                repeatflag;
265
266              argv++;
267              if (*argv == NULL)
268                usage();
269              while (*argv != NULL && **argv != '-')
270                pathList[numPaths++] = *argv++;
271              break;
272
273            case 'e':
274              if (eflag)
275                repeatflag;
276              argv++;
277              eflag++;
278              break;
279
280            case 'c':
281              if (cflag)
282                repeatflag;
283              argv++;
284              cflag++;
285              break;
286
287            case 'l':
288              if (lflag)
289                repeatflag;
290              argv++;
291              lflag++;
292              break;
293
294            case 's':
295              if (sflag)
296                repeatflag;
297              argv++;
298              if (*argv == NULL)
299                usage();
300              athsys = *argv++;
301              sflag++;
302              break;
303
304            case 'm':
305              if (mflag)
306                repeatflag;
307              argv++;
308              if (*argv == NULL)
309                usage();
310              hosttype = *argv++;
311              hosttypeset = 1;
312              mflag++;
313              break;
314
315            case 'f':
316              if (conventions[0].name)
317                repeatflag;
318              argv++;
319              if (*argv == NULL)
320                usage();
321              conventions[0].name = *argv++;
322              break;
323
324            case 'r':
325              if (recsep != NULL)
326                repeatflag;
327              argv++;
328              if (*argv == NULL)
329                usage();
330              recsep = *argv++;
331              break;
332
333            case 'd':
334              if (dflag)
335                repeatflag;
336              argv++;
337              dflag++;
338              preferredFlavor = DEPENDENTflavor;
339              break;
340
341            case 'i':
342              if (iflag)
343                repeatflag;
344              argv++;
345              iflag++;
346              preferredFlavor = INDEPENDENTflavor;
347              break;
348
349            default:
350              fprintf(stderr, "%s: unknown option: %s\n", progName, *argv);
351              usage();
352              break;
353            }
354        }
355    }
356
357  if (!numPaths)
358    pathList[numPaths++] = NULL;
359
360  if (!recsep)
361    recsep = "\n";
362
363  /*
364   * You are in a twisty little maze of interconnecting
365   * command line options, all different.
366   */
367  for (i = 0; i < numPaths; i++)
368    {
369      /* Find matching editorial. */
370      for (t = 0; editorials[t].type != NULL; t++)
371        if (type != NULL &&
372            !strcmp(type, editorials[t].type))
373          break;
374
375      if (!preferredFlavor)
376        preferredFlavor = editorials[t].preferredFlavor;
377
378      failed = 1;
379
380      /* Cycle through matching conventions */
381      for (j = 0; j < NUMCONVENTIONS; j++)
382        {
383          if (conventions[j].name == NULL)
384            continue; /* User specified convention is not set. */
385
386          if (/* -e: explicit editorial override */
387              eflag ||
388
389              /* -d, -i also imply override, but only have meaning with -c */
390              ((dflag || iflag) && cflag) ||
391
392              /* otherwise, we make our editorial comments */
393              (editorials[t].allowedFlavors & conventions[j].flavor))
394            {
395              if (cflag &&
396                  !(preferredFlavor & conventions[j].flavor))
397                continue;
398
399              complete = !expand(path, conventions[j].name,
400                                pathList[i], type, athsys, hosttype);
401
402              if (lflag ||
403                  (cflag && complete))
404                {
405                  if (!first)
406                    fprintf(stdout, "%s", recsep);
407                  fprintf(stdout, "%s", path);
408                  first = 0;
409                  failed = 0;
410                  if (cflag)
411                    break;
412                }
413
414              if (complete && !lflag && !cflag &&
415                  !stat(path, &statbuf))
416                {
417                  if (!first)
418                    fprintf(stdout, "%s", recsep);
419                  fprintf(stdout, "%s", path);
420                  first = 0;
421                  failed = 0;
422                  break;
423                }
424            }
425        }
426      if (failed)
427        status = 1;
428    }
429
430  if (!first)
431    fprintf(stdout, "\n");
432
433#ifdef DEBUG
434  fprintf(stdout, "%s ", progName);
435  if (type != NULL)
436    fprintf(stdout, "-t %s ", type);
437  if (numPaths)
438    {
439      fprintf(stdout, "-p ");
440      for (i = 0; i < numPaths; i++)
441        fprintf(stdout, "%s ", pathList[i]);
442    }
443  if (eflag)
444    fprintf(stdout, "-e ");
445  if (cflag)
446    fprintf(stdout, "-c ");
447  if (lflag)
448    fprintf(stdout, "-l ");
449  fprintf(stdout, "\n");
450#endif
451
452  exit(status);
453}
Note: See TracBrowser for help on using the repository browser.