root/src/noit_filters_rest.c

Revision 70c30ef22f6d1312375e0392164d755db5824cb5, 8.4 kB (checked in by Phil Maddox <philip.maddox@circonus.com>, 2 months ago)

Use mtevAssert and mtevFatal Instead Of assert() and abort()

Use libmtev calls to safely flush logs and abort rather than calling
the assert and abort calls directly.

  • 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 <errno.h>
37 #include <libxml/parser.h>
38 #include <libxml/tree.h>
39 #include <libxml/xpath.h>
40
41 #include <mtev_listener.h>
42 #include <mtev_http.h>
43 #include <mtev_rest.h>
44 #include <mtev_conf.h>
45 #include <mtev_conf_private.h>
46
47 #include "noit_mtev_bridge.h"
48 #include "noit_filters.h"
49 #include "noit_check.h"
50 #include "noit_check_tools.h"
51
52 #define FAIL(a) do { error = (a); goto error; } while(0)
53
54 static int
55 rest_show_filter(mtev_http_rest_closure_t *restc,
56                  int npats, char **pats) {
57   mtev_http_session_ctx *ctx = restc->http_ctx;
58   xmlDocPtr doc = NULL;
59   xmlNodePtr node, root;
60   char xpath[1024];
61   int error_code = 500;
62
63   if(npats != 2) goto error;
64
65   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
66            pats[0], pats[1]);
67
68   node = mtev_conf_get_section(NULL, xpath);
69   if(!node) goto not_found;
70
71   doc = xmlNewDoc((xmlChar *)"1.0");
72   root = xmlCopyNode(node, 1);
73   xmlDocSetRootElement(doc, root);
74   mtev_http_response_ok(ctx, "text/xml");
75   mtev_http_response_xml(ctx, doc);
76   mtev_http_response_end(ctx);
77   goto cleanup;
78
79  not_found:
80   mtev_http_response_not_found(ctx, "text/html");
81   mtev_http_response_end(ctx);
82   goto cleanup;
83
84  error:
85   mtev_http_response_standard(ctx, error_code, "ERROR", "text/html");
86   mtev_http_response_end(ctx);
87   goto cleanup;
88
89  cleanup:
90   if(doc) xmlFreeDoc(doc);
91   return 0;
92 }
93
94 static xmlNodePtr
95 make_conf_path(char *path) {
96   xmlNodePtr start, tmp;
97   char fullpath[1024], *tok, *brk;
98   if(!path || strlen(path) < 1) return NULL;
99   snprintf(fullpath, sizeof(fullpath), "%s", path+1);
100   fullpath[strlen(fullpath)-1] = '\0';
101   start = mtev_conf_get_section(NULL, "/noit/filtersets");
102   if(!start) return NULL;
103   for (tok = strtok_r(fullpath, "/", &brk);
104        tok;
105        tok = strtok_r(NULL, "/", &brk)) {
106     if(!xmlValidateNameValue((xmlChar *)tok)) return NULL;
107     if(!strcmp(tok, "filterset")) return NULL;
108     for (tmp = start->children; tmp; tmp = tmp->next) {
109       if(!strcmp((char *)tmp->name, tok)) break;
110     }
111     if(!tmp) {
112       tmp = xmlNewNode(NULL, (xmlChar *)tok);
113       xmlAddChild(start, tmp);
114       CONF_DIRTY(tmp);
115     }
116     start = tmp;
117   }
118   return start;
119 }
120 static xmlNodePtr
121 validate_filter_post(xmlDocPtr doc) {
122   xmlNodePtr root, r;
123   root = xmlDocGetRootElement(doc);
124   if(!root) return NULL;
125   if(strcmp((char *)root->name, "filterset")) return NULL;
126   if(xmlHasProp(root, (xmlChar *)"name")) return NULL;
127   if(!root->children) return NULL;
128   for(r = root->children; r; r = r->next) {
129     char *type;
130     if(strcmp((char *)r->name, "rule")) return NULL;
131     type = (char *)xmlGetProp(r, (xmlChar *)"type");
132     if(!type || (strcmp(type, "deny") && strcmp(type, "accept"))) {
133       if(type) xmlFree(type);
134       return NULL;
135     }
136     if(type) xmlFree(type);
137   }
138   return root;
139 }
140 static int
141 rest_delete_filter(mtev_http_rest_closure_t *restc,
142                    int npats, char **pats) {
143   mtev_http_session_ctx *ctx = restc->http_ctx;
144   xmlNodePtr node;
145   char xpath[1024];
146   int error_code = 500;
147
148   if(npats != 2) goto error;
149
150   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
151            pats[0], pats[1]);
152   node = mtev_conf_get_section(NULL, xpath);
153   if(!node) goto not_found;
154   if(noit_filter_remove(node) == 0) goto not_found;
155   CONF_REMOVE(node);
156   xmlUnlinkNode(node);
157   xmlFreeNode(node);
158
159   if(mtev_conf_write_file(NULL) != 0)
160     mtevL(noit_error, "local config write failed\n");
161   mtev_conf_mark_changed();
162   mtev_http_response_ok(ctx, "text/html");
163   mtev_http_response_end(ctx);
164   goto cleanup;
165
166  not_found:
167   mtev_http_response_not_found(ctx, "text/html");
168   mtev_http_response_end(ctx);
169   goto cleanup;
170
171  error:
172   mtev_http_response_standard(ctx, error_code, "ERROR", "text/html");
173   mtev_http_response_end(ctx);
174   goto cleanup;
175
176  cleanup:
177   return 0;
178 }
179
180 static int
181 rest_cull_filter(mtev_http_rest_closure_t *restc,
182                  int npats, char **pats) {
183   int rv;
184   char cnt_str[32];
185   mtev_http_session_ctx *ctx = restc->http_ctx;
186
187   rv = noit_filtersets_cull_unused();
188   if(rv > 0) mtev_conf_mark_changed();
189   snprintf(cnt_str, sizeof(cnt_str), "%d", rv);
190   mtev_http_response_ok(ctx, "text/html");
191   mtev_http_response_header_set(ctx, "X-Filters-Removed", cnt_str);
192   mtev_http_response_end(ctx);
193   return 0;
194 }
195
196 static int
197 rest_set_filter(mtev_http_rest_closure_t *restc,
198                 int npats, char **pats) {
199   mtev_http_session_ctx *ctx = restc->http_ctx;
200   xmlDocPtr doc = NULL, indoc = NULL;
201   xmlNodePtr node, parent, root, newfilter;
202   char xpath[1024];
203   int error_code = 500, complete = 0, mask = 0;
204   const char *error = "internal error";
205
206   if(npats != 2) goto error;
207
208   indoc = rest_get_xml_upload(restc, &mask, &complete);
209   if(!complete) return mask;
210   if(indoc == NULL) FAIL("xml parse error");
211
212   snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]",
213            pats[0], pats[1]);
214   node = mtev_conf_get_section(NULL, xpath);
215   if(!node && noit_filter_exists(pats[1])) {
216     /* It's someone else's */
217     error_code = 403;
218     goto error;
219   }
220
221   if((newfilter = validate_filter_post(indoc)) == NULL) goto error;
222   xmlSetProp(newfilter, (xmlChar *)"name", (xmlChar *)pats[1]);
223
224   parent = make_conf_path(pats[0]);
225   if(!parent) FAIL("invalid path");
226   if(node) {
227     CONF_REMOVE(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   mtevAssert(mtev_http_rest_register_auth(
263     "GET", "/filters/", "^show(/.*)(?<=/)([^/]+)$",
264     rest_show_filter, mtev_http_rest_client_cert_auth
265   ) == 0);
266   mtevAssert(mtev_http_rest_register_auth(
267     "PUT", "/filters/", "^set(/.*)(?<=/)([^/]+)$",
268     rest_set_filter, mtev_http_rest_client_cert_auth
269   ) == 0);
270   mtevAssert(mtev_http_rest_register_auth(
271     "DELETE", "/filters/", "^delete(/.*)(?<=/)([^/]+)$",
272     rest_delete_filter, mtev_http_rest_client_cert_auth
273   ) == 0);
274   mtevAssert(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.