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