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