blob: 3785d99d7fdafe998c00ad9230e41ec6b7bd50d7 [file] [log] [blame]
Guido van Rossumffa257d1995-07-20 21:57:15 +00001/*
2 Template for a setuid program that calls a script.
3
4 The script should be in an unwritable directory and should itself
5 be unwritable. In fact all parent directories up to the root
6 should be unwritable. The script must not be setuid, that's what
7 this program is for.
8
9 This is a template program. You need to fill in the name of the
10 script that must be executed. This is done by changing the
11 definition of FULL_PATH below.
12
13 There are also some rules that should be adhered to when writing
14 the script itself.
15
16 The first and most important rule is to never, ever trust that the
17 user of the program will behave properly. Program defensively.
18 Check your arguments for reasonableness. If the user is allowed to
19 create files, check the names of the files. If the program depends
20 on argv[0] for the action it should perform, check it.
21
22 Assuming the script is a Bourne shell script, the first line of the
23 script should be
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000024 #!/bin/sh -
Guido van Rossumffa257d1995-07-20 21:57:15 +000025 The - is important, don't omit it. If you're using esh, the first
26 line should be
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000027 #!/usr/local/bin/esh -f
Guido van Rossumffa257d1995-07-20 21:57:15 +000028 and for ksh, the first line should be
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 #!/usr/local/bin/ksh -p
Guido van Rossumffa257d1995-07-20 21:57:15 +000030 The script should then set the variable IFS to the string
31 consisting of <space>, <tab>, and <newline>. After this (*not*
32 before!), the PATH variable should be set to a reasonable value and
33 exported. Do not expect the PATH to have a reasonable value, so do
34 not trust the old value of PATH. You should then set the umask of
35 the program by calling
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000036 umask 077 # or 022 if you want the files to be readable
Guido van Rossumffa257d1995-07-20 21:57:15 +000037 If you plan to change directories, you should either unset CDPATH
38 or set it to a good value. Setting CDPATH to just ``.'' (dot) is a
39 good idea.
40 If, for some reason, you want to use csh, the first line should be
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000041 #!/bin/csh -fb
Guido van Rossumffa257d1995-07-20 21:57:15 +000042 You should then set the path variable to something reasonable,
43 without trusting the inherited path. Here too, you should set the
44 umask using the command
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000045 umask 077 # or 022 if you want the files to be readable
Guido van Rossumffa257d1995-07-20 21:57:15 +000046*/
47
48#include <unistd.h>
49#include <stdlib.h>
50#include <stdio.h>
51#include <sys/types.h>
52#include <sys/stat.h>
Jeremy Hylton1deebab1998-09-10 18:10:59 +000053#include <string.h>
Guido van Rossumffa257d1995-07-20 21:57:15 +000054
55/* CONFIGURATION SECTION */
56
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000057#ifndef FULL_PATH /* so that this can be specified from the Makefile */
Jeremy Hyltonfaff0bd1998-09-10 20:18:09 +000058/* Uncomment the following line:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000059#define FULL_PATH "/full/path/of/script"
Jeremy Hylton1deebab1998-09-10 18:10:59 +000060* Then comment out the #error line. */
Guido van Rossum106a4701998-09-10 18:22:18 +000061#error "You must define FULL_PATH somewhere"
Guido van Rossumffa257d1995-07-20 21:57:15 +000062#endif
63#ifndef UMASK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064#define UMASK 077
Guido van Rossumffa257d1995-07-20 21:57:15 +000065#endif
66
67/* END OF CONFIGURATION SECTION */
68
69#if defined(__STDC__) && defined(__sgi)
70#define environ _environ
71#endif
72
73/* don't change def_IFS */
74char def_IFS[] = "IFS= \t\n";
75/* you may want to change def_PATH, but you should really change it in */
76/* your script */
77#ifdef __sgi
78char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin";
79#else
80char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin";
81#endif
82/* don't change def_CDPATH */
83char def_CDPATH[] = "CDPATH=.";
84/* don't change def_ENV */
85char def_ENV[] = "ENV=:";
86
87/*
88 This function changes all environment variables that start with LD_
89 into variables that start with XD_. This is important since we
90 don't want the script that is executed to use any funny shared
91 libraries.
92
93 The other changes to the environment are, strictly speaking, not
94 needed here. They can safely be done in the script. They are done
95 here because we don't trust the script writer (just like the script
96 writer shouldn't trust the user of the script).
97 If IFS is set in the environment, set it to space,tab,newline.
98 If CDPATH is set in the environment, set it to ``.''.
99 Set PATH to a reasonable default.
100*/
101void
102clean_environ(void)
103{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 char **p;
105 extern char **environ;
Guido van Rossumffa257d1995-07-20 21:57:15 +0000106
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 for (p = environ; *p; p++) {
108 if (strncmp(*p, "LD_", 3) == 0)
109 **p = 'X';
110 else if (strncmp(*p, "_RLD", 4) == 0)
111 **p = 'X';
112 else if (strncmp(*p, "PYTHON", 6) == 0)
113 **p = 'X';
114 else if (strncmp(*p, "IFS=", 4) == 0)
115 *p = def_IFS;
116 else if (strncmp(*p, "CDPATH=", 7) == 0)
117 *p = def_CDPATH;
118 else if (strncmp(*p, "ENV=", 4) == 0)
119 *p = def_ENV;
120 }
121 putenv(def_PATH);
Guido van Rossumffa257d1995-07-20 21:57:15 +0000122}
123
124int
125main(int argc, char **argv)
126{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 struct stat statb;
128 gid_t egid = getegid();
129 uid_t euid = geteuid();
Guido van Rossumffa257d1995-07-20 21:57:15 +0000130
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 /*
132 Sanity check #1.
133 This check should be made compile-time, but that's not possible.
134 If you're sure that you specified a full path name for FULL_PATH,
135 you can omit this check.
136 */
137 if (FULL_PATH[0] != '/') {
138 fprintf(stderr, "%s: %s is not a full path name\n", argv[0],
139 FULL_PATH);
140 fprintf(stderr, "You can only use this wrapper if you\n");
141 fprintf(stderr, "compile it with an absolute path.\n");
142 exit(1);
143 }
Guido van Rossumffa257d1995-07-20 21:57:15 +0000144
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 /*
146 Sanity check #2.
147 Check that the owner of the script is equal to either the
148 effective uid or the super user.
149 */
150 if (stat(FULL_PATH, &statb) < 0) {
151 perror("stat");
152 exit(1);
153 }
154 if (statb.st_uid != 0 && statb.st_uid != euid) {
155 fprintf(stderr, "%s: %s has the wrong owner\n", argv[0],
156 FULL_PATH);
157 fprintf(stderr, "The script should be owned by root,\n");
158 fprintf(stderr, "and shouldn't be writable by anyone.\n");
159 exit(1);
160 }
Guido van Rossumffa257d1995-07-20 21:57:15 +0000161
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 if (setregid(egid, egid) < 0)
163 perror("setregid");
164 if (setreuid(euid, euid) < 0)
165 perror("setreuid");
Guido van Rossumffa257d1995-07-20 21:57:15 +0000166
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 clean_environ();
Guido van Rossumffa257d1995-07-20 21:57:15 +0000168
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 umask(UMASK);
Guido van Rossumffa257d1995-07-20 21:57:15 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 while (**argv == '-') /* don't let argv[0] start with '-' */
172 (*argv)++;
173 execv(FULL_PATH, argv);
174 fprintf(stderr, "%s: could not execute the script\n", argv[0]);
175 exit(1);
Guido van Rossumffa257d1995-07-20 21:57:15 +0000176}