systems.c revision 31918
1222417Sjulian/*
2222417Sjulian *	          System configuration routines
3241310Sdteske *
4222417Sjulian *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5222417Sjulian *
6222417Sjulian *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7222417Sjulian *
8222417Sjulian * Redistribution and use in source and binary forms are permitted
9222417Sjulian * provided that the above copyright notice and this paragraph are
10222417Sjulian * duplicated in all such forms and that any documentation,
11222417Sjulian * advertising materials, and other materials related to such
12222417Sjulian * distribution and use acknowledge that the software was developed
13222417Sjulian * by the Internet Initiative Japan, Inc.  The name of the
14222417Sjulian * IIJ may not be used to endorse or promote products derived
15222417Sjulian * from this software without specific prior written permission.
16222417Sjulian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17222417Sjulian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18222417Sjulian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19222417Sjulian *
20222417Sjulian * $Id: systems.c,v 1.32 1997/12/21 02:11:48 brian Exp $
21222417Sjulian *
22222417Sjulian *  TODO:
23222417Sjulian */
24222417Sjulian#include <sys/param.h>
25222417Sjulian#include <netinet/in.h>
26222417Sjulian
27222417Sjulian#include <ctype.h>
28222417Sjulian#include <pwd.h>
29222417Sjulian#include <stdio.h>
30222417Sjulian#include <stdlib.h>
31222417Sjulian#include <string.h>
32222417Sjulian#include <unistd.h>
33222417Sjulian
34222417Sjulian#include "command.h"
35222417Sjulian#include "mbuf.h"
36222417Sjulian#include "log.h"
37222417Sjulian#include "id.h"
38222417Sjulian#include "defs.h"
39222417Sjulian#include "timer.h"
40222417Sjulian#include "fsm.h"
41222417Sjulian#include "loadalias.h"
42222417Sjulian#include "ipcp.h"
43222417Sjulian#include "pathnames.h"
44222417Sjulian#include "vars.h"
45222417Sjulian#include "server.h"
46222417Sjulian#include "chat.h"
47222417Sjulian#include "systems.h"
48222417Sjulian
49222417Sjulian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
50222417Sjulian
51222417SjulianFILE *
52222417SjulianOpenSecret(const char *file)
53222417Sjulian{
54222417Sjulian  FILE *fp;
55222417Sjulian  char line[100];
56222417Sjulian
57222417Sjulian  snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
58222417Sjulian  fp = ID0fopen(line, "r");
59222417Sjulian  if (fp == NULL)
60222417Sjulian    LogPrintf(LogWARN, "OpenSecret: Can't open %s.\n", line);
61222417Sjulian  return (fp);
62222417Sjulian}
63222417Sjulian
64222417Sjulianvoid
65222417SjulianCloseSecret(FILE * fp)
66222417Sjulian{
67222417Sjulian  fclose(fp);
68222417Sjulian}
69222417Sjulian
70222417Sjulian/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
71222417Sjulianstatic void
72222417SjulianInterpretArg(char *from, char *to)
73222417Sjulian{
74222417Sjulian  const char *env;
75222417Sjulian  char *ptr, *startto, *endto;
76222417Sjulian  int len;
77222417Sjulian
78222417Sjulian  startto = to;
79222417Sjulian  endto = to + LINE_LEN - 1;
80222417Sjulian
81222417Sjulian  while(issep(*from))
82222417Sjulian    from++;
83222417Sjulian  if (*from == '~') {
84222417Sjulian    ptr = strchr(++from, '/');
85222417Sjulian    len = ptr ? ptr - from : strlen(from);
86222417Sjulian    if (len == 0) {
87222417Sjulian      if ((env = getenv("HOME")) == NULL)
88222417Sjulian        env = _PATH_PPP;
89222417Sjulian      strncpy(to, env, endto - to);
90222417Sjulian    } else {
91222417Sjulian      struct passwd *pwd;
92222417Sjulian
93222417Sjulian      strncpy(to, from, len);
94222417Sjulian      to[len] = '\0';
95222417Sjulian      pwd = getpwnam(to);
96222417Sjulian      if (pwd)
97222417Sjulian        strncpy(to, pwd->pw_dir, endto-to);
98222417Sjulian      else
99222417Sjulian        strncpy(to, _PATH_PPP, endto - to);
100222417Sjulian      endpwent();
101222417Sjulian    }
102222417Sjulian    *endto = '\0';
103222417Sjulian    to += strlen(to);
104222417Sjulian    from += len;
105222417Sjulian  }
106222417Sjulian
107222417Sjulian  while (to < endto && *from != '\0') {
108222417Sjulian    if (*from == '$') {
109222417Sjulian      if (from[1] == '$') {
110222417Sjulian        *to = '\0';	/* For an empty var name below */
111222417Sjulian        from += 2;
112222417Sjulian      } else if (from[1] == '{') {
113222417Sjulian        ptr = strchr(from+2, '}');
114222417Sjulian        if (ptr) {
115222417Sjulian          len = ptr - from - 2;
116222417Sjulian          if (endto - to < len )
117222417Sjulian            len = endto - to;
118222417Sjulian          if (len) {
119222417Sjulian            strncpy(to, from+2, len);
120222417Sjulian            to[len] = '\0';
121222417Sjulian            from = ptr+1;
122222417Sjulian          } else {
123222417Sjulian            *to++ = *from++;
124222417Sjulian            continue;
125222417Sjulian          }
126222417Sjulian        } else {
127222417Sjulian          *to++ = *from++;
128222417Sjulian          continue;
129222417Sjulian        }
130222417Sjulian      } else {
131222417Sjulian        ptr = to;
132222417Sjulian        for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
133222417Sjulian          *ptr++ = *from;
134228985Spluknet        *ptr = '\0';
135222417Sjulian      }
136222417Sjulian      if (*to == '\0')
137222417Sjulian        *to++ = '$';
138228985Spluknet      else if ((env = getenv(to)) != NULL) {
139222417Sjulian        strncpy(to, env, endto - to);
140222417Sjulian        *endto = '\0';
141222417Sjulian        to += strlen(to);
142222417Sjulian      }
143222417Sjulian    } else
144222417Sjulian      *to++ = *from++;
145222417Sjulian  }
146222417Sjulian  while (to > startto) {
147222417Sjulian    to--;
148222417Sjulian    if (!issep(*to)) {
149222417Sjulian      to++;
150222417Sjulian      break;
151222417Sjulian    }
152222417Sjulian  }
153222417Sjulian  *to = '\0';
154222417Sjulian}
155222417Sjulian
156222417Sjulian#define CTRL_UNKNOWN (0)
157222417Sjulian#define CTRL_INCLUDE (1)
158222417Sjulian
159222417Sjulianstatic int
160222417SjulianDecodeCtrlCommand(char *line, char *arg)
161222417Sjulian{
162222417Sjulian  if (!strncasecmp(line, "include", 7) && issep(line[7])) {
163222417Sjulian    InterpretArg(line+8, arg);
164222417Sjulian    return CTRL_INCLUDE;
165222417Sjulian  }
166222417Sjulian  return CTRL_UNKNOWN;
167222417Sjulian}
168222417Sjulian
169222417Sjulianstatic int userok;
170222417Sjulian
171222417Sjulianint
172222417SjulianAllowUsers(struct cmdargs const *arg)
173222417Sjulian{
174222417Sjulian  int f;
175222417Sjulian  char *user;
176222417Sjulian
177222417Sjulian  userok = 0;
178222417Sjulian  user = getlogin();
179222417Sjulian  if (user && *user)
180222417Sjulian    for (f = 0; f < arg->argc; f++)
181222417Sjulian      if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
182222417Sjulian        userok = 1;
183222417Sjulian        break;
184222417Sjulian      }
185222417Sjulian
186222417Sjulian  return 0;
187222417Sjulian}
188222417Sjulian
189222417Sjulianstatic struct {
190222417Sjulian  int mode;
191222417Sjulian  const char *name;
192222417Sjulian} modes[] = {
193222417Sjulian  { MODE_INTER, "interactive" },
194222417Sjulian  { MODE_AUTO, "auto" },
195222417Sjulian  { MODE_DIRECT, "direct" },
196222417Sjulian  { MODE_DEDICATED, "dedicated" },
197222417Sjulian  { MODE_DDIAL, "ddial" },
198222417Sjulian  { MODE_BACKGROUND, "background" },
199222417Sjulian  { ~0, "*" },
200222417Sjulian  { 0, 0 }
201222417Sjulian};
202222417Sjulian
203222417Sjulianstatic int modeok;
204222417Sjulian
205222417Sjulianint
206222417SjulianAllowModes(struct cmdargs const *arg)
207222417Sjulian{
208222417Sjulian  int f;
209222417Sjulian  int m;
210222417Sjulian  int allowed;
211222417Sjulian
212222417Sjulian  allowed = 0;
213222417Sjulian  for (f = 0; f < arg->argc; f++) {
214222417Sjulian    for (m = 0; modes[m].mode; m++)
215222417Sjulian      if (!strcasecmp(modes[m].name, arg->argv[f])) {
216222417Sjulian        allowed |= modes[m].mode;
217222417Sjulian        break;
218222417Sjulian      }
219222417Sjulian    if (modes[m].mode == 0)
220222417Sjulian      LogPrintf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
221222417Sjulian  }
222222417Sjulian
223222417Sjulian  modeok = (mode | allowed) == allowed ? 1 : 0;
224222417Sjulian  return 0;
225222417Sjulian}
226222417Sjulian
227222417Sjulianstatic int
228222417SjulianReadSystem(const char *name, const char *file, int doexec)
229222417Sjulian{
230222417Sjulian  FILE *fp;
231222417Sjulian  char *cp, *wp;
232222417Sjulian  int n, len;
233222417Sjulian  u_char olauth;
234222417Sjulian  char line[LINE_LEN];
235222417Sjulian  char filename[MAXPATHLEN];
236222417Sjulian  int linenum;
237222417Sjulian  int argc;
238222417Sjulian  char **argv;
239222417Sjulian  int allowcmd;
240222417Sjulian
241222417Sjulian  if (*file == '/')
242222417Sjulian    snprintf(filename, sizeof filename, "%s", file);
243222417Sjulian  else
244222417Sjulian    snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
245222417Sjulian  fp = ID0fopen(filename, "r");
246222417Sjulian  if (fp == NULL) {
247222417Sjulian    LogPrintf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
248222417Sjulian    return (-1);
249222417Sjulian  }
250222417Sjulian  LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
251222417Sjulian
252222417Sjulian  linenum = 0;
253222417Sjulian  while (fgets(line, sizeof(line), fp)) {
254222417Sjulian    linenum++;
255222417Sjulian    cp = line;
256222417Sjulian    switch (*cp) {
257222417Sjulian    case '#':			/* comment */
258222417Sjulian      break;
259222417Sjulian    case ' ':
260222417Sjulian    case '\t':
261222417Sjulian      break;
262222417Sjulian    default:
263222417Sjulian      wp = strpbrk(cp, ":\n");
264222417Sjulian      if (wp == NULL) {
265222417Sjulian	LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
266222417Sjulian		  filename, linenum);
267222417Sjulian	ServerClose();
268222417Sjulian	exit(1);
269222417Sjulian      }
270222417Sjulian      *wp = '\0';
271222417Sjulian      if (*cp == '!') {
272222417Sjulian        char arg[LINE_LEN];
273222417Sjulian        switch (DecodeCtrlCommand(cp+1, arg)) {
274222417Sjulian        case CTRL_INCLUDE:
275222417Sjulian          LogPrintf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
276222417Sjulian          n = ReadSystem(name, arg, doexec);
277222417Sjulian          LogPrintf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
278222417Sjulian          if (!n)
279222417Sjulian            return 0;	/* got it */
280222417Sjulian          break;
281222417Sjulian        default:
282222417Sjulian          LogPrintf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
283222417Sjulian          break;
284222417Sjulian        }
285222417Sjulian      } else if (strcmp(cp, name) == 0) {
286222417Sjulian	while (fgets(line, sizeof(line), fp)) {
287222417Sjulian	  cp = line;
288222417Sjulian          if (issep(*cp)) {
289222417Sjulian	    n = strspn(cp, " \t");
290222417Sjulian	    cp += n;
291222417Sjulian            len = strlen(cp);
292222417Sjulian            if (!len || *cp == '#')
293222417Sjulian              continue;
294222417Sjulian            if (cp[len-1] == '\n')
295222417Sjulian              cp[--len] = '\0';
296222417Sjulian            if (!len)
297222417Sjulian              continue;
298222417Sjulian            InterpretCommand(cp, len, &argc, &argv);
299222417Sjulian            allowcmd = argc > 0 && !strcasecmp(*argv, "allow");
300222417Sjulian            if ((!doexec && allowcmd) || (doexec && !allowcmd)) {
301222417Sjulian	      olauth = VarLocalAuth;
302222417Sjulian	      if (VarLocalAuth == LOCAL_NO_AUTH)
303222417Sjulian	        VarLocalAuth = LOCAL_AUTH;
304222417Sjulian	      RunCommand(argc, (char const *const *)argv, name);
305222417Sjulian	      VarLocalAuth = olauth;
306222417Sjulian	    }
307222417Sjulian	  } else if (*cp == '#' || *cp == '\n' || *cp == '\0') {
308222417Sjulian	    continue;
309222417Sjulian	  } else
310222417Sjulian	    break;
311222417Sjulian	}
312222417Sjulian	fclose(fp);
313222417Sjulian	return (0);
314222417Sjulian      }
315222417Sjulian      break;
316222417Sjulian    }
317222417Sjulian  }
318222417Sjulian  fclose(fp);
319222417Sjulian  return -1;
320222417Sjulian}
321222417Sjulian
322222417Sjulianint
323222417SjulianValidSystem(const char *name)
324222417Sjulian{
325222417Sjulian  if (ID0realuid() == 0)
326222417Sjulian    return userok = modeok = 1;
327222417Sjulian  userok = 0;
328222417Sjulian  modeok = 1;
329222417Sjulian  ReadSystem("default", CONFFILE, 0);
330222417Sjulian  if (name != NULL)
331222417Sjulian    ReadSystem(name, CONFFILE, 0);
332222417Sjulian  return userok && modeok;
333222417Sjulian}
334222417Sjulian
335222417Sjulianint
336222417SjulianSelectSystem(const char *name, const char *file)
337222417Sjulian{
338222417Sjulian  userok = modeok = 1;
339222417Sjulian  return ReadSystem(name, file, 1);
340222417Sjulian}
341222417Sjulian
342222417Sjulianint
343222417SjulianLoadCommand(struct cmdargs const *arg)
344222417Sjulian{
345222417Sjulian  const char *name;
346222417Sjulian
347222417Sjulian  if (arg->argc > 0)
348222417Sjulian    name = *arg->argv;
349222417Sjulian  else
350222417Sjulian    name = "default";
351222417Sjulian
352222417Sjulian  if (!ValidSystem(name)) {
353222417Sjulian    LogPrintf(LogERROR, "%s: Label not allowed\n", name);
354222417Sjulian    return 1;
355222417Sjulian  } else if (SelectSystem(name, CONFFILE) < 0) {
356222417Sjulian    LogPrintf(LogWARN, "%s: label not found.\n", name);
357222417Sjulian    return -1;
358222417Sjulian  } else
359222417Sjulian    SetLabel(arg->argc ? name : NULL);
360222417Sjulian  return 0;
361222417Sjulian}
362222417Sjulian
363222417Sjulianint
364222417SjulianSaveCommand(struct cmdargs const *arg)
365222417Sjulian{
366222417Sjulian  LogPrintf(LogWARN, "save command is not implemented (yet).\n");
367222417Sjulian  return 1;
368222417Sjulian}
369222417Sjulian