systems.c revision 36285
1/*
2 *	          System configuration routines
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: systems.c,v 1.35.2.10 1998/05/15 23:58:29 brian Exp $
21 *
22 *  TODO:
23 */
24#include <sys/param.h>
25
26#include <ctype.h>
27#include <pwd.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "command.h"
34#include "log.h"
35#include "id.h"
36#include "defs.h"
37#include "systems.h"
38
39#define issep(ch) ((ch) == ' ' || (ch) == '\t')
40
41FILE *
42OpenSecret(const char *file)
43{
44  FILE *fp;
45  char line[100];
46
47  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
48  fp = ID0fopen(line, "r");
49  if (fp == NULL)
50    log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
51  return (fp);
52}
53
54void
55CloseSecret(FILE * fp)
56{
57  fclose(fp);
58}
59
60/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
61static void
62InterpretArg(char *from, char *to)
63{
64  const char *env;
65  char *ptr, *startto, *endto;
66  int len;
67
68  startto = to;
69  endto = to + LINE_LEN - 1;
70
71  while(issep(*from))
72    from++;
73  if (*from == '~') {
74    ptr = strchr(++from, '/');
75    len = ptr ? ptr - from : strlen(from);
76    if (len == 0) {
77      if ((env = getenv("HOME")) == NULL)
78        env = _PATH_PPP;
79      strncpy(to, env, endto - to);
80    } else {
81      struct passwd *pwd;
82
83      strncpy(to, from, len);
84      to[len] = '\0';
85      pwd = getpwnam(to);
86      if (pwd)
87        strncpy(to, pwd->pw_dir, endto-to);
88      else
89        strncpy(to, _PATH_PPP, endto - to);
90      endpwent();
91    }
92    *endto = '\0';
93    to += strlen(to);
94    from += len;
95  }
96
97  while (to < endto && *from != '\0') {
98    if (*from == '$') {
99      if (from[1] == '$') {
100        *to = '\0';	/* For an empty var name below */
101        from += 2;
102      } else if (from[1] == '{') {
103        ptr = strchr(from+2, '}');
104        if (ptr) {
105          len = ptr - from - 2;
106          if (endto - to < len )
107            len = endto - to;
108          if (len) {
109            strncpy(to, from+2, len);
110            to[len] = '\0';
111            from = ptr+1;
112          } else {
113            *to++ = *from++;
114            continue;
115          }
116        } else {
117          *to++ = *from++;
118          continue;
119        }
120      } else {
121        ptr = to;
122        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
123          *ptr++ = *from;
124        *ptr = '\0';
125      }
126      if (*to == '\0')
127        *to++ = '$';
128      else if ((env = getenv(to)) != NULL) {
129        strncpy(to, env, endto - to);
130        *endto = '\0';
131        to += strlen(to);
132      }
133    } else
134      *to++ = *from++;
135  }
136  while (to > startto) {
137    to--;
138    if (!issep(*to)) {
139      to++;
140      break;
141    }
142  }
143  *to = '\0';
144}
145
146#define CTRL_UNKNOWN (0)
147#define CTRL_INCLUDE (1)
148
149static int
150DecodeCtrlCommand(char *line, char *arg)
151{
152  if (!strncasecmp(line, "include", 7) && issep(line[7])) {
153    InterpretArg(line+8, arg);
154    return CTRL_INCLUDE;
155  }
156  return CTRL_UNKNOWN;
157}
158
159/* Initialised in system_IsValid(), set in ReadSystem(), used by system_IsValid() */
160static int modeok;
161static int userok;
162static int modereq;
163
164int
165AllowUsers(struct cmdargs const *arg)
166{
167  /* arg->bundle may be NULL (see system_IsValid()) ! */
168  int f;
169  char *user;
170
171  userok = 0;
172  user = getlogin();
173  if (user && *user)
174    for (f = arg->argn; f < arg->argc; f++)
175      if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
176        userok = 1;
177        break;
178      }
179
180  return 0;
181}
182
183int
184AllowModes(struct cmdargs const *arg)
185{
186  /* arg->bundle may be NULL (see system_IsValid()) ! */
187  int f, mode, allowed;
188
189  allowed = 0;
190  for (f = arg->argn; f < arg->argc; f++) {
191    mode = Nam2mode(arg->argv[f]);
192    if (mode == PHYS_NONE || mode == PHYS_ALL)
193      log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
194    else
195      allowed |= mode;
196  }
197
198  modeok = modereq & allowed ? 1 : 0;
199  return 0;
200}
201
202static char *
203strip(char *line)
204{
205  int len;
206
207  len = strlen(line);
208  while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
209                 issep(line[len-1])))
210    line[--len] = '\0';
211
212  while (issep(*line))
213    line++;
214
215  if (*line == '#')
216    *line = '\0';
217
218  return line;
219}
220
221static int
222xgets(char *buf, int buflen, FILE *fp)
223{
224  int len, n;
225
226  n = 0;
227  while (fgets(buf, buflen-1, fp)) {
228    n++;
229    buf[buflen-1] = '\0';
230    len = strlen(buf);
231    while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
232      buf[--len] = '\0';
233    if (len && buf[len-1] == '\\') {
234      buf += len - 1;
235      buflen -= len - 1;
236      if (!buflen)        /* No buffer space */
237        break;
238    } else
239      break;
240  }
241  return n;
242}
243
244static int
245ReadSystem(struct bundle *bundle, const char *name, const char *file,
246           int doexec, struct prompt *prompt)
247{
248  FILE *fp;
249  char *cp, *wp;
250  int n, len;
251  char line[LINE_LEN];
252  char filename[MAXPATHLEN];
253  int linenum;
254  int argc;
255  char **argv;
256  int allowcmd;
257  int indent;
258  char arg[LINE_LEN];
259
260  if (*file == '/')
261    snprintf(filename, sizeof filename, "%s", file);
262  else
263    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
264  fp = ID0fopen(filename, "r");
265  if (fp == NULL) {
266    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
267    return (-1);
268  }
269  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
270
271  linenum = 0;
272  while ((n = xgets(line, sizeof line, fp))) {
273    linenum += n;
274    if (issep(*line))
275      continue;
276
277    cp = strip(line);
278
279    switch (*cp) {
280    case '\0':			/* empty/comment */
281      break;
282
283    case '!':
284      switch (DecodeCtrlCommand(cp+1, arg)) {
285      case CTRL_INCLUDE:
286        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
287        n = ReadSystem(bundle, name, arg, doexec, prompt);
288        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
289        if (!n)
290          return 0;	/* got it */
291        break;
292      default:
293        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
294        break;
295      }
296      break;
297
298    default:
299      wp = strchr(cp, ':');
300      if (wp == NULL || wp[1] != '\0') {
301	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
302		  filename, linenum);
303	continue;
304      }
305      *wp = '\0';
306      cp = strip(cp);  /* lose any spaces between the label and the ':' */
307
308      if (strcmp(cp, name) == 0) {
309        /* We're in business */
310	while ((n = xgets(line, sizeof line, fp))) {
311          linenum += n;
312          indent = issep(*line);
313          cp = strip(line);
314
315          if (*cp == '\0')  /* empty / comment */
316            continue;
317
318          if (!indent)      /* start of next section */
319            break;
320
321          len = strlen(cp);
322          command_Interpret(cp, len, &argc, &argv);
323          allowcmd = argc > 0 && !strcasecmp(*argv, "allow");
324          if ((!doexec && allowcmd) || (doexec && !allowcmd))
325	    command_Run(bundle, argc, (char const *const *)argv, prompt, name);
326        }
327
328	fclose(fp);  /* everything read - get out */
329	return 0;
330      }
331      break;
332    }
333  }
334  fclose(fp);
335  return -1;
336}
337
338int
339system_IsValid(const char *name, struct prompt *prompt, int mode)
340{
341  /*
342   * Note:  The ReadSystem() calls only result in calls to the Allow*
343   * functions.  arg->bundle will be set to NULL for these commands !
344   */
345  if (ID0realuid() == 0)
346    return userok = modeok = 1;
347  userok = 0;
348  modeok = 1;
349  modereq = mode;
350  ReadSystem(NULL, "default", CONFFILE, 0, prompt);
351  if (name != NULL)
352    ReadSystem(NULL, name, CONFFILE, 0, prompt);
353  return userok && modeok;
354}
355
356int
357system_Select(struct bundle *bundle, const char *name, const char *file,
358             struct prompt *prompt)
359{
360  userok = modeok = 1;
361  modereq = PHYS_ALL;
362  return ReadSystem(bundle, name, file, 1, prompt);
363}
364