Package: didiwiki / 0.5-13

91_check_page_path.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
From: Alexander Izmailov <yarolig@gmail.com>
Subject: Correct a major security issue allowing didiwiki to 
         display any file on the filesystem
Updated by: Ignace Mouzannar <mouzannar@gmail.com> with the help
            Sergio Gelato <Sergio.Gelato@astro.su.se>. Thanks Sergio!
Last-Updated: 03-April-2016
Index: didiwiki-0.5/src/wiki.c
===================================================================
--- didiwiki-0.5.orig/src/wiki.c
+++ didiwiki-0.5/src/wiki.c
@@ -812,6 +812,28 @@ wiki_show_footer(HttpResponse *res)
 		       );
 }
 
+int page_name_is_good(char* page_name)
+{
+/* We should give access only to subdirs of didiwiki root.
+   I guess that check for absense of '/' is enough.
+
+   TODO: Use realpath()
+*/
+    if (!page_name)
+        return FALSE;
+
+    if (page_name[0] == '/')
+        return FALSE;
+
+    if (strncmp(page_name, "../", 3) == 0)
+        return FALSE;
+
+    if (strstr(page_name, "/../"))
+        return FALSE;
+
+    return TRUE;
+}
+
 void
 wiki_handle_rest_call(HttpRequest  *req, 
 		      HttpResponse *res,
@@ -827,7 +849,7 @@ wiki_handle_rest_call(HttpRequest  *req,
 	  if (page == NULL)
 	    page = http_request_get_query_string(req);
 
-	  if (page && (access(page, R_OK) == 0)) 
+    if (page && page_name_is_good(page) && (access(page, R_OK) == 0))
 	    {
 	      http_response_printf(res, "%s", file_read(page));
 	      http_response_send(res);
@@ -840,11 +862,14 @@ wiki_handle_rest_call(HttpRequest  *req,
 	  if( ( (wikitext = http_request_param_get(req, "text")) != NULL)
 	      && ( (page = http_request_param_get(req, "page")) != NULL))
 	    {
-	      file_write(page, wikitext);	      
+    if (page_name_is_good(page))
+	    {
+	      file_write(page, wikitext);
 	      http_response_printf(res, "success");
 	      http_response_send(res);
 	      return;
 	    }
+        }
 	}
       else if (!strcmp(func, "page/delete"))
 	{
@@ -853,7 +878,7 @@ wiki_handle_rest_call(HttpRequest  *req,
 	  if (page == NULL)
 	    page = http_request_get_query_string(req);
 
-	  if (page && (unlink(page) > 0))
+    if (page && page_name_is_good(page) && (unlink(page) > 0))
 	    {
 	      http_response_printf(res, "success");
 	      http_response_send(res);
@@ -867,7 +892,7 @@ wiki_handle_rest_call(HttpRequest  *req,
 	  if (page == NULL)
 	    page = http_request_get_query_string(req);
 
-	  if (page && (access(page, R_OK) == 0)) 
+    if (page && page_name_is_good(page) && (access(page, R_OK) == 0))
 	    {
 	      http_response_printf(res, "success");
 	      http_response_send(res);
@@ -966,7 +991,7 @@ wiki_handle_http_request(HttpRequest *re
   /* A little safety. issue a malformed request for any paths,
    * There shouldn't need to be any..
    */
-  if (strchr(page, '/'))
+  if (!page_name_is_good(page))
     {
       http_response_set_status(res, 404, "Not Found");
       http_response_printf(res, "<html><body>404 Not Found</body></html>\n");