root/src/noit_filters_rest.c

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

make the rest calls dirty the right bits for shatter output

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