systems.c revision 55065
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: head/usr.sbin/ppp/systems.c 55065 1999-12-23 21:43:12Z brian $ 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) 57{ 58 fclose(fp); 59} 60 61/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 62static const char * 63InterpretArg(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 156static int 157DecodeCtrlCommand(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 */ 175static int modeok; 176static int userok; 177static int modereq; 178 179int 180AllowUsers(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 199int 200AllowModes(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 218static char * 219strip(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 237static int 238xgets(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 265static char * 266GetLabel(char *line, const char *filename, int linenum) 267{ 268 char *wp; 269 270 if ((wp = findblank(line, 1)) != NULL) { 271 while (issep(*wp)) 272 *wp++ = '\0'; 273 if (*wp == '#') 274 *wp = '\0'; 275 if (*wp != '\0') { 276 log_Printf(LogWARN, "Bad label in %s (line %d) - too many words.\n", 277 filename, linenum); 278 return NULL; 279 } 280 } 281 wp = strchr(line, ':'); 282 if (wp == NULL || wp[1] != '\0') { 283 log_Printf(LogWARN, "Bad rule in %s (line %d) - missing colon.\n", 284 filename, linenum); 285 return NULL; 286 } 287 *wp = '\0'; 288 289 return line; 290} 291 292/* Returns -2 for ``file not found'' and -1 for ``label not found'' */ 293 294static int 295ReadSystem(struct bundle *bundle, const char *name, const char *file, 296 struct prompt *prompt, struct datalink *cx, int how) 297{ 298 FILE *fp; 299 char *cp; 300 int n, len; 301 char line[LINE_LEN]; 302 char filename[MAXPATHLEN]; 303 int linenum; 304 int argc; 305 char *argv[MAXARGS]; 306 int allowcmd; 307 int indent; 308 char arg[LINE_LEN]; 309 struct prompt *op; 310 311 if (*file == '/') 312 snprintf(filename, sizeof filename, "%s", file); 313 else 314 snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 315 fp = ID0fopen(filename, "r"); 316 if (fp == NULL) { 317 log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 318 return -2; 319 } 320 log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 321 322 linenum = 0; 323 while ((n = xgets(line, sizeof line, fp))) { 324 linenum += n; 325 if (issep(*line)) 326 continue; 327 328 cp = strip(line); 329 330 switch (*cp) { 331 case '\0': /* empty/comment */ 332 break; 333 334 case '!': 335 switch (DecodeCtrlCommand(cp+1, arg)) { 336 case CTRL_INCLUDE: 337 log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 338 n = ReadSystem(bundle, name, arg, prompt, cx, how); 339 log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 340 if (!n) 341 return 0; /* got it */ 342 break; 343 default: 344 log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 345 break; 346 } 347 break; 348 349 default: 350 if ((cp = GetLabel(cp, filename, linenum)) == NULL) 351 continue; 352 cp = strip(cp); /* lose any spaces between the label and the ':' */ 353 354 if (strcmp(cp, name) == 0) { 355 /* We're in business */ 356 if (how == SYSTEM_EXISTS) 357 return 0; 358 while ((n = xgets(line, sizeof line, fp))) { 359 linenum += n; 360 indent = issep(*line); 361 cp = strip(line); 362 363 if (*cp == '\0') /* empty / comment */ 364 continue; 365 366 if (!indent) { /* start of next section */ 367 if (*cp != '!' && how == SYSTEM_EXEC) 368 GetLabel(cp, filename, linenum); 369 break; 370 } 371 372 len = strlen(cp); 373 if ((argc = command_Interpret(cp, len, argv)) < 0) 374 log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum); 375 else { 376 allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 377 if ((how != SYSTEM_EXEC && allowcmd) || 378 (how == SYSTEM_EXEC && !allowcmd)) { 379 /* 380 * Disable any context so that warnings are given to everyone, 381 * including syslog. 382 */ 383 op = log_PromptContext; 384 log_PromptContext = NULL; 385 command_Run(bundle, argc, (char const *const *)argv, prompt, 386 name, cx); 387 log_PromptContext = op; 388 } 389 } 390 } 391 392 fclose(fp); /* everything read - get out */ 393 return 0; 394 } 395 break; 396 } 397 } 398 fclose(fp); 399 return -1; 400} 401 402const char * 403system_IsValid(const char *name, struct prompt *prompt, int mode) 404{ 405 /* 406 * Note: The ReadSystem() calls only result in calls to the Allow* 407 * functions. arg->bundle will be set to NULL for these commands ! 408 */ 409 int def, how, rs; 410 411 def = !strcmp(name, "default"); 412 how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE; 413 userok = 0; 414 modeok = 1; 415 modereq = mode; 416 417 rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how); 418 419 if (!def) { 420 if (rs == -1) 421 rs = 0; /* we don't care that ``default'' doesn't exist */ 422 423 if (rs == 0) 424 rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how); 425 426 if (rs == -1) 427 return "Configuration label not found"; 428 429 if (rs == -2) 430 return _PATH_PPP "/" CONFFILE ": File not found"; 431 } 432 433 if (how == SYSTEM_EXISTS) 434 userok = modeok = 1; 435 436 if (!userok) 437 return "User access denied"; 438 439 if (!modeok) 440 return "Mode denied for this label"; 441 442 return NULL; 443} 444 445int 446system_Select(struct bundle *bundle, const char *name, const char *file, 447 struct prompt *prompt, struct datalink *cx) 448{ 449 userok = modeok = 1; 450 modereq = PHYS_ALL; 451 return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC); 452} 453