systems.c revision 55252
1193326Sed/*
2193326Sed *	          System configuration routines
3193326Sed *
4193326Sed *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5193326Sed *
6193326Sed *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7193326Sed *
8193326Sed * Redistribution and use in source and binary forms are permitted
9193326Sed * provided that the above copyright notice and this paragraph are
10193326Sed * duplicated in all such forms and that any documentation,
11193326Sed * advertising materials, and other materials related to such
12193326Sed * distribution and use acknowledge that the software was developed
13193326Sed * by the Internet Initiative Japan, Inc.  The name of the
14193326Sed * IIJ may not be used to endorse or promote products derived
15193326Sed * from this software without specific prior written permission.
16223017Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17263508Sdim * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18193326Sed * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19193326Sed *
20193326Sed * $FreeBSD: head/usr.sbin/ppp/systems.c 55252 1999-12-30 03:36:11Z brian $
21239462Sdim *
22239462Sdim *  TODO:
23193326Sed */
24263508Sdim#include <sys/param.h>
25193326Sed
26193326Sed#include <ctype.h>
27193326Sed#include <pwd.h>
28198092Srdivacky#include <stdio.h>
29193326Sed#include <stdlib.h>
30193326Sed#include <string.h>
31193326Sed#include <termios.h>
32263508Sdim#include <unistd.h>
33193326Sed
34208600Srdivacky#include "defs.h"
35208600Srdivacky#include "command.h"
36249423Sdim#include "log.h"
37263508Sdim#include "id.h"
38249423Sdim#include "systems.h"
39263508Sdim
40249423Sdim#define issep(ch) ((ch) == ' ' || (ch) == '\t')
41263508Sdim
42249423SdimFILE *
43249423SdimOpenSecret(const char *file)
44249423Sdim{
45263508Sdim  FILE *fp;
46234353Sdim  char line[100];
47263508Sdim
48263508Sdim  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
49193326Sed  fp = ID0fopen(line, "r");
50193326Sed  if (fp == NULL)
51193326Sed    log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
52263508Sdim  return (fp);
53263508Sdim}
54263508Sdim
55263508Sdimvoid
56221345SdimCloseSecret(FILE *fp)
57263508Sdim{
58263508Sdim  fclose(fp);
59263508Sdim}
60263508Sdim
61263508Sdim/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62263508Sdimstatic const char *
63263508SdimInterpretArg(const char *from, char *to)
64263508Sdim{
65263508Sdim  const char *env;
66263508Sdim  char *ptr, *startto, *endto;
67263508Sdim  int len;
68263508Sdim
69198092Srdivacky  startto = to;
70239462Sdim  endto = to + LINE_LEN - 1;
71239462Sdim
72263508Sdim  while(issep(*from))
73263508Sdim    from++;
74239462Sdim
75239462Sdim  if (*from == '~') {
76263508Sdim    struct passwd *pwd;
77263508Sdim
78263508Sdim    ptr = strchr(++from, '/');
79193326Sed    len = ptr ? ptr - from : strlen(from);
80208600Srdivacky    if (len == 0) {
81193326Sed      pwd = getpwuid(ID0realuid());
82207619Srdivacky    } else {
83203955Srdivacky      strncpy(to, from, len);
84193326Sed      to[len] = '\0';
85193326Sed      pwd = getpwnam(to);
86193326Sed    }
87198092Srdivacky    strncpy(to, pwd ? pwd->pw_dir : _PATH_PPP, endto - to);
88198092Srdivacky    endpwent();
89263508Sdim
90193326Sed    *endto = '\0';
91193326Sed    to += strlen(to);
92193326Sed    from += len;
93208600Srdivacky  }
94208600Srdivacky
95208600Srdivacky  while (to < endto && !issep(*from) && *from != '#' && *from != '\0') {
96208600Srdivacky    if (*from == '$') {
97208600Srdivacky      if (from[1] == '$') {
98208600Srdivacky        *to = '\0';	/* For an empty var name below */
99208600Srdivacky        from += 2;
100208600Srdivacky      } else if (from[1] == '{') {
101208600Srdivacky        ptr = strchr(from+2, '}');
102208600Srdivacky        if (ptr) {
103208600Srdivacky          len = ptr - from - 2;
104208600Srdivacky          if (endto - to < len )
105208600Srdivacky            len = endto - to;
106263508Sdim          if (len) {
107208600Srdivacky            strncpy(to, from+2, len);
108208600Srdivacky            to[len] = '\0';
109208600Srdivacky            from = ptr+1;
110193326Sed          } else {
111193326Sed            *to++ = *from++;
112208600Srdivacky            continue;
113193326Sed          }
114208600Srdivacky        } else {
115208600Srdivacky          *to++ = *from++;
116193326Sed          continue;
117193326Sed        }
118198092Srdivacky      } else {
119198092Srdivacky        ptr = to;
120263508Sdim        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
121193326Sed          *ptr++ = *from;
122193326Sed        *ptr = '\0';
123193326Sed      }
124193326Sed      if (*to == '\0')
125263508Sdim        *to++ = '$';
126263508Sdim      else if ((env = getenv(to)) != NULL) {
127263508Sdim        strncpy(to, env, endto - to);
128193326Sed        *endto = '\0';
129193326Sed        to += strlen(to);
130208600Srdivacky      }
131193326Sed    } else {
132208600Srdivacky      if (*from == '\\')
133208600Srdivacky        from++;
134193326Sed      *to++ = *from++;
135207619Srdivacky    }
136193326Sed  }
137193326Sed
138203955Srdivacky  while (to > startto) {
139263508Sdim    to--;
140193326Sed    if (!issep(*to)) {
141193326Sed      to++;
142208600Srdivacky      break;
143193326Sed    }
144208600Srdivacky  }
145208600Srdivacky  *to = '\0';
146193326Sed
147207619Srdivacky  while (issep(*from))
148193326Sed    from++;
149193326Sed
150203955Srdivacky  return from;
151263508Sdim}
152193326Sed
153193326Sed#define CTRL_UNKNOWN (0)
154208600Srdivacky#define CTRL_INCLUDE (1)
155193326Sed
156208600Srdivackystatic int
157208600SrdivackyDecodeCtrlCommand(char *line, char *arg)
158193326Sed{
159207619Srdivacky  const char *end;
160193326Sed
161193326Sed  if (!strncasecmp(line, "include", 7) && issep(line[7])) {
162203955Srdivacky    end = InterpretArg(line+8, arg);
163263508Sdim    if (*end && *end != '#')
164193326Sed      log_Printf(LogWARN, "Usage: !include filename\n");
165193326Sed    else
166208600Srdivacky      return CTRL_INCLUDE;
167193326Sed  }
168208600Srdivacky  return CTRL_UNKNOWN;
169208600Srdivacky}
170193326Sed
171193326Sed/*
172193326Sed * Initialised in system_IsValid(), set in ReadSystem(),
173203955Srdivacky * used by system_IsValid()
174263508Sdim */
175193326Sedstatic int modeok;
176193326Sedstatic int userok;
177208600Srdivackystatic int modereq;
178193326Sed
179208600Srdivackyint
180208600SrdivackyAllowUsers(struct cmdargs const *arg)
181193326Sed{
182193326Sed  /* arg->bundle may be NULL (see system_IsValid()) ! */
183234353Sdim  int f;
184193326Sed  struct passwd *pwd;
185203955Srdivacky
186263508Sdim  userok = 0;
187193326Sed  pwd = getpwuid(ID0realuid());
188193326Sed  if (pwd != NULL)
189193326Sed    for (f = arg->argn; f < arg->argc; f++)
190234353Sdim      if (!strcmp("*", arg->argv[f]) || !strcmp(pwd->pw_name, arg->argv[f])) {
191234353Sdim        userok = 1;
192234353Sdim        break;
193234353Sdim      }
194234353Sdim  endpwent();
195234353Sdim
196234353Sdim  return 0;
197234353Sdim}
198234353Sdim
199234353Sdimint
200234353SdimAllowModes(struct cmdargs const *arg)
201263508Sdim{
202234353Sdim  /* arg->bundle may be NULL (see system_IsValid()) ! */
203234353Sdim  int f, mode, allowed;
204234353Sdim
205263508Sdim  allowed = 0;
206234353Sdim  for (f = arg->argn; f < arg->argc; f++) {
207234353Sdim    mode = Nam2mode(arg->argv[f]);
208234353Sdim    if (mode == PHYS_NONE || mode == PHYS_ALL)
209234353Sdim      log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
210234353Sdim    else
211234353Sdim      allowed |= mode;
212234353Sdim  }
213234353Sdim
214234353Sdim  modeok = modereq & allowed ? 1 : 0;
215234353Sdim  return 0;
216234353Sdim}
217234353Sdim
218263508Sdimstatic char *
219234353Sdimstrip(char *line)
220234353Sdim{
221234353Sdim  int len;
222263508Sdim
223234353Sdim  len = strlen(line);
224234353Sdim  while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
225234353Sdim                 issep(line[len-1])))
226234353Sdim    line[--len] = '\0';
227234353Sdim
228193326Sed  while (issep(*line))
229243830Sdim    line++;
230243830Sdim
231208600Srdivacky  if (*line == '#')
232234353Sdim    *line = '\0';
233198092Srdivacky
234263508Sdim  return line;
235263508Sdim}
236198092Srdivacky
237198092Srdivackystatic int
238198092Srdivackyxgets(char *buf, int buflen, FILE *fp)
239198092Srdivacky{
240198092Srdivacky  int len, n;
241193326Sed
242208600Srdivacky  n = 0;
243208600Srdivacky  while (fgets(buf, buflen-1, fp)) {
244198092Srdivacky    n++;
245198092Srdivacky    buf[buflen-1] = '\0';
246208600Srdivacky    len = strlen(buf);
247193326Sed    while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
248208600Srdivacky      buf[--len] = '\0';
249208600Srdivacky    if (len && buf[len-1] == '\\') {
250193326Sed      buf += len - 1;
251193326Sed      buflen -= len - 1;
252193326Sed      if (!buflen)        /* No buffer space */
253193326Sed        break;
254198092Srdivacky    } else
255198092Srdivacky      break;
256263508Sdim  }
257193326Sed  return n;
258193326Sed}
259193326Sed
260208600Srdivacky/* Values for ``how'' in ReadSystem */
261243830Sdim#define SYSTEM_EXISTS	1
262263508Sdim#define SYSTEM_VALIDATE	2
263263508Sdim#define SYSTEM_EXEC	3
264263508Sdim
265193326Sedstatic char *
266193326SedGetLabel(char *line, const char *filename, int linenum)
267208600Srdivacky{
268193326Sed  char *argv[MAXARGS];
269193326Sed  int argc, len;
270234353Sdim
271193326Sed  argc = MakeArgs(line, argv, MAXARGS, PARSE_REDUCE);
272193326Sed
273198092Srdivacky  if (argc == 2 && !strcmp(argv[1], ":"))
274198092Srdivacky    return argv[0];
275263508Sdim
276193326Sed  if (argc != 1 || (len = strlen(argv[0])) < 2 || argv[0][len-1] != ':') {
277193326Sed      log_Printf(LogWARN, "Bad label in %s (line %d) - missing colon\n",
278193326Sed                 filename, linenum);
279208600Srdivacky      return NULL;
280193326Sed  }
281208600Srdivacky  argv[0][len-1] = '\0';	/* Lose the ':' */
282193326Sed
283193326Sed  return argv[0];
284193326Sed}
285193326Sed
286198092Srdivacky/* Returns -2 for ``file not found'' and -1 for ``label not found'' */
287198092Srdivacky
288263508Sdimstatic int
289193326SedReadSystem(struct bundle *bundle, const char *name, const char *file,
290193326Sed           struct prompt *prompt, struct datalink *cx, int how)
291210299Sed{
292210299Sed  FILE *fp;
293210299Sed  char *cp;
294210299Sed  int n, len;
295210299Sed  char line[LINE_LEN];
296210299Sed  char filename[MAXPATHLEN];
297210299Sed  int linenum;
298249423Sdim  int argc;
299210299Sed  char *argv[MAXARGS];
300210299Sed  int allowcmd;
301210299Sed  int indent;
302210299Sed  char arg[LINE_LEN];
303263508Sdim  struct prompt *op;
304210299Sed
305210299Sed  if (*file == '/')
306226633Sdim    snprintf(filename, sizeof filename, "%s", file);
307226633Sdim  else
308226633Sdim    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
309226633Sdim  fp = ID0fopen(filename, "r");
310249423Sdim  if (fp == NULL) {
311226633Sdim    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
312226633Sdim    return -2;
313226633Sdim  }
314226633Sdim  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
315249423Sdim
316249423Sdim  linenum = 0;
317263508Sdim  while ((n = xgets(line, sizeof line, fp))) {
318249423Sdim    linenum += n;
319226633Sdim    if (issep(*line))
320226633Sdim      continue;
321193326Sed
322193326Sed    cp = strip(line);
323195341Sed
324195341Sed    switch (*cp) {
325208600Srdivacky    case '\0':			/* empty/comment */
326195341Sed      break;
327208600Srdivacky
328208600Srdivacky    case '!':
329195341Sed      switch (DecodeCtrlCommand(cp+1, arg)) {
330195341Sed      case CTRL_INCLUDE:
331195341Sed        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
332195341Sed        n = ReadSystem(bundle, name, arg, prompt, cx, how);
333198092Srdivacky        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
334198092Srdivacky        if (!n)
335263508Sdim          return 0;	/* got it */
336195341Sed        break;
337195341Sed      default:
338208600Srdivacky        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
339195341Sed        break;
340208600Srdivacky      }
341195341Sed      break;
342195341Sed
343234353Sdim    default:
344195341Sed      if ((cp = GetLabel(cp, filename, linenum)) == NULL)
345195341Sed        continue;
346198092Srdivacky
347198092Srdivacky      if (strcmp(cp, name) == 0) {
348263508Sdim        /* We're in business */
349195341Sed        if (how == SYSTEM_EXISTS)
350195341Sed	  return 0;
351198092Srdivacky	while ((n = xgets(line, sizeof line, fp))) {
352195341Sed          linenum += n;
353239462Sdim          indent = issep(*line);
354239462Sdim          cp = strip(line);
355239462Sdim
356239462Sdim          if (*cp == '\0')			/* empty / comment */
357239462Sdim            continue;
358239462Sdim
359239462Sdim          if (!indent) {			/* start of next section */
360239462Sdim            if (*cp != '!' && how == SYSTEM_EXEC)
361239462Sdim              cp = GetLabel(cp, filename, linenum);
362239462Sdim            break;
363239462Sdim          }
364239462Sdim
365263508Sdim          len = strlen(cp);
366239462Sdim          if ((argc = command_Interpret(cp, len, argv)) < 0)
367239462Sdim            log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum);
368239462Sdim          else {
369239462Sdim            allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
370239462Sdim            if ((how != SYSTEM_EXEC && allowcmd) ||
371239462Sdim                (how == SYSTEM_EXEC && !allowcmd)) {
372239462Sdim              /*
373239462Sdim               * Disable any context so that warnings are given to everyone,
374239462Sdim               * including syslog.
375239462Sdim               */
376239462Sdim              op = log_PromptContext;
377239462Sdim              log_PromptContext = NULL;
378263508Sdim	      command_Run(bundle, argc, (char const *const *)argv, prompt,
379239462Sdim                          name, cx);
380239462Sdim              log_PromptContext = op;
381239462Sdim            }
382239462Sdim          }
383193326Sed        }
384193326Sed
385208600Srdivacky	fclose(fp);  /* everything read - get out */
386193326Sed	return 0;
387208600Srdivacky      }
388208600Srdivacky      break;
389193326Sed    }
390193326Sed  }
391193326Sed  fclose(fp);
392193326Sed  return -1;
393198092Srdivacky}
394198092Srdivacky
395263508Sdimconst char *
396193326Sedsystem_IsValid(const char *name, struct prompt *prompt, int mode)
397193326Sed{
398208600Srdivacky  /*
399193326Sed   * Note:  The ReadSystem() calls only result in calls to the Allow*
400208600Srdivacky   * functions.  arg->bundle will be set to NULL for these commands !
401193326Sed   */
402193326Sed  int def, how, rs;
403234353Sdim
404193326Sed  def = !strcmp(name, "default");
405193326Sed  how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
406198092Srdivacky  userok = 0;
407198092Srdivacky  modeok = 1;
408263508Sdim  modereq = mode;
409193326Sed
410193326Sed  rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
411198092Srdivacky
412193326Sed  if (!def) {
413218893Sdim    if (rs == -1)
414218893Sdim      rs = 0;		/* we don't care that ``default'' doesn't exist */
415218893Sdim
416223017Sdim    if (rs == 0)
417218893Sdim      rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
418234353Sdim
419234353Sdim    if (rs == -1)
420218893Sdim      return "Configuration label not found";
421218893Sdim
422218893Sdim    if (rs == -2)
423218893Sdim      return _PATH_PPP "/" CONFFILE ": File not found";
424218893Sdim  }
425218893Sdim
426263508Sdim  if (how == SYSTEM_EXISTS)
427218893Sdim    userok = modeok = 1;
428218893Sdim
429218893Sdim  if (!userok)
430223017Sdim    return "User access denied";
431218893Sdim
432234353Sdim  if (!modeok)
433234353Sdim    return "Mode denied for this label";
434218893Sdim
435218893Sdim  return NULL;
436234353Sdim}
437218893Sdim
438218893Sdimint
439218893Sdimsystem_Select(struct bundle *bundle, const char *name, const char *file,
440218893Sdim             struct prompt *prompt, struct datalink *cx)
441263508Sdim{
442218893Sdim  userok = modeok = 1;
443218893Sdim  modereq = PHYS_ALL;
444218893Sdim  return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
445218893Sdim}
446249423Sdim