summaryrefslogtreecommitdiff
path: root/src/systems.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systems.c')
-rw-r--r--src/systems.c483
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);
+}