]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/systems.c
This commit was generated by cvs2svn to compensate for changes in r53796,
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / systems.c
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 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   struct prompt *op;
271
272   if (*file == '/')
273     snprintf(filename, sizeof filename, "%s", file);
274   else
275     snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file);
276   fp = ID0fopen(filename, "r");
277   if (fp == NULL) {
278     log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename);
279     return -2;
280   }
281   log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename);
282
283   linenum = 0;
284   while ((n = xgets(line, sizeof line, fp))) {
285     linenum += n;
286     if (issep(*line))
287       continue;
288
289     cp = strip(line);
290
291     switch (*cp) {
292     case '\0':                  /* empty/comment */
293       break;
294
295     case '!':
296       switch (DecodeCtrlCommand(cp+1, arg)) {
297       case CTRL_INCLUDE:
298         log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
299         n = ReadSystem(bundle, name, arg, prompt, cx, how);
300         log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg);
301         if (!n)
302           return 0;     /* got it */
303         break;
304       default:
305         log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp);
306         break;
307       }
308       break;
309
310     default:
311       wp = strchr(cp, ':');
312       if (wp == NULL || wp[1] != '\0') {
313         log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n",
314                   filename, linenum);
315         continue;
316       }
317       *wp = '\0';
318       cp = strip(cp);  /* lose any spaces between the label and the ':' */
319
320       if (strcmp(cp, name) == 0) {
321         /* We're in business */
322         if (how == SYSTEM_EXISTS)
323           return 0;
324         while ((n = xgets(line, sizeof line, fp))) {
325           linenum += n;
326           indent = issep(*line);
327           cp = strip(line);
328
329           if (*cp == '\0')  /* empty / comment */
330             continue;
331
332           if (!indent) {    /* start of next section */
333             if (*cp != '!') {
334               wp = strchr(cp, ':');
335               if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
336                 log_Printf(LogWARN, "Unindented command (%s line %d) -"
337                            " ignored\n", filename, linenum);
338             }
339             break;
340           }
341
342           len = strlen(cp);
343           argc = command_Interpret(cp, len, argv);
344           allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
345           if ((!(how == SYSTEM_EXEC) && allowcmd) ||
346               ((how == SYSTEM_EXEC) && !allowcmd)) {
347             /*
348              * Disable any context so that warnings are given to everyone,
349              * including syslog.
350              */
351             op = log_PromptContext;
352             log_PromptContext = NULL;
353             command_Run(bundle, argc, (char const *const *)argv, prompt,
354                         name, cx);
355             log_PromptContext = op;
356           }
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 const char *
370 system_IsValid(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   int def, how, rs;
377
378   def = !strcmp(name, "default");
379   how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
380   userok = 0;
381   modeok = 1;
382   modereq = mode;
383
384   rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
385
386   if (!def) {
387     if (rs == -1)
388       rs = 0;           /* we don't care that ``default'' doesn't exist */
389
390     if (rs == 0)
391       rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
392
393     if (rs == -1)
394       return "Configuration label not found";
395
396     if (rs == -2)
397       return _PATH_PPP "/" CONFFILE ": File not found";
398   }
399
400   if (how == SYSTEM_EXISTS)
401     userok = modeok = 1;
402
403   if (!userok)
404     return "User access denied";
405
406   if (!modeok)
407     return "Mode denied for this label";
408
409   return NULL;
410 }
411
412 int
413 system_Select(struct bundle *bundle, const char *name, const char *file,
414              struct prompt *prompt, struct datalink *cx)
415 {
416   userok = modeok = 1;
417   modereq = PHYS_ALL;
418   return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
419 }