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