-/* IPFire helper program - fireinfoctrl\r
- *\r
- * This program is distributed under the terms of the GNU General Public\r
- * Licence. See the file COPYING for details.\r
- *\r
- * (c) IPFire Team, 2011\r
- *\r
- * Simple program that calls "sendprofile" as the root user.\r
- * \r
- */\r
- \r
-#include <stdlib.h>\r
-#include "setuid.h"\r
-\r
-int main(void)\r
-{\r
- if (!(initsetuid()))\r
- exit(1);\r
- \r
- safe_system("/usr/bin/sendprofile");\r
- \r
- return 0;\r
-}\r
+/* IPFire helper program - fireinfoctrl
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * Licence. See the file COPYING for details.
+ *
+ * (c) IPFire Team, 2011
+ *
+ * Simple program that calls "sendprofile" as the root user.
+ *
+ */
+
+#include <stdlib.h>
+#include "setuid.h"
+
+int main(void)
+{
+ if (!(initsetuid()))
+ exit(1);
+
+ safe_system("/usr/bin/sendprofile");
+
+ return 0;
+}
-/* IPFire helper program - getconntracktable\r
- *\r
- * This program is distributed under the terms of the GNU General Public\r
- * Licence. See the file COPYING for details.\r
- *\r
- * The kernel's connection tracking table is not readable by\r
- * non-root users. So this helper will just read and output it.\r
- */\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include "setuid.h"\r
-\r
-int main(void) {\r
- if (!(initsetuid()))\r
- exit(1);\r
-\r
- FILE *fp = fopen("/proc/net/nf_conntrack", "r");\r
- if (fp == NULL) {\r
- exit(1);\r
- }\r
-\r
- /* Read content line by line and write it to stdout. */\r
- char linebuf[STRING_SIZE];\r
- while (fgets(linebuf, STRING_SIZE, fp)) {\r
- printf("%s", linebuf);\r
- }\r
-\r
- fclose(fp);\r
- return 0;\r
-}\r
+/* IPFire helper program - getconntracktable
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * Licence. See the file COPYING for details.
+ *
+ * The kernel's connection tracking table is not readable by
+ * non-root users. So this helper will just read and output it.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "setuid.h"
+
+int main(void) {
+ if (!(initsetuid()))
+ exit(1);
+
+ FILE *fp = fopen("/proc/net/nf_conntrack", "r");
+ if (fp == NULL) {
+ exit(1);
+ }
+
+ /* Read content line by line and write it to stdout. */
+ char linebuf[STRING_SIZE];
+ while (fgets(linebuf, STRING_SIZE, fp)) {
+ printf("%s", linebuf);
+ }
+
+ fclose(fp);
+ return 0;
+}
-/* SmoothWall helper program - iowrap.\r
- *\r
- * This program is distributed under the terms of the GNU General Public\r
- * Licence. See the file COPYING for details.\r
- *\r
- * (c) Lawrence Manning, 2001\r
- * Installer helper for redirecting stdout/stderr to a file/terminal.\r
- * init calls ash through this program to shove it on a tty.\r
- * \r
- * $Id: iowrap.c,v 1.2 2001/11/27 15:20:50 riddles Exp $\r
- * \r
- */\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <fcntl.h>\r
-#include <unistd.h>\r
-\r
-int main(int argc, char *argv[])\r
-{\r
- /* Prog takes one argument. A device to run on (like a getty) */\r
- if (argc >= 2)\r
- {\r
- int fd;\r
- \r
- if ((fd = open(argv[1], O_RDWR)) == -1)\r
- {\r
- printf("Couldn't open device\n");\r
- return 0;\r
- }\r
- dup2(fd, 0);\r
- dup2(fd, 1);\r
- dup2(fd, 2);\r
- /* Now its sending/reading on that device. */\r
- }\r
- \r
- if (argc >= 3) \r
- execvp(argv[2], &argv[2]);\r
- else\r
- printf("No command\n");\r
-\r
- return 0;\r
-}\r
+/* SmoothWall helper program - iowrap.
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * Licence. See the file COPYING for details.
+ *
+ * (c) Lawrence Manning, 2001
+ * Installer helper for redirecting stdout/stderr to a file/terminal.
+ * init calls ash through this program to shove it on a tty.
+ *
+ * $Id: iowrap.c,v 1.2 2001/11/27 15:20:50 riddles Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ /* Prog takes one argument. A device to run on (like a getty) */
+ if (argc >= 2)
+ {
+ int fd;
+
+ if ((fd = open(argv[1], O_RDWR)) == -1)
+ {
+ printf("Couldn't open device\n");
+ return 0;
+ }
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ /* Now its sending/reading on that device. */
+ }
+
+ if (argc >= 3)
+ execvp(argv[2], &argv[2]);
+ else
+ printf("No command\n");
+
+ return 0;
+}
-/* SmoothWall helper program - smoothiedeath\r
- *\r
- * This program is distributed under the terms of the GNU General Public\r
- * Licence. See the file COPYING for details.\r
- *\r
- * (c) Lawrence Manning, 2001\r
- * Simple program intended to be installed setuid(0) that can be used for\r
- * starting shutdown.\r
- * \r
- * $Id: ipcopdeath.c,v 1.2 2003/12/11 10:57:34 riddles Exp $\r
- * \r
- */\r
- \r
-#include <stdlib.h>\r
-#include "setuid.h"\r
-\r
-int main(void)\r
-{\r
- if (!(initsetuid()))\r
- exit(1);\r
- \r
- safe_system("/sbin/shutdown -h now");\r
- \r
- return 0;\r
-}\r
+/* SmoothWall helper program - smoothiedeath
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * Licence. See the file COPYING for details.
+ *
+ * (c) Lawrence Manning, 2001
+ * Simple program intended to be installed setuid(0) that can be used for
+ * starting shutdown.
+ *
+ * $Id: ipcopdeath.c,v 1.2 2003/12/11 10:57:34 riddles Exp $
+ *
+ */
+
+#include <stdlib.h>
+#include "setuid.h"
+
+int main(void)
+{
+ if (!(initsetuid()))
+ exit(1);
+
+ safe_system("/sbin/shutdown -h now");
+
+ return 0;
+}
-/* SmoothWall helper program - smoothierebirth\r
- *\r
- * This program is distributed under the terms of the GNU General Public\r
- * Licence. See the file COPYING for details.\r
- *\r
- * (c) Lawrence Manning, 2001\r
- * Simple program intended to be installed setuid(0) that can be used for\r
- * starting reboot.\r
- * \r
- * $Id: ipcoprebirth.c,v 1.2 2003/12/11 10:57:34 riddles Exp $\r
- * \r
- */\r
- \r
-#include <stdlib.h>\r
-#include "setuid.h"\r
-\r
-int main(void)\r
-{\r
- if (!(initsetuid()))\r
- exit(1);\r
- \r
- safe_system("/sbin/shutdown -r now");\r
- \r
- return 0;\r
-}\r
+/* SmoothWall helper program - smoothierebirth
+ *
+ * This program is distributed under the terms of the GNU General Public
+ * Licence. See the file COPYING for details.
+ *
+ * (c) Lawrence Manning, 2001
+ * Simple program intended to be installed setuid(0) that can be used for
+ * starting reboot.
+ *
+ * $Id: ipcoprebirth.c,v 1.2 2003/12/11 10:57:34 riddles Exp $
+ *
+ */
+
+#include <stdlib.h>
+#include "setuid.h"
+
+int main(void)
+{
+ if (!(initsetuid()))
+ exit(1);
+
+ safe_system("/sbin/shutdown -r now");
+
+ return 0;
+}
-/*\r
- * This file is part of the IPCop Firewall.\r
- *\r
- * IPCop is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * IPCop is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with IPCop; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- *\r
- * Copyright (C) 2005-10-25 Franck Bourdonnec\r
- *\r
- * $Id: ipcopreboot.c,v 1.1.2.2 2005/10/24 23:05:50 franck78 Exp $\r
- *\r
- */\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include "setuid.h"\r
-\r
-\r
-/* define operations */\r
-#define OP_REBOOT "boot"\r
-#define OP_REBOOT_FS "bootfs" // add filesystem check option (not yet in GUI)\r
-#define OP_SHUTDOWN "down"\r
-#define OP_SCHEDULE_ADD "cron+"\r
-#define OP_SCHEDULE_REM "cron-"\r
-#define OP_SCHEDULE_GET "cron?"\r
-\r
-int main(int argc, char**argv)\r
-{\r
-\r
- if (!(initsetuid()))\r
- return 1;\r
-\r
- // Check what command is asked\r
- if (argc==1)\r
- { \r
- fprintf (stderr, "Missing reboot command!\n");\r
- return 1;\r
- }\r
-\r
- if (argc==2 && strcmp(argv[1], OP_SHUTDOWN)==0)\r
- {\r
- safe_system("/sbin/shutdown -h now");\r
- return 0;\r
- }\r
-\r
- if (argc==2 && strcmp(argv[1], OP_REBOOT)==0)\r
- {\r
- safe_system("/sbin/shutdown -r now");\r
- return 0;\r
- }\r
-\r
- if (argc==2 && strcmp(argv[1], OP_REBOOT_FS)==0)\r
- {\r
- safe_system("/sbin/shutdown -F -r now");\r
- return 0;\r
- }\r
-\r
- // output schedule to stdout\r
- if (argc==2 && strcmp(argv[1], OP_SCHEDULE_GET)==0)\r
- {\r
- safe_system("/bin/grep /sbin/shutdown /var/spool/cron/root.orig");\r
- return 0;\r
- }\r
-\r
- if (argc==2 && strcmp(argv[1], OP_SCHEDULE_REM)==0)\r
- {\r
- safe_system("/usr/bin/perl -i -p -e 's/^.*\\/sbin\\/shutdown.*$//s' /var/spool/cron/root.orig");\r
- safe_system("/usr/bin/fcrontab -u root -z");\r
- return 0;\r
- }\r
-\r
- if (argc==6 && strcmp(argv[1], OP_SCHEDULE_ADD)==0)\r
- {\r
- // check args\r
- if (!( strlen(argv[2])<3 &&\r
- strspn(argv[2], "0123456789") == strlen (argv[2]) &&\r
- strlen(argv[3])<3 &&\r
- strspn(argv[3], "0123456789") == strlen (argv[3]) &&\r
- strlen(argv[4])<14 &&\r
- strspn(argv[4], "1234567,*") == strlen (argv[4]) &&\r
- ((strcmp(argv[5], "-r")==0) || //reboot\r
- (strcmp(argv[5], "-h")==0)) ) //hangup\r
- ) {\r
- fprintf (stderr, "Bad cron+ parameters!\n");\r
- return 1;\r
- }\r
- \r
- // remove old entry \r
- safe_system("/usr/bin/perl -i -p -e 's/^.*\\/sbin\\/shutdown.*$//s' /var/spool/cron/root.orig");\r
-\r
- // add new entry\r
- FILE *fd = NULL;\r
- if ((fd = fopen("/var/spool/cron/root.orig", "a")))\r
- {\r
- fprintf (fd,"%s %s * * %s /sbin/shutdown %s 1\n",argv[2],argv[3],argv[4],argv[5]);\r
- fclose (fd);\r
- }\r
- \r
- // inform cron\r
- safe_system("/usr/bin/fcrontab -u root -z");\r
- return 0;\r
- }\r
-\r
- fprintf (stderr, "Bad reboot command!\n");\r
- return 1;\r
-}\r
+/*
+ * This file is part of the IPCop Firewall.
+ *
+ * IPCop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * IPCop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with IPCop; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-10-25 Franck Bourdonnec
+ *
+ * $Id: ipcopreboot.c,v 1.1.2.2 2005/10/24 23:05:50 franck78 Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "setuid.h"
+
+
+/* define operations */
+#define OP_REBOOT "boot"
+#define OP_REBOOT_FS "bootfs" // add filesystem check option (not yet in GUI)
+#define OP_SHUTDOWN "down"
+#define OP_SCHEDULE_ADD "cron+"
+#define OP_SCHEDULE_REM "cron-"
+#define OP_SCHEDULE_GET "cron?"
+
+int main(int argc, char**argv)
+{
+
+ if (!(initsetuid()))
+ return 1;
+
+ // Check what command is asked
+ if (argc==1)
+ {
+ fprintf (stderr, "Missing reboot command!\n");
+ return 1;
+ }
+
+ if (argc==2 && strcmp(argv[1], OP_SHUTDOWN)==0)
+ {
+ safe_system("/sbin/shutdown -h now");
+ return 0;
+ }
+
+ if (argc==2 && strcmp(argv[1], OP_REBOOT)==0)
+ {
+ safe_system("/sbin/shutdown -r now");
+ return 0;
+ }
+
+ if (argc==2 && strcmp(argv[1], OP_REBOOT_FS)==0)
+ {
+ safe_system("/sbin/shutdown -F -r now");
+ return 0;
+ }
+
+ // output schedule to stdout
+ if (argc==2 && strcmp(argv[1], OP_SCHEDULE_GET)==0)
+ {
+ safe_system("/bin/grep /sbin/shutdown /var/spool/cron/root.orig");
+ return 0;
+ }
+
+ if (argc==2 && strcmp(argv[1], OP_SCHEDULE_REM)==0)
+ {
+ safe_system("/usr/bin/perl -i -p -e 's/^.*\\/sbin\\/shutdown.*$//s' /var/spool/cron/root.orig");
+ safe_system("/usr/bin/fcrontab -u root -z");
+ return 0;
+ }
+
+ if (argc==6 && strcmp(argv[1], OP_SCHEDULE_ADD)==0)
+ {
+ // check args
+ if (!( strlen(argv[2])<3 &&
+ strspn(argv[2], "0123456789") == strlen (argv[2]) &&
+ strlen(argv[3])<3 &&
+ strspn(argv[3], "0123456789") == strlen (argv[3]) &&
+ strlen(argv[4])<14 &&
+ strspn(argv[4], "1234567,*") == strlen (argv[4]) &&
+ ((strcmp(argv[5], "-r")==0) || //reboot
+ (strcmp(argv[5], "-h")==0)) ) //hangup
+ ) {
+ fprintf (stderr, "Bad cron+ parameters!\n");
+ return 1;
+ }
+
+ // remove old entry
+ safe_system("/usr/bin/perl -i -p -e 's/^.*\\/sbin\\/shutdown.*$//s' /var/spool/cron/root.orig");
+
+ // add new entry
+ FILE *fd = NULL;
+ if ((fd = fopen("/var/spool/cron/root.orig", "a")))
+ {
+ fprintf (fd,"%s %s * * %s /sbin/shutdown %s 1\n",argv[2],argv[3],argv[4],argv[5]);
+ fclose (fd);
+ }
+
+ // inform cron
+ safe_system("/usr/bin/fcrontab -u root -z");
+ return 0;
+ }
+
+ fprintf (stderr, "Bad reboot command!\n");
+ return 1;
+}
-/* This file is part of the IPCop Firewall.\r
- *\r
- * IPCop is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * IPCop is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with IPCop; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- *\r
- * Copyright (C) 2003-04-22 Robert Kerr <rkerr@go.to>\r
- *\r
- * $Id: setuid.c,v 1.2.2.1 2005/11/18 14:51:43 franck78 Exp $\r
- *\r
- */\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <errno.h>\r
-#include <unistd.h>\r
-#include <stdlib.h>\r
-#include <sys/types.h>\r
-#include <limits.h>\r
-#include <sys/time.h>\r
-#include <sys/resource.h>\r
-#include <sys/stat.h>\r
-#include <fcntl.h>\r
-#include <grp.h>\r
-#include <signal.h>\r
-#include <sys/wait.h>\r
-#include <glob.h>\r
-#include "setuid.h"\r
-\r
-#ifndef OPEN_MAX\r
-#define OPEN_MAX 256\r
-#endif\r
-\r
-/* Trusted environment for executing commands */\r
-char * trusted_env[4]={\r
- "PATH=/usr/bin:/usr/sbin:/sbin:/bin",\r
- "SHELL=/bin/sh",\r
- "TERM=dumb",\r
- NULL};\r
-\r
-/* Spawns a child process that uses /bin/sh to interpret a command.\r
- * This is much the same in use and purpose as system(), yet as it uses execve\r
- * to pass a trusted environment it's immune to attacks based upon changing\r
- * IFS, ENV, BASH_ENV and other such variables.\r
- * Note this does NOT guard against any other attacks, inparticular you MUST\r
- * validate the command you are passing. If the command is formed from user\r
- * input be sure to check this input is what you expect. Nasty things can\r
- * happen if a user can inject ; or `` into your command for example */\r
-int safe_system(char* command)\r
-{\r
- return system_core( command, 0, 0, "safe_system" );\r
-}\r
-\r
-/* Much like safe_system but lets you specify a non-root uid and gid to run\r
- * the command as */\r
-int unpriv_system(char* command, uid_t uid, gid_t gid)\r
-{\r
- return system_core(command, uid, gid, "unpriv_system" );\r
-}\r
-\r
-int system_core(char* command, uid_t uid, gid_t gid, char *error)\r
-{\r
- int pid, status;\r
-\r
- if(!command)\r
- return 1;\r
-\r
- switch( pid = fork() )\r
- {\r
- case -1:\r
- return -1;\r
- case 0: /* child */\r
- {\r
- char * argv[4];\r
- if (gid && setgid(gid)) \r
- {\r
- fprintf(stderr, "%s: ", error);\r
- perror("Couldn't setgid");\r
- exit(127);\r
- }\r
- if (uid && setuid(uid))\r
- {\r
- fprintf(stderr, "%s: ", error);\r
- perror("Couldn't setuid");\r
- exit(127);\r
- }\r
- argv[0] = "sh";\r
- argv[1] = "-c";\r
- argv[2] = command;\r
- argv[3] = NULL;\r
- execve("/bin/sh", argv, trusted_env);\r
- fprintf(stderr, "%s: ", error);\r
- perror("execve failed");\r
- exit(127);\r
- }\r
- default: /* parent */\r
- do {\r
- if( waitpid(pid, &status, 0) == -1 ) {\r
- if( errno != EINTR )\r
- return -1;\r
- } else\r
- return status;\r
- } while (1);\r
- }\r
-\r
-}\r
-\r
-/* General routine to initialise a setuid root program, and put the\r
- * environment in a known state. Returns 1 on success, if initsetuid() returns\r
- * 0 then you should exit(1) immediately, DON'T attempt to recover from the\r
- * error */\r
-int initsetuid(void)\r
-{\r
- int fds,i;\r
- struct stat st;\r
- struct rlimit rlim;\r
-\r
- /* Prevent signal tricks by ignoring all except SIGKILL and SIGCHILD */\r
- for( i = 0; i < NSIG; i++ ) {\r
- if( i != SIGKILL && i != SIGCHLD )\r
- signal(i, SIG_IGN);\r
- }\r
-\r
- /* dump all non-standard file descriptors (a full descriptor table could\r
- * lead to DoS by preventing us opening files) */\r
- if ((fds = getdtablesize()) == -1) fds = OPEN_MAX;\r
- for( i = 3; i < fds; i++ ) close(i);\r
-\r
- /* check stdin, stdout & stderr are open before going any further */\r
- for( i = 0; i < 3; i++ )\r
- if( fstat(i, &st) == -1 && ((errno != EBADF) || (close(i), open("/dev/null", O_RDWR, 0)) != i ))\r
- return 0;\r
-\r
- /* disable core dumps in case we're processing sensitive information */\r
- rlim.rlim_cur = rlim.rlim_max = 0;\r
- if(setrlimit(RLIMIT_CORE, &rlim))\r
- { perror("Couldn't disable core dumps"); return 0; }\r
-\r
- /* drop any supplementary groups, set uid & gid to root */\r
- if (setgroups(0, NULL)) { perror("Couldn't clear group list"); return 0; }\r
- if (setgid(0)) { perror("Couldn't setgid(0)"); return 0; }\r
- if (setuid(0)) { perror("Couldn't setuid(0)"); return 0; }\r
-\r
- return 1;\r
-}\r
+/* This file is part of the IPCop Firewall.
+ *
+ * IPCop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * IPCop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with IPCop; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2003-04-22 Robert Kerr <rkerr@go.to>
+ *
+ * $Id: setuid.c,v 1.2.2.1 2005/11/18 14:51:43 franck78 Exp $
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <glob.h>
+#include "setuid.h"
+
+#ifndef OPEN_MAX
+#define OPEN_MAX 256
+#endif
+
+/* Trusted environment for executing commands */
+char * trusted_env[4] = {
+ "PATH=/usr/bin:/usr/sbin:/sbin:/bin",
+ "SHELL=/bin/sh",
+ "TERM=dumb",
+ NULL
+};
+
+/* Spawns a child process that uses /bin/sh to interpret a command.
+ * This is much the same in use and purpose as system(), yet as it uses execve
+ * to pass a trusted environment it's immune to attacks based upon changing
+ * IFS, ENV, BASH_ENV and other such variables.
+ * Note this does NOT guard against any other attacks, inparticular you MUST
+ * validate the command you are passing. If the command is formed from user
+ * input be sure to check this input is what you expect. Nasty things can
+ * happen if a user can inject ; or `` into your command for example */
+int safe_system(char* command)
+{
+ return system_core( command, 0, 0, "safe_system" );
+}
+
+/* Much like safe_system but lets you specify a non-root uid and gid to run
+ * the command as */
+int unpriv_system(char* command, uid_t uid, gid_t gid)
+{
+ return system_core(command, uid, gid, "unpriv_system" );
+}
+
+int system_core(char* command, uid_t uid, gid_t gid, char *error)
+{
+ int pid, status;
+
+ if(!command)
+ return 1;
+
+ switch( pid = fork() )
+ {
+ case -1:
+ return -1;
+ case 0: /* child */
+ {
+ char * argv[4];
+ if (gid && setgid(gid))
+ {
+ fprintf(stderr, "%s: ", error);
+ perror("Couldn't setgid");
+ exit(127);
+ }
+ if (uid && setuid(uid))
+ {
+ fprintf(stderr, "%s: ", error);
+ perror("Couldn't setuid");
+ exit(127);
+ }
+ argv[0] = "sh";
+ argv[1] = "-c";
+ argv[2] = command;
+ argv[3] = NULL;
+ execve("/bin/sh", argv, trusted_env);
+ fprintf(stderr, "%s: ", error);
+ perror("execve failed");
+ exit(127);
+ }
+ default: /* parent */
+ do {
+ if( waitpid(pid, &status, 0) == -1 ) {
+ if( errno != EINTR )
+ return -1;
+ } else
+ return status;
+ } while (1);
+ }
+
+}
+
+/* General routine to initialise a setuid root program, and put the
+ * environment in a known state. Returns 1 on success, if initsetuid() returns
+ * 0 then you should exit(1) immediately, DON'T attempt to recover from the
+ * error */
+int initsetuid(void)
+{
+ int fds,i;
+ struct stat st;
+ struct rlimit rlim;
+
+ /* Prevent signal tricks by ignoring all except SIGKILL and SIGCHILD */
+ for( i = 0; i < NSIG; i++ ) {
+ if( i != SIGKILL && i != SIGCHLD )
+ signal(i, SIG_IGN);
+ }
+
+ /* dump all non-standard file descriptors (a full descriptor table could
+ * lead to DoS by preventing us opening files) */
+ if ((fds = getdtablesize()) == -1) fds = OPEN_MAX;
+ for( i = 3; i < fds; i++ ) close(i);
+
+ /* check stdin, stdout & stderr are open before going any further */
+ for( i = 0; i < 3; i++ )
+ if( fstat(i, &st) == -1 && ((errno != EBADF) || (close(i), open("/dev/null", O_RDWR, 0)) != i ))
+ return 0;
+
+ /* disable core dumps in case we're processing sensitive information */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ if(setrlimit(RLIMIT_CORE, &rlim))
+ { perror("Couldn't disable core dumps"); return 0; }
+
+ /* drop any supplementary groups, set uid & gid to root */
+ if (setgroups(0, NULL)) { perror("Couldn't clear group list"); return 0; }
+ if (setgid(0)) { perror("Couldn't setgid(0)"); return 0; }
+ if (setuid(0)) { perror("Couldn't setuid(0)"); return 0; }
+
+ return 1;
+}