178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD$ 296059Samurai */ 3078189Sbrian 3130715Sbrian#include <sys/param.h> 3230715Sbrian 3331077Sbrian#include <ctype.h> 3431077Sbrian#include <pwd.h> 3530715Sbrian#include <stdio.h> 3630715Sbrian#include <stdlib.h> 3730715Sbrian#include <string.h> 3846686Sbrian#include <termios.h> 3930715Sbrian 4037009Sbrian#include "defs.h" 4131343Sbrian#include "command.h" 4230715Sbrian#include "log.h" 4331061Sbrian#include "id.h" 4430715Sbrian#include "systems.h" 456059Samurai 4631077Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t') 4731077Sbrian 486059SamuraiFILE * 4931343SbrianOpenSecret(const char *file) 506059Samurai{ 516059Samurai FILE *fp; 526059Samurai char line[100]; 536059Samurai 5474687Sbrian snprintf(line, sizeof line, "%s/%s", PPP_CONFDIR, file); 5531061Sbrian fp = ID0fopen(line, "r"); 5631061Sbrian if (fp == NULL) 5736285Sbrian log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line); 5828679Sbrian return (fp); 596059Samurai} 606059Samurai 616059Samuraivoid 6246828SbrianCloseSecret(FILE *fp) 636059Samurai{ 646059Samurai fclose(fp); 656059Samurai} 666059Samurai 6731077Sbrian/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ 6858045Sbrianconst char * 6954915SbrianInterpretArg(const char *from, char *to) 7031077Sbrian{ 7158045Sbrian char *ptr, *startto, *endto; 7258045Sbrian struct passwd *pwd; 73134789Sbrian int instring; 74134789Sbrian size_t len; 7531077Sbrian const char *env; 7631077Sbrian 7758045Sbrian instring = 0; 7831077Sbrian startto = to; 7931077Sbrian endto = to + LINE_LEN - 1; 8031077Sbrian 8131077Sbrian while(issep(*from)) 8231077Sbrian from++; 8354915Sbrian 8458045Sbrian while (*from != '\0') { 8558045Sbrian switch (*from) { 8658045Sbrian case '"': 8758045Sbrian instring = !instring; 8858045Sbrian *to++ = *from++; 8958045Sbrian break; 9058045Sbrian case '\\': 9158045Sbrian switch (*++from) { 9258045Sbrian case '$': 9358045Sbrian case '~': 9458045Sbrian break; /* Swallow the escapes */ 9554919Sbrian 9658045Sbrian default: 9758045Sbrian *to++ = '\\'; /* Pass the escapes on, maybe skipping \# */ 9858045Sbrian break; 9958045Sbrian } 10058045Sbrian *to++ = *from++; 10158045Sbrian break; 10258045Sbrian case '$': 10358045Sbrian if (from[1] == '$') { 10458045Sbrian *to = '\0'; /* For an empty var name below */ 10558045Sbrian from += 2; 10658045Sbrian } else if (from[1] == '{') { 10758045Sbrian ptr = strchr(from+2, '}'); 10858045Sbrian if (ptr) { 10958045Sbrian len = ptr - from - 2; 110134789Sbrian if (endto - to < (int)len ) 11158045Sbrian len = endto - to; 11258045Sbrian if (len) { 11358045Sbrian strncpy(to, from+2, len); 11458045Sbrian to[len] = '\0'; 11558045Sbrian from = ptr+1; 11658045Sbrian } else { 11758045Sbrian *to++ = *from++; 11858045Sbrian continue; 11958045Sbrian } 12031077Sbrian } else { 12131077Sbrian *to++ = *from++; 12231077Sbrian continue; 12331077Sbrian } 12431077Sbrian } else { 12558045Sbrian ptr = to; 12658045Sbrian for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++) 12758045Sbrian *ptr++ = *from; 12858045Sbrian *ptr = '\0'; 12931077Sbrian } 13058045Sbrian if (*to == '\0') 13158045Sbrian *to++ = '$'; 13258045Sbrian else if ((env = getenv(to)) != NULL) { 13358045Sbrian strncpy(to, env, endto - to); 13458045Sbrian *endto = '\0'; 13558045Sbrian to += strlen(to); 13658045Sbrian } 13758045Sbrian break; 13858045Sbrian 13958045Sbrian case '~': 14058045Sbrian ptr = strchr(++from, '/'); 141134789Sbrian len = ptr ? (size_t)(ptr - from) : strlen(from); 14258045Sbrian if (len == 0) 14358045Sbrian pwd = getpwuid(ID0realuid()); 14458045Sbrian else { 14558045Sbrian strncpy(to, from, len); 14658045Sbrian to[len] = '\0'; 14758045Sbrian pwd = getpwnam(to); 14858045Sbrian } 14958045Sbrian if (pwd == NULL) 15058045Sbrian *to++ = '~'; 15158045Sbrian else { 15258045Sbrian strncpy(to, pwd->pw_dir, endto - to); 15358045Sbrian *endto = '\0'; 15458045Sbrian to += strlen(to); 15558045Sbrian from += len; 15658045Sbrian } 15758045Sbrian endpwent(); 15858045Sbrian break; 15958045Sbrian 16058045Sbrian default: 16158045Sbrian *to++ = *from++; 16258045Sbrian break; 16354915Sbrian } 16431077Sbrian } 16554915Sbrian 16631077Sbrian while (to > startto) { 16731077Sbrian to--; 16831077Sbrian if (!issep(*to)) { 16931077Sbrian to++; 17031077Sbrian break; 17131077Sbrian } 17231077Sbrian } 17331077Sbrian *to = '\0'; 17454915Sbrian 17554915Sbrian return from; 17631077Sbrian} 17731077Sbrian 17831077Sbrian#define CTRL_UNKNOWN (0) 17931077Sbrian#define CTRL_INCLUDE (1) 18031077Sbrian 18131077Sbrianstatic int 18231077SbrianDecodeCtrlCommand(char *line, char *arg) 18331077Sbrian{ 18454915Sbrian const char *end; 18554915Sbrian 18631077Sbrian if (!strncasecmp(line, "include", 7) && issep(line[7])) { 18754915Sbrian end = InterpretArg(line+8, arg); 18854915Sbrian if (*end && *end != '#') 18995258Sdes log_Printf(LogWARN, "usage: !include filename\n"); 19054915Sbrian else 19154915Sbrian return CTRL_INCLUDE; 19231077Sbrian } 19331077Sbrian return CTRL_UNKNOWN; 19431077Sbrian} 19531077Sbrian 19640797Sbrian/* 19740797Sbrian * Initialised in system_IsValid(), set in ReadSystem(), 19840797Sbrian * used by system_IsValid() 19940797Sbrian */ 20036285Sbrianstatic int modeok; 20131121Sbrianstatic int userok; 20236285Sbrianstatic int modereq; 20331121Sbrian 2046059Samuraiint 20531343SbrianAllowUsers(struct cmdargs const *arg) 2066059Samurai{ 20736285Sbrian /* arg->bundle may be NULL (see system_IsValid()) ! */ 20831121Sbrian int f; 20954918Sbrian struct passwd *pwd; 21031121Sbrian 21163052Sbrian if (userok == -1) 21263052Sbrian userok = 0; 21363052Sbrian 21455252Sbrian pwd = getpwuid(ID0realuid()); 21554918Sbrian if (pwd != NULL) 21636285Sbrian for (f = arg->argn; f < arg->argc; f++) 21754918Sbrian if (!strcmp("*", arg->argv[f]) || !strcmp(pwd->pw_name, arg->argv[f])) { 21831121Sbrian userok = 1; 21931121Sbrian break; 22031121Sbrian } 22154918Sbrian endpwent(); 22231121Sbrian 22331121Sbrian return 0; 22431121Sbrian} 22531121Sbrian 22631121Sbrianint 22731343SbrianAllowModes(struct cmdargs const *arg) 22831121Sbrian{ 22936285Sbrian /* arg->bundle may be NULL (see system_IsValid()) ! */ 23036285Sbrian int f, mode, allowed; 23131121Sbrian 23231121Sbrian allowed = 0; 23336285Sbrian for (f = arg->argn; f < arg->argc; f++) { 23436285Sbrian mode = Nam2mode(arg->argv[f]); 23536285Sbrian if (mode == PHYS_NONE || mode == PHYS_ALL) 23636285Sbrian log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); 23736285Sbrian else 23836285Sbrian allowed |= mode; 23931121Sbrian } 24031121Sbrian 24136285Sbrian modeok = modereq & allowed ? 1 : 0; 24231121Sbrian return 0; 24331121Sbrian} 24431121Sbrian 24536285Sbrianstatic char * 24636285Sbrianstrip(char *line) 24736285Sbrian{ 24836285Sbrian int len; 24936285Sbrian 25036285Sbrian len = strlen(line); 25136285Sbrian while (len && (line[len-1] == '\n' || line[len-1] == '\r' || 25236285Sbrian issep(line[len-1]))) 25336285Sbrian line[--len] = '\0'; 25436285Sbrian 25536285Sbrian while (issep(*line)) 25636285Sbrian line++; 25736285Sbrian 25836285Sbrian if (*line == '#') 25936285Sbrian *line = '\0'; 26036285Sbrian 26136285Sbrian return line; 26236285Sbrian} 26336285Sbrian 26431121Sbrianstatic int 26536285Sbrianxgets(char *buf, int buflen, FILE *fp) 26631121Sbrian{ 26736285Sbrian int len, n; 26836285Sbrian 26936285Sbrian n = 0; 27036285Sbrian while (fgets(buf, buflen-1, fp)) { 27136285Sbrian n++; 27236285Sbrian buf[buflen-1] = '\0'; 27336285Sbrian len = strlen(buf); 27436285Sbrian while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 27536285Sbrian buf[--len] = '\0'; 27636285Sbrian if (len && buf[len-1] == '\\') { 27736285Sbrian buf += len - 1; 27836285Sbrian buflen -= len - 1; 27936285Sbrian if (!buflen) /* No buffer space */ 28036285Sbrian break; 28136285Sbrian } else 28236285Sbrian break; 28336285Sbrian } 28436285Sbrian return n; 28536285Sbrian} 28636285Sbrian 28743526Sbrian/* Values for ``how'' in ReadSystem */ 28843526Sbrian#define SYSTEM_EXISTS 1 28943526Sbrian#define SYSTEM_VALIDATE 2 29043526Sbrian#define SYSTEM_EXEC 3 29143526Sbrian 29255064Sbrianstatic char * 29355064SbrianGetLabel(char *line, const char *filename, int linenum) 29455064Sbrian{ 29555145Sbrian char *argv[MAXARGS]; 29655145Sbrian int argc, len; 29755064Sbrian 29855145Sbrian argc = MakeArgs(line, argv, MAXARGS, PARSE_REDUCE); 29955145Sbrian 30055145Sbrian if (argc == 2 && !strcmp(argv[1], ":")) 30155145Sbrian return argv[0]; 30255145Sbrian 30355145Sbrian if (argc != 1 || (len = strlen(argv[0])) < 2 || argv[0][len-1] != ':') { 30455145Sbrian log_Printf(LogWARN, "Bad label in %s (line %d) - missing colon\n", 30555064Sbrian filename, linenum); 30655064Sbrian return NULL; 30755064Sbrian } 30855145Sbrian argv[0][len-1] = '\0'; /* Lose the ':' */ 30955064Sbrian 31055145Sbrian return argv[0]; 31155064Sbrian} 31255064Sbrian 31344612Sbrian/* Returns -2 for ``file not found'' and -1 for ``label not found'' */ 31444612Sbrian 31536285Sbrianstatic int 31636285SbrianReadSystem(struct bundle *bundle, const char *name, const char *file, 31743526Sbrian struct prompt *prompt, struct datalink *cx, int how) 31836285Sbrian{ 3196059Samurai FILE *fp; 32055064Sbrian char *cp; 32130913Sbrian int n, len; 32231070Sbrian char line[LINE_LEN]; 32374001Sbrian char filename[PATH_MAX]; 32425630Sbrian int linenum; 32531121Sbrian int argc; 32637009Sbrian char *argv[MAXARGS]; 32731121Sbrian int allowcmd; 32836285Sbrian int indent; 32936285Sbrian char arg[LINE_LEN]; 33051005Sbrian struct prompt *op; 3316059Samurai 33231077Sbrian if (*file == '/') 33331077Sbrian snprintf(filename, sizeof filename, "%s", file); 33431077Sbrian else 33574687Sbrian snprintf(filename, sizeof filename, "%s/%s", PPP_CONFDIR, file); 33631061Sbrian fp = ID0fopen(filename, "r"); 3376059Samurai if (fp == NULL) { 33836285Sbrian log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); 33944612Sbrian return -2; 3406059Samurai } 34136285Sbrian log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); 34225630Sbrian 34325630Sbrian linenum = 0; 34436285Sbrian while ((n = xgets(line, sizeof line, fp))) { 34536285Sbrian linenum += n; 34636285Sbrian if (issep(*line)) 34736285Sbrian continue; 34836285Sbrian 34936285Sbrian cp = strip(line); 35036285Sbrian 3516059Samurai switch (*cp) { 35236285Sbrian case '\0': /* empty/comment */ 3536059Samurai break; 35436285Sbrian 35536285Sbrian case '!': 35636285Sbrian switch (DecodeCtrlCommand(cp+1, arg)) { 35736285Sbrian case CTRL_INCLUDE: 35836285Sbrian log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); 35943526Sbrian n = ReadSystem(bundle, name, arg, prompt, cx, how); 36036285Sbrian log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); 36158983Sbrian if (!n) { 36258983Sbrian fclose(fp); 36336285Sbrian return 0; /* got it */ 36458983Sbrian } 36536285Sbrian break; 36636285Sbrian default: 36736285Sbrian log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); 36836285Sbrian break; 36936285Sbrian } 3706059Samurai break; 37136285Sbrian 3726059Samurai default: 37355064Sbrian if ((cp = GetLabel(cp, filename, linenum)) == NULL) 37455064Sbrian continue; 37536285Sbrian 37636285Sbrian if (strcmp(cp, name) == 0) { 37736285Sbrian /* We're in business */ 37858983Sbrian if (how == SYSTEM_EXISTS) { 37958983Sbrian fclose(fp); 38043526Sbrian return 0; 38158983Sbrian } 38236285Sbrian while ((n = xgets(line, sizeof line, fp))) { 38336285Sbrian linenum += n; 38436285Sbrian indent = issep(*line); 38536285Sbrian cp = strip(line); 38636285Sbrian 38755064Sbrian if (*cp == '\0') /* empty / comment */ 38836285Sbrian continue; 38936285Sbrian 39055064Sbrian if (!indent) { /* start of next section */ 39155064Sbrian if (*cp != '!' && how == SYSTEM_EXEC) 39255145Sbrian cp = GetLabel(cp, filename, linenum); 39336285Sbrian break; 39440481Sbrian } 39536285Sbrian 39636285Sbrian len = strlen(cp); 39758045Sbrian if ((argc = command_Expand_Interpret(cp, len, argv, cp - line)) < 0) 39854914Sbrian log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum); 39954914Sbrian else { 40054914Sbrian allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); 40154916Sbrian if ((how != SYSTEM_EXEC && allowcmd) || 40254916Sbrian (how == SYSTEM_EXEC && !allowcmd)) { 40354914Sbrian /* 40454914Sbrian * Disable any context so that warnings are given to everyone, 40554914Sbrian * including syslog. 40654914Sbrian */ 40754914Sbrian op = log_PromptContext; 40854914Sbrian log_PromptContext = NULL; 40954914Sbrian command_Run(bundle, argc, (char const *const *)argv, prompt, 41054914Sbrian name, cx); 41154914Sbrian log_PromptContext = op; 41254914Sbrian } 41351005Sbrian } 41431077Sbrian } 41536285Sbrian 41636285Sbrian fclose(fp); /* everything read - get out */ 41736285Sbrian return 0; 4186059Samurai } 4196059Samurai break; 4206059Samurai } 4216059Samurai } 4226059Samurai fclose(fp); 42326516Sbrian return -1; 4246059Samurai} 4256059Samurai 42640797Sbrianconst char * 42736285Sbriansystem_IsValid(const char *name, struct prompt *prompt, int mode) 42831121Sbrian{ 42936285Sbrian /* 43036285Sbrian * Note: The ReadSystem() calls only result in calls to the Allow* 43136285Sbrian * functions. arg->bundle will be set to NULL for these commands ! 43236285Sbrian */ 43344612Sbrian int def, how, rs; 43463052Sbrian int defuserok; 43540797Sbrian 43640797Sbrian def = !strcmp(name, "default"); 43743526Sbrian how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE; 43863052Sbrian userok = -1; 43931121Sbrian modeok = 1; 44036285Sbrian modereq = mode; 44140797Sbrian 44244612Sbrian rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how); 44340797Sbrian 44463052Sbrian defuserok = userok; 44563052Sbrian userok = -1; 44663052Sbrian 44744612Sbrian if (!def) { 44844612Sbrian if (rs == -1) 44944612Sbrian rs = 0; /* we don't care that ``default'' doesn't exist */ 45040797Sbrian 45144612Sbrian if (rs == 0) 45244612Sbrian rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how); 45344612Sbrian 45444612Sbrian if (rs == -1) 45544612Sbrian return "Configuration label not found"; 45644612Sbrian 45744612Sbrian if (rs == -2) 45874687Sbrian return PPP_CONFDIR "/" CONFFILE " : File not found"; 45944612Sbrian } 46044612Sbrian 46163052Sbrian if (userok == -1) 46263052Sbrian userok = defuserok; 46363052Sbrian 46443526Sbrian if (how == SYSTEM_EXISTS) 46543526Sbrian userok = modeok = 1; 46643526Sbrian 46740797Sbrian if (!userok) 46843526Sbrian return "User access denied"; 46940797Sbrian 47040797Sbrian if (!modeok) 47143526Sbrian return "Mode denied for this label"; 47240797Sbrian 47340797Sbrian return NULL; 47431121Sbrian} 47531121Sbrian 47631121Sbrianint 47736285Sbriansystem_Select(struct bundle *bundle, const char *name, const char *file, 47837008Sbrian struct prompt *prompt, struct datalink *cx) 47931121Sbrian{ 48031121Sbrian userok = modeok = 1; 48136285Sbrian modereq = PHYS_ALL; 48243526Sbrian return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC); 48331121Sbrian} 484