systems.c revision 55252
1193326Sed/* 2193326Sed * System configuration routines 3193326Sed * 4193326Sed * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5193326Sed * 6193326Sed * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7193326Sed * 8193326Sed * Redistribution and use in source and binary forms are permitted 9193326Sed * provided that the above copyright notice and this paragraph are 10193326Sed * duplicated in all such forms and that any documentation, 11193326Sed * advertising materials, and other materials related to such 12193326Sed * distribution and use acknowledge that the software was developed 13193326Sed * by the Internet Initiative Japan, Inc. The name of the 14193326Sed * IIJ may not be used to endorse or promote products derived 15193326Sed * from this software without specific prior written permission. 16223017Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17263508Sdim * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18193326Sed * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19193326Sed * 20193326Sed * $FreeBSD: head/usr.sbin/ppp/systems.c 55252 1999-12-30 03:36:11Z brian $ 21239462Sdim * 22239462Sdim * TODO: 23193326Sed */ 24263508Sdim#include <sys/param.h> 25193326Sed 26193326Sed#include <ctype.h> 27193326Sed#include <pwd.h> 28198092Srdivacky#include <stdio.h> 29193326Sed#include <stdlib.h> 30193326Sed#include <string.h> 31193326Sed#include <termios.h> 32263508Sdim#include <unistd.h> 33193326Sed 34208600Srdivacky#include "defs.h" 35208600Srdivacky#include "command.h" 36249423Sdim#include "log.h" 37263508Sdim#include "id.h" 38249423Sdim#include "systems.h" 39263508Sdim 40249423Sdim#define issep(ch) ((ch) == ' ' || (ch) == '\t') 41263508Sdim 42249423SdimFILE * 43249423SdimOpenSecret(const char *file) 44249423Sdim{ 45263508Sdim FILE *fp; 46234353Sdim char line[100]; 47263508Sdim 48263508Sdim snprintf(line, sizeof line, "%s/%s", _PATH_PPP, file); 49193326Sed fp = ID0fopen(line, "r"); 50193326Sed if (fp == NULL) 51193326Sed log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line); 52263508Sdim return (fp); 53263508Sdim} 54263508Sdim 55263508Sdimvoid 56221345SdimCloseSecret(FILE *fp) 57263508Sdim{ 58263508Sdim fclose(fp); 59263508Sdim} 60263508Sdim 61263508Sdim/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 62263508Sdimstatic const char * 63263508SdimInterpretArg(const char *from, char *to) 64263508Sdim{ 65263508Sdim const char *env; 66263508Sdim char *ptr, *startto, *endto; 67263508Sdim int len; 68263508Sdim 69198092Srdivacky startto = to; 70239462Sdim endto = to + LINE_LEN - 1; 71239462Sdim 72263508Sdim while(issep(*from)) 73263508Sdim from++; 74239462Sdim 75239462Sdim if (*from == '~') { 76263508Sdim struct passwd *pwd; 77263508Sdim 78263508Sdim ptr = strchr(++from, '/'); 79193326Sed len = ptr ? ptr - from : strlen(from); 80208600Srdivacky if (len == 0) { 81193326Sed pwd = getpwuid(ID0realuid()); 82207619Srdivacky } else { 83203955Srdivacky strncpy(to, from, len); 84193326Sed to[len] = '\0'; 85193326Sed pwd = getpwnam(to); 86193326Sed } 87198092Srdivacky strncpy(to, pwd ? pwd->pw_dir : _PATH_PPP, endto - to); 88198092Srdivacky endpwent(); 89263508Sdim 90193326Sed *endto = '\0'; 91193326Sed to += strlen(to); 92193326Sed from += len; 93208600Srdivacky } 94208600Srdivacky 95208600Srdivacky while (to < endto && !issep(*from) && *from != '#' && *from != '\0') { 96208600Srdivacky if (*from == '$') { 97208600Srdivacky if (from[1] == '$') { 98208600Srdivacky *to = '\0'; /* For an empty var name below */ 99208600Srdivacky from += 2; 100208600Srdivacky } else if (from[1] == '{') { 101208600Srdivacky ptr = strchr(from+2, '}'); 102208600Srdivacky if (ptr) { 103208600Srdivacky len = ptr - from - 2; 104208600Srdivacky if (endto - to < len ) 105208600Srdivacky len = endto - to; 106263508Sdim if (len) { 107208600Srdivacky strncpy(to, from+2, len); 108208600Srdivacky to[len] = '\0'; 109208600Srdivacky from = ptr+1; 110193326Sed } else { 111193326Sed *to++ = *from++; 112208600Srdivacky continue; 113193326Sed } 114208600Srdivacky } else { 115208600Srdivacky *to++ = *from++; 116193326Sed continue; 117193326Sed } 118198092Srdivacky } else { 119198092Srdivacky ptr = to; 120263508Sdim for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++) 121193326Sed *ptr++ = *from; 122193326Sed *ptr = '\0'; 123193326Sed } 124193326Sed if (*to == '\0') 125263508Sdim *to++ = '$'; 126263508Sdim else if ((env = getenv(to)) != NULL) { 127263508Sdim strncpy(to, env, endto - to); 128193326Sed *endto = '\0'; 129193326Sed to += strlen(to); 130208600Srdivacky } 131193326Sed } else { 132208600Srdivacky if (*from == '\\') 133208600Srdivacky from++; 134193326Sed *to++ = *from++; 135207619Srdivacky } 136193326Sed } 137193326Sed 138203955Srdivacky while (to > startto) { 139263508Sdim to--; 140193326Sed if (!issep(*to)) { 141193326Sed to++; 142208600Srdivacky break; 143193326Sed } 144208600Srdivacky } 145208600Srdivacky *to = '\0'; 146193326Sed 147207619Srdivacky while (issep(*from)) 148193326Sed from++; 149193326Sed 150203955Srdivacky return from; 151263508Sdim} 152193326Sed 153193326Sed#define CTRL_UNKNOWN (0) 154208600Srdivacky#define CTRL_INCLUDE (1) 155193326Sed 156208600Srdivackystatic int 157208600SrdivackyDecodeCtrlCommand(char *line, char *arg) 158193326Sed{ 159207619Srdivacky const char *end; 160193326Sed 161193326Sed if (!strncasecmp(line, "include", 7) && issep(line[7])) { 162203955Srdivacky end = InterpretArg(line+8, arg); 163263508Sdim if (*end && *end != '#') 164193326Sed log_Printf(LogWARN, "Usage: !include filename\n"); 165193326Sed else 166208600Srdivacky return CTRL_INCLUDE; 167193326Sed } 168208600Srdivacky return CTRL_UNKNOWN; 169208600Srdivacky} 170193326Sed 171193326Sed/* 172193326Sed * Initialised in system_IsValid(), set in ReadSystem(), 173203955Srdivacky * used by system_IsValid() 174263508Sdim */ 175193326Sedstatic int modeok; 176193326Sedstatic int userok; 177208600Srdivackystatic int modereq; 178193326Sed 179208600Srdivackyint 180208600SrdivackyAllowUsers(struct cmdargs const *arg) 181193326Sed{ 182193326Sed /* arg->bundle may be NULL (see system_IsValid()) ! */ 183234353Sdim int f; 184193326Sed struct passwd *pwd; 185203955Srdivacky 186263508Sdim userok = 0; 187193326Sed pwd = getpwuid(ID0realuid()); 188193326Sed if (pwd != NULL) 189193326Sed for (f = arg->argn; f < arg->argc; f++) 190234353Sdim if (!strcmp("*", arg->argv[f]) || !strcmp(pwd->pw_name, arg->argv[f])) { 191234353Sdim userok = 1; 192234353Sdim break; 193234353Sdim } 194234353Sdim endpwent(); 195234353Sdim 196234353Sdim return 0; 197234353Sdim} 198234353Sdim 199234353Sdimint 200234353SdimAllowModes(struct cmdargs const *arg) 201263508Sdim{ 202234353Sdim /* arg->bundle may be NULL (see system_IsValid()) ! */ 203234353Sdim int f, mode, allowed; 204234353Sdim 205263508Sdim allowed = 0; 206234353Sdim for (f = arg->argn; f < arg->argc; f++) { 207234353Sdim mode = Nam2mode(arg->argv[f]); 208234353Sdim if (mode == PHYS_NONE || mode == PHYS_ALL) 209234353Sdim log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); 210234353Sdim else 211234353Sdim allowed |= mode; 212234353Sdim } 213234353Sdim 214234353Sdim modeok = modereq & allowed ? 1 : 0; 215234353Sdim return 0; 216234353Sdim} 217234353Sdim 218263508Sdimstatic char * 219234353Sdimstrip(char *line) 220234353Sdim{ 221234353Sdim int len; 222263508Sdim 223234353Sdim len = strlen(line); 224234353Sdim while (len && (line[len-1] == '\n' || line[len-1] == '\r' || 225234353Sdim issep(line[len-1]))) 226234353Sdim line[--len] = '\0'; 227234353Sdim 228193326Sed while (issep(*line)) 229243830Sdim line++; 230243830Sdim 231208600Srdivacky if (*line == '#') 232234353Sdim *line = '\0'; 233198092Srdivacky 234263508Sdim return line; 235263508Sdim} 236198092Srdivacky 237198092Srdivackystatic int 238198092Srdivackyxgets(char *buf, int buflen, FILE *fp) 239198092Srdivacky{ 240198092Srdivacky int len, n; 241193326Sed 242208600Srdivacky n = 0; 243208600Srdivacky while (fgets(buf, buflen-1, fp)) { 244198092Srdivacky n++; 245198092Srdivacky buf[buflen-1] = '\0'; 246208600Srdivacky len = strlen(buf); 247193326Sed while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 248208600Srdivacky buf[--len] = '\0'; 249208600Srdivacky if (len && buf[len-1] == '\\') { 250193326Sed buf += len - 1; 251193326Sed buflen -= len - 1; 252193326Sed if (!buflen) /* No buffer space */ 253193326Sed break; 254198092Srdivacky } else 255198092Srdivacky break; 256263508Sdim } 257193326Sed return n; 258193326Sed} 259193326Sed 260208600Srdivacky/* Values for ``how'' in ReadSystem */ 261243830Sdim#define SYSTEM_EXISTS 1 262263508Sdim#define SYSTEM_VALIDATE 2 263263508Sdim#define SYSTEM_EXEC 3 264263508Sdim 265193326Sedstatic char * 266193326SedGetLabel(char *line, const char *filename, int linenum) 267208600Srdivacky{ 268193326Sed char *argv[MAXARGS]; 269193326Sed int argc, len; 270234353Sdim 271193326Sed argc = MakeArgs(line, argv, MAXARGS, PARSE_REDUCE); 272193326Sed 273198092Srdivacky if (argc == 2 && !strcmp(argv[1], ":")) 274198092Srdivacky return argv[0]; 275263508Sdim 276193326Sed if (argc != 1 || (len = strlen(argv[0])) < 2 || argv[0][len-1] != ':') { 277193326Sed log_Printf(LogWARN, "Bad label in %s (line %d) - missing colon\n", 278193326Sed filename, linenum); 279208600Srdivacky return NULL; 280193326Sed } 281208600Srdivacky argv[0][len-1] = '\0'; /* Lose the ':' */ 282193326Sed 283193326Sed return argv[0]; 284193326Sed} 285193326Sed 286198092Srdivacky/* Returns -2 for ``file not found'' and -1 for ``label not found'' */ 287198092Srdivacky 288263508Sdimstatic int 289193326SedReadSystem(struct bundle *bundle, const char *name, const char *file, 290193326Sed struct prompt *prompt, struct datalink *cx, int how) 291210299Sed{ 292210299Sed FILE *fp; 293210299Sed char *cp; 294210299Sed int n, len; 295210299Sed char line[LINE_LEN]; 296210299Sed char filename[MAXPATHLEN]; 297210299Sed int linenum; 298249423Sdim int argc; 299210299Sed char *argv[MAXARGS]; 300210299Sed int allowcmd; 301210299Sed int indent; 302210299Sed char arg[LINE_LEN]; 303263508Sdim struct prompt *op; 304210299Sed 305210299Sed if (*file == '/') 306226633Sdim snprintf(filename, sizeof filename, "%s", file); 307226633Sdim else 308226633Sdim snprintf(filename, sizeof filename, "%s/%s", _PATH_PPP, file); 309226633Sdim fp = ID0fopen(filename, "r"); 310249423Sdim if (fp == NULL) { 311226633Sdim log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 312226633Sdim return -2; 313226633Sdim } 314226633Sdim log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 315249423Sdim 316249423Sdim linenum = 0; 317263508Sdim while ((n = xgets(line, sizeof line, fp))) { 318249423Sdim linenum += n; 319226633Sdim if (issep(*line)) 320226633Sdim continue; 321193326Sed 322193326Sed cp = strip(line); 323195341Sed 324195341Sed switch (*cp) { 325208600Srdivacky case '\0': /* empty/comment */ 326195341Sed break; 327208600Srdivacky 328208600Srdivacky case '!': 329195341Sed switch (DecodeCtrlCommand(cp+1, arg)) { 330195341Sed case CTRL_INCLUDE: 331195341Sed log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 332195341Sed n = ReadSystem(bundle, name, arg, prompt, cx, how); 333198092Srdivacky log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 334198092Srdivacky if (!n) 335263508Sdim return 0; /* got it */ 336195341Sed break; 337195341Sed default: 338208600Srdivacky log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 339195341Sed break; 340208600Srdivacky } 341195341Sed break; 342195341Sed 343234353Sdim default: 344195341Sed if ((cp = GetLabel(cp, filename, linenum)) == NULL) 345195341Sed continue; 346198092Srdivacky 347198092Srdivacky if (strcmp(cp, name) == 0) { 348263508Sdim /* We're in business */ 349195341Sed if (how == SYSTEM_EXISTS) 350195341Sed return 0; 351198092Srdivacky while ((n = xgets(line, sizeof line, fp))) { 352195341Sed linenum += n; 353239462Sdim indent = issep(*line); 354239462Sdim cp = strip(line); 355239462Sdim 356239462Sdim if (*cp == '\0') /* empty / comment */ 357239462Sdim continue; 358239462Sdim 359239462Sdim if (!indent) { /* start of next section */ 360239462Sdim if (*cp != '!' && how == SYSTEM_EXEC) 361239462Sdim cp = GetLabel(cp, filename, linenum); 362239462Sdim break; 363239462Sdim } 364239462Sdim 365263508Sdim len = strlen(cp); 366239462Sdim if ((argc = command_Interpret(cp, len, argv)) < 0) 367239462Sdim log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum); 368239462Sdim else { 369239462Sdim allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 370239462Sdim if ((how != SYSTEM_EXEC && allowcmd) || 371239462Sdim (how == SYSTEM_EXEC && !allowcmd)) { 372239462Sdim /* 373239462Sdim * Disable any context so that warnings are given to everyone, 374239462Sdim * including syslog. 375239462Sdim */ 376239462Sdim op = log_PromptContext; 377239462Sdim log_PromptContext = NULL; 378263508Sdim command_Run(bundle, argc, (char const *const *)argv, prompt, 379239462Sdim name, cx); 380239462Sdim log_PromptContext = op; 381239462Sdim } 382239462Sdim } 383193326Sed } 384193326Sed 385208600Srdivacky fclose(fp); /* everything read - get out */ 386193326Sed return 0; 387208600Srdivacky } 388208600Srdivacky break; 389193326Sed } 390193326Sed } 391193326Sed fclose(fp); 392193326Sed return -1; 393198092Srdivacky} 394198092Srdivacky 395263508Sdimconst char * 396193326Sedsystem_IsValid(const char *name, struct prompt *prompt, int mode) 397193326Sed{ 398208600Srdivacky /* 399193326Sed * Note: The ReadSystem() calls only result in calls to the Allow* 400208600Srdivacky * functions. arg->bundle will be set to NULL for these commands ! 401193326Sed */ 402193326Sed int def, how, rs; 403234353Sdim 404193326Sed def = !strcmp(name, "default"); 405193326Sed how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE; 406198092Srdivacky userok = 0; 407198092Srdivacky modeok = 1; 408263508Sdim modereq = mode; 409193326Sed 410193326Sed rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how); 411198092Srdivacky 412193326Sed if (!def) { 413218893Sdim if (rs == -1) 414218893Sdim rs = 0; /* we don't care that ``default'' doesn't exist */ 415218893Sdim 416223017Sdim if (rs == 0) 417218893Sdim rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how); 418234353Sdim 419234353Sdim if (rs == -1) 420218893Sdim return "Configuration label not found"; 421218893Sdim 422218893Sdim if (rs == -2) 423218893Sdim return _PATH_PPP "/" CONFFILE ": File not found"; 424218893Sdim } 425218893Sdim 426263508Sdim if (how == SYSTEM_EXISTS) 427218893Sdim userok = modeok = 1; 428218893Sdim 429218893Sdim if (!userok) 430223017Sdim return "User access denied"; 431218893Sdim 432234353Sdim if (!modeok) 433234353Sdim return "Mode denied for this label"; 434218893Sdim 435218893Sdim return NULL; 436234353Sdim} 437218893Sdim 438218893Sdimint 439218893Sdimsystem_Select(struct bundle *bundle, const char *name, const char *file, 440218893Sdim struct prompt *prompt, struct datalink *cx) 441263508Sdim{ 442218893Sdim userok = modeok = 1; 443218893Sdim modereq = PHYS_ALL; 444218893Sdim return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC); 445218893Sdim} 446249423Sdim