/** * @short Serves a directory listing. * * It checks if the given request is a directory listing and processes it, or fallbacks to the * next handler. */ int fileserver_page(const char *basepath, onion_request *req, onion_response *res){ if ((onion_request_get_flags(req)&OR_METHODS) == OR_GET){ // only get. const char *path=onion_request_get_path(req); // Try to get the real path, and check if its a dir char dirname[256]; snprintf(dirname, sizeof(dirname), "%s/%s", basepath, onion_request_get_path(req)); char *realp=realpath(dirname, NULL); if (!realp) return OCS_INTERNAL_ERROR; DIR *dir=opendir(realp); if (dir){ // its a dir, fill the dictionary. onion_dict *d=onion_dict_new(); onion_dict_add(d, "dirname", path, 0); if (path[0]!='\0' && path[1]!='\0') onion_dict_add(d, "go_up", "true", 0); onion_dict *files=onion_dict_new(); onion_dict_add(d, "files", files, OD_DICT|OD_FREE_VALUE); struct dirent *de; while ( (de=readdir(dir)) ){ // Fill one files.[filename] per file. onion_dict *file=onion_dict_new(); onion_dict_add(files, de->d_name, file, OD_DUP_KEY|OD_DICT|OD_FREE_VALUE); onion_dict_add(file, "name", de->d_name, OD_DUP_VALUE); char tmp[256]; snprintf(tmp, sizeof(tmp), "%s/%s", realp, de->d_name); struct stat st; stat(tmp, &st); snprintf(tmp, sizeof(tmp), "%d", (int)st.st_size); onion_dict_add(file, "size", tmp, OD_DUP_VALUE); snprintf(tmp, sizeof(tmp), "%d", st.st_uid); onion_dict_add(file, "owner", tmp, OD_DUP_VALUE); if (S_ISDIR(st.st_mode)) onion_dict_add(file, "type", "dir", 0); else onion_dict_add(file, "type", "file", 0); } closedir(dir); free(realp); return fileserver_html_template(d, req, res); } free(realp); } return OCS_NOT_PROCESSED; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ // Prepare the basepath, necesary for props. char *basepath=NULL; int pathlen=0; const char *current_path=onion_request_get_path(req); const char *fullpath=onion_request_get_fullpath(req); pathlen=(current_path-fullpath); basepath=alloca(pathlen+1); memcpy(basepath, fullpath, pathlen+1); ONION_DEBUG0("Pathbase initial <%s> %d", basepath, pathlen); while(basepath[pathlen]=='/' && pathlen>0) pathlen--; basepath[pathlen+1]=0; ONION_DEBUG0("PROPFIND; pathbase %s", basepath); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(basepath, filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write_headers(res); onion_response_flush(res); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
/** * @short Moves a resource */ onion_connection_status onion_webdav_move(const char *filename, onion_webdav *wd, onion_request *req, onion_response *res){ const char *dest=onion_request_get_header(req,"Destination"); if (!dest) return OCS_INTERNAL_ERROR; const char *dest_orig=dest; // Skip the http... part. Just 3 /. int i; for (i=0;i<3;i+=(*dest++=='/')) if (*dest==0) return OCS_INTERNAL_ERROR; dest--; const char *fullpath=onion_request_get_fullpath(req); const char *partialpath=onion_request_get_path(req); // Not the fixed URL part for this handler. int fpl=strlen(fullpath); // Full path length int ppl=strlen(onion_request_get_path(req)); // Partial, the fullpath[fpl-ppl] is the end point of the handler path if (strncmp(fullpath, dest, fpl-ppl)!=0){ char tmp[512]; int l=fpl-ppl < sizeof(tmp)-1 ? fpl-ppl : sizeof(tmp)-1; strncpy(tmp, fullpath, l); tmp[l]=0; ONION_WARNING("Move to out of this webdav share! (%s is out of %s)", dest, tmp); return onion_shortcut_response("Moving out of shared share", HTTP_FORBIDDEN, req, res); } dest=&dest[fpl-ppl]; char orig[512]; snprintf(orig, sizeof(orig), "%s/%s", wd->path, partialpath); if (wd->check_permissions(wd->path, orig, req)!=0){ return onion_shortcut_response("Forbidden", HTTP_FORBIDDEN, req, res); } const char *fdest=filename; ONION_INFO("Move %s to %s (webdav)", fullpath, dest_orig); int ok=onion_shortcut_rename(orig, fdest); if (ok==0){ ONION_DEBUG("Created %s succesfully", fdest); return onion_shortcut_response("201 Created", 201, req, res); } else{ ONION_ERROR("Could not rename %s to %s (%s)", orig, fdest, strerror(errno)); return onion_shortcut_response("Could not create resource", HTTP_FORBIDDEN, req, res); } }
/// Plexes the request depending on arguments. int oterm_get_data(oterm_data *data, onion_request *req, onion_response *res){ const char *username=onion_request_get_session(req,"username"); if (!username){ ONION_WARNING("Trying to enter authenticated area without username."); return OCS_FORBIDDEN; } oterm_session *o=(oterm_session*)onion_dict_get(data->sessions, onion_request_get_session(req,"username")); if (!o){ o=oterm_session_new(); onion_dict_lock_write(data->sessions); onion_dict_add(data->sessions,onion_request_get_session(req,"username"),o, 0); onion_dict_unlock(data->sessions); } const char *path=onion_request_get_path(req); ONION_DEBUG("Ask path %s (%p)", path, data); if (strcmp(path,"new")==0){ if (onion_request_get_post(req, "command")){ free(data->exec_command); data->exec_command=strdup(onion_request_get_post(req, "command")); } oterm_new(data, o, onion_request_get_session(req, "username"), onion_request_get_session(req, "nopam") ? 0 : 1 ); return onion_shortcut_response("ok", 200, req, res); } if (strcmp(path,"status")==0) return oterm_status(o,req, res); return OCS_NOT_PROCESSED; }
onion_connection_status oterm_uuid(void *data, onion_request *req, onion_response *res){ const char *path=onion_request_get_path(req); ONION_DEBUG("Ask path %s (%p)", path, data); // split id / function int l=strlen(path)+1; char *id=alloca(l); char *function=NULL; int i; memcpy(id,path,l); int func_pos=0; for (i=0;i<l;i++){ if (id[i]=='/'){ if (!function && id[i+1]!='\0') function=id+i+1; id[i]=0; func_pos=i; break; } } ONION_DEBUG("Id %s, function %s", id, function); process *term=oterm_get_process_by_uuid(data, id); if (!term) return OCS_INTERNAL_ERROR; if (!function) return onion_shortcut_internal_redirect("static/oterm.html", req, res); // do it onion_request_advance_path(req, func_pos); return oterm_process(data, term, function, req, res); }
/** * @short Performs the real request: checks if its for me, and then calls the inside level. */ int onion_url_handler(onion_url_data **dd, onion_request *request, onion_response *response){ onion_url_data *next=*dd; regmatch_t match[16]; int i; const char *path=onion_request_get_path(request); while (next){ ONION_DEBUG0("Check %s against %s", onion_request_get_path(request), next->orig); if (next->flags&OUD_STRCMP){ if (strcmp(path, next->str)==0){ ONION_DEBUG0("Ok, simple match."); onion_request_advance_path(request, strlen(next->str)); return onion_handler_handle(next->inside, request, response); } } else if (regexec(&next->regexp, onion_request_get_path(request), 16, match, 0)==0){ //ONION_DEBUG("Ok,match"); onion_dict *reqheader=request->GET; for (i=1;i<16;i++){ regmatch_t *rm=&match[i]; if (rm->rm_so!=-1){ char *tmp=malloc(rm->rm_eo-rm->rm_so); memcpy(tmp, &path[rm->rm_so], rm->rm_eo-rm->rm_so); char tmpn[4]; snprintf(tmpn,sizeof(tmpn),"%d",i); onion_dict_add(reqheader, tmpn, tmp, OD_DUP_KEY|OD_FREE_VALUE); ONION_DEBUG("Add group %d: %s (%d-%d)", i, tmp, rm->rm_so, rm->rm_eo); } else break; } onion_request_advance_path(request, match[0].rm_eo); ONION_DEBUG0("Ok, regexp match."); return onion_handler_handle(next->inside, request, response); } next=next->next; } return 0; }
onion_connection_status method(void *ignore, onion_request *req, onion_response *res){ if (onion_response_write_headers(res)==OR_SKIP_CONTENT) // Head return OCS_PROCESSED; onion_response_write0(res, "<html><body>\n<h1>Petition resume</h1>\n"); int flags=onion_request_get_flags(req); if (flags&OR_GET) onion_response_write0(res,"<h2>GET"); else if (flags&OR_POST) onion_response_write0(res,"<h2>POST"); else onion_response_write0(res,"<h2>UNKNOWN"); onion_response_printf(res," %s</h2>\n<ul>",onion_request_get_path(req)); const onion_dict *get=onion_request_get_query_dict(req); const onion_dict *post=onion_request_get_post_dict(req); const onion_dict *headers=onion_request_get_header_dict(req); onion_response_printf(res,"<li>Header %d elements<ul>",onion_dict_count(headers)); if (headers) onion_dict_preorder(headers, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_printf(res,"<li>GET %d elements<ul>",onion_dict_count(get)); if (get) onion_dict_preorder(get, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_printf(res,"<li>POST %d elements<ul>",onion_dict_count(post)); if (post) onion_dict_preorder(post, print_dict_element, res); onion_response_printf(res,"</ul></li>\n"); onion_response_write0(res,"<p>\n"); onion_response_write0(res,"<form method=\"GET\">" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"GET\">" "</form><p>\n"); onion_response_write0(res,"<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\">" "<textarea name=\"text\"></textarea>" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"POST urlencoded\">" "</form>" "<p>\n"); onion_response_write0(res,"<form method=\"POST\" enctype=\"multipart/form-data\">" "<input type=\"file\" name=\"file\">" "<textarea name=\"text\"></textarea>" "<input type=\"text\" name=\"test\">" "<input type=\"submit\" name=\"submit\" value=\"POST multipart\">" "</form>" "<p>\n"); onion_response_write0(res,"</body></html>"); return OCS_PROCESSED; }
int onion_handler_opack_handler(onion_handler_opack_data *d, onion_request *request, onion_response *res){ if (strcmp(d->path, onion_request_get_path(request))!=0) return 0; if (d->length) onion_response_set_length(res, d->length); onion_response_write_headers(res); d->render(res); return OCS_PROCESSED; }
/** * @short Just asks the user for the answer. */ onion_connection_status ask_handler(void *none, onion_request *req, onion_response *res){ char temp[1024]; strcpy(temp, onion_request_get_path(req)); onion_dict_preorder(onion_request_get_query_dict(req),format_query,temp); char *resp=ask_question(temp); if (!resp) return OCS_INTERNAL_ERROR; onion_response_write0(res, resp); free(resp); return OCS_PROCESSED; }
int onion_handler_export_local_handler(onion_handler_export_local_data *d, onion_request *request, onion_response *response){ char tmp[PATH_MAX]; char realp[PATH_MAX]; if (d->is_file) strncpy(tmp, d->localpath, PATH_MAX); else snprintf(tmp,PATH_MAX, "%s/%s",d->localpath,onion_request_get_path(request)); ONION_DEBUG0("Get %s (base %s)",tmp, d->localpath); // First check if it exists and so on. If it does not exist, no trying to escape message struct stat reals; int ok=stat(tmp,&reals); if (ok<0) // Cant open for even stat { ONION_DEBUG0("Not found %s.", tmp); return 0; } const char *ret=realpath(tmp, realp); if (!ret || strncmp(realp, d->localpath, strlen(d->localpath))!=0){ // out of secured dir. ONION_WARNING("Trying to escape from secured dir (secured dir %s, trying %s).", d->localpath, realp); return 0; } if (S_ISDIR(reals.st_mode)){ //ONION_DEBUG("DIR"); return onion_handler_export_local_directory(d, realp, onion_request_get_path(request), request, response); } else if (S_ISREG(reals.st_mode)){ //ONION_DEBUG("FILE"); return onion_shortcut_response_file(realp, request, response); } ONION_DEBUG0("Dont know how to handle"); return OCS_NOT_PROCESSED; }
/** * @short Main webdav handler, just redirects to the proper handler depending on headers and method */ onion_connection_status onion_webdav_handler(onion_webdav *wd, onion_request *req, onion_response *res){ onion_response_set_header(res, "Dav", "1,2"); onion_response_set_header(res, "MS-Author-Via", "DAV"); #ifdef __DEBUG__ const onion_block *data=onion_request_get_data(req); if (data){ ONION_DEBUG0("Have data!\n %s", onion_block_data(data)); } #endif char filename[512]; snprintf(filename, sizeof(filename), "%s/%s", wd->path, onion_request_get_path(req)); ONION_DEBUG("Check %s and %s", wd->path, filename); if (wd->check_permissions(wd->path, filename, req)!=0){ return onion_shortcut_response("Forbidden", HTTP_FORBIDDEN, req, res); } switch (onion_request_get_flags(req)&OR_METHODS){ case OR_GET: case OR_HEAD: return onion_webdav_get(filename, wd, req, res); case OR_OPTIONS: return onion_webdav_options(filename, wd, req, res); case OR_PROPFIND: return onion_webdav_propfind(filename, wd, req, res); case OR_PUT: return onion_webdav_put(filename, wd, req, res); case OR_DELETE: return onion_webdav_delete(filename, wd, req, res); case OR_MOVE: return onion_webdav_move(filename, wd, req, res); case OR_MKCOL: return onion_webdav_mkcol(filename, wd, req, res); case OR_PROPPATCH: return onion_webdav_proppatch(filename, wd, req, res); } onion_response_set_code(res, HTTP_NOT_IMPLEMENTED); onion_response_write0(res, "<h1>Work in progress...</h1>\n"); return OCS_PROCESSED; }
/** * @short Handler that just echoes all data, writing what was a header, what the method... */ onion_connection_status allinfo_handler(void *data, onion_request *req){ onion_response *res=onion_response_new(req); onion_response_write_headers(res); int f=onion_request_get_flags(req); onion_response_printf(res, "Method: %s\n",(f&OR_GET) ? "GET" : (f&OR_HEAD) ? "HEAD" : "POST"); onion_response_printf(res, "Path: %s\n",onion_request_get_path(req)); onion_response_printf(res, "Version: %s\n",onion_request_get_flags(req)&OR_HTTP11 ? "HTTP/1.1" : "HTTP/1.0"); allinfo_dict_print_t aid; aid.res=res; aid.part="Query"; onion_dict_preorder(onion_request_get_query_dict(req),allinfo_query, &aid); aid.part="Header"; onion_dict_preorder(onion_request_get_header_dict(req),allinfo_query, &aid); aid.part="POST"; onion_dict_preorder(onion_request_get_post_dict(req),allinfo_query, &aid); aid.part="FILE"; onion_dict_preorder(onion_request_get_file_dict(req),allinfo_query, &aid); return onion_response_free(res);; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ ONION_DEBUG0("PROPFIND"); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
std::string path() const{ return onion_request_get_path(ptr); }
int handler3(void *p, onion_request * r, onion_response * res) { ONION_DEBUG("3"); handler_called = 3; urltxt = strdup(onion_request_get_path(r)); return OCS_PROCESSED; }