"Fossies" - the Fresh Open Source Software Archive 
Member "cgiwrap-4.1/util.c" (16 Jun 2008, 35317 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: util.c
22 ** Purpose: Various utility routines used by cgiwrap
23 **/
24
25 #include "cgiwrap.h" /* Headers for all CGIwrap source files */
26 RCSID("$Id: util.c 306 2008-06-13 14:02:02Z nneul $");
27
28 /*
29 * Encode string to protect against cross-site scripting, but only
30 * encode if we are outputting in HTML. Otherwise send as is so that
31 * error message shows up as transmitted.
32 *
33 * Strings is returned in malloced space, but should be treated as if
34 * it was allocated staticly.
35 */
36 char *HTMLEncode(char *what)
37 {
38 static char *res = NULL;
39 static int len = 0;
40 int i,j;
41
42 /* passed a null string, so return same */
43 if ( !what )
44 {
45 return NULL;
46 }
47
48 /* if we are in plaintext mode, just return string as is */
49 if ( ! MSG_HTMLMessages )
50 {
51 return what;
52 }
53
54 /* deallocate previous mem if not sufficient for current string */
55 /* largest encoding is & so *5 should be sufficient. */
56 if ( res && ((strlen(what)*5+1) > len) )
57 {
58 free(res);
59 res = NULL;
60 len = 0;
61 }
62
63 /* allocate mem */
64 if ( ! res )
65 {
66 /* default to HUGE_STRING_LEN to eliminate excess mallocing */
67 len = (strlen(what)*5+1);
68 if ( len < HUGE_STRING_LEN )
69 {
70 len = HUGE_STRING_LEN;
71 }
72 res = SafeMalloc(len, "SafeEncode");
73 }
74
75 /* copy string to result, encoding as we go */
76 j = 0;
77 for ( i = 0; i<=strlen(what); i++ )
78 {
79 if ( what[i] == '<' )
80 {
81 res[j++] = '&';
82 res[j++] = 'l';
83 res[j++] = 't';
84 res[j++] = ';';
85 }
86 else if ( what[i] == '>' )
87 {
88 res[j++] = '&';
89 res[j++] = 'g';
90 res[j++] = 't';
91 res[j++] = ';';
92 }
93 else if ( what[i] == '&' )
94 {
95 res[j++] = '&';
96 res[j++] = 'a';
97 res[j++] = 'm';
98 res[j++] = 'p';
99 res[j++] = ';';
100 }
101 else
102 {
103 res[j++] = what[i];
104 }
105 }
106 res[j] = '\0';
107
108 return res;
109 }
110
111 /*
112 * Safe malloc
113 */
114 char *SafeMalloc(size_t size, char *what)
115 {
116 char *tmp;
117
118 tmp = (char *) malloc( size );
119 if ( !tmp )
120 {
121 char msg[500];
122 sprintf(msg, "Couldn't malloc() (%d) bytes for (%s).\n",
123 size, what);
124 MSG_Error_SystemError(msg);
125 }
126 return tmp;
127 }
128
129 /*
130 * Safe putenv
131 */
132 void SafePutenv(char * string, char *what)
133 {
134 if (putenv(string) != 0)
135 {
136 char msg[500];
137 sprintf(msg, "Malloc failure caused putenv() failure for (%s).\n", what);
138 MSG_Error_SystemError(msg);
139 }
140 }
141
142 /*
143 * Build the ARGV array for passing to the called script
144 */
145 char **CreateARGV( char *scrStr, int argc, char *argv[])
146 {
147 char **temp;
148 int i;
149
150 temp = (char **) SafeMalloc( (argc+1) * sizeof(char *), "ARGV array");
151
152 temp[0] = StripPathComponents( CountSubDirs(scrStr) - 1, scrStr );
153 temp[argc] = 0;
154
155 for (i=1; i<argc; i++)
156 {
157 temp[i] = argv[i];
158 }
159
160 return temp;
161 }
162
163
164 /*
165 * Build the ARGV array for passing to the called script via interpreter
166 */
167 char **CreateInterpreterARGV( char *interp, char *scrStr, int argc, char *argv[])
168 {
169 char **temp;
170 int i, cnt;
171
172 temp = (char **) SafeMalloc( (argc+2) * sizeof(char *), "ARGV array");
173
174 temp[0] = interp;
175
176 cnt = CountSubDirs(scrStr);
177 if ( cnt < 1 )
178 {
179 temp[1] = scrStr;
180 }
181 else
182 {
183 char *newpath = StripPathComponents( cnt, scrStr );
184 if ( newpath[0] == '/' )
185 {
186 temp[1] = newpath + 1;
187 }
188 else
189 {
190 temp[1] = newpath;
191 }
192 }
193 temp[argc+1] = 0;
194
195 for (i=1; i<argc; i++)
196 {
197 temp[i+1] = argv[i];
198 }
199
200 return temp;
201 }
202
203
204 /*
205 * Extract and return the value portion of a key=value pair found in a string
206 */
207 char *GetValue( char *keyword, char *string )
208 {
209 char *returnStr;
210 char *dataStr;
211 char *tempStr;
212 char *theString;
213
214 theString = strdup(string);
215
216 returnStr = (char *) 0;
217 tempStr = (char *) strtok(theString, "&");
218 while (tempStr)
219 {
220 dataStr = (char *) strstr(tempStr, keyword);
221 if ( dataStr == tempStr )
222 {
223 returnStr = (char *) strchr (dataStr, '=');
224 if ( returnStr) returnStr++;
225 tempStr = (char *) 0;
226 }
227 else
228 {
229 tempStr = (char *) strtok( (char *) 0, "&");
230 }
231 }
232
233 if ( returnStr )
234 {
235 returnStr = strdup(returnStr);
236 }
237 free(theString);
238 return returnStr;
239 }
240
241 /*
242 * Check if a script name ends with a particular string (i.e. .php)
243 */
244 int StringEndsWith(char *string, char *ending)
245 {
246 int len = strlen(string);
247 int elen = strlen(ending);
248
249 if ( len >= elen && !strncmp(string + len - elen, ending, elen) )
250 {
251 return 1;
252 }
253 else
254 {
255 return 0;
256 }
257 }
258
259 /*
260 * Check if a path is safe to use
261 * Return true if 'path' contains any whitespace or non-printables
262 * Return true if 'path' contains '../'
263 */
264 int CheckPath(char *path)
265 {
266 int i,c;
267
268 #if defined(CONF_STRICT_NAMES)
269 for (i=0; i< strlen(path); i++)
270 {
271 c = path[i];
272 if ( !isprint(c) || isspace(c) )
273 {
274 return 1;
275 }
276 }
277 #endif
278
279 return ( strstr(path, "../") != NULL );
280 }
281
282 /*
283 * Condense slashes, removing duplicates and trailers
284 */
285 char *CondenseSlashes(char *path)
286 {
287 char *tmp;
288 int i,j;
289
290 tmp = (char *) SafeMalloc( strlen(path)+1, "CondenseSlashes");
291
292 for (i=0, j=0; i<strlen(path); i++)
293 {
294 if ( !((path[i] == '/') &&
295 ((path[i+1] == '/') || (path[i+1] == '\0')) ))
296 {
297 tmp[j++] = path[i];
298 }
299 }
300 tmp[j] = 0;
301
302 return tmp;
303 }
304
305 /*
306 * Count the number of /'s in a string
307 */
308 int CountSubDirs(char *path)
309 {
310 int i, count;
311 count = 0;
312
313 for (i=0; i<strlen(path); i++)
314 {
315 if ( path[i] == '/' )
316 {
317 count++;
318 }
319 }
320 return count;
321 }
322
323
324
325
326
327 /*
328 * Output the contents of several important environment variables
329 */
330 void OutputEnvironment(void)
331 {
332 DEBUG_Msg("");
333 DEBUG_Msg("Environment Variables:");
334 DEBUG_Str(" QUERY_STRING:", (char *) getenv("QUERY_STRING") );
335 DEBUG_Str(" SCRIPT_NAME:", (char *) getenv("SCRIPT_NAME") );
336 DEBUG_Str(" SCRIPT_FILENAME:", (char *) getenv("SCRIPT_FILENAME") );
337 DEBUG_Str(" REDIRECT_URL:", (char *) getenv("REDIRECT_URL") );
338 DEBUG_Str(" PATH_INFO:", (char *) getenv("PATH_INFO") );
339 DEBUG_Str(" PATH_TRANSLATED:", (char *) getenv("PATH_TRANSLATED") );
340 DEBUG_Str(" REMOTE_USER:", (char *) getenv("REMOTE_USER") );
341 DEBUG_Str(" REMOTE_HOST:", (char *) getenv("REMOTE_HOST") );
342 DEBUG_Str(" REMOTE_ADDR:", (char *) getenv("REMOTE_ADDR") );
343 }
344
345 /*
346 * Save a copy of the old environment variables
347 */
348 void SaveEnvironment(void)
349 {
350 char *c;
351
352 c = getenv("PATH_INFO");
353 if ( c )
354 {
355 Context.origPathInfo = strdup(c);
356 }
357 }
358
359 /*
360 * Change to the users cgi-bin directory, this serves to provide
361 * a consistent strting point for paths.
362 */
363 void ChangeToCGIDir(char *scriptPath)
364 {
365 char *tempdir;
366 char *tempstring;
367 int i;
368
369 i = CountSubDirs(scriptPath) - 1;
370 tempdir = GetPathComponents(i, scriptPath);
371
372 tempstring = (char *) SafeMalloc (strlen(tempdir) + 5,
373 "cgi directory path");
374 tempstring[0] = '/';
375 tempstring[1] = 0;
376 strcat(tempstring, tempdir);
377
378 DEBUG_Str("\nChanging current directory to", tempstring);
379 if (chdir(tempstring) == -1)
380 {
381 MSG_Error_SystemError("Cannot change to user's CGI directory via chdir()!");
382 }
383
384 free(tempdir);
385 free(tempstring);
386 }
387
388 /*
389 * Perform checks on the userid (global checks)
390 */
391 void CheckUser(struct passwd *user)
392 {
393 #if defined(CONF_CHECKHOST)
394 DEBUG_Msg("Checking remote host information.");
395 if ( ( !getenv("REMOTE_ADDR") ) || (getenv("REMOTE_ADDR")[0] == '\0') )
396 {
397 Log(user->pw_name, "-", "no remote host");
398 MSG_Error_General("Cannot determine if your host is allowed to run this script.");
399 }
400 #endif
401
402
403 #if defined(CONF_MINIMUM_UID)
404 DEBUG_Msg("Checking user minimum uid.");
405 if ( user->pw_uid < CONF_MINIMUM_UID )
406 {
407 Log(user->pw_name, "-", "uid less than minimum");
408 MSG_Error_AccessControl("UID of script userid less than configured minimum.",
409 NULL, NULL);
410 }
411 #endif
412
413 #if defined(CONF_MINIMUM_GID)
414 DEBUG_Msg("Checking user minimum gid.");
415 if ( user->pw_gid < CONF_MINIMUM_GID )
416 {
417 Log(user->pw_name, "-", "gid less than minimum");
418 MSG_Error_AccessControl("GID of script userid less than configured minimum.",
419 NULL, NULL);
420 }
421 #endif
422
423 #if defined(CONF_CHECKSHELL)
424 {
425 char *sh, *getusershell();
426 int found = 0;
427
428 DEBUG_Msg("Checking user shell.");
429 while ( (sh = getusershell()) )
430 {
431 if (0 == strcmp( sh, user->pw_shell ))
432 {
433 found = 1;
434 break;
435 }
436 }
437 if (found == 0)
438 {
439 Log(user->pw_name, "-", "restricted login shell");
440 MSG_Error_AccessControl("Restricted login shell, permission denied.",
441 NULL, NULL);
442 }
443 }
444 #endif
445
446 #if defined(CONF_REQUIRE_REDIRECT_URL)
447 DEBUG_Msg("Checking for required REDIRECT_URL.");
448 if ( ( !getenv("REDIRECT_URL") ) || (getenv("REDIRECT_URL")[0] == '\0') )
449 {
450 Log(user->pw_name, "-", "no redirect url");
451 MSG_Error_AccessControl("REDIRECT_URL not in environment, cgiwrap not invoked via Action/Handler.",
452 NULL, NULL);
453 }
454 #endif
455
456 #if defined(CONF_ENV_REQUIRE_USER)
457 DEBUG_Msg("Checking for CGIWRAP_REQUIRE_USER in environment.");
458 if ( getenv("CGIWRAP_REQUIRE_USER") )
459 {
460 if ( strcmp(getenv("CGIWRAP_REQUIRE_USER"), user->pw_name) )
461 {
462 Log(user->pw_name, "-", "CGIWRAP_REQUIRE_USER mismatch");
463 MSG_Error_AccessControl("User does not match CGIWRAP_REQUIRE_USER in environment.",
464 NULL, NULL);
465 }
466 }
467 #endif
468
469 }
470
471
472 /*
473 * Perform checks on the userid (global checks)
474 */
475 void CheckUserAccess(struct passwd *user)
476 {
477 #if defined(CONF_DENYFILE) || defined(CONF_ALLOWFILE)
478 char *denyfile = NULL;
479 char *allowfile = NULL;
480
481 #if defined(CONF_DENYFILE)
482 denyfile = CONF_DENYFILE;
483 DEBUG_Str("Global Deny File: ", denyfile);
484 #endif
485 #if defined(CONF_ALLOWFILE)
486 allowfile = CONF_ALLOWFILE;
487 DEBUG_Str("Global Allow File: ", allowfile);
488 #endif
489
490 CheckAccess_Helper(user, allowfile, denyfile);
491 #endif
492 }
493
494 /*
495 * Build paths of the vhost access control files, and check to
496 * see if they allow this access. If not found, fail.
497 */
498 void CheckVHostUserAccess(struct passwd *user)
499 {
500 #if defined(CONF_VHOST_ALLOWDIR) || defined(CONF_VHOST_DENYDIR)
501 char *denyfile = NULL;
502 char *allowfile = NULL;
503 char *http_host = getenv("HTTP_HOST");
504 char *lower_http_host = NULL;
505 int i;
506
507 #ifdef CONF_VHOST_OVERRIDE
508 char *cgiwrap_auth_vhost = getenv("CGIWRAP_AUTH_VHOST");
509
510 if ( cgiwrap_auth_vhost && cgiwrap_auth_vhost[0])
511 {
512 DEBUG_Str("Overriding Access Control Virtual Host: ", HTMLEncode(cgiwrap_auth_vhost));
513 http_host = cgiwrap_auth_vhost;
514 }
515 #endif
516
517 /* Get the vhost we are running on */
518 if ( ! http_host || ! http_host[0] )
519 {
520 MSG_Error_AccessControl(
521 "Cannot determine virtual host for access control.", NULL, NULL);
522 }
523
524 /* Force to all lowercase */
525 DEBUG_Msg("Determining virtual host for access control.");
526 lower_http_host = (char *) SafeMalloc(strlen(http_host) + 1,
527 "lower_http_host");
528 for (i=0; i<=strlen(http_host); i++)
529 {
530 lower_http_host[i] = tolower(http_host[i]);
531 }
532
533 DEBUG_Msg("\n");
534 DEBUG_Str("Access Control Virtual Host: ", lower_http_host);
535
536 /* Now build the two filenames */
537 #if defined(CONF_VHOST_ALLOWDIR)
538 allowfile = (char *) SafeMalloc(strlen(CONF_VHOST_ALLOWDIR) + 1 +
539 strlen(lower_http_host) + 1, "vhost allowfile");
540 strcpy(allowfile, CONF_VHOST_ALLOWDIR);
541 strcat(allowfile, "/");
542 strcat(allowfile, lower_http_host);
543
544 DEBUG_Str(" VHost Allow File: ", allowfile);
545 #endif
546
547 #if defined(CONF_VHOST_DENYDIR)
548 denyfile = (char *) SafeMalloc(strlen(CONF_VHOST_DENYDIR) + 1 +
549 strlen(lower_http_host) + 1, "vhost denyfile");
550 strcpy(denyfile, CONF_VHOST_DENYDIR);
551 strcat(denyfile, "/");
552 strcat(denyfile, lower_http_host);
553
554 DEBUG_Str(" VHost Deny File: ", denyfile);
555 #endif
556
557 CheckAccess_Helper(user, allowfile, denyfile);
558
559 /* Clean up */
560 if ( denyfile ) free(denyfile);
561 if ( allowfile ) free(allowfile);
562 free(lower_http_host);
563 #endif
564 }
565
566 void CheckAccess_Helper(struct passwd *user, char *allowfile, char *denyfile)
567 {
568 int deny_exists=0, allow_exists=0;
569 int in_deny=0, in_allow=0;
570
571 /* If neither specified, we're not configured for it */
572 if ( !allowfile && !denyfile )
573 {
574 return;
575 }
576
577 DEBUG_Msg("\nChecking Access Files:");
578
579 if ( denyfile )
580 {
581 deny_exists = FileExists(denyfile);
582 if ( deny_exists )
583 {
584 DEBUG_Str(" Deny file exists: ", denyfile);
585 }
586 }
587 if ( allowfile )
588 {
589 allow_exists = FileExists(allowfile);
590 if ( allow_exists )
591 {
592 DEBUG_Str(" Allow file exists: ", allowfile);
593 }
594 }
595
596 if ( !deny_exists && !allow_exists )
597 {
598 Log(user->pw_name, "-", "access control files not found");
599 MSG_Error_AccessControl("Access control files not found!",
600 allowfile, denyfile);
601 }
602
603 if ( deny_exists )
604 {
605 DEBUG_Str(" Checking deny file for",user->pw_name);
606 in_deny = UserInFile(denyfile, user->pw_name);
607 }
608 if ( allow_exists )
609 {
610 DEBUG_Str(" Checking allow file for",user->pw_name);
611 in_allow = UserInFile(allowfile, user->pw_name);
612 }
613
614 if ( (in_allow && in_deny) ||
615 ( allow_exists && !in_allow ) ||
616 ( deny_exists && in_deny ) )
617 {
618 Log(user->pw_name, "-", "user/host not permitted");
619 MSG_Error_AccessControl(
620 "Script userid and/or remote host not permitted!",
621 NULL, NULL);
622 }
623 }
624
625
626 /*
627 * Perform file checks on the script file
628 */
629 void CheckScriptFile(void)
630 {
631 struct stat fileStat; /* For checking file status */
632 struct stat fileLStat; /* For checking symlink status */
633
634 if ( CheckPath(Context.scriptFullPath) )
635 {
636 MSG_Error_ExecutionNotPermitted(Context.scriptFullPath,
637 "Script path contains illegal components");
638 }
639
640 #if !defined(CONF_SUBDIRS)
641 /* Check if script is in a subdirectory */
642 if ( CountSubDirs(Context.scriptRelativePath) > 0 )
643 {
644 Log(Context.user.pw_name, Context.scriptFullPath,
645 "script in subdir not allowed");
646 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
647 "Scripts in subdirectories are not allowed");
648 }
649 #endif
650
651 if ( stat(Context.scriptFullPath, &fileStat) )
652 {
653 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
654 "Script file not found.");
655 }
656
657 if ( lstat(Context.scriptFullPath, &fileLStat) )
658 {
659 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
660 "Script file not found.");
661 }
662
663 #if defined(CONF_CHECK_SYMLINK)
664 if ( S_ISLNK(fileLStat.st_mode) )
665 {
666 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
667 "Script is a symbolic link");
668 }
669 #endif
670
671 if ( !S_ISREG(fileStat.st_mode) )
672 {
673 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
674 "Script is not a regular file");
675 }
676
677 if (fileStat.st_mode & S_IXUSR)
678 {
679 Context.script_is_executable = 1; /* record this in case we might use interpreter later */
680 }
681 else if ( !Context.interpreted_script ) /* if we're passing to interpreter, isn't an error to be non-executable */
682 {
683 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
684 "Script is not executable. Issue 'chmod 755 filename'");
685 }
686
687
688 #if defined(CONF_CHECK_SCRUID)
689 if (!S_ISLNK(fileLStat.st_mode))
690 {
691 if (!Context.multiuser_cgi_script && fileStat.st_uid != Context.user.pw_uid)
692 {
693 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
694 "Script does not have same UID");
695 }
696 }
697 else
698 {
699 if (!Context.multiuser_cgi_script && fileLStat.st_uid != Context.user.pw_uid)
700 {
701 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
702 "Symlink to script does not have same UID");
703 }
704 }
705 #endif
706
707
708 #if defined(CONF_CHECK_SCRGID)
709 if (!Context.multiuser_cgi_script && fileStat.st_gid != Context.user.pw_gid)
710 {
711 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
712 "Script does not have same GID");
713 }
714 #endif
715
716
717 #if defined(CONF_CHECK_SCRSUID)
718 if (fileStat.st_mode & S_ISUID)
719 {
720 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
721 "Script is setuid");
722 }
723 #endif
724
725
726 #if defined(CONF_CHECK_SCRSGID)
727 if (fileStat.st_mode & S_ISGID)
728 {
729 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
730 "Script is setgid");
731 }
732 #endif
733
734 #if defined(CONF_CHECK_SCRGWRITE)
735 if (fileStat.st_mode & S_IWGRP)
736 {
737 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
738 "Script is group writable.");
739 }
740 #endif
741
742 #if defined(CONF_CHECK_SCROWRITE)
743 if (fileStat.st_mode & S_IWOTH)
744 {
745 MSG_Error_ExecutionNotPermitted(Context.scriptRelativePath,
746 "Script is world writable.");
747 }
748 #endif
749 }
750
751
752 /*
753 * Verify the CGIwrap is being executed by the server userid
754 * and that it is running as effective uid root.
755 */
756 void VerifyExecutingUser(void)
757 {
758 #if defined(CONF_CHECK_HTTPD_USER)
759 struct passwd *user;
760
761 if ( !(user = getpwnam(CONF_HTTPD_USER)) )
762 {
763 MSG_Error_ServerUserNotFound();
764 }
765
766 if ( getuid() != user->pw_uid )
767 {
768 MSG_Error_ServerUserMismatch();
769 }
770 #endif
771
772 if ( geteuid() != 0 )
773 {
774 MSG_Error_CGIWrapNotSetUID();
775 }
776 }
777
778 /*
779 * Construct string containing full path to script
780 */
781 char *BuildScriptPath(char *basedir, char *scrStr)
782 {
783 char *tmp;
784 tmp = (char *) SafeMalloc ( strlen(basedir) + strlen(scrStr) + 5,
785 "scriptPath");
786
787 sprintf(tmp, "%s/%s", basedir, scrStr);
788 return tmp;
789 }
790
791
792 /*
793 * Extract the first 'count' components of 'path'
794 */
795 char *GetPathComponents(int count, char *path)
796 {
797 char *tmp;
798 int i, j, found;
799 int done;
800 int len;
801
802 tmp = strdup(path);
803 len = strlen(tmp);
804
805 /* First skip over any leading /'s */
806 i = 0;
807 done = 0;
808 while ( i<len && !done )
809 {
810 if ( path[i] == '/' )
811 {
812 i++;
813 }
814 else
815 {
816 done = 1;
817 }
818 }
819
820
821 /* Now, only copy a certain number of components */
822 j = 0;
823 found = 0;
824 while ( i<len && found < count)
825 {
826 if ( path[i] == '/' )
827 {
828 found++;
829 }
830 if ( found < count )
831 {
832 tmp[j] = path[i];
833 j++;
834 }
835 i++;
836 }
837 tmp[j] = 0;
838
839 return tmp;
840 }
841
842
843
844 /*
845 * Extract all but the first 'count' components of 'path'
846 */
847 char *StripPathComponents(int count, char *path)
848 {
849 char *tmp;
850 int i, found;
851 int done;
852 int len;
853
854 len = strlen(path);
855
856 /* First skip over any leading /'s */
857 i = 0;
858 done = 0;
859 while ( i<len && !done )
860 {
861 if ( path[i] == '/' )
862 {
863 i++;
864 }
865 else
866 {
867 done = 1;
868 }
869 }
870
871
872 /* Now, skip over a certain number of components */
873 found = 0;
874 while ( i<len && found < count)
875 {
876 if ( path[i] == '/' )
877 {
878 found++;
879 }
880 if ( found < count )
881 {
882 i++;
883 }
884 }
885 tmp = strdup(path + i);
886
887 return tmp;
888 }
889
890
891 /*
892 * Set Environment Variables
893 */
894 void SetEnvironmentVariables(void)
895 {
896 #if defined(CONF_SETENV_ANY)
897 int i;
898 char msg[500];
899
900 struct cgiwrap_setenv_table
901 {
902 char *variable;
903 char *value;
904 char *setstring;
905 } cgiwrap_setenvs[] = {
906 #if defined(CONF_SETENV_PATH)
907 {"PATH", CONF_SETENV_PATH, "PATH=" CONF_SETENV_PATH},
908 #endif
909 #if defined(CONF_SETENV_TZ)
910 {"TZ", CONF_SETENV_TZ, "TZ=" CONF_SETENV_TZ},
911 #endif
912 #if defined(CONF_SETENV_LD_LIBRARY_PATH)
913 {"LD_LIBRARY_PATH", CONF_SETENV_LD_LIBRARY_PATH,
914 "LD_LIBRARY_PATH=" CONF_SETENV_LD_LIBRARY_PATH},
915 #endif
916 {0,0,0}
917 };
918
919 for (i=0; cgiwrap_setenvs[i].variable; i++)
920 {
921 sprintf(msg, "Setting Environment Variable(%s) to (%s)\n",
922 cgiwrap_setenvs[i].variable,
923 cgiwrap_setenvs[i].value);
924 DEBUG_Msg(msg);
925
926 #if defined(HAS_PUTENV)
927 SafePutenv(cgiwrap_setenvs[i].setstring,
928 "set environment variable");
929 #endif
930 }
931 #endif
932 }
933
934
935 /*
936 * Set Resource Limits
937 */
938 void SetResourceLimits(void)
939 {
940 #if defined(CONF_USE_RLIMIT_ANY)
941 struct rlimit limstruct;
942 int i;
943 char msg[200];
944
945 struct cgiwrap_rlimit_table
946 {
947 int which;
948 char *label;
949 long value;
950 } cgiwrap_rlimits[] = {
951 #if defined(CONF_USE_RLIMIT_CPU) && defined(RLIMIT_CPU)
952 {RLIMIT_CPU, "cpu time", CONF_USE_RLIMIT_CPU},
953 #endif
954 #if defined(CONF_USE_RLIMIT_VMEM) && defined(RLIMIT_VMEM)
955 {RLIMIT_VMEM, "virtual memory", CONF_USE_RLIMIT_VMEM},
956 #endif
957 #if defined(CONF_USE_RLIMIT_FSIZE) && defined(RLIMIT_FSIZE)
958 {RLIMIT_FSIZE, "writable file size", CONF_USE_RLIMIT_FSIZE},
959 #endif
960 #if defined(CONF_USE_RLIMIT_DATA) && defined(RLIMIT_DATA)
961 {RLIMIT_DATA, "data size", CONF_USE_RLIMIT_DATA},
962 #endif
963 #if defined(CONF_USE_RLIMIT_STACK) && defined(RLIMIT_STACK)
964 {RLIMIT_STACK, "stack size", CONF_USE_RLIMIT_STACK},
965 #endif
966 #if defined(CONF_USE_RLIMIT_AS) && defined(RLIMIT_AS)
967 {RLIMIT_AS, "total available memory", CONF_USE_RLIMIT_AS},
968 #endif
969 #if defined(CONF_USE_RLIMIT_CORE) && defined(RLIMIT_CORE)
970 {RLIMIT_CORE, "core file size", CONF_USE_RLIMIT_CORE},
971 #endif
972 #if defined(CONF_USE_RLIMIT_RSS) && defined(RLIMIT_RSS)
973 {RLIMIT_RSS, "resident set size", CONF_USE_RLIMIT_RSS},
974 #endif
975 #if defined(CONF_USE_RLIMIT_NPROC) && defined(RLIMIT_NPROC)
976 {RLIMIT_NPROC, "number of processes", CONF_USE_RLIMIT_NPROC},
977 #endif
978 #if defined(CONF_USE_RLIMIT_NOFILE) && defined(RLIMIT_NOFILE)
979 {RLIMIT_NOFILE, "number of open files", CONF_USE_RLIMIT_NOFILE},
980 #endif
981 #if defined(CONF_USE_RLIMIT_MEMLOCK) && defined(RLIMIT_MEMLOCK)
982 {RLIMIT_MEMLOCK, "lockable memory", CONF_USE_RLIMIT_MEMLOCK},
983 #endif
984 {0,0,0}
985 };
986
987 for (i=0; cgiwrap_rlimits[i].label; i++)
988 {
989 limstruct.rlim_cur = cgiwrap_rlimits[i].value;
990
991 #if defined(CONF_SOFT_RLIMIT_ONLY)
992 limstruct.rlim_max = RLIM_INFINITY;
993 #else
994 limstruct.rlim_max = cgiwrap_rlimits[i].value;
995 #endif
996
997 sprintf(msg, "Limiting (%s) to (%ld)\n",
998 cgiwrap_rlimits[i].label,
999 cgiwrap_rlimits[i].value);
1000 DEBUG_Msg(msg);
1001
1002 setrlimit(cgiwrap_rlimits[i].which, &limstruct);
1003 }
1004 #endif
1005 }
1006
1007
1008 /*
1009 * Set default signal behavior
1010 */
1011 void SetSignals(void)
1012 {
1013 #if defined(SIGXCPU) && defined(HAS_SIGSET)
1014 DEBUG_Msg("Setting SIGXCPU to default behaviour\n");
1015 sigset(SIGXCPU, SIG_DFL);
1016 #elif defined(SIGXCPU)
1017 struct sigaction default_action;
1018 default_action.sa_handler = SIG_DFL;
1019 default_action.sa_flags = 0;
1020 DEBUG_Msg("Setting SIGXCPU to default behaviour\n");
1021 sigaction(SIGXCPU, &default_action, NULL);
1022 #endif
1023 }
1024
1025
1026 /*
1027 * Change real and effective UID and GID to those of 'user'
1028 */
1029 void ChangeID ( struct passwd *user)
1030 {
1031
1032
1033 #if defined(HAS_SETGID) && defined(HAS_SETUID)
1034 setgid( user->pw_gid );
1035 setuid( user->pw_uid );
1036 #elif defined(HAS_SETRESGID) && defined(HAS_SETRESUID)
1037 setresgid( user->pw_gid, user->pw_gid, user->pw_gid );
1038 setresuid( user->pw_uid, user->pw_uid, user->pw_uid );
1039 #elif defined(HAS_SETREGID) && defined(HAS_SETREUID)
1040 setregid( user->pw_gid, user->pw_gid );
1041 setreuid( user->pw_uid, user->pw_uid );
1042 #elif defined(HAS_SETEGID) && defined(HAS_SETEUID) && defined(HAS_SETRGID) && defined(HAS_SETRUID)
1043 setegid( user->pw_gid );
1044 setrgid( user->pw_gid );
1045 seteuid( user->pw_uid );
1046 setruid( user->pw_uid );
1047 #else
1048 #error "Configuration Error, No Way to Change IDs"
1049 #endif
1050
1051
1052 DEBUG_Msg("\nUIDs/GIDs Changed To:");
1053 DEBUG_Int(" RUID:", getuid());
1054 DEBUG_Int(" EUID:", geteuid());
1055 DEBUG_Int(" RGID:", getgid());
1056 DEBUG_Int(" EGID:", getegid());
1057
1058
1059 /***/
1060 /** Check if ID's were actually changed */
1061 /***/
1062 if ( getuid() != user->pw_uid )
1063 {
1064 MSG_Error_General("Real UID could not be changed!");
1065 }
1066 if ( geteuid() != user->pw_uid )
1067 {
1068 MSG_Error_General("Effective UID could not be changed!");
1069 }
1070 if ( getgid() != user->pw_gid )
1071 {
1072 MSG_Error_General("Real GID could not be changed!");
1073 }
1074 if ( getegid() != user->pw_gid )
1075 {
1076 MSG_Error_General("Effective GID could not be changed!");
1077 }
1078 }
1079
1080 /*
1081 * Set the process's auxilliary groups
1082 */
1083 void ChangeAuxGroups(struct passwd *user)
1084 {
1085 #if defined(CONF_MINIMUM_GID) && defined(HAS_GETGROUPS)
1086 int i,j;
1087 gid_t *groups;
1088 #endif
1089
1090 #if defined(HAS_SETGROUPS) && defined(CONF_SETGROUPS)
1091 gid_t grouplist[1];
1092 grouplist[0] = user->pw_gid;
1093
1094 if ( setgroups(1, grouplist) == -1 )
1095 MSG_Error_SystemError("setgroups() failed!");
1096 #endif
1097
1098 #if defined(HAS_INITGROUPS) && defined(CONF_INITGROUPS)
1099 if ( initgroups( user->pw_name, user->pw_gid ) == -1 )
1100 MSG_Error_SystemError("initgroups() failed!");
1101 #endif
1102
1103 /* verify here that we didn't enable a group less than minimum */
1104 #if defined(CONF_MINIMUM_GID) && defined(HAS_GETGROUPS)
1105 i = getgroups(0, groups);
1106 if ( i > 0 )
1107 {
1108 groups = (gid_t *)SafeMalloc(i * sizeof(gid_t), "Auxilliary Group List");
1109 getgroups(i, groups);
1110
1111 for ( j=0; j<i; j++ )
1112 {
1113 if ( groups[j] < CONF_MINIMUM_GID )
1114 {
1115 Log(user->pw_name, "-", "supplementary gid less than minimum");
1116 MSG_Error_AccessControl(
1117 "Supplementary GID of script userid less than configured minimum.",
1118 NULL, NULL);
1119 }
1120 }
1121 }
1122 #endif
1123 }
1124
1125
1126 /*
1127 * Return true if 'user' is listed in file 'filename'
1128 */
1129 int UserInFile(char *filename, char *user)
1130 {
1131 FILE *file;
1132 char temp[HUGE_STRING_LEN];
1133 #if defined(CONF_CHECKHOST)
1134 int count, remote_addr[4],spec_mask[4],spec_addr[4];
1135 char *i, *tmpuser;
1136 #endif
1137 int j, intail;
1138
1139 #if defined(CONF_CHECKHOST)
1140 if (sscanf(getenv("REMOTE_ADDR"),"%d.%d.%d.%d",
1141 &remote_addr[0],&remote_addr[1],
1142 &remote_addr[2],&remote_addr[3]) != 4 )
1143 {
1144 Log(user, "-", "no remote host");
1145 MSG_Error_General("Your host is not allowed to run this");
1146 }
1147 #endif
1148
1149 if ( (file=fopen(filename,"r")) == NULL )
1150 {
1151 MSG_Error_SystemError("Couldn't open access control file");
1152 }
1153
1154 while ( !feof(file) )
1155 {
1156 temp[0] = 0;
1157 if ( !fgets(temp, HUGE_STRING_LEN, file) )
1158 {
1159 fclose(file);
1160 return 0;
1161 }
1162 intail=1;
1163 for (j=strlen(temp)-1; j>=0; j--)
1164 {
1165 if ( !isprint(temp[j]) )
1166 {
1167 temp[j] = 0;
1168 }
1169 else
1170 {
1171 if (intail)
1172 {
1173 if (isspace(temp[j]))
1174 {
1175 temp[j] = 0;
1176 }
1177 else
1178 {
1179 intail = 0;
1180 }
1181 }
1182 }
1183 }
1184
1185 if ( !strcmp(temp,user) )
1186 {
1187 fclose(file);
1188 DEBUG_Str(" Found",user);
1189 return 1;
1190 }
1191
1192 #if defined(CONF_ALLOWDENY_NETGROUPS) && defined(HAS_INNETGR)
1193 if ( strlen(temp) > 3 && temp[0] == '+' && temp[1] == '@' )
1194 {
1195 if ( innetgr(&temp[2], NULL, user, NULL) )
1196 {
1197 DEBUG_Str(" Found in netgroup ", user);
1198 return 1;
1199 }
1200 }
1201 #elif defined(CONF_ALLOWDENY_NETGROUPS)
1202 #error netgroup support requested, but innetgr not available
1203 #endif
1204
1205 #if defined(CONF_CHECKHOST)
1206 i = strchr(temp, '@');
1207 tmpuser = strtok(temp, "@");
1208 if ( (i != NULL) && (tmpuser != NULL) &&
1209 ( (!strcmp(tmpuser,user)) || (!strcmp(tmpuser, "*")) ) )
1210 {
1211 while (i != NULL)
1212 {
1213 spec_mask[0]=255;
1214 spec_mask[1]=255;
1215 spec_mask[2]=255;
1216 spec_mask[3]=255;
1217 i++;
1218 count = sscanf(i,"%d.%d.%d.%d/%d.%d.%d.%d",
1219 &spec_addr[0], &spec_addr[1],
1220 &spec_addr[2], &spec_addr[3],
1221 &spec_mask[0], &spec_mask[1],
1222 &spec_mask[2], &spec_mask[3]);
1223
1224 if (count != 4 && count != 8) {
1225 Log(user, "-", "incorrectly formatted allow/deny line");
1226 MSG_Error_General("Invalid line in access control file");
1227 }
1228
1229 if (((spec_mask[0] & spec_addr[0]) == (spec_mask[0] & remote_addr[0])) &&
1230 ((spec_mask[1] & spec_addr[1]) == (spec_mask[1] & remote_addr[1])) &&
1231 ((spec_mask[2] & spec_addr[2]) == (spec_mask[2] & remote_addr[2])) &&
1232 ((spec_mask[3] & spec_addr[3]) == (spec_mask[3] & remote_addr[3])))
1233 {
1234 fclose(file);
1235 return 1;
1236 }
1237 i = strchr(i,',');
1238 }
1239 }
1240 #endif
1241 }
1242 fclose(file);
1243
1244 return 0;
1245 }
1246
1247
1248 /*
1249 * Initialize the logging
1250 */
1251 void LogInit (void)
1252 {
1253 #if defined(CONF_LOG_USEFILE)
1254 FILE *logFile;
1255 int logfd;
1256 #endif
1257
1258 DEBUG_Msg("Initializing Logging");
1259
1260 #if defined(CONF_LOG_USEFILE)
1261 logfd = open(CONF_LOG_LOGFILE, O_WRONLY | O_CREAT | O_APPEND,
1262 S_IRUSR | S_IWUSR);
1263 if ( logfd == -1 )
1264 {
1265 MSG_Error_SystemError("Could not open log file for appending!");
1266 }
1267 /* set the close-on-exec flag for logfd */
1268 if (fcntl(logfd, F_SETFD, 1) == -1)
1269 {
1270 MSG_Error_SystemError("Could not set close-on-exec flag for log file!");
1271 }
1272
1273 /* open a file pointer from that file descriptor */
1274 logFile = fdopen(logfd, "a");
1275 if ( !logFile )
1276 {
1277 MSG_Error_SystemError("Could not open file stream from file descriptor!");
1278 }
1279
1280 Context.logFile = logFile;
1281 #endif
1282 #if defined(CONF_LOG_USESYSLOG) && defined(HAS_SYSLOG)
1283 openlog("cgiwrap", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
1284 #endif
1285 }
1286
1287 /*
1288 * Add an entry to the log file
1289 */
1290 void Log (char *user, char *script, char *msg)
1291 {
1292 time_t timevar;
1293 char *timeString;
1294
1295 time(&timevar);
1296 timeString = ctime(&timevar);
1297
1298 DEBUG_Msg("");
1299
1300 #if defined(CONF_LOG_USEFILE)
1301 DEBUG_Msg("Logging Request (File)");
1302
1303 fprintf(Context.logFile, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
1304 NullCheck( user ),
1305 NullCheck( script ),
1306 NullCheck( getenv("REMOTE_HOST") ),
1307 NullCheck( getenv("REMOTE_ADDR") ),
1308 NullCheck( getenv("REMOTE_USER") ),
1309 NullCheck( msg ),
1310 NullCheck( timeString ) );
1311 fflush(Context.logFile);
1312 #endif
1313 #if defined(CONF_LOG_USESYSLOG) && defined(HAS_SYSLOG)
1314 DEBUG_Msg("Logging Request (syslog)");
1315
1316 syslog(LOG_INFO, "[%s] %s, %s, %s, %s, %s, %s",
1317 NullCheck( CONF_LOG_LABEL ),
1318 NullCheck( user ),
1319 NullCheck( script ),
1320 NullCheck( getenv("REMOTE_HOST") ),
1321 NullCheck( getenv("REMOTE_ADDR") ),
1322 NullCheck( getenv("REMOTE_USER") ),
1323 NullCheck( msg ) );
1324
1325 /* don't want to close log at this point */
1326 /* closelog(); */
1327 #endif
1328 }
1329
1330 /*
1331 * Terminate logging
1332 */
1333 void LogEnd(void)
1334 {
1335 #if defined(CONF_LOG_USEFILE)
1336 if ( Context.logFile )
1337 {
1338 fclose(Context.logFile);
1339 }
1340 #endif
1341 }
1342
1343 /*
1344 * Set the correct SCRIPT_NAME environment variable
1345 */
1346 void SetScriptName(char *userStr, char *scrStr )
1347 {
1348 char *buf;
1349 char *name;
1350
1351 #if defined(CONF_USE_REDIRECT_URL)
1352 char *redurl = getenv("REDIRECT_URL");
1353 int len;
1354
1355 /* Use REDIRECT_URL to build SCRIPT_NAME so we can
1356 * keep the URL the way user specified them.
1357 * For this to work we need to have already set
1358 * the correct PATH_INFO env if needed (this is
1359 * done by FetchScriptString).
1360 * NOTE: REDIRECT_URL is not a CGI standard
1361 * environment variable. --san@cobalt.rmnet.it;
1362 */
1363 if ( redurl )
1364 {
1365 name = getenv("PATH_INFO");
1366 if ( name ) {
1367 /* We need to strip PATH_INFO from REDIRECT_URL */
1368 /* this code doesn't appear to be completely implemented */
1369 len = strlen(redurl);
1370 buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") +
1371 len + 2,
1372 "new SCRIPT_NAME environment variable");
1373 snprintf(buf, strlen("SCRIPT_NAME=")+len+1,
1374 "SCRIPT_NAME=%s", redurl);
1375
1376 }
1377 else {
1378 buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") +
1379 strlen(redurl) + 2,
1380 "new SCRIPT_NAME environment variable");
1381 sprintf(buf, "SCRIPT_NAME=%s", redurl);
1382 }
1383 SafePutenv(buf, "set SCRIPT_NAME environment variable");
1384 return;
1385 }
1386 #endif
1387
1388 #if defined(CONF_USE_SCRIPT_URL)
1389 name = getenv("SCRIPT_URL");
1390 if ( name ) {
1391 buf = (char*) SafeMalloc (strlen("SCRIPT_NAME=") + strlen(name) + 3,
1392 "new SCRIPT_NAME environment variable");
1393
1394 sprintf(buf, "SCRIPT_NAME=%s", name);
1395 SafePutenv(buf,"set SCRIPT_NAME environment variable");
1396 return;
1397 }
1398
1399 #endif
1400
1401 name = getenv("SCRIPT_NAME");
1402 if ( name ) {
1403 /* only set SCRIPT_NAME if it was already set */
1404
1405 buf = (char*) SafeMalloc (strlen("SCRIPT_NAME") +
1406 strlen(name) + strlen(userStr)
1407 + strlen(scrStr) + 5, "new SCRIPT_NAME environment variable");
1408
1409 sprintf(buf, "%s=%s/%s/%s", "SCRIPT_NAME",
1410 name, userStr, scrStr);
1411 SafePutenv(buf, "set SCRIPT_NAME environment variable");
1412 }
1413 }
1414
1415
1416 /*
1417 * Set the correct SCRIPT_FILENAME environment variable (PHP uses this)
1418 */
1419 void SetScriptFilename (char *scriptPath)
1420 {
1421 char *buf;
1422 char *name;
1423
1424 name = getenv ("SCRIPT_FILENAME");
1425 if ( name ) {
1426 /* only set SCRIPT_FILENAME if it was already set */
1427
1428 buf = (char*) SafeMalloc (strlen("SCRIPT_FILENAME") +
1429 + strlen(scriptPath) + 5, "new SCRIPT_FILENAME environment variable");
1430
1431 sprintf(buf, "%s=%s", "SCRIPT_FILENAME", scriptPath);
1432 SafePutenv(buf, "set SCRIPT_NAME environment variable");
1433 }
1434 }
1435
1436
1437
1438 /*
1439 * Set the correct PATH_TRANSLATED environment variable
1440 */
1441 void SetPathTranslated( char *cgiBaseDir, char *scriptPath )
1442 {
1443 char *buf;
1444 char *old_pt, *new_pt;
1445 char *old_pi, *new_pi;
1446 char *docroot;
1447
1448 old_pt = getenv("PATH_TRANSLATED");
1449 if ( ! old_pt )
1450 {
1451 /* don't set one if the server didn't */
1452 return;
1453 }
1454 new_pt = strdup(old_pt);
1455
1456 old_pi = Context.origPathInfo;
1457 new_pi = Context.newPathInfo;
1458 if ( !old_pi || !new_pi )
1459 {
1460 /* can't match against anything */
1461 return;
1462 }
1463
1464 /* check if we find old path_info (with user) in the path_translated string */
1465 buf = strstr(new_pt, old_pi);
1466 if ( buf )
1467 {
1468 /* if so, copy in what we determined pathinfo should be after stripping off user portion */
1469 if ( Context.interpreted_script ) /* for PHP we do not strip script path from PATH_TRANSLATED */
1470 {
1471 strcpy(buf, "/");
1472 strcat(buf, Context.scriptRelativePath);
1473 strcat(buf, new_pi);
1474 } else {
1475 strcpy(buf, new_pi);
1476 }
1477
1478 buf = (char *) SafeMalloc( strlen(new_pt) + strlen("PATH_TRANSLATED") + 5,
1479 "new PATH_TRANSLATED environment variable");
1480 sprintf(buf, "%s=%s", "PATH_TRANSLATED", new_pt);
1481 SafePutenv(buf, "new PATH_TRANSLATED environment variable");
1482
1483 return;
1484 }
1485
1486 /* we might be able to fall back to using docroot if we have it */
1487
1488 docroot = getenv("DOCUMENT_ROOT");
1489 if ( docroot )
1490 {
1491 buf = (char *) SafeMalloc( strlen("PATH_TRANSLATED") + strlen(docroot) +
1492 strlen(new_pi) + 5, "new PATH_TRANSLATED environment variable");
1493 sprintf(buf, "PATH_TRANSLATED=%s%s", docroot, new_pi);
1494 SafePutenv(buf, "new PATH_TRANSLATED environment variable");
1495
1496 return;
1497 }
1498 }
1499
1500
1501
1502 /*
1503 * If using AFS, create a process authentication group for this process
1504 * This protects the server from any authentication changes that the script
1505 * might make. It also prevents the script from inheriting the servers
1506 * authentication if it is running authenticated
1507 */
1508 #if defined(CONF_AFS_SETPAG)
1509 void setpag(void);
1510 #endif
1511 void Create_AFS_PAG(void)
1512 {
1513 #if defined(CONF_AFS_SETPAG)
1514 DEBUG_Msg("");
1515 DEBUG_Msg("Setting AFS Process Authentication Group (PAG)");
1516 setpag();
1517 #endif
1518 }
1519
1520 /*
1521 * Rewrite user dir from configuration file if option is enabled
1522 */
1523 char *GetUserDir(char *user)
1524 {
1525 #if defined(CONF_USERDIRFILE)
1526 FILE *file;
1527 static char temp[500];
1528 int i, j;
1529
1530 DEBUG_Msg("\nProcessing user directory configuration file.");
1531
1532 if ( (file=fopen(CONF_USERDIRFILE,"r")) == NULL )
1533 {
1534 MSG_Error_SystemError("Couldn't open user directory config file");
1535 }
1536
1537 temp[0]=0;
1538 while ( !feof(file) )
1539 {
1540 fgets(temp, 450, file);
1541 i = strlen(user);
1542
1543 if ( !strncmp(user, temp, i) && temp[i] == ':' )
1544 {
1545 for ( j=0; j<strlen(temp); j++)
1546 {
1547 if ( !isprint(temp[j]) )
1548 {
1549 temp[j] = 0;
1550 }
1551 }
1552
1553 fclose(file);
1554 return &temp[i+1];
1555 }
1556 }
1557 fclose(file);
1558 #endif
1559
1560 return NULL;
1561 }
1562
1563
1564 /*
1565 * Determine the base directory for user's scripts
1566 */
1567 char *GetBaseDirectory(struct passwd *user)
1568 {
1569 char *userdir, *basedir;
1570
1571 userdir = GetUserDir(user->pw_name);
1572
1573 if ( userdir )
1574 {
1575 DEBUG_Msg("Using configured base directory.\n");
1576 basedir = (char *) SafeMalloc ( strlen(userdir) + 4,
1577 "script base directory");
1578 strcpy(basedir, userdir);
1579 }
1580 else
1581 {
1582 basedir = (char *) SafeMalloc (strlen(user->pw_dir) +
1583 strlen(CONF_CGIDIR) + 4, "script base directory");
1584 sprintf(basedir, "%s/%s", user->pw_dir, CONF_CGIDIR);
1585 }
1586
1587 return basedir;
1588 }
1589
1590
1591
1592 /*
1593 * Check that a file exists
1594 */
1595 int FileExists(char *path)
1596 {
1597 struct stat fileStat; /* For checking file status */
1598
1599 if ( stat(path, &fileStat) )
1600 {
1601 return 0;
1602 }
1603
1604 if ( !S_ISREG(fileStat.st_mode) )
1605 {
1606 return 0;
1607 }
1608
1609 return 1;
1610 }
1611
1612
1613
1614 /*
1615 * Check that a directory exists
1616 */
1617 int DirExists(char *path)
1618 {
1619 struct stat fileStat; /* For checking file status */
1620
1621 if ( stat(path, &fileStat) )
1622 {
1623 return 0;
1624 }
1625
1626 if ( !S_ISDIR(fileStat.st_mode) )
1627 {
1628 return 0;
1629 }
1630
1631 return 1;
1632 }