diff options
Diffstat (limited to 'src/systems.c')
-rw-r--r-- | src/systems.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/src/systems.c b/src/systems.c new file mode 100644 index 0000000..61bef70 --- /dev/null +++ b/src/systems.c @@ -0,0 +1,483 @@ +/*- + * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> + * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> + * Internet Initiative Japan, Inc (IIJ) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/usr.sbin/ppp/systems.c,v 1.68.26.1 2010/12/21 17:10:29 kensmith Exp $ + */ + +#include <sys/param.h> + +#include <ctype.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> + +#include "defs.h" +#include "command.h" +#include "log.h" +#include "id.h" +#include "systems.h" + +#define issep(ch) ((ch) == ' ' || (ch) == '\t') + +FILE * +OpenSecret(const char *file) +{ + FILE *fp; + char line[100]; + + snprintf(line, sizeof line, "%s/%s", PPP_CONFDIR, file); + fp = ID0fopen(line, "r"); + if (fp == NULL) + log_Printf(LogWARN, "OpenSecret: Can't open %s.\n", line); + return (fp); +} + +void +CloseSecret(FILE *fp) +{ + fclose(fp); +} + +/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */ +const char * +InterpretArg(const char *from, char *to) +{ + char *ptr, *startto, *endto; + struct passwd *pwd; + int instring; + size_t len; + const char *env; + + instring = 0; + startto = to; + endto = to + LINE_LEN - 1; + + while(issep(*from)) + from++; + + while (*from != '\0') { + switch (*from) { + case '"': + instring = !instring; + *to++ = *from++; + break; + case '\\': + switch (*++from) { + case '$': + case '~': + break; /* Swallow the escapes */ + + default: + *to++ = '\\'; /* Pass the escapes on, maybe skipping \# */ + break; + } + *to++ = *from++; + break; + case '$': + if (from[1] == '$') { + *to = '\0'; /* For an empty var name below */ + from += 2; + } else if (from[1] == '{') { + ptr = strchr(from+2, '}'); + if (ptr) { + len = ptr - from - 2; + if (endto - to < (int)len ) + len = endto - to; + if (len) { + strncpy(to, from+2, len); + to[len] = '\0'; + from = ptr+1; + } else { + *to++ = *from++; + continue; + } + } else { + *to++ = *from++; + continue; + } + } else { + ptr = to; + for (from++; (isalnum(*from) || *from == '_') && ptr < endto; from++) + *ptr++ = *from; + *ptr = '\0'; + } + if (*to == '\0') + *to++ = '$'; + else if ((env = getenv(to)) != NULL) { + strncpy(to, env, endto - to); + *endto = '\0'; + to += strlen(to); + } + break; + + case '~': + ptr = strchr(++from, '/'); + len = ptr ? (size_t)(ptr - from) : strlen(from); + if (len == 0) + pwd = getpwuid(ID0realuid()); + else { + strncpy(to, from, len); + to[len] = '\0'; + pwd = getpwnam(to); + } + if (pwd == NULL) + *to++ = '~'; + else { + strncpy(to, pwd->pw_dir, endto - to); + *endto = '\0'; + to += strlen(to); + from += len; + } + endpwent(); + break; + + default: + *to++ = *from++; + break; + } + } + + while (to > startto) { + to--; + if (!issep(*to)) { + to++; + break; + } + } + *to = '\0'; + + return from; +} + +#define CTRL_UNKNOWN (0) +#define CTRL_INCLUDE (1) + +static int +DecodeCtrlCommand(char *line, char *arg) +{ + const char *end; + + if (!strncasecmp(line, "include", 7) && issep(line[7])) { + end = InterpretArg(line+8, arg); + if (*end && *end != '#') + log_Printf(LogWARN, "usage: !include filename\n"); + else + return CTRL_INCLUDE; + } + return CTRL_UNKNOWN; +} + +/* + * Initialised in system_IsValid(), set in ReadSystem(), + * used by system_IsValid() + */ +static int modeok; +static int userok; +static int modereq; + +int +AllowUsers(struct cmdargs const *arg) +{ + /* arg->bundle may be NULL (see system_IsValid()) ! */ + int f; + struct passwd *pwd; + + if (userok == -1) + userok = 0; + + pwd = getpwuid(ID0realuid()); + if (pwd != NULL) + for (f = arg->argn; f < arg->argc; f++) + if (!strcmp("*", arg->argv[f]) || !strcmp(pwd->pw_name, arg->argv[f])) { + userok = 1; + break; + } + endpwent(); + + return 0; +} + +int +AllowModes(struct cmdargs const *arg) +{ + /* arg->bundle may be NULL (see system_IsValid()) ! */ + int f, mode, allowed; + + allowed = 0; + for (f = arg->argn; f < arg->argc; f++) { + mode = Nam2mode(arg->argv[f]); + if (mode == PHYS_NONE || mode == PHYS_ALL) + log_Printf(LogWARN, "allow modes: %s: Invalid mode\n", arg->argv[f]); + else + allowed |= mode; + } + + modeok = modereq & allowed ? 1 : 0; + return 0; +} + +static char * +strip(char *line) +{ + int len; + + len = strlen(line); + while (len && (line[len-1] == '\n' || line[len-1] == '\r' || + issep(line[len-1]))) + line[--len] = '\0'; + + while (issep(*line)) + line++; + + if (*line == '#') + *line = '\0'; + + return line; +} + +static int +xgets(char *buf, int buflen, FILE *fp) +{ + int len, n; + + n = 0; + while (fgets(buf, buflen-1, fp)) { + n++; + buf[buflen-1] = '\0'; + len = strlen(buf); + while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) + buf[--len] = '\0'; + if (len && buf[len-1] == '\\') { + buf += len - 1; + buflen -= len - 1; + if (!buflen) /* No buffer space */ + break; + } else + break; + } + return n; +} + +/* Values for ``how'' in ReadSystem */ +#define SYSTEM_EXISTS 1 +#define SYSTEM_VALIDATE 2 +#define SYSTEM_EXEC 3 + +static char * +GetLabel(char *line, const char *filename, int linenum) +{ + char *argv[MAXARGS]; + int argc, len; + + argc = MakeArgs(line, argv, MAXARGS, PARSE_REDUCE); + + if (argc == 2 && !strcmp(argv[1], ":")) + return argv[0]; + + if (argc != 1 || (len = strlen(argv[0])) < 2 || argv[0][len-1] != ':') { + log_Printf(LogWARN, "Bad label in %s (line %d) - missing colon\n", + filename, linenum); + return NULL; + } + argv[0][len-1] = '\0'; /* Lose the ':' */ + + return argv[0]; +} + +/* Returns -2 for ``file not found'' and -1 for ``label not found'' */ + +static int +ReadSystem(struct bundle *bundle, const char *name, const char *file, + struct prompt *prompt, struct datalink *cx, int how) +{ + FILE *fp; + char *cp; + int n, len; + char line[LINE_LEN]; + char filename[PATH_MAX]; + int linenum; + int argc; + char *argv[MAXARGS]; + int allowcmd; + int indent; + char arg[LINE_LEN]; + struct prompt *op; + + if (*file == '/') + snprintf(filename, sizeof filename, "%s", file); + else + snprintf(filename, sizeof filename, "%s/%s", PPP_CONFDIR, file); + fp = ID0fopen(filename, "r"); + if (fp == NULL) { + log_Printf(LogDEBUG, "ReadSystem: Can't open %s.\n", filename); + return -2; + } + log_Printf(LogDEBUG, "ReadSystem: Checking %s (%s).\n", name, filename); + + linenum = 0; + while ((n = xgets(line, sizeof line, fp))) { + linenum += n; + if (issep(*line)) + continue; + + cp = strip(line); + + switch (*cp) { + case '\0': /* empty/comment */ + break; + + case '!': + switch (DecodeCtrlCommand(cp+1, arg)) { + case CTRL_INCLUDE: + log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg); + n = ReadSystem(bundle, name, arg, prompt, cx, how); + log_Printf(LogCOMMAND, "%s: Done include of \"%s\"\n", filename, arg); + if (!n) { + fclose(fp); + return 0; /* got it */ + } + break; + default: + log_Printf(LogWARN, "%s: %s: Invalid command\n", filename, cp); + break; + } + break; + + default: + if ((cp = GetLabel(cp, filename, linenum)) == NULL) + continue; + + if (strcmp(cp, name) == 0) { + /* We're in business */ + if (how == SYSTEM_EXISTS) { + fclose(fp); + return 0; + } + while ((n = xgets(line, sizeof line, fp))) { + linenum += n; + indent = issep(*line); + cp = strip(line); + + if (*cp == '\0') /* empty / comment */ + continue; + + if (!indent) { /* start of next section */ + if (*cp != '!' && how == SYSTEM_EXEC) + cp = GetLabel(cp, filename, linenum); + break; + } + + len = strlen(cp); + if ((argc = command_Expand_Interpret(cp, len, argv, cp - line)) < 0) + log_Printf(LogWARN, "%s: %d: Syntax error\n", filename, linenum); + else { + allowcmd = argc > 0 && !strcasecmp(argv[0], "allow"); + if ((how != SYSTEM_EXEC && allowcmd) || + (how == SYSTEM_EXEC && !allowcmd)) { + /* + * Disable any context so that warnings are given to everyone, + * including syslog. + */ + op = log_PromptContext; + log_PromptContext = NULL; + command_Run(bundle, argc, (char const *const *)argv, prompt, + name, cx); + log_PromptContext = op; + } + } + } + + fclose(fp); /* everything read - get out */ + return 0; + } + break; + } + } + fclose(fp); + return -1; +} + +const char * +system_IsValid(const char *name, struct prompt *prompt, int mode) +{ + /* + * Note: The ReadSystem() calls only result in calls to the Allow* + * functions. arg->bundle will be set to NULL for these commands ! + */ + int def, how, rs; + int defuserok; + + def = !strcmp(name, "default"); + how = ID0realuid() == 0 ? SYSTEM_EXISTS : SYSTEM_VALIDATE; + userok = -1; + modeok = 1; + modereq = mode; + + rs = ReadSystem(NULL, "default", CONFFILE, prompt, NULL, how); + + defuserok = userok; + userok = -1; + + if (!def) { + if (rs == -1) + rs = 0; /* we don't care that ``default'' doesn't exist */ + + if (rs == 0) + rs = ReadSystem(NULL, name, CONFFILE, prompt, NULL, how); + + if (rs == -1) + return "Configuration label not found"; + + if (rs == -2) + return PPP_CONFDIR "/" CONFFILE " : File not found"; + } + + if (userok == -1) + userok = defuserok; + + if (how == SYSTEM_EXISTS) + userok = modeok = 1; + + if (!userok) + return "User access denied"; + + if (!modeok) + return "Mode denied for this label"; + + return NULL; +} + +int +system_Select(struct bundle *bundle, const char *name, const char *file, + struct prompt *prompt, struct datalink *cx) +{ + userok = modeok = 1; + modereq = PHYS_ALL; + return ReadSystem(bundle, name, file, prompt, cx, SYSTEM_EXEC); +} |