root/src/noit_filters_rest.c

Revision fc257c3a0ca0ba485d58c775959836e7fdc50721, 7.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

closes #196

  • 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, "allow"))) {
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   noit_filter_remove(node);
150
151   if(noit_conf_write_file(NULL) != 0)
152     noitL(noit_error, "local config write failed\n");
153   noit_conf_mark_changed();
154   noit_http_response_ok(ctx, "text/html");
155   noit_http_response_end(ctx);
156   goto cleanup;
157
158  not_found:
159   noit_http_response_not_found(ctx, "text/html");
160   noit_http_response_end(ctx);
161   goto cleanup;
162
163  error:
164   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
165   noit_http_response_end(ctx);
166   goto cleanup;
167
168  cleanup:
169   return 0;
170 }
171
172 static int
173 rest_set_filter(noit_http_rest_closure_t *restc,
174                 int npats, char **pats) {
175   noit_http_session_ctx *ctx = restc->http_ctx;
176   xmlDocPtr doc = NULL, indoc = NULL;
177   xmlNodePtr node, parent, root, newfilter;
178   char xpath[1024];
179   int error_code = 500, complete = 0, mask = 0;
180   const char *error = "internal error";
181
182   if(npats != 2) goto error;
183
184   indoc = rest_get_xml_upload(restc, &mask, &complete);
185   if(!complete) return mask;
186   if(indoc == NULL) FAIL("xml parse error");
187
188   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
189            pats[0], pats[1]);
190   node = noit_conf_get_section(NULL, xpath);
191   if(!node && noit_filter_exists(pats[1])) {
192     /* It's someone else's */
193     error_code = 403;
194     goto error;
195   }
196
197   if((newfilter = validate_filter_post(indoc)) == NULL) goto error;
198   xmlSetProp(newfilter, (xmlChar *)"name", (xmlChar *)pats[1]);
199
200   parent = make_conf_path(pats[0]);
201   if(!parent) FAIL("invalid path");
202   if(node) {
203     xmlUnlinkNode(node);
204     xmlFreeNode(node);
205   }
206   xmlUnlinkNode(newfilter);
207   xmlAddChild(parent, newfilter);
208
209   if(noit_conf_write_file(NULL) != 0)
210     noitL(noit_error, "local config write failed\n");
211   noit_conf_mark_changed();
212   noit_filter_compile_add(newfilter);
213   if(restc->call_closure_free) restc->call_closure_free(restc->call_closure);
214   restc->call_closure_free = NULL;
215   restc->call_closure = NULL;
216   restc->fastpath = rest_show_filter;
217   return restc->fastpath(restc, restc->nparams, restc->params);
218
219  error:
220   noit_http_response_standard(ctx, error_code, "ERROR", "text/html");
221   doc = xmlNewDoc((xmlChar *)"1.0");
222   root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL);
223   xmlDocSetRootElement(doc, root);
224   xmlNodeAddContent(root, (xmlChar *)error);
225   noit_http_response_xml(ctx, doc);
226   noit_http_response_end(ctx);
227   goto cleanup;
228
229  cleanup:
230   if(doc) xmlFreeDoc(doc);
231   return 0;
232 }
233
234 void
235 noit_filters_rest_init() {
236   assert(noit_http_rest_register_auth(
237     "GET", "/filters/", "^show(/.*)(?<=/)([^/]+)$",
238     rest_show_filter, noit_http_rest_client_cert_auth
239   ) == 0);
240   assert(noit_http_rest_register_auth(
241     "PUT", "/filters/", "^set(/.*)(?<=/)([^/]+)$",
242     rest_set_filter, noit_http_rest_client_cert_auth
243   ) == 0);
244   assert(noit_http_rest_register_auth(
245     "DELETE", "/filters/", "^delete(/.*)(?<=/)([^/]+)$",
246     rest_delete_filter, noit_http_rest_client_cert_auth
247   ) == 0);
248 }
249
Note: See TracBrowser for help on using the browser.