xref: /freebsd/usr.sbin/ppp/systems.c (revision d24f017be800e31ad16d74ae3366abab383cefe0)
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  * $Id: systems.c,v 1.35.2.4 1998/04/03 19:25:58 brian Exp $
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 <unistd.h>
32 
33 #include "command.h"
34 #include "log.h"
35 #include "id.h"
36 #include "defs.h"
37 #include "pathnames.h"
38 #include "systems.h"
39 
40 #define issep(ch) ((ch) == ' ' || (ch) == '\t')
41 
42 FILE *
43 OpenSecret(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     LogPrintf(LogWARN, "OpenSecret: Can't open %s.\n", line);
52   return (fp);
53 }
54 
55 void
56 CloseSecret(FILE * fp)
57 {
58   fclose(fp);
59 }
60 
61 /* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62 static void
63 InterpretArg(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 
150 static int
151 DecodeCtrlCommand(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 static int userok;
161 
162 int
163 AllowUsers(struct cmdargs const *arg)
164 {
165   /* arg->bundle may be NULL (see ValidSystem()) ! */
166   int f;
167   char *user;
168 
169   userok = 0;
170   user = getlogin();
171   if (user && *user)
172     for (f = 0; f < arg->argc; f++)
173       if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
174         userok = 1;
175         break;
176       }
177 
178   return 0;
179 }
180 
181 static struct {
182   int mode;
183   const char *name;
184 } modes[] = {
185   { MODE_INTER, "interactive" },
186   { MODE_AUTO, "auto" },
187   { MODE_DIRECT, "direct" },
188   { MODE_DEDICATED, "dedicated" },
189   { MODE_DDIAL, "ddial" },
190   { MODE_BACKGROUND, "background" },
191   { ~0, "*" },
192   { 0, 0 }
193 };
194 
195 static int modeok;
196 
197 int
198 AllowModes(struct cmdargs const *arg)
199 {
200   /* arg->bundle may be NULL (see ValidSystem()) ! */
201   int f;
202   int m;
203   int allowed;
204 
205   allowed = 0;
206   for (f = 0; f < arg->argc; f++) {
207     for (m = 0; modes[m].mode; m++)
208       if (!strcasecmp(modes[m].name, arg->argv[f])) {
209         allowed |= modes[m].mode;
210         break;
211       }
212     if (modes[m].mode == 0)
213       LogPrintf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
214   }
215 
216   modeok = (mode | allowed) == allowed ? 1 : 0;
217   return 0;
218 }
219 
220 static char *
221 strip(char *line)
222 {
223   int len;
224 
225   len = strlen(line);
226   while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
227                  issep(line[len-1])))
228     line[--len] = '\0';
229 
230   while (issep(*line))
231     line++;
232 
233   if (*line == '#')
234     *line = '\0';
235 
236   return line;
237 }
238 
239 static int
240 xgets(char *buf, int buflen, FILE *fp)
241 {
242   int len, n;
243 
244   n = 0;
245   while (fgets(buf, buflen-1, fp)) {
246     n++;
247     buf[buflen-1] = '\0';
248     len = strlen(buf);
249     while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
250       buf[--len] = '\0';
251     if (len && buf[len-1] == '\\') {
252       buf += len - 1;
253       buflen -= len - 1;
254       if (!buflen)        /* No buffer space */
255         break;
256     } else
257       break;
258   }
259   return n;
260 }
261 
262 static int
263 ReadSystem(struct bundle *bundle, const char *name, const char *file,
264            int doexec, struct prompt *prompt)
265 {
266   FILE *fp;
267   char *cp, *wp;
268   int n, len;
269   char line[LINE_LEN];
270   char filename[MAXPATHLEN];
271   int linenum;
272   int argc;
273   char **argv;
274   int allowcmd;
275   int indent;
276   char arg[LINE_LEN];
277 
278   if (*file == '/')
279     snprintf(filename, sizeof filename, "%s", file);
280   else
281     snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
282   fp = ID0fopen(filename, "r");
283   if (fp == NULL) {
284     LogPrintf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
285     return (-1);
286   }
287   LogPrintf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
288 
289   linenum = 0;
290   while ((n = xgets(line, sizeof line, fp))) {
291     linenum += n;
292     if (issep(*line))
293       continue;
294 
295     cp = strip(line);
296 
297     switch (*cp) {
298     case '\0':			/* empty/comment */
299       break;
300 
301     case '!':
302       switch (DecodeCtrlCommand(cp+1, arg)) {
303       case CTRL_INCLUDE:
304         LogPrintf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
305         n = ReadSystem(bundle, name, arg, doexec, prompt);
306         LogPrintf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
307         if (!n)
308           return 0;	/* got it */
309         break;
310       default:
311         LogPrintf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
312         break;
313       }
314       break;
315 
316     default:
317       wp = strchr(cp, ':');
318       if (wp == NULL || wp[1] != '\0') {
319 	LogPrintf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
320 		  filename, linenum);
321 	continue;
322       }
323       *wp = '\0';
324       cp = strip(cp);  /* lose any spaces between the label and the ':' */
325 
326       if (strcmp(cp, name) == 0) {
327         /* We're in business */
328 	while ((n = xgets(line, sizeof line, fp))) {
329           linenum += n;
330           indent = issep(*line);
331           cp = strip(line);
332 
333           if (*cp == '\0')  /* empty / comment */
334             continue;
335 
336           if (!indent)      /* start of next section */
337             break;
338 
339           len = strlen(cp);
340           InterpretCommand(cp, len, &argc, &argv);
341           allowcmd = argc > 0 && !strcasecmp(*argv, "allow");
342           if ((!doexec && allowcmd) || (doexec && !allowcmd))
343 	    RunCommand(bundle, argc, (char const *const *)argv, prompt, name);
344         }
345 
346 	fclose(fp);  /* everything read - get out */
347 	return 0;
348       }
349       break;
350     }
351   }
352   fclose(fp);
353   return -1;
354 }
355 
356 int
357 ValidSystem(const char *name, struct prompt *prompt)
358 {
359   /*
360    * Note:  The ReadSystem() calls only result in calls to the Allow*
361    * functions.  arg->bundle will be set to NULL for these commands !
362    */
363   if (ID0realuid() == 0)
364     return userok = modeok = 1;
365   userok = 0;
366   modeok = 1;
367   ReadSystem(NULL, "default", CONFFILE, 0, prompt);
368   if (name != NULL)
369     ReadSystem(NULL, name, CONFFILE, 0, prompt);
370   return userok && modeok;
371 }
372 
373 int
374 SelectSystem(struct bundle *bundle, const char *name, const char *file,
375              struct prompt *prompt)
376 {
377   userok = modeok = 1;
378   return ReadSystem(bundle, name, file, 1, prompt);
379 }
380 
381 int
382 LoadCommand(struct cmdargs const *arg)
383 {
384   const char *name;
385 
386   if (arg->argc > 0)
387     name = *arg->argv;
388   else
389     name = "default";
390 
391   if (!ValidSystem(name, arg->prompt)) {
392     LogPrintf(LogERROR, "%s: Label not allowed\n", name);
393     return 1;
394   } else if (SelectSystem(arg->bundle, name, CONFFILE, arg->prompt) < 0) {
395     LogPrintf(LogWARN, "%s: label not found.\n", name);
396     return -1;
397   } else
398     SetLabel(arg->argc ? name : NULL);
399   return 0;
400 }
401 
402 int
403 SaveCommand(struct cmdargs const *arg)
404 {
405   LogPrintf(LogWARN, "save command is not implemented (yet).\n");
406   return 1;
407 }
408