systems.c revision 44612
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.41 1999/02/02 09:35:30 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 "defs.h"
34#include "command.h"
35#include "log.h"
36#include "id.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/*
160 * Initialised in system_IsValid(), set in ReadSystem(),
161 * used by system_IsValid()
162 */
163static int modeok;
164static int userok;
165static int modereq;
166
167int
168AllowUsers(struct cmdargs const *arg)
169{
170  /* arg->bundle may be NULL (see system_IsValid()) ! */
171  int f;
172  char *user;
173
174  userok = 0;
175  user = getlogin();
176  if (user && *user)
177    for (f = arg->argn; f < arg->argc; f++)
178      if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
179        userok = 1;
180        break;
181      }
182
183  return 0;
184}
185
186int
187AllowModes(struct cmdargs const *arg)
188{
189  /* arg->bundle may be NULL (see system_IsValid()) ! */
190  int f, mode, allowed;
191
192  allowed = 0;
193  for (f = arg->argn; f < arg->argc; f++) {
194    mode = Nam2mode(arg->argv[f]);
195    if (mode == PHYS_NONE || mode == PHYS_ALL)
196      log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
197    else
198      allowed |= mode;
199  }
200
201  modeok = modereq & allowed ? 1 : 0;
202  return 0;
203}
204
205static char *
206strip(char *line)
207{
208  int len;
209
210  len = strlen(line);
211  while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
212                 issep(line[len-1])))
213    line[--len] = '\0';
214
215  while (issep(*line))
216    line++;
217
218  if (*line == '#')
219    *line = '\0';
220
221  return line;
222}
223
224static int
225xgets(char *buf, int buflen, FILE *fp)
226{
227  int len, n;
228
229  n = 0;
230  while (fgets(buf, buflen-1, fp)) {
231    n++;
232    buf[buflen-1] = '\0';
233    len = strlen(buf);
234    while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
235      buf[--len] = '\0';
236    if (len && buf[len-1] == '\\') {
237      buf += len - 1;
238      buflen -= len - 1;
239      if (!buflen)        /* No buffer space */
240        break;
241    } else
242      break;
243  }
244  return n;
245}
246
247/* Values for ``how'' in ReadSystem */
248#define SYSTEM_EXISTS	1
249#define SYSTEM_VALIDATE	2
250#define SYSTEM_EXEC	3
251
252/* Returns -2 for ``file not found'' and -1 for ``label not found'' */
253
254static int
255ReadSystem(struct bundle *bundle, const char *name, const char *file,
256           struct prompt *prompt, struct datalink *cx, int how)
257{
258  FILE *fp;
259  char *cp, *wp;
260  int n, len;
261  char line[LINE_LEN];
262  char filename[MAXPATHLEN];
263  int linenum;
264  int argc;
265  char *argv[MAXARGS];
266  int allowcmd;
267  int indent;
268  char arg[LINE_LEN];
269
270  if (*file == '/')
271    snprintf(filename, sizeof filename, "%s", file);
272  else
273    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
274  fp = ID0fopen(filename, "r");
275  if (fp == NULL) {
276    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
277    return -2;
278  }
279  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
280
281  linenum = 0;
282  while ((n = xgets(line, sizeof line, fp))) {
283    linenum += n;
284    if (issep(*line))
285      continue;
286
287    cp = strip(line);
288
289    switch (*cp) {
290    case '\0':			/* empty/comment */
291      break;
292
293    case '!':
294      switch (DecodeCtrlCommand(cp+1, arg)) {
295      case CTRL_INCLUDE:
296        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
297        n = ReadSystem(bundle, name, arg, prompt, cx, how);
298        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
299        if (!n)
300          return 0;	/* got it */
301        break;
302      default:
303        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
304        break;
305      }
306      break;
307
308    default:
309      wp = strchr(cp, ':');
310      if (wp == NULL || wp[1] != '\0') {
311	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
312		  filename, linenum);
313	continue;
314      }
315      *wp = '\0';
316      cp = strip(cp);  /* lose any spaces between the label and the ':' */
317
318      if (strcmp(cp, name) == 0) {
319        /* We're in business */
320        if (how == SYSTEM_EXISTS)
321	  return 0;
322	while ((n = xgets(line, sizeof line, fp))) {
323          linenum += n;
324          indent = issep(*line);
325          cp = strip(line);
326
327          if (*cp == '\0')  /* empty / comment */
328            continue;
329
330          if (!indent) {    /* start of next section */
331            wp = strchr(cp, ':');
332            if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
333	      log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n",
334		         filename, linenum);
335            break;
336          }
337
338          len = strlen(cp);
339          argc = command_Interpret(cp, len, argv);
340          allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
341          if ((!(how == SYSTEM_EXEC) && allowcmd) ||
342              ((how == SYSTEM_EXEC) && !allowcmd))
343	    command_Run(bundle, argc, (char const *const *)argv, prompt,
344                        name, cx);
345        }
346
347	fclose(fp);  /* everything read - get out */
348	return 0;
349      }
350      break;
351    }
352  }
353  fclose(fp);
354  return -1;
355}
356
357const char *
358system_IsValid(const char *name, struct prompt *prompt, int mode)
359{
360  /*
361   * Note:  The ReadSystem() calls only result in calls to the Allow*
362   * functions.  arg->bundle will be set to NULL for these commands !
363   */
364  int def, how, rs;
365
366  def = !strcmp(name, "default");
367  how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
368  userok = 0;
369  modeok = 1;
370  modereq = mode;
371
372  rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
373
374  if (!def) {
375    if (rs == -1)
376      rs = 0;		/* we don't care that ``default'' doesn't exist */
377
378    if (rs == 0)
379      rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
380
381    if (rs == -1)
382      return "Configuration label not found";
383
384    if (rs == -2)
385      return _PATH_PPP "/" CONFFILE ": File not found";
386  }
387
388  if (how == SYSTEM_EXISTS)
389    userok = modeok = 1;
390
391  if (!userok)
392    return "User access denied";
393
394  if (!modeok)
395    return "Mode denied for this label";
396
397  return NULL;
398}
399
400int
401system_Select(struct bundle *bundle, const char *name, const char *file,
402             struct prompt *prompt, struct datalink *cx)
403{
404  userok = modeok = 1;
405  modereq = PHYS_ALL;
406  return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
407}
408