systems.c revision 54914
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 * $FreeBSD: head/usr.sbin/ppp/systems.c 54914 1999-12-20 20:30:02Z brian $
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 <termios.h>
32#include <unistd.h>
33
34#include "defs.h"
35#include "command.h"
36#include "log.h"
37#include "id.h"
38#include "systems.h"
39
40#define issep(ch) ((ch) == ' ' || (ch) == '\t')
41
42FILE *
43OpenSecret(const char *file)
44{
45  FILE *fp;
46  char line[100];
47
48  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
49  fp = ID0fopen(line, "r");
50  if (fp == NULL)
51    log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
52  return (fp);
53}
54
55void
56CloseSecret(FILE *fp)
57{
58  fclose(fp);
59}
60
61/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62static void
63InterpretArg(char *from, char *to)
64{
65  const char *env;
66  char *ptr, *startto, *endto;
67  int len;
68
69  startto = to;
70  endto = to + LINE_LEN - 1;
71
72  while(issep(*from))
73    from++;
74  if (*from == '~') {
75    ptr = strchr(++from, '/');
76    len = ptr ? ptr - from : strlen(from);
77    if (len == 0) {
78      if ((env = getenv("HOME")) == NULL)
79        env = _PATH_PPP;
80      strncpy(to, env, endto - to);
81    } else {
82      struct passwd *pwd;
83
84      strncpy(to, from, len);
85      to[len] = '\0';
86      pwd = getpwnam(to);
87      if (pwd)
88        strncpy(to, pwd->pw_dir, endto-to);
89      else
90        strncpy(to, _PATH_PPP, endto - to);
91      endpwent();
92    }
93    *endto = '\0';
94    to += strlen(to);
95    from += len;
96  }
97
98  while (to < endto && *from != '\0') {
99    if (*from == '$') {
100      if (from[1] == '$') {
101        *to = '\0';	/* For an empty var name below */
102        from += 2;
103      } else if (from[1] == '{') {
104        ptr = strchr(from+2, '}');
105        if (ptr) {
106          len = ptr - from - 2;
107          if (endto - to < len )
108            len = endto - to;
109          if (len) {
110            strncpy(to, from+2, len);
111            to[len] = '\0';
112            from = ptr+1;
113          } else {
114            *to++ = *from++;
115            continue;
116          }
117        } else {
118          *to++ = *from++;
119          continue;
120        }
121      } else {
122        ptr = to;
123        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
124          *ptr++ = *from;
125        *ptr = '\0';
126      }
127      if (*to == '\0')
128        *to++ = '$';
129      else if ((env = getenv(to)) != NULL) {
130        strncpy(to, env, endto - to);
131        *endto = '\0';
132        to += strlen(to);
133      }
134    } else
135      *to++ = *from++;
136  }
137  while (to > startto) {
138    to--;
139    if (!issep(*to)) {
140      to++;
141      break;
142    }
143  }
144  *to = '\0';
145}
146
147#define CTRL_UNKNOWN (0)
148#define CTRL_INCLUDE (1)
149
150static int
151DecodeCtrlCommand(char *line, char *arg)
152{
153  if (!strncasecmp(line, "include", 7) && issep(line[7])) {
154    InterpretArg(line+8, arg);
155    return CTRL_INCLUDE;
156  }
157  return CTRL_UNKNOWN;
158}
159
160/*
161 * Initialised in system_IsValid(), set in ReadSystem(),
162 * used by system_IsValid()
163 */
164static int modeok;
165static int userok;
166static int modereq;
167
168int
169AllowUsers(struct cmdargs const *arg)
170{
171  /* arg->bundle may be NULL (see system_IsValid()) ! */
172  int f;
173  char *user;
174
175  userok = 0;
176  user = getlogin();
177  if (user && *user)
178    for (f = arg->argn; f < arg->argc; f++)
179      if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
180        userok = 1;
181        break;
182      }
183
184  return 0;
185}
186
187int
188AllowModes(struct cmdargs const *arg)
189{
190  /* arg->bundle may be NULL (see system_IsValid()) ! */
191  int f, mode, allowed;
192
193  allowed = 0;
194  for (f = arg->argn; f < arg->argc; f++) {
195    mode = Nam2mode(arg->argv[f]);
196    if (mode == PHYS_NONE || mode == PHYS_ALL)
197      log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
198    else
199      allowed |= mode;
200  }
201
202  modeok = modereq & allowed ? 1 : 0;
203  return 0;
204}
205
206static char *
207strip(char *line)
208{
209  int len;
210
211  len = strlen(line);
212  while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
213                 issep(line[len-1])))
214    line[--len] = '\0';
215
216  while (issep(*line))
217    line++;
218
219  if (*line == '#')
220    *line = '\0';
221
222  return line;
223}
224
225static int
226xgets(char *buf, int buflen, FILE *fp)
227{
228  int len, n;
229
230  n = 0;
231  while (fgets(buf, buflen-1, fp)) {
232    n++;
233    buf[buflen-1] = '\0';
234    len = strlen(buf);
235    while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
236      buf[--len] = '\0';
237    if (len && buf[len-1] == '\\') {
238      buf += len - 1;
239      buflen -= len - 1;
240      if (!buflen)        /* No buffer space */
241        break;
242    } else
243      break;
244  }
245  return n;
246}
247
248/* Values for ``how'' in ReadSystem */
249#define SYSTEM_EXISTS	1
250#define SYSTEM_VALIDATE	2
251#define SYSTEM_EXEC	3
252
253/* Returns -2 for ``file not found'' and -1 for ``label not found'' */
254
255static int
256ReadSystem(struct bundle *bundle, const char *name, const char *file,
257           struct prompt *prompt, struct datalink *cx, int how)
258{
259  FILE *fp;
260  char *cp, *wp;
261  int n, len;
262  char line[LINE_LEN];
263  char filename[MAXPATHLEN];
264  int linenum;
265  int argc;
266  char *argv[MAXARGS];
267  int allowcmd;
268  int indent;
269  char arg[LINE_LEN];
270  struct prompt *op;
271
272  if (*file == '/')
273    snprintf(filename, sizeof filename, "%s", file);
274  else
275    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
276  fp = ID0fopen(filename, "r");
277  if (fp == NULL) {
278    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
279    return -2;
280  }
281  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
282
283  linenum = 0;
284  while ((n = xgets(line, sizeof line, fp))) {
285    linenum += n;
286    if (issep(*line))
287      continue;
288
289    cp = strip(line);
290
291    switch (*cp) {
292    case '\0':			/* empty/comment */
293      break;
294
295    case '!':
296      switch (DecodeCtrlCommand(cp+1, arg)) {
297      case CTRL_INCLUDE:
298        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
299        n = ReadSystem(bundle, name, arg, prompt, cx, how);
300        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
301        if (!n)
302          return 0;	/* got it */
303        break;
304      default:
305        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
306        break;
307      }
308      break;
309
310    default:
311      wp = strchr(cp, ':');
312      if (wp == NULL || wp[1] != '\0') {
313	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
314		  filename, linenum);
315	continue;
316      }
317      *wp = '\0';
318      cp = strip(cp);  /* lose any spaces between the label and the ':' */
319
320      if (strcmp(cp, name) == 0) {
321        /* We're in business */
322        if (how == SYSTEM_EXISTS)
323	  return 0;
324	while ((n = xgets(line, sizeof line, fp))) {
325          linenum += n;
326          indent = issep(*line);
327          cp = strip(line);
328
329          if (*cp == '\0')  /* empty / comment */
330            continue;
331
332          if (!indent) {    /* start of next section */
333            if (*cp != '!') {
334              wp = strchr(cp, ':');
335              if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
336	        log_Printf(LogWARN, "Unindented command (%s line %d) -"
337                           " ignored\n", filename, linenum);
338            }
339            break;
340          }
341
342          len = strlen(cp);
343          if ((argc = command_Interpret(cp, len, argv)) < 0)
344            log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum);
345          else {
346            allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
347            if ((!(how == SYSTEM_EXEC) && allowcmd) ||
348                ((how == SYSTEM_EXEC) && !allowcmd)) {
349              /*
350               * Disable any context so that warnings are given to everyone,
351               * including syslog.
352               */
353              op = log_PromptContext;
354              log_PromptContext = NULL;
355	      command_Run(bundle, argc, (char const *const *)argv, prompt,
356                          name, cx);
357              log_PromptContext = op;
358            }
359          }
360        }
361
362	fclose(fp);  /* everything read - get out */
363	return 0;
364      }
365      break;
366    }
367  }
368  fclose(fp);
369  return -1;
370}
371
372const char *
373system_IsValid(const char *name, struct prompt *prompt, int mode)
374{
375  /*
376   * Note:  The ReadSystem() calls only result in calls to the Allow*
377   * functions.  arg->bundle will be set to NULL for these commands !
378   */
379  int def, how, rs;
380
381  def = !strcmp(name, "default");
382  how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
383  userok = 0;
384  modeok = 1;
385  modereq = mode;
386
387  rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
388
389  if (!def) {
390    if (rs == -1)
391      rs = 0;		/* we don't care that ``default'' doesn't exist */
392
393    if (rs == 0)
394      rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
395
396    if (rs == -1)
397      return "Configuration label not found";
398
399    if (rs == -2)
400      return _PATH_PPP "/" CONFFILE ": File not found";
401  }
402
403  if (how == SYSTEM_EXISTS)
404    userok = modeok = 1;
405
406  if (!userok)
407    return "User access denied";
408
409  if (!modeok)
410    return "Mode denied for this label";
411
412  return NULL;
413}
414
415int
416system_Select(struct bundle *bundle, const char *name, const char *file,
417             struct prompt *prompt, struct datalink *cx)
418{
419  userok = modeok = 1;
420  modereq = PHYS_ALL;
421  return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
422}
423