xref: /freebsd/usr.sbin/ppp/systems.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
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  * $FreeBSD$
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 <termios.h>
32 #include <unistd.h>
33 
34 #include "defs.h"
35 #include "command.h"
36 #include "log.h"
37 #include "id.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     log_Printf(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 const char *
63 InterpretArg(const 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 
75   if (*from == '~') {
76     struct passwd *pwd;
77 
78     ptr = strchr(++from, '/');
79     len = ptr ? ptr - from : strlen(from);
80     if (len == 0) {
81       pwd = getpwuid(getuid());
82     } else {
83       strncpy(to, from, len);
84       to[len] = '\0';
85       pwd = getpwnam(to);
86     }
87     strncpy(to, pwd ? pwd->pw_dir : _PATH_PPP, endto - to);
88     endpwent();
89 
90     *endto = '\0';
91     to += strlen(to);
92     from += len;
93   }
94 
95   while (to < endto && !issep(*from) && *from != '#' && *from != '\0') {
96     if (*from == '$') {
97       if (from[1] == '$') {
98         *to = '\0';	/* For an empty var name below */
99         from += 2;
100       } else if (from[1] == '{') {
101         ptr = strchr(from+2, '}');
102         if (ptr) {
103           len = ptr - from - 2;
104           if (endto - to < len )
105             len = endto - to;
106           if (len) {
107             strncpy(to, from+2, len);
108             to[len] = '\0';
109             from = ptr+1;
110           } else {
111             *to++ = *from++;
112             continue;
113           }
114         } else {
115           *to++ = *from++;
116           continue;
117         }
118       } else {
119         ptr = to;
120         for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++)
121           *ptr++ = *from;
122         *ptr = '\0';
123       }
124       if (*to == '\0')
125         *to++ = '$';
126       else if ((env = getenv(to)) != NULL) {
127         strncpy(to, env, endto - to);
128         *endto = '\0';
129         to += strlen(to);
130       }
131     } else {
132       if (*from == '\\')
133         from++;
134       *to++ = *from++;
135     }
136   }
137 
138   while (to > startto) {
139     to--;
140     if (!issep(*to)) {
141       to++;
142       break;
143     }
144   }
145   *to = '\0';
146 
147   while (issep(*from))
148     from++;
149 
150   return from;
151 }
152 
153 #define CTRL_UNKNOWN (0)
154 #define CTRL_INCLUDE (1)
155 
156 static int
157 DecodeCtrlCommand(char *line, char *arg)
158 {
159   const char *end;
160 
161   if (!strncasecmp(line, "include", 7) && issep(line[7])) {
162     end = InterpretArg(line+8, arg);
163     if (*end && *end != '#')
164       log_Printf(LogWARN, "Usage: !include filename\n");
165     else
166       return CTRL_INCLUDE;
167   }
168   return CTRL_UNKNOWN;
169 }
170 
171 /*
172  * Initialised in system_IsValid(), set in ReadSystem(),
173  * used by system_IsValid()
174  */
175 static int modeok;
176 static int userok;
177 static int modereq;
178 
179 int
180 AllowUsers(struct cmdargs const *arg)
181 {
182   /* arg->bundle may be NULL (see system_IsValid()) ! */
183   int f;
184   struct passwd *pwd;
185 
186   userok = 0;
187   pwd = getpwuid(getuid());
188   if (pwd != NULL)
189     for (f = arg->argn; f < arg->argc; f++)
190       if (!strcmp("*", arg->argv[f]) || !strcmp(pwd->pw_name, arg->argv[f])) {
191         userok = 1;
192         break;
193       }
194   endpwent();
195 
196   return 0;
197 }
198 
199 int
200 AllowModes(struct cmdargs const *arg)
201 {
202   /* arg->bundle may be NULL (see system_IsValid()) ! */
203   int f, mode, allowed;
204 
205   allowed = 0;
206   for (f = arg->argn; f < arg->argc; f++) {
207     mode = Nam2mode(arg->argv[f]);
208     if (mode == PHYS_NONE || mode == PHYS_ALL)
209       log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]);
210     else
211       allowed |= mode;
212   }
213 
214   modeok = modereq & allowed ? 1 : 0;
215   return 0;
216 }
217 
218 static char *
219 strip(char *line)
220 {
221   int len;
222 
223   len = strlen(line);
224   while (len && (line[len-1] == '\n' || line[len-1] == '\r' ||
225                  issep(line[len-1])))
226     line[--len] = '\0';
227 
228   while (issep(*line))
229     line++;
230 
231   if (*line == '#')
232     *line = '\0';
233 
234   return line;
235 }
236 
237 static int
238 xgets(char *buf, int buflen, FILE *fp)
239 {
240   int len, n;
241 
242   n = 0;
243   while (fgets(buf, buflen-1, fp)) {
244     n++;
245     buf[buflen-1] = '\0';
246     len = strlen(buf);
247     while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
248       buf[--len] = '\0';
249     if (len && buf[len-1] == '\\') {
250       buf += len - 1;
251       buflen -= len - 1;
252       if (!buflen)        /* No buffer space */
253         break;
254     } else
255       break;
256   }
257   return n;
258 }
259 
260 /* Values for ``how'' in ReadSystem */
261 #define SYSTEM_EXISTS	1
262 #define SYSTEM_VALIDATE	2
263 #define SYSTEM_EXEC	3
264 
265 /* Returns -2 for ``file not found'' and -1 for ``label not found'' */
266 
267 static int
268 ReadSystem(struct bundle *bundle, const char *name, const char *file,
269            struct prompt *prompt, struct datalink *cx, int how)
270 {
271   FILE *fp;
272   char *cp, *wp;
273   int n, len;
274   char line[LINE_LEN];
275   char filename[MAXPATHLEN];
276   int linenum;
277   int argc;
278   char *argv[MAXARGS];
279   int allowcmd;
280   int indent;
281   char arg[LINE_LEN];
282   struct prompt *op;
283 
284   if (*file == '/')
285     snprintf(filename, sizeof filename, "%s", file);
286   else
287     snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
288   fp = ID0fopen(filename, "r");
289   if (fp == NULL) {
290     log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
291     return -2;
292   }
293   log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
294 
295   linenum = 0;
296   while ((n = xgets(line, sizeof line, fp))) {
297     linenum += n;
298     if (issep(*line))
299       continue;
300 
301     cp = strip(line);
302 
303     switch (*cp) {
304     case '\0':			/* empty/comment */
305       break;
306 
307     case '!':
308       switch (DecodeCtrlCommand(cp+1, arg)) {
309       case CTRL_INCLUDE:
310         log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
311         n = ReadSystem(bundle, name, arg, prompt, cx, how);
312         log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
313         if (!n)
314           return 0;	/* got it */
315         break;
316       default:
317         log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
318         break;
319       }
320       break;
321 
322     default:
323       if ((wp = findblank(cp, 0)) != NULL) {
324         while (issep(*wp))
325           *wp++ = '\0';
326         if (*wp == '#')
327           *wp = '\0';
328         if (*wp != '\0') {
329 	  log_Printf(LogWARN, "Bad label in %s (line %d) - too many words.\n",
330 		    filename, linenum);
331 	  continue;
332         }
333       }
334       wp = strchr(cp, ':');
335       if (wp == NULL || wp[1] != '\0') {
336 	log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
337 		  filename, linenum);
338 	continue;
339       }
340       *wp = '\0';
341       cp = strip(cp);  /* lose any spaces between the label and the ':' */
342 
343       if (strcmp(cp, name) == 0) {
344         /* We're in business */
345         if (how == SYSTEM_EXISTS)
346 	  return 0;
347 	while ((n = xgets(line, sizeof line, fp))) {
348           linenum += n;
349           indent = issep(*line);
350           cp = strip(line);
351 
352           if (*cp == '\0')  /* empty / comment */
353             continue;
354 
355           if (!indent) {    /* start of next section */
356             if (*cp != '!') {
357               wp = strchr(cp, ':');
358               if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
359 	        log_Printf(LogWARN, "Unindented command (%s line %d) -"
360                            " ignored\n", filename, linenum);
361             }
362             break;
363           }
364 
365           len = strlen(cp);
366           if ((argc = command_Interpret(cp, len, argv)) < 0)
367             log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum);
368           else {
369             allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
370             if ((how != SYSTEM_EXEC && allowcmd) ||
371                 (how == SYSTEM_EXEC && !allowcmd)) {
372               /*
373                * Disable any context so that warnings are given to everyone,
374                * including syslog.
375                */
376               op = log_PromptContext;
377               log_PromptContext = NULL;
378 	      command_Run(bundle, argc, (char const *const *)argv, prompt,
379                           name, cx);
380               log_PromptContext = op;
381             }
382           }
383         }
384 
385 	fclose(fp);  /* everything read - get out */
386 	return 0;
387       }
388       break;
389     }
390   }
391   fclose(fp);
392   return -1;
393 }
394 
395 const char *
396 system_IsValid(const char *name, struct prompt *prompt, int mode)
397 {
398   /*
399    * Note:  The ReadSystem() calls only result in calls to the Allow*
400    * functions.  arg->bundle will be set to NULL for these commands !
401    */
402   int def, how, rs;
403 
404   def = !strcmp(name, "default");
405   how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
406   userok = 0;
407   modeok = 1;
408   modereq = mode;
409 
410   rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
411 
412   if (!def) {
413     if (rs == -1)
414       rs = 0;		/* we don't care that ``default'' doesn't exist */
415 
416     if (rs == 0)
417       rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
418 
419     if (rs == -1)
420       return "Configuration label not found";
421 
422     if (rs == -2)
423       return _PATH_PPP "/" CONFFILE ": File not found";
424   }
425 
426   if (how == SYSTEM_EXISTS)
427     userok = modeok = 1;
428 
429   if (!userok)
430     return "User access denied";
431 
432   if (!modeok)
433     return "Mode denied for this label";
434 
435   return NULL;
436 }
437 
438 int
439 system_Select(struct bundle *bundle, const char *name, const char *file,
440              struct prompt *prompt, struct datalink *cx)
441 {
442   userok = modeok = 1;
443   modereq = PHYS_ALL;
444   return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
445 }
446