systems.c revision 50479
1158979Snetchild/*
2158979Snetchild *	          System configuration routines
3158979Snetchild *
4158979Snetchild *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5158979Snetchild *
6158979Snetchild *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7158979Snetchild *
8158979Snetchild * Redistribution and use in source and binary forms are permitted
9158979Snetchild * provided that the above copyright notice and this paragraph are
10158979Snetchild * duplicated in all such forms and that any documentation,
11158979Snetchild * advertising materials, and other materials related to such
12158979Snetchild * distribution and use acknowledge that the software was developed
13158979Snetchild * by the Internet Initiative Japan, Inc.  The name of the
14158979Snetchild * IIJ may not be used to endorse or promote products derived
15158979Snetchild * from this software without specific prior written permission.
16158979Snetchild * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17158979Snetchild * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18158979Snetchild * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19158979Snetchild *
20158979Snetchild * $FreeBSD: head/usr.sbin/ppp/systems.c 50479 1999-08-28 01:35:59Z peter $
21158979Snetchild *
22158979Snetchild *  TODO:
23158979Snetchild */
24158979Snetchild#include <sys/param.h>
25158979Snetchild
26158979Snetchild#include <ctype.h>
27158979Snetchild#include <pwd.h>
28158979Snetchild#include <stdio.h>
29158979Snetchild#include <stdlib.h>
30158979Snetchild#include <string.h>
31158979Snetchild#include <termios.h>
32158979Snetchild#include <unistd.h>
33158979Snetchild
34158979Snetchild#include "defs.h"
35158979Snetchild#include "command.h"
36158979Snetchild#include "log.h"
37158979Snetchild#include "id.h"
38158979Snetchild#include "systems.h"
39158979Snetchild
40158979Snetchild#define issep(ch) ((ch) == ' ' || (ch) == '\t')
41158979Snetchild
42158979SnetchildFILE *
43158979SnetchildOpenSecret(const char *file)
44158979Snetchild{
45158979Snetchild  FILE *fp;
46158979Snetchild  char line[100];
47158979Snetchild
48158979Snetchild  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
49158979Snetchild  fp = ID0fopen(line, "r");
50158979Snetchild  if (fp == NULL)
51158979Snetchild    log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
52158979Snetchild  return (fp);
53158979Snetchild}
54158979Snetchild
55158979Snetchildvoid
56158979SnetchildCloseSecret(FILE *fp)
57158979Snetchild{
58158979Snetchild  fclose(fp);
59158979Snetchild}
60158979Snetchild
61158979Snetchild/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62158979Snetchildstatic void
63158979SnetchildInterpretArg(char *from, char *to)
64158979Snetchild{
65158979Snetchild  const char *env;
66158979Snetchild  char *ptr, *startto, *endto;
67158979Snetchild  int len;
68158979Snetchild
69158979Snetchild  startto = to;
70158979Snetchild  endto = to + LINE_LEN - 1;
71158979Snetchild
72158979Snetchild  while(issep(*from))
73158979Snetchild    from++;
74158979Snetchild  if (*from == '~') {
75158979Snetchild    ptr = strchr(++from, '/');
76158979Snetchild    len = ptr ? ptr - from : strlen(from);
77158979Snetchild    if (len == 0) {
78158979Snetchild      if ((env = getenv("HOME")) == NULL)
79158979Snetchild        env = _PATH_PPP;
80158979Snetchild      strncpy(to, env, endto - to);
81158979Snetchild    } else {
82158979Snetchild      struct passwd *pwd;
83158979Snetchild
84158979Snetchild      strncpy(to, from, len);
85158979Snetchild      to[len] = '\0';
86158979Snetchild      pwd = getpwnam(to);
87158979Snetchild      if (pwd)
88158979Snetchild        strncpy(to, pwd->pw_dir, endto-to);
89158979Snetchild      else
90158979Snetchild        strncpy(to, _PATH_PPP, endto - to);
91158979Snetchild      endpwent();
92158979Snetchild    }
93158979Snetchild    *endto = '\0';
94158979Snetchild    to += strlen(to);
95158979Snetchild    from += len;
96158979Snetchild  }
97158979Snetchild
98158979Snetchild  while (to < endto && *from != '\0') {
99158979Snetchild    if (*from == '$') {
100158979Snetchild      if (from[1] == '$') {
101158979Snetchild        *to = '\0';	/* For an empty var name below */
102158979Snetchild        from += 2;
103158979Snetchild      } else if (from[1] == '{') {
104158979Snetchild        ptr = strchr(from+2, '}');
105158979Snetchild        if (ptr) {
106158979Snetchild          len = ptr - from - 2;
107158979Snetchild          if (endto - to < len )
108158979Snetchild            len = endto - to;
109158979Snetchild          if (len) {
110158979Snetchild            strncpy(to, from+2, len);
111158979Snetchild            to[len] = '\0';
112158979Snetchild            from = ptr+1;
113158979Snetchild          } else {
114158979Snetchild            *to++ = *from++;
115158979Snetchild            continue;
116158979Snetchild          }
117158979Snetchild        } else {
118158979Snetchild          *to++ = *from++;
119158979Snetchild          continue;
120158979Snetchild        }
121158979Snetchild      } else {
122158979Snetchild        ptr = to;
123158979Snetchild        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
124158979Snetchild          *ptr++ = *from;
125158979Snetchild        *ptr = '\0';
126158979Snetchild      }
127158979Snetchild      if (*to == '\0')
128158979Snetchild        *to++ = '$';
129158979Snetchild      else if ((env = getenv(to)) != NULL) {
130158979Snetchild        strncpy(to, env, endto - to);
131158979Snetchild        *endto = '\0';
132158979Snetchild        to += strlen(to);
133158979Snetchild      }
134158979Snetchild    } else
135158979Snetchild      *to++ = *from++;
136158979Snetchild  }
137158979Snetchild  while (to > startto) {
138158979Snetchild    to--;
139158979Snetchild    if (!issep(*to)) {
140158979Snetchild      to++;
141158979Snetchild      break;
142158979Snetchild    }
143158979Snetchild  }
144158979Snetchild  *to = '\0';
145158979Snetchild}
146158979Snetchild
147158979Snetchild#define CTRL_UNKNOWN (0)
148158979Snetchild#define CTRL_INCLUDE (1)
149158979Snetchild
150158979Snetchildstatic int
151158979SnetchildDecodeCtrlCommand(char *line, char *arg)
152158979Snetchild{
153158979Snetchild  if (!strncasecmp(line, "include", 7) && issep(line[7])) {
154158979Snetchild    InterpretArg(line+8, arg);
155158979Snetchild    return CTRL_INCLUDE;
156158979Snetchild  }
157158979Snetchild  return CTRL_UNKNOWN;
158158979Snetchild}
159158979Snetchild
160158979Snetchild/*
161158979Snetchild * Initialised in system_IsValid(), set in ReadSystem(),
162158979Snetchild * used by system_IsValid()
163158979Snetchild */
164158979Snetchildstatic int modeok;
165158979Snetchildstatic int userok;
166158979Snetchildstatic int modereq;
167158979Snetchild
168158979Snetchildint
169158979SnetchildAllowUsers(struct cmdargs const *arg)
170158979Snetchild{
171158979Snetchild  /* arg->bundle may be NULL (see system_IsValid()) ! */
172158979Snetchild  int f;
173158979Snetchild  char *user;
174158979Snetchild
175158979Snetchild  userok = 0;
176158979Snetchild  user = getlogin();
177158979Snetchild  if (user && *user)
178158979Snetchild    for (f = arg->argn; f < arg->argc; f++)
179158979Snetchild      if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
180158979Snetchild        userok = 1;
181158979Snetchild        break;
182158979Snetchild      }
183158979Snetchild
184158979Snetchild  return 0;
185158979Snetchild}
186158979Snetchild
187158979Snetchildint
188158979SnetchildAllowModes(struct cmdargs const *arg)
189158979Snetchild{
190158979Snetchild  /* arg->bundle may be NULL (see system_IsValid()) ! */
191158979Snetchild  int f, mode, allowed;
192158979Snetchild
193158979Snetchild  allowed = 0;
194158979Snetchild  for (f = arg->argn; f < arg->argc; f++) {
195158979Snetchild    mode = Nam2mode(arg->argv[f]);
196158979Snetchild    if (mode == PHYS_NONE || mode == PHYS_ALL)
197158979Snetchild      log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
198158979Snetchild    else
199158979Snetchild      allowed |= mode;
200158979Snetchild  }
201158979Snetchild
202158979Snetchild  modeok = modereq & allowed ? 1 : 0;
203158979Snetchild  return 0;
204158979Snetchild}
205158979Snetchild
206158979Snetchildstatic char *
207158979Snetchildstrip(char *line)
208158979Snetchild{
209158979Snetchild  int len;
210158979Snetchild
211158979Snetchild  len = strlen(line);
212158979Snetchild  while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
213158979Snetchild                 issep(line[len-1])))
214158979Snetchild    line[--len] = '\0';
215158979Snetchild
216158979Snetchild  while (issep(*line))
217158979Snetchild    line++;
218158979Snetchild
219158979Snetchild  if (*line == '#')
220158979Snetchild    *line = '\0';
221158979Snetchild
222158979Snetchild  return line;
223158979Snetchild}
224158979Snetchild
225158979Snetchildstatic int
226158979Snetchildxgets(char *buf, int buflen, FILE *fp)
227158979Snetchild{
228158979Snetchild  int len, n;
229158979Snetchild
230158979Snetchild  n = 0;
231158979Snetchild  while (fgets(buf, buflen-1, fp)) {
232158979Snetchild    n++;
233158979Snetchild    buf[buflen-1] = '\0';
234158979Snetchild    len = strlen(buf);
235158979Snetchild    while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
236158979Snetchild      buf[--len] = '\0';
237158979Snetchild    if (len && buf[len-1] == '\\') {
238158979Snetchild      buf += len - 1;
239158979Snetchild      buflen -= len - 1;
240158979Snetchild      if (!buflen)        /* No buffer space */
241158979Snetchild        break;
242158979Snetchild    } else
243158979Snetchild      break;
244158979Snetchild  }
245158979Snetchild  return n;
246158979Snetchild}
247158979Snetchild
248158979Snetchild/* Values for ``how'' in ReadSystem */
249158979Snetchild#define SYSTEM_EXISTS	1
250158979Snetchild#define SYSTEM_VALIDATE	2
251158979Snetchild#define SYSTEM_EXEC	3
252158979Snetchild
253158979Snetchild/* Returns -2 for ``file not found'' and -1 for ``label not found'' */
254158979Snetchild
255158979Snetchildstatic int
256158979SnetchildReadSystem(struct bundle *bundle, const char *name, const char *file,
257158979Snetchild           struct prompt *prompt, struct datalink *cx, int how)
258158979Snetchild{
259158979Snetchild  FILE *fp;
260158979Snetchild  char *cp, *wp;
261158979Snetchild  int n, len;
262158979Snetchild  char line[LINE_LEN];
263158979Snetchild  char filename[MAXPATHLEN];
264158979Snetchild  int linenum;
265158979Snetchild  int argc;
266158979Snetchild  char *argv[MAXARGS];
267158979Snetchild  int allowcmd;
268158979Snetchild  int indent;
269158979Snetchild  char arg[LINE_LEN];
270158979Snetchild
271158979Snetchild  if (*file == '/')
272158979Snetchild    snprintf(filename, sizeof filename, "%s", file);
273158979Snetchild  else
274158979Snetchild    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
275158979Snetchild  fp = ID0fopen(filename, "r");
276158979Snetchild  if (fp == NULL) {
277158979Snetchild    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
278158979Snetchild    return -2;
279158979Snetchild  }
280158979Snetchild  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
281158979Snetchild
282158979Snetchild  linenum = 0;
283158979Snetchild  while ((n = xgets(line, sizeof line, fp))) {
284158979Snetchild    linenum += n;
285158979Snetchild    if (issep(*line))
286158979Snetchild      continue;
287158979Snetchild
288158979Snetchild    cp = strip(line);
289158979Snetchild
290158979Snetchild    switch (*cp) {
291158979Snetchild    case '\0':			/* empty/comment */
292158979Snetchild      break;
293158979Snetchild
294158979Snetchild    case '!':
295158979Snetchild      switch (DecodeCtrlCommand(cp+1, arg)) {
296158979Snetchild      case CTRL_INCLUDE:
297158979Snetchild        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
298158979Snetchild        n = ReadSystem(bundle, name, arg, prompt, cx, how);
299158979Snetchild        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
300158979Snetchild        if (!n)
301158979Snetchild          return 0;	/* got it */
302158979Snetchild        break;
303158979Snetchild      default:
304158979Snetchild        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
305158979Snetchild        break;
306158979Snetchild      }
307158979Snetchild      break;
308158979Snetchild
309158979Snetchild    default:
310158979Snetchild      wp = strchr(cp, ':');
311158979Snetchild      if (wp == NULL || wp[1] != '\0') {
312	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
313		  filename, linenum);
314	continue;
315      }
316      *wp = '\0';
317      cp = strip(cp);  /* lose any spaces between the label and the ':' */
318
319      if (strcmp(cp, name) == 0) {
320        /* We're in business */
321        if (how == SYSTEM_EXISTS)
322	  return 0;
323	while ((n = xgets(line, sizeof line, fp))) {
324          linenum += n;
325          indent = issep(*line);
326          cp = strip(line);
327
328          if (*cp == '\0')  /* empty / comment */
329            continue;
330
331          if (!indent) {    /* start of next section */
332            if (*cp != '!') {
333              wp = strchr(cp, ':');
334              if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
335	        log_Printf(LogWARN, "Unindented command (%s line %d) -"
336                           " ignored\n", filename, linenum);
337            }
338            break;
339          }
340
341          len = strlen(cp);
342          argc = command_Interpret(cp, len, argv);
343          allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
344          if ((!(how == SYSTEM_EXEC) && allowcmd) ||
345              ((how == SYSTEM_EXEC) && !allowcmd))
346	    command_Run(bundle, argc, (char const *const *)argv, prompt,
347                        name, cx);
348        }
349
350	fclose(fp);  /* everything read - get out */
351	return 0;
352      }
353      break;
354    }
355  }
356  fclose(fp);
357  return -1;
358}
359
360const char *
361system_IsValid(const char *name, struct prompt *prompt, int mode)
362{
363  /*
364   * Note:  The ReadSystem() calls only result in calls to the Allow*
365   * functions.  arg->bundle will be set to NULL for these commands !
366   */
367  int def, how, rs;
368
369  def = !strcmp(name, "default");
370  how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
371  userok = 0;
372  modeok = 1;
373  modereq = mode;
374
375  rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
376
377  if (!def) {
378    if (rs == -1)
379      rs = 0;		/* we don't care that ``default'' doesn't exist */
380
381    if (rs == 0)
382      rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
383
384    if (rs == -1)
385      return "Configuration label not found";
386
387    if (rs == -2)
388      return _PATH_PPP "/" CONFFILE ": File not found";
389  }
390
391  if (how == SYSTEM_EXISTS)
392    userok = modeok = 1;
393
394  if (!userok)
395    return "User access denied";
396
397  if (!modeok)
398    return "Mode denied for this label";
399
400  return NULL;
401}
402
403int
404system_Select(struct bundle *bundle, const char *name, const char *file,
405             struct prompt *prompt, struct datalink *cx)
406{
407  userok = modeok = 1;
408  modereq = PHYS_ALL;
409  return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
410}
411