w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

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]&nbsp; ");
    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 }