"Fossies" - the Fresh Open Source Software Archive 
Member "cgiwrap-4.1/cgiwrap.c" (16 Jun 2008, 9616 Bytes) of package /linux/www/old/cgiwrap-4.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * CGIWrap is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * CGIWrap is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with CGIWrap; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15 *
16 * Copyright 2003-2005, Nathan Neulinger <nneul@neulinger.org>
17 *
18 */
19
20 /**
21 ** File: cgiwrap.c
22 ** Purpose: Main program for cgiwrap
23 **/
24
25 #include "cgiwrap.h" /* Headers for all CGIwrap source files */
26 RCSID("$Id: cgiwrap.c 306 2008-06-13 14:02:02Z nneul $");
27
28 /*
29 * Global context structure
30 */
31 struct cgiwrap_context Context;
32
33 /*
34 * Main program
35 */
36 int main (int argc, char *argv[])
37 {
38 char *userStr; /* User name */
39 char *scrStr; /* Name of script */
40 char *scriptPath; /* Path to script file */
41 char *cgiBaseDir; /* Base directory for cgi scripts in user's dir */
42 struct passwd *user; /* For getting uid from name */
43 char *interPath = NULL; /* Path to interpreter - i.e. php */
44 #ifdef CONF_REPORT_RUSAGE
45 pid_t childpid;
46 struct rusage childrusage;
47 int childstatus;
48 char rusagemsg[1000];
49 time_t stime;
50 time_t etime;
51 time_t elap_time;
52 #endif
53
54 /* Initially not a multiuser cgi script */
55 Context.multiuser_cgi_script = 0;
56 Context.interpreted_script = 0;
57
58 /* Determine if debugging output should be done */
59 if ( strlen(argv[0]) >= 1 )
60 {
61 CONF_DEBUG = !strcmp( argv[0] + strlen(argv[0]) - 1, "d");
62 if (CONF_DEBUG)
63 {
64 MSG_QuietErrors = 0;
65 MSG_HTMLMessages = 0;
66 }
67 }
68
69 /* Output a status header if running in NoParseHeaders mode */
70 if ( !strncmp(argv[0], "nph-", 4) )
71 {
72 MSG_Need_NPH_Header = 1;
73 }
74 #if defined(PATH_PROG_PHP)
75 else if ( !strncmp(argv[0], "php-", 4) )
76 {
77 Context.interpreted_script = 1;
78 interPath = PATH_PROG_PHP;
79 }
80 #endif
81
82 /* Output a Content-type header if in debugging mode */
83 if ( CONF_DEBUG )
84 {
85 MSG_ContentType("text/plain");
86 }
87
88 /* Initialize the log */
89 LogInit();
90
91 /* Redirect stderr to stdout */
92 #if defined(CONF_REDIR_STDERR)
93 DEBUG_Msg("Redirecting STDERR to STDOUT\n");
94 if (dup2(1,2) == -1)
95 {
96 MSG_Error_SystemError("Call to dup2() to redirect stderr to stdout failed!");
97 }
98 #endif
99
100 /* Check who is running this script */
101 VerifyExecutingUser();
102
103 /* Set any default signal behavior */
104 SetSignals();
105
106 /* Set Environment Variables */
107 SetEnvironmentVariables();
108
109 /* Set CPU and other limits */
110 SetResourceLimits();
111
112 /* Output the contents of important environment variables */
113 OutputEnvironment();
114
115 /* Save copies of the original values for use later */
116 SaveEnvironment();
117
118 /* Get the user name from the given data */
119 userStr = FetchUserString();
120 DEBUG_Str("Retrieved User Name: ", userStr);
121
122 /* Now, get whatever information that is available about that */
123 /* user - fetch this information from the passwd file or NIS */
124 if ( !(user = getpwnam(userStr)) )
125 {
126 MSG_Error_NoSuchUser(userStr);
127 }
128 memcpy(&Context.user, user, sizeof(struct passwd));
129
130 DEBUG_Msg("\nUser Data Retrieved:");
131 DEBUG_Str(" UserID:", user->pw_name);
132 DEBUG_Int(" UID:", user->pw_uid);
133 DEBUG_Int(" GID:", user->pw_gid);
134 DEBUG_Str(" Home Dir:", user->pw_dir);
135
136 /* Perform checks to make sure this user is allow to use CGI scripts */
137 CheckUser(user); /* minuid/mingid/shell */
138 CheckUserAccess(user); /* global config files */
139 CheckVHostUserAccess(user); /* vhost config files */
140
141 /* Determine the base directory where this user's CGI scripts
142 are to be stored */
143 DEBUG_Msg("");
144 cgiBaseDir = GetBaseDirectory(user);
145 DEBUG_Str("Script Base Directory: ", cgiBaseDir);
146 #if defined(CONF_MULTIUSER_CGI_DIR)
147 DEBUG_Str("MultiUser Script Base Directory: ", CONF_MULTIUSER_CGI_DIR);
148 if ( !DirExists(cgiBaseDir) &&
149 !DirExists(CONF_MULTIUSER_CGI_DIR) )
150 #else
151 if ( !DirExists(cgiBaseDir) )
152 #endif
153 {
154 MSG_Error_NoScriptDir();
155 }
156
157 /* Get the script name from the given data */
158 DEBUG_Msg("\tFetching script string\n");
159 scrStr = FetchScriptString(cgiBaseDir);
160 DEBUG_Msg("\tBuilding script path\n");
161 #ifdef CONF_MULTIUSER_CGI_DIR
162 if ( Context.multiuser_cgi_script )
163 {
164 scriptPath = BuildScriptPath(CONF_MULTIUSER_CGI_DIR,scrStr);
165 }
166 else
167 #endif
168 {
169 scriptPath = BuildScriptPath(cgiBaseDir,scrStr);
170 }
171
172 DEBUG_Msg("\tCondensing slashes.\n");
173 Context.scriptFullPath = CondenseSlashes(scriptPath);
174 Context.scriptRelativePath = CondenseSlashes(scrStr);
175
176 DEBUG_Str("\tScript Relative Path: ", scrStr);
177 DEBUG_Str("\tScript Absolute Path: ", scriptPath);
178
179 #if defined(CONF_BLOCK_SVN_PATHS)
180 if ( strstr(scriptPath, "/.svn/") )
181 {
182 MSG_Error_ExecutionNotPermitted(scriptPath, "Script is located in .svn directory.");
183 }
184 #endif
185 #if defined(CONF_BLOCK_CVS_PATHS)
186 if ( strstr(scriptPath, "/CVS/") )
187 {
188 MSG_Error_ExecutionNotPermitted(scriptPath, "Script is located in CVS directory.");
189 }
190 #endif
191
192 #if defined(CONF_PHP_INTERPRETER) && defined(PATH_PROG_PHP)
193 DEBUG_Msg("\tChecking for special interpreted script (php).");
194 /* don't double check if already php-cgiwrap */
195 if ( ! interPath )
196 {
197
198 if (
199 StringEndsWith(scriptPath, ".php") ||
200 StringEndsWith(scriptPath, ".php3") ||
201 StringEndsWith(scriptPath, ".php4") ||
202 StringEndsWith(scriptPath, ".phtml") )
203 {
204 Context.interpreted_script = 1;
205 interPath = PATH_PROG_PHP;
206 }
207 }
208 #endif
209 #if defined(CONF_ERUBY_INTERPRETER) && defined(PATH_PROG_ERUBY)
210 DEBUG_Msg("\tChecking for special interpreted script (eRuby).");
211 if ( ! interPath )
212 {
213
214 if ( StringEndsWith(scriptPath, ".rhtml") )
215 {
216 Context.interpreted_script = 1;
217 interPath = PATH_PROG_ERUBY;
218 }
219 }
220 #endif
221 #if defined(CONF_ASP_INTERPRETER) && defined(PATH_PROG_ASP)
222 DEBUG_Msg("\tChecking for special interpreted script (asp).");
223 if ( ! interPath )
224 {
225
226 if ( StringEndsWith(scriptPath, ".asp") )
227 {
228 Context.interpreted_script = 1;
229 interPath = PATH_PROG_ASP;
230 }
231 }
232 #endif
233
234 if ( interPath )
235 {
236 DEBUG_Str("\tInterpreter Path: ", interPath);
237 }
238
239 /* Set the Correct Values of environment variables */
240 DEBUG_Msg("\nFixing Environment Variables.");
241 SetScriptName(userStr, scrStr);
242 SetScriptFilename( scriptPath );
243 #if defined(CONF_MULTIUSER_CGI_DIR)
244 if ( Context.multiuser_cgi_script )
245 {
246 SetPathTranslated( CONF_MULTIUSER_CGI_DIR, scriptPath );
247 }
248 else
249 #endif
250 {
251 SetPathTranslated( cgiBaseDir, scriptPath );
252 }
253
254 /* Output the modified environment variables */
255 OutputEnvironment();
256
257 #if !defined(CONF_REPORT_RUSAGE)
258 /* Log the query request to the log file */
259 Log(userStr, scrStr, "ok");
260 #endif
261
262 /* Once log is initialized, we can chroot */
263 #if defined(CONF_CHROOT_PREFIX)
264 DEBUG_Str("Attempting to chroot: ", CONF_CHROOT_PREFIX);
265 if ( chdir(CONF_CHROOT_PREFIX) == -1 )
266 {
267 MSG_Error_SystemError("Failed to chdir for chrooting!");
268 }
269 if ( chroot(CONF_CHROOT_PREFIX) == -1 )
270 {
271 MSG_Error_SystemError("Failed to chroot!");
272 }
273 #endif
274
275 /* Change auxilliary groups to match this user */
276 ChangeAuxGroups(user);
277
278 /* Change real and effective user and group id's to match this user */
279 ChangeID(user);
280
281 /* Change to the directory the cgi script is in */
282 ChangeToCGIDir(scriptPath);
283
284 /* Check to see if ok to execute script file */
285 CheckScriptFile();
286
287 /* Check to see if we should force handling with #! line */
288 #if defined(CONF_PHP_NONEXEC_ONLY)
289 if ( Context.interpreted_script && Context.script_is_executable )
290 {
291 DEBUG_Msg("\nScript is executable, ignoring interpreter and using #! line.");
292 Context.interpreted_script = 0;
293 }
294 #endif
295
296 /* Perform any AFS related tasks before executing script */
297 Create_AFS_PAG();
298
299 /* Set execPath & execArgv appropriately, depending whether an
300 interpreter is in use. Maybe this could be moved to the PHP & ASP
301 sections, & the interpreted_script conditional & interPath variable
302 removed? */
303 if (interPath && Context.interpreted_script) {
304 Context.execPath = interPath;
305 Context.execArgv = CreateInterpreterARGV(interPath, scrStr, argc, argv);
306 } else {
307 Context.execPath = scriptPath;
308 Context.execArgv = CreateARGV(scrStr, argc, argv);
309 }
310
311 /* If we're debugging, print the executable & argument array before
312 calling execv. */
313 DEBUG_Exec(Context.execPath, Context.execArgv);
314
315 /* Execute the script */
316 DEBUG_Msg("\n\n");
317 DEBUG_Msg("Output of script follows:");
318 DEBUG_Msg("=====================================================");
319
320 #if defined(CONF_REPORT_RUSAGE) && defined(HAS_WAIT3)
321 stime = time(NULL);
322 childpid = fork();
323 if ( childpid < 0 ) /* fork failed */
324 {
325 Log(userStr, scrStr, "fork failed");
326 exit(1);
327 }
328 else if ( childpid == 0 )
329 {
330 execv(Context.execPath, Context.execArgv);
331 MSG_Error_ExecFailed();
332 Log(userStr, scrStr, "failed execv of script");
333 exit(1);
334 }
335 else /* fork ok */
336 {
337 wait3(&childstatus, 0, &childrusage);
338 etime = time(NULL);
339 elap_time = etime-stime;
340 sprintf(rusagemsg,
341 "status=%d wtime='%lds' utime='%ds %dus' stime='%ds %dus'",
342 WEXITSTATUS(childstatus),
343 elap_time,
344 (int) childrusage.ru_utime.tv_sec,
345 (int) childrusage.ru_utime.tv_usec,
346 (int) childrusage.ru_stime.tv_sec,
347 (int) childrusage.ru_stime.tv_usec);
348 Log(userStr, scrStr, rusagemsg);
349 exit(WEXITSTATUS(childstatus));
350 }
351 #else
352 execv(Context.execPath, Context.execArgv);
353 MSG_Error_ExecFailed();
354 exit(1);
355 #endif
356 }