Commit | Line | Data |
---|---|---|
6a580c17 | 1 | /* |
2 | * Usage: as CGI script, but called by userv | |
3 | * environment variables are USERV_U_E_... | |
4 | */ | |
a33962ba | 5 | /* |
9028e234 IJ |
6 | * Copyright 1996-2013 Ian Jackson <ijackson@chiark.greenend.org.uk> |
7 | * Copyright 1998 David Damerell <damerell@chiark.greenend.org.uk> | |
8 | * Copyright 1999,2003 | |
9 | * Chancellor Masters and Scholars of the University of Cambridge | |
10 | * Copyright 2010 Tony Finch <fanf@dotat.at> | |
93733bee | 11 | * Copyright 2013,2016 Mark Wooding <mdw@distorted.org.uk> |
a33962ba | 12 | * |
13 | * This is free software; you can redistribute it and/or modify it | |
14 | * under the terms of the GNU General Public License as published by | |
9028e234 | 15 | * the Free Software Foundation; either version 3 of the License, or |
a33962ba | 16 | * (at your option) any later version. |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, but | |
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 | * General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
9028e234 | 24 | * along with userv-utils; if not, see http://www.gnu.org/licenses/. |
a33962ba | 25 | */ |
6a580c17 | 26 | |
27 | #include <stdio.h> | |
28 | #include <string.h> | |
29 | #include <ctype.h> | |
f7b4be5a | 30 | #include <getopt.h> |
6a580c17 | 31 | #include <unistd.h> |
32 | #include <sys/types.h> | |
33 | #include <sys/wait.h> | |
34 | #include <sys/stat.h> | |
35 | ||
36 | #include "ucgi.h" | |
37 | ||
f7b4be5a | 38 | static const char *const default_envok[]= { |
a8e8db26 MW |
39 | "AUTH_TYPE", |
40 | "CONTENT_LENGTH", | |
41 | "CONTENT_TYPE", | |
42 | "DOCUMENT_ROOT", | |
43 | "GATEWAY_INTERFACE", | |
44 | "HTTP_ACCEPT", | |
45 | "HTTP_ACCEPT_CHARSET", | |
46 | "HTTP_ACCEPT_ENCODING", | |
47 | "HTTP_ACCEPT_LANGUAGE", | |
48 | "HTTP_CACHE_CONTROL", | |
49 | "HTTP_CONNECTION", | |
50 | "HTTP_CONTENT_ENCODING", | |
51 | "HTTP_COOKIE", | |
52 | "HTTP_DNT", | |
53 | "HTTP_HOST", | |
54 | "HTTP_KEEP_ALIVE", | |
55 | "HTTP_NEGOTIATE", | |
56 | "HTTP_PRAGMA", | |
57 | "HTTP_REFERER", | |
58 | "HTTP_USER_AGENT", | |
59 | "HTTP_VIA", | |
60 | "HTTP_X_FORWARDED_FOR", | |
61 | "HTTPS", | |
62 | "PATH_INFO", | |
63 | "PATH_TRANSLATED", | |
64 | "QUERY_STRING", | |
564fbf9b MW |
65 | "REDIRECT_HANDLER", |
66 | "REDIRECT_SCRIPT_URI", | |
67 | "REDIRECT_SCRIPT_URL", | |
68 | "REDIRECT_STATUS", | |
69 | "REDIRECT_URL", | |
a8e8db26 MW |
70 | "REMOTE_ADDR", |
71 | "REMOTE_HOST", | |
72 | "REMOTE_USER", | |
73 | "REMOTE_IDENT", | |
74 | "REQUEST_METHOD", | |
75 | "REQUEST_URI", | |
76 | "SCRIPT_FILENAME", | |
77 | "SCRIPT_NAME", | |
78 | "SCRIPT_URI", | |
79 | "SCRIPT_URL", | |
80 | "SERVER_ADDR", | |
81 | "SERVER_ADMIN", | |
82 | "SERVER_NAME", | |
83 | "SERVER_PORT", | |
84 | "SERVER_PROTOCOL", | |
85 | "SERVER_SIGNATURE", | |
86 | "SERVER_SOFTWARE", | |
564fbf9b MW |
87 | "SSL_CIPHER", |
88 | "SSL_CLIENT_S_DN", | |
89 | "SSL_CLIENT_VERIFY", | |
90 | "SSL_PROTOCOL", | |
a8e8db26 MW |
91 | 0 |
92 | }; | |
6a580c17 | 93 | |
f601a2c6 MW |
94 | static void setenvar(const char *fulln, |
95 | const char *en, const char *ep, void *p) { | |
96 | xsetenv(en, ep, 1); | |
97 | unsetenv(fulln); | |
6a580c17 | 98 | } |
99 | ||
f7b4be5a | 100 | int main(int argc, char **argv) { |
f601a2c6 MW |
101 | char *scriptpath, *newvar; |
102 | const char *nextslash, *lastslash, *pathi, *ev, *ev2, *scriptdir, *av; | |
f7b4be5a | 103 | const char *const *envok; |
6a580c17 | 104 | const char **arguments; |
f601a2c6 | 105 | size_t scriptdirlen, scriptpathlen, l; |
6a580c17 | 106 | struct stat stab; |
f7b4be5a MW |
107 | int i, r, nargs; |
108 | const char *filters= 0; | |
6a580c17 | 109 | |
110 | ev= getenv("USERV_U_DEBUG"); | |
111 | if (ev && *ev) debugmode= 1; | |
112 | ||
6a3086f1 | 113 | D( if (debugmode) printf(";;; UCGITARGET\n"); ) |
0cd9d59d | 114 | if (argc > MAX_ARGS) error("too many arguments", 500); |
6a580c17 | 115 | |
f7b4be5a MW |
116 | for (;;) { |
117 | i= getopt(argc, argv, "+e:"); if (i < 0) break; | |
118 | switch (i) { | |
119 | case 'e': filters= optarg; break; | |
0cd9d59d | 120 | default: error("bad command line", 500); break; |
f7b4be5a MW |
121 | } |
122 | } | |
123 | argc -= optind; argv += optind; | |
124 | ||
0cd9d59d MW |
125 | if (!*argv) error("no script directory argument", 500); |
126 | ev= getenv("HOME"); if (!ev) error("no HOME env. var", 500); | |
6a580c17 | 127 | l= strlen(*argv)+strlen(ev); |
128 | newvar= xmalloc(l+2); | |
129 | sprintf(newvar,"%s/%s",ev,*argv); | |
130 | scriptdir= newvar; | |
131 | scriptdirlen= strlen(scriptdir); | |
132 | ||
f7b4be5a MW |
133 | if (filters) |
134 | envok= load_filters(LOADF_MUST, filters, LF_END); | |
135 | else { | |
136 | envok= load_filters(0, | |
137 | ".userv/ucgitarget.env-filter", | |
138 | "/etc/userv/ucgitarget.env-filter", | |
139 | LF_END); | |
6a580c17 | 140 | } |
141 | ||
aa0bce91 | 142 | filter_environment(0, "USERV_U_E_", envok, default_envok, setenvar, 0); |
6a580c17 | 143 | |
144 | scriptpath= 0; | |
145 | pathi= getenv("PATH_INFO"); | |
0cd9d59d | 146 | if (!pathi) error("PATH_INFO not found", 500); |
6a580c17 | 147 | lastslash= pathi; |
6a3086f1 MW |
148 | D( if (debugmode) { |
149 | printf(";; find script name...\n" | |
150 | ";; PATH_INFO = `%s'\n", | |
151 | pathi); | |
152 | } ) | |
6a580c17 | 153 | for (;;) { |
0cd9d59d MW |
154 | if (*lastslash != '/') error("PATH_INFO expected slash not found", 400); |
155 | if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) | |
156 | error("bad char begin", 400); | |
6a580c17 | 157 | nextslash= strchr(lastslash+1,'/'); |
158 | if (!nextslash) nextslash= lastslash+1+strlen(lastslash+1); | |
0cd9d59d MW |
159 | if (!nextslash) error("insufficient elements in PATH_INFO", 400); |
160 | if (nextslash==lastslash+1) error("empty component in PATH_INFO", 400); | |
161 | if (nextslash-pathi > MAX_SCRIPTPATH_LEN) | |
162 | error("PATH_INFO script path too long", 400); | |
6a580c17 | 163 | scriptpathlen= scriptdirlen+(nextslash-pathi); |
164 | scriptpath= xrealloc(scriptpath,scriptpathlen+1); | |
165 | strcpy(scriptpath,scriptdir); | |
166 | memcpy(scriptpath+scriptdirlen,pathi,nextslash-pathi); | |
167 | scriptpath[scriptpathlen]= 0; | |
0cd9d59d | 168 | if (scriptpath[scriptpathlen-1]=='~') error("bad char end", 400); |
6a3086f1 | 169 | D( if (debugmode) printf(";; try `%s'\n", scriptpath); ) |
6a580c17 | 170 | r= stat(scriptpath,&stab); if (r) syserror("stat script"); |
171 | if (S_ISREG(stab.st_mode)) break; | |
0cd9d59d | 172 | if (!S_ISDIR(stab.st_mode)) error("script not directory or file", 500); |
6a580c17 | 173 | lastslash= nextslash; |
174 | } | |
6a3086f1 | 175 | D( if (debugmode) printf(";; found script: tail = `%s'\n", nextslash); ) |
6a580c17 | 176 | if (*nextslash) xsetenv("PATH_INFO",nextslash,1); |
177 | else unsetenv("PATH_INFO"); | |
178 | ||
179 | newvar= xmalloc(scriptpathlen+strlen(nextslash)+3); | |
180 | sprintf(newvar,"%s%s",scriptpath,nextslash); | |
181 | xsetenv("PATH_TRANSLATED",newvar,1); | |
182 | ||
183 | xsetenv("SCRIPT_FILENAME",scriptpath,1); | |
184 | ||
185 | ev= getenv("SCRIPT_NAME"); | |
186 | if (ev) { | |
0cd9d59d | 187 | ev2= getenv("USER"); if (!ev2) error("no USER variable", 500); |
6a580c17 | 188 | newvar= xmalloc(strlen(ev)+2+strlen(ev2)+scriptpathlen-scriptdirlen+2); |
189 | sprintf(newvar,"%s/~%s%s",ev,ev2,scriptpath+scriptdirlen); | |
190 | xsetenv("SCRIPT_NAME",newvar,1); | |
191 | } | |
192 | ||
193 | arguments= xmalloc(sizeof(const char*)*(argc+5)); | |
194 | nargs= 0; | |
195 | ||
196 | arguments[nargs++]= scriptpath; | |
197 | while ((av= (*++argv))) arguments[nargs++]= av; | |
198 | arguments[nargs++]= 0; | |
199 | ||
6a3086f1 MW |
200 | D( if (debugmode) { |
201 | int i; | |
202 | ||
203 | printf(";; final environment...\n"); | |
204 | for (i = 0; environ[i]; i++) | |
205 | printf(";; %s\n", environ[i]); | |
206 | ||
207 | printf(";; final command line...\n"); | |
208 | for (i = 0; arguments[i]; i++) | |
209 | printf(";; %s\n", arguments[i]); | |
210 | fflush(stdout); | |
211 | } ) | |
212 | ||
6a580c17 | 213 | execvp(scriptpath,(char*const*)arguments); |
214 | syserror("exec script"); | |
215 | return -1; | |
216 | } |