local.c (10354B)
1 /* $Id$ */ 2 #include "fm.h" 3 #include <string.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <signal.h> 9 #include <errno.h> 10 #ifdef HAVE_READLINK 11 #include <unistd.h> 12 #endif /* HAVE_READLINK */ 13 #ifdef __EMX__ 14 #include <limits.h> /* _MAX_PATH ? */ 15 #endif /* __EMX__ */ 16 #include "local.h" 17 #include "hash.h" 18 19 #ifdef __MINGW32_VERSION 20 #include <winsock.h> 21 #endif 22 23 #define CGIFN_NORMAL 0 24 #define CGIFN_LIBDIR 1 25 #define CGIFN_CGIBIN 2 26 27 static Str Local_cookie = NULL; 28 static char *Local_cookie_file = NULL; 29 30 static void 31 writeLocalCookie() 32 { 33 FILE *f; 34 35 if (no_rc_dir) 36 return; 37 if (Local_cookie_file) 38 return; 39 Local_cookie_file = tmpfname(TMPF_COOKIE, NULL)->ptr; 40 set_environ("LOCAL_COOKIE_FILE", Local_cookie_file); 41 f = fopen(Local_cookie_file, "wb"); 42 if (!f) 43 return; 44 localCookie(); 45 fwrite(Local_cookie->ptr, sizeof(char), Local_cookie->length, f); 46 fclose(f); 47 chmod(Local_cookie_file, S_IRUSR | S_IWUSR); 48 } 49 50 /* setup cookie for local CGI */ 51 Str 52 localCookie() 53 { 54 char hostname[256]; 55 56 if (Local_cookie) 57 return Local_cookie; 58 gethostname(hostname, 256); 59 srand48((long)New(char) + (long)time(NULL)); 60 Local_cookie = Sprintf("%ld@%s", lrand48(), hostname); 61 return Local_cookie; 62 } 63 64 Str 65 loadLocalDir(char *dname) 66 { 67 Str tmp; 68 DIR *d; 69 Directory *dir; 70 struct stat st; 71 char **flist; 72 char *p, *qdir; 73 Str fbuf = Strnew(); 74 #ifdef HAVE_LSTAT 75 struct stat lst; 76 #ifdef HAVE_READLINK 77 char lbuf[1024]; 78 #endif /* HAVE_READLINK */ 79 #endif /* HAVE_LSTAT */ 80 int i, l, nrow = 0, n = 0, maxlen = 0; 81 int nfile, nfile_max = 100; 82 Str dirname; 83 84 d = opendir(dname); 85 if (d == NULL) 86 return NULL; 87 dirname = Strnew_charp(dname); 88 if (Strlastchar(dirname) != '/') 89 Strcat_char(dirname, '/'); 90 qdir = html_quote(Str_conv_from_system(dirname)->ptr); 91 /* FIXME: gettextize? */ 92 tmp = Strnew_m_charp("<HTML>\n<HEAD>\n<BASE HREF=\"file://", 93 html_quote(file_quote(dirname->ptr)), 94 "\">\n<TITLE>Directory list of ", qdir, 95 "</TITLE>\n</HEAD>\n<BODY>\n<H1>Directory list of ", 96 qdir, "</H1>\n", NULL); 97 flist = New_N(char *, nfile_max); 98 nfile = 0; 99 while ((dir = readdir(d)) != NULL) { 100 flist[nfile++] = allocStr(dir->d_name, -1); 101 if (nfile == nfile_max) { 102 nfile_max *= 2; 103 flist = New_Reuse(char *, flist, nfile_max); 104 } 105 if (multicolList) { 106 l = strlen(dir->d_name); 107 if (l > maxlen) 108 maxlen = l; 109 n++; 110 } 111 } 112 113 if (multicolList) { 114 l = COLS / (maxlen + 2); 115 if (!l) 116 l = 1; 117 nrow = (n + l - 1) / l; 118 n = 1; 119 Strcat_charp(tmp, "<TABLE CELLPADDING=0>\n<TR VALIGN=TOP>\n"); 120 } 121 qsort((void *)flist, nfile, sizeof(char *), strCmp); 122 for (i = 0; i < nfile; i++) { 123 p = flist[i]; 124 if (strcmp(p, ".") == 0) 125 continue; 126 Strcopy(fbuf, dirname); 127 if (Strlastchar(fbuf) != '/') 128 Strcat_char(fbuf, '/'); 129 Strcat_charp(fbuf, p); 130 #ifdef HAVE_LSTAT 131 if (lstat(fbuf->ptr, &lst) < 0) 132 continue; 133 #endif /* HAVE_LSTAT */ 134 if (stat(fbuf->ptr, &st) < 0) 135 continue; 136 if (multicolList) { 137 if (n == 1) 138 Strcat_charp(tmp, "<TD><NOBR>"); 139 } 140 else { 141 #ifdef HAVE_LSTAT 142 if (S_ISLNK(lst.st_mode)) 143 Strcat_charp(tmp, "[LINK] "); 144 else 145 #endif /* HAVE_LSTAT */ 146 if (S_ISDIR(st.st_mode)) 147 Strcat_charp(tmp, "[DIR] "); 148 else 149 Strcat_charp(tmp, "[FILE] "); 150 } 151 Strcat_m_charp(tmp, "<A HREF=\"", html_quote(file_quote(p)), NULL); 152 if (S_ISDIR(st.st_mode)) 153 Strcat_char(tmp, '/'); 154 Strcat_m_charp(tmp, "\">", html_quote(conv_from_system(p)), NULL); 155 if (S_ISDIR(st.st_mode)) 156 Strcat_char(tmp, '/'); 157 Strcat_charp(tmp, "</A>"); 158 if (multicolList) { 159 if (n++ == nrow) { 160 Strcat_charp(tmp, "</NOBR></TD>\n"); 161 n = 1; 162 } 163 else { 164 Strcat_charp(tmp, "<BR>\n"); 165 } 166 } 167 else { 168 #if defined(HAVE_LSTAT) && defined(HAVE_READLINK) 169 if (S_ISLNK(lst.st_mode)) { 170 if ((l = readlink(fbuf->ptr, lbuf, sizeof(lbuf))) > 0) { 171 lbuf[l] = '\0'; 172 Strcat_m_charp(tmp, " -> ", 173 html_quote(conv_from_system(lbuf)), NULL); 174 if (S_ISDIR(st.st_mode)) 175 Strcat_char(tmp, '/'); 176 } 177 } 178 #endif /* HAVE_LSTAT && HAVE_READLINK */ 179 Strcat_charp(tmp, "<br>\n"); 180 } 181 } 182 if (multicolList) { 183 Strcat_charp(tmp, "</TR>\n</TABLE>\n"); 184 } 185 Strcat_charp(tmp, "</BODY>\n</HTML>\n"); 186 187 return tmp; 188 } 189 190 static int 191 check_local_cgi(char *file, int status) 192 { 193 struct stat st; 194 195 if (status != CGIFN_LIBDIR && status != CGIFN_CGIBIN) 196 return -1; 197 if (stat(file, &st) < 0) 198 return -1; 199 if (S_ISDIR(st.st_mode)) 200 return -1; 201 #ifndef __MINGW32_VERSION 202 if ((st.st_uid == geteuid() && (st.st_mode & S_IXUSR)) || (st.st_gid == getegid() && (st.st_mode & S_IXGRP)) || (st.st_mode & S_IXOTH)) /* executable */ 203 return 0; 204 #endif 205 return -1; 206 } 207 208 void 209 set_environ(char *var, char *value) 210 { 211 #ifdef HAVE_SETENV 212 if (var != NULL && value != NULL) 213 setenv(var, value, 1); 214 #else /* not HAVE_SETENV */ 215 #ifdef HAVE_PUTENV 216 static Hash_sv *env_hash = NULL; 217 Str tmp = Strnew_m_charp(var, "=", value, NULL); 218 219 if (env_hash == NULL) 220 env_hash = newHash_sv(20); 221 putHash_sv(env_hash, var, (void *)tmp->ptr); 222 putenv(tmp->ptr); 223 #else /* not HAVE_PUTENV */ 224 extern char **environ; 225 char **ne; 226 char *p; 227 int i, l, el; 228 char **e, **newenv; 229 230 /* I have no setenv() nor putenv() */ 231 /* This part is taken from terms.c of skkfep */ 232 l = strlen(var); 233 for (e = environ, i = 0; *e != NULL; e++, i++) { 234 if (strncmp(e, var, l) == 0 && (*e)[l] == '=') { 235 el = strlen(*e) - l - 1; 236 if (el >= strlen(value)) { 237 strcpy(*e + l + 1, value); 238 return 0; 239 } 240 else { 241 for (; *e != NULL; e++, i++) { 242 *e = *(e + 1); 243 } 244 i--; 245 break; 246 } 247 } 248 } 249 newenv = (char **)GC_malloc((i + 2) * sizeof(char *)); 250 if (newenv == NULL) 251 return; 252 for (e = environ, ne = newenv; *e != NULL; *(ne++) = *(e++)) ; 253 *(ne++) = p; 254 *ne = NULL; 255 environ = newenv; 256 #endif /* not HAVE_PUTENV */ 257 #endif /* not HAVE_SETENV */ 258 } 259 260 static void 261 set_cgi_environ(char *name, char *fn, char *req_uri) 262 { 263 set_environ("SERVER_SOFTWARE", w3m_version); 264 set_environ("SERVER_PROTOCOL", "HTTP/1.0"); 265 set_environ("SERVER_NAME", "localhost"); 266 set_environ("SERVER_PORT", "80"); /* dummy */ 267 set_environ("REMOTE_HOST", "localhost"); 268 set_environ("REMOTE_ADDR", "127.0.0.1"); 269 set_environ("GATEWAY_INTERFACE", "CGI/1.1"); 270 271 set_environ("SCRIPT_NAME", name); 272 set_environ("SCRIPT_FILENAME", fn); 273 set_environ("REQUEST_URI", req_uri); 274 } 275 276 static Str 277 checkPath(char *fn, char *path) 278 { 279 char *p; 280 Str tmp; 281 struct stat st; 282 while (*path) { 283 p = strchr(path, ':'); 284 tmp = Strnew_charp(expandPath(p ? allocStr(path, p - path) : path)); 285 if (Strlastchar(tmp) != '/') 286 Strcat_char(tmp, '/'); 287 Strcat_charp(tmp, fn); 288 if (stat(tmp->ptr, &st) == 0) 289 return tmp; 290 if (!p) 291 break; 292 path = p + 1; 293 while (*path == ':') 294 path++; 295 } 296 return NULL; 297 } 298 299 static int 300 cgi_filename(char *uri, char **fn, char **name, char **path_info) 301 { 302 Str tmp; 303 int offset; 304 305 *fn = uri; 306 *name = uri; 307 *path_info = NULL; 308 309 if (cgi_bin != NULL && strncmp(uri, "/cgi-bin/", 9) == 0) { 310 offset = 9; 311 if ((*path_info = strchr(uri + offset, '/'))) 312 *name = allocStr(uri, *path_info - uri); 313 tmp = checkPath(*name + offset, cgi_bin); 314 if (tmp == NULL) 315 return CGIFN_NORMAL; 316 *fn = tmp->ptr; 317 return CGIFN_CGIBIN; 318 } 319 320 #ifdef __EMX__ 321 { 322 char lib[_MAX_PATH]; 323 _abspath(lib, w3m_lib_dir(), _MAX_PATH); /* Translate '\\' to '/' */ 324 tmp = Strnew_charp(lib); 325 } 326 #else 327 tmp = Strnew_charp(w3m_lib_dir()); 328 #endif 329 if (Strlastchar(tmp) != '/') 330 Strcat_char(tmp, '/'); 331 if (strncmp(uri, "/$LIB/", 6) == 0) 332 offset = 6; 333 else if (strncmp(uri, tmp->ptr, tmp->length) == 0) 334 offset = tmp->length; 335 else if (*uri == '/' && document_root != NULL) { 336 Str tmp2 = Strnew_charp(document_root); 337 if (Strlastchar(tmp2) != '/') 338 Strcat_char(tmp2, '/'); 339 Strcat_charp(tmp2, uri + 1); 340 if (strncmp(tmp2->ptr, tmp->ptr, tmp->length) != 0) 341 return CGIFN_NORMAL; 342 uri = tmp2->ptr; 343 *name = uri; 344 offset = tmp->length; 345 } 346 else 347 return CGIFN_NORMAL; 348 if ((*path_info = strchr(uri + offset, '/'))) 349 *name = allocStr(uri, *path_info - uri); 350 Strcat_charp(tmp, *name + offset); 351 *fn = tmp->ptr; 352 return CGIFN_LIBDIR; 353 } 354 355 FILE * 356 localcgi_post(char *uri, char *qstr, FormList *request, char *referer) 357 { 358 FILE *fr = NULL, *fw = NULL; 359 int status; 360 pid_t pid; 361 char *file = uri, *name = uri, *path_info = NULL, *tmpf = NULL; 362 363 #ifdef __MINGW32_VERSION 364 return NULL; 365 #else 366 status = cgi_filename(uri, &file, &name, &path_info); 367 if (check_local_cgi(file, status) < 0) 368 return NULL; 369 writeLocalCookie(); 370 if (request && request->enctype != FORM_ENCTYPE_MULTIPART) { 371 tmpf = tmpfname(TMPF_DFL, NULL)->ptr; 372 fw = fopen(tmpf, "w"); 373 if (!fw) 374 return NULL; 375 } 376 pid = open_pipe_rw(&fr, NULL); 377 if (pid < 0) 378 return NULL; 379 else if (pid) { 380 if (fw) 381 fclose(fw); 382 return fr; 383 } 384 setup_child(TRUE, 2, fw ? fileno(fw) : -1); 385 386 if (qstr) 387 uri = Strnew_m_charp(uri, "?", qstr, NULL)->ptr; 388 set_cgi_environ(name, file, uri); 389 if (path_info) 390 set_environ("PATH_INFO", path_info); 391 if (referer && referer != NO_REFERER) 392 set_environ("HTTP_REFERER", referer); 393 if (request) { 394 set_environ("REQUEST_METHOD", "POST"); 395 if (qstr) 396 set_environ("QUERY_STRING", qstr); 397 set_environ("CONTENT_LENGTH", Sprintf("%d", request->length)->ptr); 398 if (request->enctype == FORM_ENCTYPE_MULTIPART) { 399 set_environ("CONTENT_TYPE", 400 Sprintf("multipart/form-data; boundary=%s", 401 request->boundary)->ptr); 402 freopen(request->body, "r", stdin); 403 } 404 else { 405 set_environ("CONTENT_TYPE", "application/x-www-form-urlencoded"); 406 fwrite(request->body, sizeof(char), request->length, fw); 407 fclose(fw); 408 freopen(tmpf, "r", stdin); 409 } 410 } 411 else { 412 set_environ("REQUEST_METHOD", "GET"); 413 set_environ("QUERY_STRING", qstr ? qstr : ""); 414 freopen(DEV_NULL_PATH, "r", stdin); 415 } 416 417 #ifdef HAVE_CHDIR /* ifndef __EMX__ ? */ 418 chdir(mydirname(file)); 419 #endif 420 execl(file, mybasename(file), NULL); 421 fprintf(stderr, "execl(\"%s\", \"%s\", NULL): %s\n", 422 file, mybasename(file), strerror(errno)); 423 exit(1); 424 return NULL; 425 #endif 426 }