systems.c revision 46828
1139743Simp/*
239212Sgibbs *	          System configuration routines
339212Sgibbs *
439212Sgibbs *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
539212Sgibbs *
639212Sgibbs *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
739212Sgibbs *
839212Sgibbs * Redistribution and use in source and binary forms are permitted
939212Sgibbs * provided that the above copyright notice and this paragraph are
1039212Sgibbs * duplicated in all such forms and that any documentation,
1139212Sgibbs * advertising materials, and other materials related to such
1239212Sgibbs * distribution and use acknowledge that the software was developed
1339212Sgibbs * by the Internet Initiative Japan, Inc.  The name of the
1439212Sgibbs * IIJ may not be used to endorse or promote products derived
1539212Sgibbs * from this software without specific prior written permission.
1639212Sgibbs * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1739212Sgibbs * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1839212Sgibbs * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1939212Sgibbs *
2039212Sgibbs * $Id: systems.c,v 1.43 1999/05/08 11:07:43 brian Exp $
2139212Sgibbs *
2239212Sgibbs *  TODO:
2339212Sgibbs */
2439212Sgibbs#include <sys/param.h>
2539212Sgibbs
2639212Sgibbs#include <ctype.h>
2739212Sgibbs#include <pwd.h>
2850477Speter#include <stdio.h>
2939212Sgibbs#include <stdlib.h>
3039212Sgibbs#include <string.h>
3139212Sgibbs#include <termios.h>
3239212Sgibbs#include <unistd.h>
3339212Sgibbs
3455206Speter#include "defs.h"
3539212Sgibbs#include "command.h"
3639212Sgibbs#include "log.h"
3739212Sgibbs#include "id.h"
3839212Sgibbs#include "systems.h"
3939212Sgibbs
4039212Sgibbs#define issep(ch) ((ch) == ' ' || (ch) == '\t')
4139212Sgibbs
4239212SgibbsFILE *
4339212SgibbsOpenSecret(const char *file)
4439212Sgibbs{
4539212Sgibbs  FILE *fp;
4639212Sgibbs  char line[100];
4739212Sgibbs
4839212Sgibbs  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
4939212Sgibbs  fp = ID0fopen(line, "r");
5039212Sgibbs  if (fp == NULL)
5139212Sgibbs    log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
5239212Sgibbs  return (fp);
5339212Sgibbs}
5439212Sgibbs
5539212Sgibbsvoid
5671507SjhbCloseSecret(FILE *fp)
5739212Sgibbs{
5839212Sgibbs  fclose(fp);
59168752Sscottl}
6046581Sken
6146581Sken/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
6239212Sgibbsstatic void
6339212SgibbsInterpretArg(char *from, char *to)
64186185Strasz{
65186185Strasz  const char *env;
6639212Sgibbs  char *ptr, *startto, *endto;
6739212Sgibbs  int len;
6839212Sgibbs
6939212Sgibbs  startto = to;
7039212Sgibbs  endto = to + LINE_LEN - 1;
7139212Sgibbs
7239212Sgibbs  while(issep(*from))
7371507Sjhb    from++;
7471507Sjhb  if (*from == '~') {
7571507Sjhb    ptr = strchr(++from, '/');
7671507Sjhb    len = ptr ? ptr - from : strlen(from);
7771507Sjhb    if (len == 0) {
7839212Sgibbs      if ((env = getenv("HOME")) == NULL)
7939212Sgibbs        env = _PATH_PPP;
8039212Sgibbs      strncpy(to, env, endto - to);
8139212Sgibbs    } else {
8239212Sgibbs      struct passwd *pwd;
8339212Sgibbs
8439212Sgibbs      strncpy(to, from, len);
8539212Sgibbs      to[len] = '\0';
8639212Sgibbs      pwd = getpwnam(to);
8739212Sgibbs      if (pwd)
8839212Sgibbs        strncpy(to, pwd->pw_dir, endto-to);
8939212Sgibbs      else
9039212Sgibbs        strncpy(to, _PATH_PPP, endto - to);
9139212Sgibbs      endpwent();
9239212Sgibbs    }
9339212Sgibbs    *endto = '\0';
9471507Sjhb    to += strlen(to);
9539212Sgibbs    from += len;
96168752Sscottl  }
97168864Sscottl
98168864Sscottl  while (to < endto && *from != '\0') {
9939212Sgibbs    if (*from == '$') {
10039212Sgibbs      if (from[1] == '$') {
10139212Sgibbs        *to = '\0';	/* For an empty var name below */
10246581Sken        from += 2;
10346581Sken      } else if (from[1] == '{') {
10439212Sgibbs        ptr = strchr(from+2, '}');
105168752Sscottl        if (ptr) {
106168752Sscottl          len = ptr - from - 2;
107168752Sscottl          if (endto - to < len )
10839212Sgibbs            len = endto - to;
109186185Strasz          if (len) {
11039212Sgibbs            strncpy(to, from+2, len);
11139212Sgibbs            to[len] = '\0';
112249224Smav            from = ptr+1;
113249224Smav          } else {
114168752Sscottl            *to++ = *from++;
11539212Sgibbs            continue;
11639212Sgibbs          }
11739212Sgibbs        } else {
11839212Sgibbs          *to++ = *from++;
11939212Sgibbs          continue;
12039212Sgibbs        }
12171507Sjhb      } else {
12239212Sgibbs        ptr = to;
12339212Sgibbs        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
12439212Sgibbs          *ptr++ = *from;
12539212Sgibbs        *ptr = '\0';
12639212Sgibbs      }
12739212Sgibbs      if (*to == '\0')
12839212Sgibbs        *to++ = '$';
12939212Sgibbs      else if ((env = getenv(to)) != NULL) {
13039212Sgibbs        strncpy(to, env, endto - to);
13139212Sgibbs        *endto = '\0';
13239212Sgibbs        to += strlen(to);
13339212Sgibbs      }
13439212Sgibbs    } else
13539212Sgibbs      *to++ = *from++;
13639212Sgibbs  }
13739212Sgibbs  while (to > startto) {
13839212Sgibbs    to--;
13939212Sgibbs    if (!issep(*to)) {
14039212Sgibbs      to++;
14139212Sgibbs      break;
14239212Sgibbs    }
14339212Sgibbs  }
14439212Sgibbs  *to = '\0';
14555206Speter}
14639212Sgibbs
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
271  if (*file == '/')
272    snprintf(filename, sizeof filename, "%s", file);
273  else
274    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
275  fp = ID0fopen(filename, "r");
276  if (fp == NULL) {
277    log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
278    return -2;
279  }
280  log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
281
282  linenum = 0;
283  while ((n = xgets(line, sizeof line, fp))) {
284    linenum += n;
285    if (issep(*line))
286      continue;
287
288    cp = strip(line);
289
290    switch (*cp) {
291    case '\0':			/* empty/comment */
292      break;
293
294    case '!':
295      switch (DecodeCtrlCommand(cp+1, arg)) {
296      case CTRL_INCLUDE:
297        log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
298        n = ReadSystem(bundle, name, arg, prompt, cx, how);
299        log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
300        if (!n)
301          return 0;	/* got it */
302        break;
303      default:
304        log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
305        break;
306      }
307      break;
308
309    default:
310      wp = strchr(cp, ':');
311      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            wp = strchr(cp, ':');
333            if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
334	      log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n",
335		         filename, linenum);
336            break;
337          }
338
339          len = strlen(cp);
340          argc = command_Interpret(cp, len, argv);
341          allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
342          if ((!(how == SYSTEM_EXEC) && allowcmd) ||
343              ((how == SYSTEM_EXEC) && !allowcmd))
344	    command_Run(bundle, argc, (char const *const *)argv, prompt,
345                        name, cx);
346        }
347
348	fclose(fp);  /* everything read - get out */
349	return 0;
350      }
351      break;
352    }
353  }
354  fclose(fp);
355  return -1;
356}
357
358const char *
359system_IsValid(const char *name, struct prompt *prompt, int mode)
360{
361  /*
362   * Note:  The ReadSystem() calls only result in calls to the Allow*
363   * functions.  arg->bundle will be set to NULL for these commands !
364   */
365  int def, how, rs;
366
367  def = !strcmp(name, "default");
368  how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
369  userok = 0;
370  modeok = 1;
371  modereq = mode;
372
373  rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
374
375  if (!def) {
376    if (rs == -1)
377      rs = 0;		/* we don't care that ``default'' doesn't exist */
378
379    if (rs == 0)
380      rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
381
382    if (rs == -1)
383      return "Configuration label not found";
384
385    if (rs == -2)
386      return _PATH_PPP "/" CONFFILE ": File not found";
387  }
388
389  if (how == SYSTEM_EXISTS)
390    userok = modeok = 1;
391
392  if (!userok)
393    return "User access denied";
394
395  if (!modeok)
396    return "Mode denied for this label";
397
398  return NULL;
399}
400
401int
402system_Select(struct bundle *bundle, const char *name, const char *file,
403             struct prompt *prompt, struct datalink *cx)
404{
405  userok = modeok = 1;
406  modereq = PHYS_ALL;
407  return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
408}
409