From 0a121a8ecd6de894c14d60daf9da2022ec47405c Mon Sep 17 00:00:00 2001 From: Guillaume Cottenceau Date: Mon, 11 Jun 2001 13:49:39 +0000 Subject: Initial revision --- mdk-stage1/rp-pppoe/gui/wrapper.c | 234 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 mdk-stage1/rp-pppoe/gui/wrapper.c (limited to 'mdk-stage1/rp-pppoe/gui/wrapper.c') diff --git a/mdk-stage1/rp-pppoe/gui/wrapper.c b/mdk-stage1/rp-pppoe/gui/wrapper.c new file mode 100644 index 000000000..e2b99662a --- /dev/null +++ b/mdk-stage1/rp-pppoe/gui/wrapper.c @@ -0,0 +1,234 @@ +/* -*-Mode: C;-*- */ + +/*********************************************************************** +* +* wrapper.c +* +* C wrapper designed to run SUID root for controlling PPPoE connections. +* +* Copyright (C) 2001 by Roaring Penguin Software Inc. +* +***********************************************************************/ + +static char const RCSID[] = +"$Id$"; + +#define _SVID_SOURCE 1 /* For putenv */ +#define _POSIX_SOURCE 1 /* For fileno */ +#define _BSD_SOURCE 1 /* For setreuid */ +#include +#include +#include +#include +#include +#include + +#define CONN_NAME_LEN 64 +#define LINELEN 512 + +static char const *adsl_start = ADSL_START_PATH; +static char const *adsl_stop = ADSL_STOP_PATH; +static char const *adsl_status = ADSL_STATUS_PATH; + +/********************************************************************** + *%FUNCTION: PathOK + *%ARGUMENTS: + * fname -- a file name. + *%RETURNS: + * 1 if path to fname is secure; 0 otherwise. + *%DESCRIPTION: + * Makes sure ownership/permissions of file and parent directories + * are safe. + **********************************************************************/ +static int +PathOK(char const *fname) +{ + char path[LINELEN]; + struct stat buf; + char const *slash; + + if (strlen(fname) > LINELEN) { + fprintf(stderr, "Pathname '%s' too long\n", fname); + return 0; + } + + /* Must be absolute path */ + if (*fname != '/') { + fprintf(stderr, "Unsafe path '%s' not absolute\n", fname); + return 0; + } + + /* Check root directory */ + if (stat("/", &buf) < 0) { + perror("stat"); + return 0; + } + if (buf.st_uid) { + fprintf(stderr, "SECURITY ALERT: Root directory (/) not owned by root\n"); + return 0; + } + if (buf.st_mode & (S_IWGRP | S_IWOTH)) { + fprintf(stderr, "SECURITY ALERT: Root directory (/) writable by group or other\n"); + return 0; + } + + /* Check each component */ + slash = fname; + + while(*slash) { + slash = strchr(slash+1, '/'); + if (!slash) { + slash = fname + strlen(fname); + } + memcpy(path, fname, slash-fname); + path[slash-fname] = 0; + if (stat(path, &buf) < 0) { + perror("stat"); + return 0; + } + if (buf.st_uid) { + fprintf(stderr, "SECURITY ALERT: '%s' not owned by root\n", path); + return 0; + } + + if (buf.st_mode & (S_IWGRP | S_IWOTH)) { + fprintf(stderr, "SECURITY ALERT: '%s' writable by group or other\n", + path); + return 0; + } + } + return 1; +} + +/********************************************************************** + *%FUNCTION: CleanEnvironment + *%ARGUMENTS: + * envp -- environment passed to main + *%RETURNS: + * Nothing + *%DESCRIPTION: + * Deletes all environment variables; makes safe environment + **********************************************************************/ +static void +CleanEnvironment(char *envp[]) +{ + envp[0] = NULL; + putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin"); +} + +/********************************************************************** + *%FUNCTION: main + *%ARGUMENTS: + * argc, argv -- usual suspects + * Usage: pppoe-wrapper {start|stop|status} {connection_name} + *%RETURNS: + * Whatever adsl-start, adsl-stop or adsl-status returns. + *%DESCRIPTION: + * Runs adsl-start, adsl-stop or adsl-status on given connection if + * non-root users are allowed to do it. + **********************************************************************/ +int +main(int argc, char *argv[]) +{ + int amRoot; + char *cp; + char fname[64+CONN_NAME_LEN]; + char line[LINELEN+1]; + int allowed = 0; + + FILE *fp; + + extern char **environ; + + /* Clean out environment */ + CleanEnvironment(environ); + + /* Are we root? */ + amRoot = (getuid() == 0); + + /* Validate arguments */ + if (argc != 3) { + fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n", + argv[0]); + exit(1); + } + + if (strcmp(argv[1], "start") && + strcmp(argv[1], "stop") && + strcmp(argv[1], "status")) { + fprintf(stderr, "Usage: %s {start|stop|status} connection_name\n", + argv[0]); + exit(1); + } + + /* Connection name can be at most CONN_NAME_LEN chars; alpha, num, underscore */ + if (strlen(argv[2]) > CONN_NAME_LEN) { + fprintf(stderr, "%s: Connection name '%s' too long.\n", + argv[0], argv[2]); + exit(1); + } + + for (cp = argv[2]; *cp; cp++) { + if (!strchr("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789_-", *cp)) { + fprintf(stderr, "%s: Connection name '%s' contains illegal character '%c'\n", argv[0], argv[2], *cp); + exit(1); + } + } + + /* Open the connection file */ + sprintf(fname, "/etc/ppp/rp-pppoe-gui/conf.%s", argv[2]); + /* Check path sanity */ + if (!PathOK(fname)) { + exit(1); + } + + fp = fopen(fname, "r"); + if (!fp) { + fprintf(stderr, "%s: Could not open '%s': %s\n", + argv[0], fname, strerror(errno)); + exit(1); + } + + /* Check if non-root users can control it */ + if (amRoot) { + allowed = 1; + } else { + while (!feof(fp)) { + if (!fgets(line, LINELEN, fp)) { + break; + } + if (!strcmp(line, "NONROOT=OK\n")) { + allowed = 1; + break; + } + } + } + fclose(fp); + + if (!allowed) { + fprintf(stderr, "%s: Non-root users are not permitted to control connection '%s'\n", argv[0], argv[2]); + exit(1); + } + + /* Become root with setuid() to defeat is-root checks in shell scripts */ + if (setreuid(0, 0) < 0) { + perror("setreuid"); + exit(1); + } + + /* It's OK -- do it. */ + if (!strcmp(argv[1], "start")) { + if (!PathOK(adsl_start)) exit(1); + execl(adsl_start, "adsl-start", fname, NULL); + } else if (!strcmp(argv[1], "stop")) { + if (!PathOK(adsl_stop)) exit(1); + execl(adsl_stop, "adsl-stop", fname, NULL); + } else { + if (!PathOK(adsl_status)) exit(1); + execl(adsl_status, "adsl-status", fname, NULL); + } + fprintf(stderr, "%s: execl: %s\n", argv[0], strerror(errno)); + exit(1); +} -- cgit v1.2.1