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