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> | |
a33962ba | 11 | * |
12 | * This is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by | |
9028e234 | 14 | * the Free Software Foundation; either version 3 of the License, or |
a33962ba | 15 | * (at your option) any later version. |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
9028e234 | 23 | * along with userv-utils; if not, see http://www.gnu.org/licenses/. |
a33962ba | 24 | */ |
6a580c17 | 25 | |
26 | #include <stdio.h> | |
27 | #include <string.h> | |
28 | #include <ctype.h> | |
29 | #include <unistd.h> | |
30 | #include <sys/types.h> | |
31 | #include <sys/wait.h> | |
32 | #include <sys/stat.h> | |
33 | ||
34 | #include "ucgi.h" | |
35 | ||
36 | static void *xrealloc(void *ptr, size_t sz) { | |
37 | void *r; | |
38 | ||
39 | r= realloc(ptr,sz); | |
40 | if (!r) syserror("realloc failed"); | |
41 | return r; | |
42 | } | |
43 | ||
44 | int main(int argc, const char **argv) { | |
45 | char *uservarn, *scriptpath, *newvar; | |
46 | const char *nextslash, *lastslash, *pathi, *ev, *ev2, *en, *scriptdir, *av; | |
47 | const char *const *ep; | |
48 | const char **arguments; | |
49 | size_t scriptdirlen, scriptpathlen, l, uservarnl; | |
50 | struct stat stab; | |
51 | int r, nargs; | |
52 | ||
53 | ev= getenv("USERV_U_DEBUG"); | |
54 | if (ev && *ev) debugmode= 1; | |
55 | ||
56 | if (argc > MAX_ARGS) error("too many arguments"); | |
57 | ||
58 | if (!*++argv) error("no script directory argument"); | |
59 | ev= getenv("HOME"); if (!ev) error("no HOME env. var"); | |
60 | l= strlen(*argv)+strlen(ev); | |
61 | newvar= xmalloc(l+2); | |
62 | sprintf(newvar,"%s/%s",ev,*argv); | |
63 | scriptdir= newvar; | |
64 | scriptdirlen= strlen(scriptdir); | |
65 | ||
66 | uservarn= 0; | |
67 | uservarnl= 0; | |
68 | for (ep= envok; (en= *ep); ep++) { | |
69 | l= strlen(en)+11; | |
70 | if (uservarnl<l) { uservarn= xrealloc(uservarn,l); uservarnl= l; } | |
71 | sprintf(uservarn,"USERV_U_E_%s",en); | |
72 | ev= getenv(uservarn); if (!ev) continue; | |
73 | if (strlen(ev) > MAX_ENVVAR_VALUE) error("environment variable too long"); | |
74 | if (setenv(en,ev,1)) syserror("setenv"); | |
75 | unsetenv(uservarn); | |
76 | } | |
77 | ||
78 | scriptpath= 0; | |
79 | pathi= getenv("PATH_INFO"); | |
80 | if (!pathi) error("PATH_INFO not found"); | |
81 | lastslash= pathi; | |
82 | for (;;) { | |
83 | if (*lastslash != '/') error("PATH_INFO expected slash not found"); | |
84 | if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) error("bad char begin"); | |
85 | nextslash= strchr(lastslash+1,'/'); | |
86 | if (!nextslash) nextslash= lastslash+1+strlen(lastslash+1); | |
87 | if (!nextslash) error("insufficient elements in PATH_INFO"); | |
88 | if (nextslash==lastslash+1) error("empty component in PATH_INFO"); | |
89 | if (nextslash-pathi > MAX_SCRIPTPATH_LEN) error("PATH_INFO script path too long"); | |
90 | scriptpathlen= scriptdirlen+(nextslash-pathi); | |
91 | scriptpath= xrealloc(scriptpath,scriptpathlen+1); | |
92 | strcpy(scriptpath,scriptdir); | |
93 | memcpy(scriptpath+scriptdirlen,pathi,nextslash-pathi); | |
94 | scriptpath[scriptpathlen]= 0; | |
95 | if (scriptpath[scriptpathlen-1]=='~') error("bad char end"); | |
96 | r= stat(scriptpath,&stab); if (r) syserror("stat script"); | |
97 | if (S_ISREG(stab.st_mode)) break; | |
98 | if (!S_ISDIR(stab.st_mode)) syserror("script not directory or file"); | |
99 | lastslash= nextslash; | |
100 | } | |
101 | if (*nextslash) xsetenv("PATH_INFO",nextslash,1); | |
102 | else unsetenv("PATH_INFO"); | |
103 | ||
104 | newvar= xmalloc(scriptpathlen+strlen(nextslash)+3); | |
105 | sprintf(newvar,"%s%s",scriptpath,nextslash); | |
106 | xsetenv("PATH_TRANSLATED",newvar,1); | |
107 | ||
108 | xsetenv("SCRIPT_FILENAME",scriptpath,1); | |
109 | ||
110 | ev= getenv("SCRIPT_NAME"); | |
111 | if (ev) { | |
112 | ev2= getenv("USER"); if (!ev2) error("no USER variable"); | |
113 | newvar= xmalloc(strlen(ev)+2+strlen(ev2)+scriptpathlen-scriptdirlen+2); | |
114 | sprintf(newvar,"%s/~%s%s",ev,ev2,scriptpath+scriptdirlen); | |
115 | xsetenv("SCRIPT_NAME",newvar,1); | |
116 | } | |
117 | ||
118 | arguments= xmalloc(sizeof(const char*)*(argc+5)); | |
119 | nargs= 0; | |
120 | ||
121 | arguments[nargs++]= scriptpath; | |
122 | while ((av= (*++argv))) arguments[nargs++]= av; | |
123 | arguments[nargs++]= 0; | |
124 | ||
125 | execvp(scriptpath,(char*const*)arguments); | |
126 | syserror("exec script"); | |
127 | return -1; | |
128 | } |