]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/python/Misc/setuid-prog.c
mothra: fix alt display resizing, filter control characters in panel entries, use...
[plan9front.git] / sys / src / cmd / python / Misc / setuid-prog.c
1 /*
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
24         #!/bin/sh -
25    The - is important, don't omit it.  If you're using esh, the first
26    line should be
27         #!/usr/local/bin/esh -f
28    and for ksh, the first line should be
29         #!/usr/local/bin/ksh -p
30    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
36         umask 077 # or 022 if you want the files to be readable
37    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
41         #!/bin/csh -fb
42    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
45         umask 077 # or 022 if you want the files to be readable
46 */
47
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <string.h>
54
55 /* CONFIGURATION SECTION */
56
57 #ifndef FULL_PATH       /* so that this can be specified from the Makefile */
58 /* Uncomment the following line:
59 #define FULL_PATH       "/full/path/of/script" 
60 * Then comment out the #error line. */
61 #error "You must define FULL_PATH somewhere"
62 #endif
63 #ifndef UMASK
64 #define UMASK           077
65 #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 */
74 char 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
78 char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin";
79 #else
80 char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin";
81 #endif
82 /* don't change def_CDPATH */
83 char def_CDPATH[] = "CDPATH=.";
84 /* don't change def_ENV */
85 char 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 */
101 void
102 clean_environ(void)
103 {
104         char **p;
105         extern char **environ;
106
107         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);
122 }
123
124 int
125 main(int argc, char **argv)
126 {
127         struct stat statb;
128         gid_t egid = getegid();
129         uid_t euid = geteuid();
130
131         /*
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         }
144
145         /*
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 writeable by anyone.\n");
159                 exit(1);
160         }
161
162         if (setregid(egid, egid) < 0)
163                 perror("setregid");
164         if (setreuid(euid, euid) < 0)
165                 perror("setreuid");
166
167         clean_environ();
168
169         umask(UMASK);
170
171         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);
176 }