Deleted Added
full compact
systems.c (46686) systems.c (46828)
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 *
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.42 1999/03/09 20:39:03 brian Exp $
20 * $Id: systems.c,v 1.43 1999/05/08 11:07:43 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
42FILE *
43OpenSecret(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
55void
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
42FILE *
43OpenSecret(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
55void
56CloseSecret(FILE * fp)
56CloseSecret(FILE *fp)
57{
58 fclose(fp);
59}
60
61/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62static void
63InterpretArg(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
150static int
151DecodeCtrlCommand(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 */
164static int modeok;
165static int userok;
166static int modereq;
167
168int
169AllowUsers(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
187int
188AllowModes(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
206static char *
207strip(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
225static int
226xgets(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
255static int
256ReadSystem(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 wp = strchr(cp, ':');
333 if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
334 log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n",
335 filename, linenum);
336 break;
337 }
338
339 len = strlen(cp);
340 argc = command_Interpret(cp, len, argv);
341 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
342 if ((!(how == SYSTEM_EXEC) && allowcmd) ||
343 ((how == SYSTEM_EXEC) && !allowcmd))
344 command_Run(bundle, argc, (char const *const *)argv, prompt,
345 name, cx);
346 }
347
348 fclose(fp); /* everything read - get out */
349 return 0;
350 }
351 break;
352 }
353 }
354 fclose(fp);
355 return -1;
356}
357
358const char *
359system_IsValid(const char *name, struct prompt *prompt, int mode)
360{
361 /*
362 * Note: The ReadSystem() calls only result in calls to the Allow*
363 * functions. arg->bundle will be set to NULL for these commands !
364 */
365 int def, how, rs;
366
367 def = !strcmp(name, "default");
368 how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
369 userok = 0;
370 modeok = 1;
371 modereq = mode;
372
373 rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
374
375 if (!def) {
376 if (rs == -1)
377 rs = 0; /* we don't care that ``default'' doesn't exist */
378
379 if (rs == 0)
380 rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
381
382 if (rs == -1)
383 return "Configuration label not found";
384
385 if (rs == -2)
386 return _PATH_PPP "/" CONFFILE ": File not found";
387 }
388
389 if (how == SYSTEM_EXISTS)
390 userok = modeok = 1;
391
392 if (!userok)
393 return "User access denied";
394
395 if (!modeok)
396 return "Mode denied for this label";
397
398 return NULL;
399}
400
401int
402system_Select(struct bundle *bundle, const char *name, const char *file,
403 struct prompt *prompt, struct datalink *cx)
404{
405 userok = modeok = 1;
406 modereq = PHYS_ALL;
407 return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
408}
57{
58 fclose(fp);
59}
60
61/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
62static void
63InterpretArg(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
150static int
151DecodeCtrlCommand(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 */
164static int modeok;
165static int userok;
166static int modereq;
167
168int
169AllowUsers(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
187int
188AllowModes(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
206static char *
207strip(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
225static int
226xgets(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
255static int
256ReadSystem(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 wp = strchr(cp, ':');
333 if ((how == SYSTEM_EXEC) && (wp == NULL || wp[1] != '\0'))
334 log_Printf(LogWARN, "Unindented command (%s line %d) - ignored\n",
335 filename, linenum);
336 break;
337 }
338
339 len = strlen(cp);
340 argc = command_Interpret(cp, len, argv);
341 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow");
342 if ((!(how == SYSTEM_EXEC) && allowcmd) ||
343 ((how == SYSTEM_EXEC) && !allowcmd))
344 command_Run(bundle, argc, (char const *const *)argv, prompt,
345 name, cx);
346 }
347
348 fclose(fp); /* everything read - get out */
349 return 0;
350 }
351 break;
352 }
353 }
354 fclose(fp);
355 return -1;
356}
357
358const char *
359system_IsValid(const char *name, struct prompt *prompt, int mode)
360{
361 /*
362 * Note: The ReadSystem() calls only result in calls to the Allow*
363 * functions. arg->bundle will be set to NULL for these commands !
364 */
365 int def, how, rs;
366
367 def = !strcmp(name, "default");
368 how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE;
369 userok = 0;
370 modeok = 1;
371 modereq = mode;
372
373 rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how);
374
375 if (!def) {
376 if (rs == -1)
377 rs = 0; /* we don't care that ``default'' doesn't exist */
378
379 if (rs == 0)
380 rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how);
381
382 if (rs == -1)
383 return "Configuration label not found";
384
385 if (rs == -2)
386 return _PATH_PPP "/" CONFFILE ": File not found";
387 }
388
389 if (how == SYSTEM_EXISTS)
390 userok = modeok = 1;
391
392 if (!userok)
393 return "User access denied";
394
395 if (!modeok)
396 return "Mode denied for this label";
397
398 return NULL;
399}
400
401int
402system_Select(struct bundle *bundle, const char *name, const char *file,
403 struct prompt *prompt, struct datalink *cx)
404{
405 userok = modeok = 1;
406 modereq = PHYS_ALL;
407 return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC);
408}