static int ssl_set_private_paths(void) { unsigned char *path, *c; int r; #ifdef OPENVMS path = stracpy(g_argv[0]); #else path = stracpy(path_to_exe); #endif for (c = path + strlen(cast_const_char path); c > path; c--) { if (dir_sep(c[-1]) #ifdef OPENVMS || c[-1] == ']' || c[-1] == ':' #endif ) break; } c[0] = 0; add_to_strn(&path, cast_uchar stringify(LINKS_CRT_FILE)); r = SSL_CTX_load_verify_locations(context, cast_const_char path, NULL); mem_free(path); if (r != 1) return -1; return 0; }
static void walker(struct vector * v, const char * root, int (*ok)(const char *)){ DIR *dp; struct dirent *ep; char * sub; const char ** tmp = calloc(3, sizeof(char *)); if( is_dir(root) && ok(root) ){ dp = opendir(root); while( (ep = readdir(dp)) ){ if(strcmp(ep->d_name, ".") & strcmp(ep->d_name, "..")){ tmp[0] = root; tmp[1] = ep->d_name; tmp[2] = NULL; sub = join_str(tmp, dir_sep()); if( is_file(sub) && ok(sub) ){ v->add(v, sub); }else{ walker(v, sub, ok); free(sub); } } } closedir(dp); } free(tmp); };
/* Get image filename from its src attribute. */ static unsigned char * get_image_filename_from_src(int max_len, unsigned char *src) { unsigned char *text = NULL; unsigned char *start, *filename; int len; if (!src) return NULL; /* We can display image as [foo.gif]. */ len = strcspn((const char *)src, "?"); for (start = src + len; start > src; start--) if (dir_sep(start[-1])) { break; } len -= start - src; filename = memacpy(start, len); if (filename) { /* XXX: Due to a compatibility alias (added: 2004-12-15 in * 0.10pre3.CVS for document.browse.images.file_tags) this can * return a negative @max_len. */ text = truncate_label(filename, max_len); mem_free(filename); } return text; }
static void insert_wd(unsigned char **up, unsigned char *cwd) { unsigned char *url = *up; if (!url || !cwd || !*cwd) return; if (casecmp(url, cast_uchar "file://", 7)) return; if (dir_sep(url[7])) return; #ifdef DOS_FS if (upcase(url[7]) >= 'A' && upcase(url[7]) <= 'Z' && url[8] == ':' && dir_sep(url[9])) return; #endif #ifdef SPAD if (_is_absolute(cast_const_char(url + 7)) != _ABS_NO) return; #endif url = mem_alloc(strlen(cast_const_char *up) + strlen(cast_const_char cwd) + 2); memcpy(url, *up, 7); strcpy(cast_char(url + 7), cast_const_char cwd); if (!dir_sep(cwd[strlen(cast_const_char cwd) - 1])) strcat(cast_char url, "/"); strcat(cast_char url, cast_const_char(*up + 7)); mem_free(*up); *up = url; }
char * extract_dir(char * src) { char *str; strcpy(str, src); int i; for(i = strlen(str) - 1; i>0; --i) { if( str[i] == dir_sep() ) { str[i] = '\0'; break; } } return str; }
char * path_join_len(const char ** dirs, int len){ if(len <= 1){ panic("path_join: array's length <= 1",__FILE__,__LINE__); } int i; char * res; struct buffer * b = new_buffer(); for(i = 0; i < (len - 1); i++){ b->add(b, dirs[i]); b->add(b, dir_sep()); } b->add(b, dirs[len-1]); res = b->str(b); b->free(b); return res; };
void file_func(struct connection *c) { struct cache_entry *e; unsigned char *file, *name, *head; int fl; DIR *d; int h, r; struct stat stt; if (anonymous && !anonymousGinga) { setcstate(c, S_BAD_URL); abort_connection(c); return; } if (!(name = get_filename(c->url))) { setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } if (anonymousGinga && !allowedPath(name)){ setcstate(c, S_BAD_URL); abort_connection(c); return; } if (stat(name, &stt)) { mem_free(name); setcstate(c, -errno); abort_connection(c); return; } if (!S_ISDIR(stt.st_mode) && !S_ISREG(stt.st_mode)) { mem_free(name); setcstate(c, S_FILE_TYPE); abort_connection(c); return; } if ((h = open(name, O_RDONLY | O_NOCTTY)) == -1) { int er = errno; if ((d = opendir(name))) goto dir; mem_free(name); setcstate(c, -er); abort_connection(c); return; } set_bin(h); if (S_ISDIR(stt.st_mode)) { struct dirs *dir; int dirl; int i; struct dirent *de; d = opendir(name); close(h); if (!d) { mem_free(name); setcstate(c, -errno); abort_connection(c); return; } dir: dir = DUMMY, dirl = 0; if (name[0] && !dir_sep(name[strlen(name) - 1])) { if (get_cache_entry(c->url, &e)) { mem_free(name); closedir(d); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } c->cache = e; if (e->redirect) mem_free(e->redirect); e->redirect = stracpy(c->url); e->redirect_get = 1; add_to_strn(&e->redirect, "/"); mem_free(name); closedir(d); goto end; } last_uid = -1; last_gid = -1; file = init_str(); fl = 0; add_to_str(&file, &fl, "<html><head><title>"); add_conv_str(&file, &fl, name, strlen(name), -1); add_to_str(&file, &fl, "</title></head><body><h2>Directory "); add_conv_str(&file, &fl, name, strlen(name), -1); add_to_str(&file, &fl, "</h2><pre>"); while ((de = readdir(d))) { struct stat stt, *stp; unsigned char **p; int l; unsigned char *n; if (!strcmp(de->d_name, ".")) continue; if ((unsigned)dirl > MAXINT / sizeof(struct dirs) - 1) overalloc(); dir = mem_realloc(dir, (dirl + 1) * sizeof(struct dirs)); dir[dirl].f = stracpy(de->d_name); *(p = &dir[dirl++].s) = init_str(); l = 0; n = stracpy(name); add_to_strn(&n, de->d_name); #ifdef FS_UNIX_SOFTLINKS if (lstat(n, &stt)) #else if (stat(n, &stt)) #endif stp = NULL; else stp = &stt; mem_free(n); stat_mode(p, &l, stp); stat_links(p, &l, stp); stat_user(p, &l, stp, 0); stat_user(p, &l, stp, 1); stat_size(p, &l, stp); stat_date(p, &l, stp); } closedir(d); if (dirl) qsort(dir, dirl, sizeof(struct dirs), (int(*)(const void *, const void *))comp_de); for (i = 0; i < dirl; i++) { unsigned char *lnk = NULL; #ifdef FS_UNIX_SOFTLINKS if (dir[i].s[0] == 'l') { unsigned char *buf = NULL; int size = 0; int r; unsigned char *n = stracpy(name); add_to_strn(&n, dir[i].f); do { if (buf) mem_free(buf); size += ALLOC_GR; if ((unsigned)size > MAXINT) overalloc(); buf = mem_alloc(size); r = readlink(n, buf, size); } while (r == size); if (r == -1) goto yyy; buf[r] = 0; lnk = buf; goto xxx; yyy: mem_free(buf); xxx: mem_free(n); } #endif /*add_to_str(&file, &fl, " ");*/ add_to_str(&file, &fl, dir[i].s); add_to_str(&file, &fl, "<a href=\""); add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 1); if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "/"); else if (lnk) { struct stat st; unsigned char *n = stracpy(name); add_to_strn(&n, dir[i].f); if (!stat(n, &st)) if (S_ISDIR(st.st_mode)) add_to_str(&file, &fl, "/"); mem_free(n); } add_to_str(&file, &fl, "\">"); /*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "<font color=\"yellow\">");*/ add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 0); /*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "</font>");*/ add_to_str(&file, &fl, "</a>"); if (lnk) { add_to_str(&file, &fl, " -> "); add_to_str(&file, &fl, lnk); mem_free(lnk); } add_to_str(&file, &fl, "\n"); } mem_free(name); for (i = 0; i < dirl; i++) mem_free(dir[i].s), mem_free(dir[i].f); mem_free(dir); add_to_str(&file, &fl, "</pre></body></html>\n"); head = stracpy("\r\nContent-Type: text/html\r\n"); } else { mem_free(name); /* + !stt.st_size is there because of bug in Linux. Read returns -EACCES when reading 0 bytes to invalid address */ if (stt.st_size > MAXINT) { close(h); setcstate(c, S_LARGE_FILE); abort_connection(c); return; } file = mem_alloc(stt.st_size + !stt.st_size); if ((r = read(h, file, stt.st_size)) != stt.st_size) { mem_free(file); close(h); setcstate(c, r == -1 ? -errno : S_FILE_ERROR); abort_connection(c); return; } close(h); fl = stt.st_size; head = stracpy(""); } if (get_cache_entry(c->url, &e)) { mem_free(file); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } if (e->head) mem_free(e->head); e->head = head; c->cache = e; add_fragment(e, 0, file, fl); truncate_entry(e, fl, 1); mem_free(file); end: c->cache->incomplete = 0; setcstate(c, S_OK); abort_connection(c); }
static inline int is_uri_dir_sep(const struct uri *uri, unsigned char pos) { return (uri->protocol == PROTOCOL_FILE ? dir_sep(pos) : pos == '/'); }
struct connection_state init_directory_listing(struct string *page, struct uri *uri) { struct string dirpath = NULL_STRING; struct string decoded = NULL_STRING; struct string location = NULL_STRING; unsigned char *info; int local = (uri->protocol == PROTOCOL_FILE); if (!init_string(page) || !init_string(&dirpath) || !init_string(&decoded) || !init_string(&location) || !add_uri_to_string(&dirpath, uri, URI_DATA) || !add_uri_to_string(&location, uri, URI_DIR_LOCATION)) goto out_of_memory; if (dirpath.length > 0 && !dir_sep(dirpath.source[dirpath.length - 1]) && !add_char_to_string(&dirpath, local ? CHAR_DIR_SEP : '/')) goto out_of_memory; /* Decode uri for displaying. */ if (!add_string_to_string(&decoded, &dirpath)) goto out_of_memory; decode_uri_string(&decoded); if (!local && !add_char_to_string(&location, '/')) goto out_of_memory; if (!add_to_string(page, (const unsigned char *)"<html>\n<head><title>")) goto out_of_memory; if (!local && !add_html_to_string(page, location.source, location.length)) goto out_of_memory; if (!add_html_to_string(page, decoded.source, decoded.length) || !add_to_string(page, (const unsigned char *)"</title>\n<base href=\"") || !add_html_to_string(page, location.source, location.length) || !add_html_to_string(page, dirpath.source, dirpath.length)) goto out_of_memory; if (!add_to_string(page, (const unsigned char *)"\" />\n</head>\n<body>\n<h2>")) goto out_of_memory; /* Use module names? */ switch (uri->protocol) { case PROTOCOL_FILE: info = (unsigned char *)"Local"; break; case PROTOCOL_FSP: info = (unsigned char *)"FSP"; break; case PROTOCOL_FTP: info = (unsigned char *)"FTP"; break; case PROTOCOL_GOPHER: info = (unsigned char *)"Gopher"; break; case PROTOCOL_SMB: info = (unsigned char *)"Samba"; break; default: info = (unsigned char *)"?"; } if (!add_to_string(page, info) || !add_to_string(page, (const unsigned char *)" directory ")) goto out_of_memory; if (!local && !add_string_to_string(page, &location)) goto out_of_memory; /* Make the directory path with links to each subdir. */ { const unsigned char *slash = dirpath.source; const unsigned char *pslash = slash; const unsigned char sep = local ? CHAR_DIR_SEP : '/'; while ((slash = (const unsigned char *)strchr((char *)slash, sep)) != NULL) { done_string(&decoded); if (!init_string(&decoded) || !add_bytes_to_string(&decoded, pslash, slash - pslash)) goto out_of_memory; decode_uri_string(&decoded); if (!add_to_string(page, (const unsigned char *)"<a href=\"") || !add_html_to_string(page, location.source, location.length) || !add_html_to_string(page, dirpath.source, slash + 1 - dirpath.source) || !add_to_string(page, (const unsigned char *)"\">") || !add_html_to_string(page, decoded.source, decoded.length) || !add_to_string(page, (const unsigned char *)"</a>") || !add_html_to_string(page, &sep, 1)) goto out_of_memory; pslash = ++slash; } } if (!add_to_string(page, (const unsigned char *)"</h2>\n<pre>")) { out_of_memory: done_string(page); } done_string(&dirpath); done_string(&decoded); done_string(&location); return page->length > 0 ? connection_state(S_OK) : connection_state(S_OUT_OF_MEM); }
char * path_join(const char ** dirs){ return join_str(dirs, dir_sep()); };
/* To reduce redundant error handling code [calls to abort_connection()] * most of the function is build around conditions that will assign the error * code to @state if anything goes wrong. The rest of the function will then just * do the necessary cleanups. If all works out we end up with @state being S_OK * resulting in a cache entry being created with the fragment data generated by * either reading the file content or listing a directory. */ void file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool((const unsigned char *)"anonymous")) { if (strcmp((const char *)connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { abort_connection(connection, connection_state(S_FILE_ANONYMOUS)); return; } } #ifdef CONFIG_CGI if (!execute_cgi(connection)) return; #endif /* CONFIG_CGI */ /* Treat /dev/stdin in special way */ if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) { int fd = open("/dev/stdin", O_RDONLY); if (fd == -1) { abort_connection(connection, connection_state(-errno)); return; } set_nonblocking_fd(fd); if (!init_http_connection_info(connection, 1, 0, 1)) { abort_connection(connection, connection_state(S_OUT_OF_MEM)); close(fd); return; } connection->socket->fd = fd; connection->data_socket->fd = -1; read_from_stdin(connection); return; } /* This function works on already simplified file-scheme URI pre-chewed * by transform_file_url(). By now, the function contains no hostname * part anymore, possibly relative path is converted to an absolute one * and uri->data is just the final path to file/dir we should try to * show. */ if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } decode_uri_string(&name); /* In Win32, file_is_dir seems to always return 0 if the name * ends with a directory separator. */ if ((name.length > 0 && dir_sep(name.source[name.length - 1])) || file_is_dir(name.source)) { /* In order for global history and directory listing to * function properly the directory url must end with a * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = (unsigned char *)STRING_DIR_SEP; state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; } } else { state = read_encoded_file(&name, &page); /* FIXME: If state is now S_ENCODE_ERROR we should try loading * the file undecoded. --jonas */ } done_string(&name); if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either * file reading or directory listing worked out ok. */ cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); connection->from += page.length; if (!cached->head && set_dir_content_type) { unsigned char *head; /* If the system charset somehow * changes after the directory listing * has been generated, it should be * parsed with the original charset. */ head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=", get_cp_mime_name(get_cp_index((const unsigned char *)"System")), "\r\n", (unsigned char *) NULL); /* Not so gracefully handle failed memory * allocation. */ if (!head) state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); } done_string(&page); } } abort_connection(connection, state); }