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