summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/rp-pppoe/gui/wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/rp-pppoe/gui/wrapper.c')
-rw-r--r--mdk-stage1/rp-pppoe/gui/wrapper.c234
1 files changed, 234 insertions, 0 deletions
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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#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);
+}