?? wrapper.c
字號:
/* -*-Mode: C;-*- *//************************************************************************* wrapper.c** C wrapper designed to run SUID root for controlling PPPoE connections.** Copyright (C) 2005 by Roaring Penguin Software Inc.** LIC: GPL** This program may be distributed under the terms of the GNU General* Public License, Version 2, or (at your option) any later version.***********************************************************************/static char const RCSID[] ="$Id: wrapper.c,v 1.10 2005/08/09 02:49:15 dfs Exp $";#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 512static char const *pppoe_start = PPPOE_START_PATH;static char const *pppoe_stop = PPPOE_STOP_PATH;static char const *pppoe_status = PPPOE_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 intPathOK(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 voidCleanEnvironment(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 pppoe-start, pppoe-stop or pppoe-status returns. *%DESCRIPTION: * Runs pppoe-start, pppoe-stop or pppoe-status on given connection if * non-root users are allowed to do it. **********************************************************************/intmain(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(pppoe_start)) exit(1); execl(pppoe_start, "pppoe-start", fname, NULL); } else if (!strcmp(argv[1], "stop")) { if (!PathOK(pppoe_stop)) exit(1); execl(pppoe_stop, "pppoe-stop", fname, NULL); } else { if (!PathOK(pppoe_status)) exit(1); execl(pppoe_status, "pppoe-status", fname, NULL); } fprintf(stderr, "%s: execl: %s\n", argv[0], strerror(errno)); exit(1);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -