xref: /freebsd/usr.sbin/ppp/systems.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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.37 1998/06/15 19:05:47 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 "defs.h"
34 #include "command.h"
35 #include "log.h"
36 #include "id.h"
37 #include "systems.h"
38 
39 #define issep(ch) ((ch) == ' ' || (ch) == '\t')
40 
41 FILE *
42 OpenSecret(const char *file)
43 {
44   FILE *fp;
45   char line[100];
46 
47   snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file);
48   fp = ID0fopen(line, "r");
49   if (fp == NULL)
50     log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line);
51   return (fp);
52 }
53 
54 void
55 CloseSecret(FILE * fp)
56 {
57   fclose(fp);
58 }
59 
60 /* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
61 static void
62 InterpretArg(char *from, char *to)
63 {
64   const char *env;
65   char *ptr, *startto, *endto;
66   int len;
67 
68   startto = to;
69   endto = to + LINE_LEN - 1;
70 
71   while(issep(*from))
72     from++;
73   if (*from == '~') {
74     ptr = strchr(++from, '/');
75     len = ptr ? ptr - from : strlen(from);
76     if (len == 0) {
77       if ((env = getenv("HOME")) == NULL)
78         env = _PATH_PPP;
79       strncpy(to, env, endto - to);
80     } else {
81       struct passwd *pwd;
82 
83       strncpy(to, from, len);
84       to[len] = '\0';
85       pwd = getpwnam(to);
86       if (pwd)
87         strncpy(to, pwd->pw_dir, endto-to);
88       else
89         strncpy(to, _PATH_PPP, endto - to);
90       endpwent();
91     }
92     *endto = '\0';
93     to += strlen(to);
94     from += len;
95   }
96 
97   while (to < endto && *from != '\0') {
98     if (*from == '$') {
99       if (from[1] == '$') {
100         *to = '\0';	/* For an empty var name below */
101         from += 2;
102       } else if (from[1] == '{') {
103         ptr = strchr(from+2, '}');
104         if (ptr) {
105           len = ptr - from - 2;
106           if (endto - to < len )
107             len = endto - to;
108           if (len) {
109             strncpy(to, from+2, len);
110             to[len] = '\0';
111             from = ptr+1;
112           } else {
113             *to++ = *from++;
114             continue;
115           }
116         } else {
117           *to++ = *from++;
118           continue;
119         }
120       } else {
121         ptr = to;
122         for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
123           *ptr++ = *from;
124         *ptr = '\0';
125       }
126       if (*to == '\0')
127         *to++ = '$';
128       else if ((env = getenv(to)) != NULL) {
129         strncpy(to, env, endto - to);
130         *endto = '\0';
131         to += strlen(to);
132       }
133     } else
134       *to++ = *from++;
135   }
136   while (to > startto) {
137     to--;
138     if (!issep(*to)) {
139       to++;
140       break;
141     }
142   }
143   *to = '\0';
144 }
145 
146 #define CTRL_UNKNOWN (0)
147 #define CTRL_INCLUDE (1)
148 
149 static int
150 DecodeCtrlCommand(char *line, char *arg)
151 {
152   if (!strncasecmp(line, "include", 7) && issep(line[7])) {
153     InterpretArg(line+8, arg);
154     return CTRL_INCLUDE;
155   }
156   return CTRL_UNKNOWN;
157 }
158 
159 /* Initialised in system_IsValid(), set in ReadSystem(), used by system_IsValid() */
160 static int modeok;
161 static int userok;
162 static int modereq;
163 
164 int
165 AllowUsers(struct cmdargs const *arg)
166 {
167   /* arg->bundle may be NULL (see system_IsValid()) ! */
168   int f;
169   char *user;
170 
171   userok = 0;
172   user = getlogin();
173   if (user && *user)
174     for (f = arg->argn; f < arg->argc; f++)
175       if (!strcmp("*", arg->argv[f]) || !strcmp(user, arg->argv[f])) {
176         userok = 1;
177         break;
178       }
179 
180   return 0;
181 }
182 
183 int
184 AllowModes(struct cmdargs const *arg)
185 {
186   /* arg->bundle may be NULL (see system_IsValid()) ! */
187   int f, mode, allowed;
188 
189   allowed = 0;
190   for (f = arg->argn; f < arg->argc; f++) {
191     mode = Nam2mode(arg->argv[f]);
192     if (mode == PHYS_NONE || mode == PHYS_ALL)
193       log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
194     else
195       allowed |= mode;
196   }
197 
198   modeok = modereq & allowed ? 1 : 0;
199   return 0;
200 }
201 
202 static char *
203 strip(char *line)
204 {
205   int len;
206 
207   len = strlen(line);
208   while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
209                  issep(line[len-1])))
210     line[--len] = '\0';
211 
212   while (issep(*line))
213     line++;
214 
215   if (*line == '#')
216     *line = '\0';
217 
218   return line;
219 }
220 
221 static int
222 xgets(char *buf, int buflen, FILE *fp)
223 {
224   int len, n;
225 
226   n = 0;
227   while (fgets(buf, buflen-1, fp)) {
228     n++;
229     buf[buflen-1] = '\0';
230     len = strlen(buf);
231     while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
232       buf[--len] = '\0';
233     if (len && buf[len-1] == '\\') {
234       buf += len - 1;
235       buflen -= len - 1;
236       if (!buflen)        /* No buffer space */
237         break;
238     } else
239       break;
240   }
241   return n;
242 }
243 
244 static int
245 ReadSystem(struct bundle *bundle, const char *name, const char *file,
246            int doexec, struct prompt *prompt, struct datalink *cx)
247 {
248   FILE *fp;
249   char *cp, *wp;
250   int n, len;
251   char line[LINE_LEN];
252   char filename[MAXPATHLEN];
253   int linenum;
254   int argc;
255   char *argv[MAXARGS];
256   int allowcmd;
257   int indent;
258   char arg[LINE_LEN];
259 
260   if (*file == '/')
261     snprintf(filename, sizeof filename, "%s", file);
262   else
263     snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
264   fp = ID0fopen(filename, "r");
265   if (fp == NULL) {
266     log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
267     return (-1);
268   }
269   log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
270 
271   linenum = 0;
272   while ((n = xgets(line, sizeof line, fp))) {
273     linenum += n;
274     if (issep(*line))
275       continue;
276 
277     cp = strip(line);
278 
279     switch (*cp) {
280     case '\0':			/* empty/comment */
281       break;
282 
283     case '!':
284       switch (DecodeCtrlCommand(cp+1, arg)) {
285       case CTRL_INCLUDE:
286         log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
287         n = ReadSystem(bundle, name, arg, doexec, prompt, cx);
288         log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
289         if (!n)
290           return 0;	/* got it */
291         break;
292       default:
293         log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
294         break;
295       }
296       break;
297 
298     default:
299       wp = strchr(cp, ':');
300       if (wp == NULL || wp[1] != '\0') {
301 	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
302 		  filename, linenum);
303 	continue;
304       }
305       *wp = '\0';
306       cp = strip(cp);  /* lose any spaces between the label and the ':' */
307 
308       if (strcmp(cp, name) == 0) {
309         /* We're in business */
310 	while ((n = xgets(line, sizeof line, fp))) {
311           linenum += n;
312           indent = issep(*line);
313           cp = strip(line);
314 
315           if (*cp == '\0')  /* empty / comment */
316             continue;
317 
318           if (!indent)      /* start of next section */
319             break;
320 
321           len = strlen(cp);
322           argc = command_Interpret(cp, len, argv);
323           allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
324           if ((!doexec && allowcmd) || (doexec && !allowcmd))
325 	    command_Run(bundle, argc, (char const *const *)argv, prompt,
326                         name, cx);
327         }
328 
329 	fclose(fp);  /* everything read - get out */
330 	return 0;
331       }
332       break;
333     }
334   }
335   fclose(fp);
336   return -1;
337 }
338 
339 int
340 system_IsValid(const char *name, struct prompt *prompt, int mode)
341 {
342   /*
343    * Note:  The ReadSystem() calls only result in calls to the Allow*
344    * functions.  arg->bundle will be set to NULL for these commands !
345    */
346   if (ID0realuid() == 0)
347     return userok = modeok = 1;
348   userok = 0;
349   modeok = 1;
350   modereq = mode;
351   ReadSystem(NULL, "default", CONFFILE, 0, prompt, NULL);
352   if (name != NULL)
353     ReadSystem(NULL, name, CONFFILE, 0, prompt, NULL);
354   return userok && modeok;
355 }
356 
357 int
358 system_Select(struct bundle *bundle, const char *name, const char *file,
359              struct prompt *prompt, struct datalink *cx)
360 {
361   userok = modeok = 1;
362   modereq = PHYS_ALL;
363   return ReadSystem(bundle, name, file, 1, prompt, cx);
364 }
365