Beispiel #1
0
/**
 * @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;
}
Beispiel #2
0
/**
 * @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;
}
Beispiel #3
0
/**
 * @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);
	}
}
Beispiel #4
0
/// 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;
}
Beispiel #5
0
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);
}
Beispiel #6
0
/**
 * @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;
}
Beispiel #7
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
/**
 * @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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
/**
 * @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;
}
Beispiel #12
0
/**
 * @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);;
}
Beispiel #13
0
/**
 * @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;
}
Beispiel #14
0
    std::string path() const{
			return onion_request_get_path(ptr);
		}
Beispiel #15
0
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;
}