root/src/noit_filters_rest.c

Revision 304ec80b8cf842fc0abe5f9029790908b6455957, 8.4 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 months ago)

Convert to libmtev.

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