root/src/noit_filters_rest.c

Revision 637731dd84df22000af7615a62662e35d76413a9, 7.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 years ago)

fixes #350

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2009, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include <assert.h>
35 #include <errno.h>
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include <libxml/xpath.h>
39 #include "noit_listener.h"
40 #include "noit_http.h"
41 #include "noit_rest.h"
42 #include "noit_filters.h"
43 #include "noit_check.h"
44 #include "noit_check_tools.h"
45 #include "noit_conf.h"
46 #include "noit_conf_private.h"
47
48 #define FAIL(a) do { error = (a); goto error; } while(0)
49
50 static int
51 rest_show_filter(noit_http_rest_closure_t *restc,
52                  int npats, char **pats) {
53   noit_http_session_ctx *ctx = restc->http_ctx;
54   xmlDocPtr doc = NULL;
55   xmlNodePtr node, root;
56   char xpath[1024];
57   int error_code = 500;
58
59   if(npats != 2) goto error;
60
61   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
62            pats[0], pats[1]);
63
64   node = noit_conf_get_section(NULL, xpath);
65   if(!node) goto not_found;
66
67   doc = xmlNewDoc((xmlChar *)"1.0");
68   root = xmlCopyNode(node, 1);
69   xmlDocSetRootElement(doc, root);
70   noit_http_response_ok(ctx, "text/xml");
71   noit_http_response_xml(ctx, doc);
72   noit_http_response_end(ctx);
73   goto cleanup;
74
75  not_found:
76   noit_http_response_not_found(ctx, "text/html");
77   noit_http_response_end(ctx);
78   goto cleanup;
79
80  error:
81   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
82   noit_http_response_end(ctx);
83   goto cleanup;
84
85  cleanup:
86   if(doc) xmlFreeDoc(doc);
87   return 0;
88 }
89
90 static xmlNodePtr
91 make_conf_path(char *path) {
92   xmlNodePtr start, tmp;
93   char fullpath[1024], *tok, *brk;
94   if(!path || strlen(path) < 1) return NULL;
95   snprintf(fullpath, sizeof(fullpath), "%s", path+1);
96   fullpath[strlen(fullpath)-1] = '\0';
97   start = noit_conf_get_section(NULL, "/noit/filtersets");
98   if(!start) return NULL;
99   for (tok = strtok_r(fullpath, "/", &brk);
100        tok;
101        tok = strtok_r(NULL, "/", &brk)) {
102     if(!xmlValidateNameValue((xmlChar *)tok)) return NULL;
103     if(!strcmp(tok, "filterset")) return NULL;
104     for (tmp = start->children; tmp; tmp = tmp->next) {
105       if(!strcmp((char *)tmp->name, tok)) break;
106     }
107     if(!tmp) {
108       tmp = xmlNewNode(NULL, (xmlChar *)tok);
109       xmlAddChild(start, tmp);
110     }
111     start = tmp;
112   }
113   return start;
114 }
115 static xmlNodePtr
116 validate_filter_post(xmlDocPtr doc) {
117   xmlNodePtr root, r;
118   root = xmlDocGetRootElement(doc);
119   if(!root) return NULL;
120   if(strcmp((char *)root->name, "filterset")) return NULL;
121   if(xmlHasProp(root, (xmlChar *)"name")) return NULL;
122   if(!root->children) return NULL;
123   for(r = root->children; r; r = r->next) {
124     char *type;
125     if(strcmp((char *)r->name, "rule")) return NULL;
126     type = (char *)xmlGetProp(r, (xmlChar *)"type");
127     if(!type || (strcmp(type, "deny") && strcmp(type, "accept"))) {
128       if(type) xmlFree(type);
129       return NULL;
130     }
131     if(type) xmlFree(type);
132   }
133   return root;
134 }
135 static int
136 rest_delete_filter(noit_http_rest_closure_t *restc,
137                    int npats, char **pats) {
138   noit_http_session_ctx *ctx = restc->http_ctx;
139   xmlNodePtr node;
140   char xpath[1024];
141   int error_code = 500;
142
143   if(npats != 2) goto error;
144
145   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
146            pats[0], pats[1]);
147   node = noit_conf_get_section(NULL, xpath);
148   if(!node) goto not_found;
149   if(noit_filter_remove(node) == 0) goto not_found;
150   xmlUnlinkNode(node);
151   xmlFreeNode(node);
152
153   if(noit_conf_write_file(NULL) != 0)
154     noitL(noit_error, "local config write failed\n");
155   noit_conf_mark_changed();
156   noit_http_response_ok(ctx, "text/html");
157   noit_http_response_end(ctx);
158   goto cleanup;
159
160  not_found:
161   noit_http_response_not_found(ctx, "text/html");
162   noit_http_response_end(ctx);
163   goto cleanup;
164
165  error:
166   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
167   noit_http_response_end(ctx);
168   goto cleanup;
169
170  cleanup:
171   return 0;
172 }
173
174 static int
175 rest_set_filter(noit_http_rest_closure_t *restc,
176                 int npats, char **pats) {
177   noit_http_session_ctx *ctx = restc->http_ctx;
178   xmlDocPtr doc = NULL, indoc = NULL;
179   xmlNodePtr node, parent, root, newfilter;
180   char xpath[1024];
181   int error_code = 500, complete = 0, mask = 0;
182   const char *error = "internal error";
183
184   if(npats != 2) goto error;
185
186   indoc = rest_get_xml_upload(restc, &mask, &complete);
187   if(!complete) return mask;
188   if(indoc == NULL) FAIL("xml parse error");
189
190   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
191            pats[0], pats[1]);
192   node = noit_conf_get_section(NULL, xpath);
193   if(!node && noit_filter_exists(pats[1])) {
194     /* It's someone else's */
195     error_code = 403;
196     goto error;
197   }
198
199   if((newfilter = validate_filter_post(indoc)) == NULL) goto error;
200   xmlSetProp(newfilter, (xmlChar *)"name", (xmlChar *)pats[1]);
201
202   parent = make_conf_path(pats[0]);
203   if(!parent) FAIL("invalid path");
204   if(node) {
205     xmlUnlinkNode(node);
206     xmlFreeNode(node);
207   }
208   xmlUnlinkNode(newfilter);
209   xmlAddChild(parent, newfilter);
210
211   if(noit_conf_write_file(NULL) != 0)
212     noitL(noit_error, "local config write failed\n");
213   noit_conf_mark_changed();
214   noit_filter_compile_add(newfilter);
215   if(restc->call_closure_free) restc->call_closure_free(restc->call_closure);
216   restc->call_closure_free = NULL;
217   restc->call_closure = NULL;
218   restc->fastpath = rest_show_filter;
219   return restc->fastpath(restc, restc->nparams, restc->params);
220
221  error:
222   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
223   doc = xmlNewDoc((xmlChar *)"1.0");
224   root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL);
225   xmlDocSetRootElement(doc, root);
226   xmlNodeAddContent(root, (xmlChar *)error);
227   noit_http_response_xml(ctx, doc);
228   noit_http_response_end(ctx);
229   goto cleanup;
230
231  cleanup:
232   if(doc) xmlFreeDoc(doc);
233   return 0;
234 }
235
236 void
237 noit_filters_rest_init() {
238   assert(noit_http_rest_register_auth(
239     "GET", "/filters/", "^show(/.*)(?<=/)([^/]+)$",
240     rest_show_filter, noit_http_rest_client_cert_auth
241   ) == 0);
242   assert(noit_http_rest_register_auth(
243     "PUT", "/filters/", "^set(/.*)(?<=/)([^/]+)$",
244     rest_set_filter, noit_http_rest_client_cert_auth
245   ) == 0);
246   assert(noit_http_rest_register_auth(
247     "DELETE", "/filters/", "^delete(/.*)(?<=/)([^/]+)$",
248     rest_delete_filter, noit_http_rest_client_cert_auth
249   ) == 0);
250 }
251
Note: See TracBrowser for help on using the browser.