Changeset 914f04715e543bf76101c324e06a062e7a10b3ba

Show
Ignore:
Timestamp:
09/15/09 05:37:42 (5 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1252993062 +0000
git-parent:

[003a683dd82a9ebcc4c43d5565e7e7c3d189384f]

git-author:
Theo Schlossnagle <jesus@omniti.com> 1252993062 +0000
Message:

adding checks, needs a lot of input validation, refs #171

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/noit_check.c

    r0ce85ca r914f047  
    136136    void *vcheck; 
    137137    char uuid_str[37]; 
    138     char target[256]
    139     char module[256]
    140     char name[256]
    141     char filterset[256]
     138    char target[256] = ""
     139    char module[256] = ""
     140    char name[256] = ""
     141    char filterset[256] = ""
    142142    char oncheck[1024] = ""; 
    143143    int no_period = 0; 
  • src/noit_check_rest.c

    r0256945 r914f047  
    3333#include "noit_defines.h" 
    3434#include <assert.h> 
     35#include <errno.h> 
    3536#include <libxml/parser.h> 
    3637#include <libxml/tree.h> 
     
    4445#include "noit_conf_private.h" 
    4546 
     47#define UUID_REGEX "[0-9a-fA-F]{4}(?:[0-9a-fA-F]{4}-){4}[0-9a-fA-F]{12}" 
     48 
     49struct rest_xml_payload { 
     50  char *buffer; 
     51  int len; 
     52  int allocd; 
     53  int complete; 
     54}; 
     55 
    4656static int 
    47 rest_host_check(noit_http_rest_closure_t *restc, 
     57rest_show_check(noit_http_rest_closure_t *restc, 
    4858                int npats, char **pats) { 
    4959  noit_http_session_ctx *ctx = restc->http_ctx; 
     
    219229} 
    220230 
     231static void 
     232rest_xml_payload_free(void *f) { 
     233  struct rest_xml_payload *xmlin = f; 
     234  if(xmlin->buffer) free(xmlin->buffer); 
     235} 
     236 
     237static int 
     238validate_check_post(xmlDocPtr doc, xmlNodePtr *a, xmlNodePtr *c) { 
     239  xmlNodePtr root, tl, an; 
     240  int name=0, module=0, target=0, period=0, timeout=0, filterset=0, disable=0; 
     241  *a = *c = NULL; 
     242  root = xmlDocGetRootElement(doc); 
     243  if(!root || strcmp((char *)root->name, "check")) return 0; 
     244  for(tl = root->children; tl; tl = tl->next) { 
     245    if(!strcmp((char *)tl->name, "attributes")) { 
     246      *a = tl->children; 
     247      for(an = tl->children; an; an = an->next) { 
     248#define CHECK_N_SET(a) if(!strcmp((char *)an->name, #a)) a = 1 
     249        CHECK_N_SET(name); 
     250        else CHECK_N_SET(module); 
     251        else CHECK_N_SET(target); 
     252        else CHECK_N_SET(period); 
     253        else CHECK_N_SET(timeout); 
     254        else CHECK_N_SET(filterset); 
     255        else CHECK_N_SET(disable); 
     256        else return 0; 
     257      } 
     258    } 
     259    else if(!strcmp((char *)tl->name, "config")) { 
     260      *c = tl->children; 
     261      /* Noop, anything goes */ 
     262    } 
     263    else return 0; 
     264  } 
     265  if(name && module && target && period && timeout && filterset) return 1; 
     266  return 0; 
     267} 
     268static void 
     269configure_xml_check(xmlNodePtr check, xmlNodePtr a, xmlNodePtr c) { 
     270  xmlNodePtr n, config, oldconfig; 
     271  for(n = a; n; n = n->next) { 
     272#define ATTR2PROP(attr) do { \ 
     273  if(!strcmp((char *)n->name, #attr)) { \ 
     274    xmlChar *v = xmlNodeGetContent(n); \ 
     275    if(v) xmlSetProp(check, n->name, v); \ 
     276    else xmlUnsetProp(check, n->name); \ 
     277    if(v) xmlFree(v); \ 
     278  } \ 
     279} while(0) 
     280    ATTR2PROP(name); 
     281    ATTR2PROP(target); 
     282    ATTR2PROP(module); 
     283    ATTR2PROP(period); 
     284    ATTR2PROP(timeout); 
     285    ATTR2PROP(disable); 
     286    ATTR2PROP(filter); 
     287  } 
     288  for(oldconfig = check->children; oldconfig; oldconfig = oldconfig->next) 
     289    if(!strcmp((char *)oldconfig->name, "config")) break; 
     290  config = xmlNewNode(NULL, (xmlChar *)"config"); 
     291  for(n = c; n; n = n->next) { 
     292    xmlNodePtr co = xmlNewNode(NULL, n->name); 
     293    xmlNodeAddContent(co, XML_GET_CONTENT(n)); 
     294    xmlAddChild(config, co); 
     295  } 
     296  if(oldconfig) { 
     297    xmlReplaceNode(oldconfig, config); 
     298    xmlFreeNode(oldconfig); 
     299  } 
     300  else xmlAddChild(check, config); 
     301} 
     302static xmlNodePtr 
     303make_conf_path(char *path) { 
     304  xmlNodePtr start, tmp; 
     305  char fullpath[1024], *tok, *brk; 
     306  if(!path || strlen(path) < 1) return NULL; 
     307  snprintf(fullpath, sizeof(fullpath), "%s", path+1); 
     308  fullpath[strlen(fullpath)-1] = '\0'; 
     309  start = noit_conf_get_section(NULL, "/noit/checks"); 
     310  if(!start) return NULL; 
     311  for (tok = strtok_r(fullpath, "/", &brk); 
     312       tok; 
     313       tok = strtok_r(NULL, "/", &brk)) { 
     314    if(!xmlValidateNameValue((xmlChar *)tok)) return NULL; 
     315    if(!strcmp(tok, "check")) return NULL;  /* These two paths */ 
     316    if(!strcmp(tok, "config")) return NULL; /* are off limits. */ 
     317    for (tmp = start->children; tmp; tmp = tmp->next) { 
     318      if(!strcmp((char *)tmp->name, tok)) break; 
     319    } 
     320    if(!tmp) { 
     321      tmp = xmlNewNode(NULL, (xmlChar *)tok); 
     322      xmlAddChild(start, tmp); 
     323    } 
     324    start = tmp; 
     325  } 
     326  return start; 
     327} 
     328static int 
     329rest_set_check(noit_http_rest_closure_t *restc, 
     330               int npats, char **pats) { 
     331  noit_http_session_ctx *ctx = restc->http_ctx; 
     332  xmlXPathObjectPtr pobj = NULL; 
     333  xmlXPathContextPtr xpath_ctxt = NULL; 
     334  xmlDocPtr doc = NULL, indoc = NULL; 
     335  xmlNodePtr node, root, attr, config, parent; 
     336  uuid_t checkid; 
     337  noit_check_t *check; 
     338  char xpath[1024], *uuid_conf; 
     339  int rv, cnt; 
     340  const char *error = "internal error"; 
     341  noit_boolean exists = noit_false; 
     342  struct rest_xml_payload *rxc; 
     343 
     344  if(npats != 2) goto error; 
     345 
     346#define FAIL(a) do { error = (a); goto error; } while(0) 
     347 
     348  if(restc->call_closure == NULL) { 
     349    rxc = restc->call_closure = calloc(1, sizeof(*rxc)); 
     350    restc->call_closure_free = rest_xml_payload_free; 
     351  } 
     352  rxc = restc->call_closure; 
     353  while(!rxc->complete) { 
     354    int len, mask; 
     355    if(rxc->len == rxc->allocd) { 
     356      char *b; 
     357      rxc->allocd += 32768; 
     358      b = rxc->buffer ? realloc(rxc->buffer, rxc->allocd) : 
     359                        malloc(rxc->allocd); 
     360      if(!b) FAIL("alloc failed"); 
     361      rxc->buffer = b; 
     362    } 
     363    len = noit_http_session_req_consume(restc->http_ctx, 
     364                                        rxc->buffer + rxc->len, 
     365                                        rxc->allocd - rxc->len, 
     366                                        &mask); 
     367    if(len > 0) rxc->len += len; 
     368    if(len < 0 && errno == EAGAIN) return mask; 
     369    if(rxc->len == restc->http_ctx->req.content_length) rxc->complete = 1; 
     370  } 
     371 
     372  indoc = xmlParseMemory(rxc->buffer, rxc->len); 
     373  if(indoc == NULL) FAIL("xml parse error"); 
     374  if(!validate_check_post(indoc, &attr, &config)) FAIL("xml validate error"); 
     375 
     376  if(uuid_parse(pats[1], checkid)) goto error; 
     377  check = noit_poller_lookup(checkid); 
     378  if(check) 
     379    exists = noit_true; 
     380 
     381  rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]); 
     382  if(rv == 0) FAIL("uuid not valid"); 
     383  if(rv < 0) FAIL("Tricky McTrickster... No"); 
     384 
     385  noit_conf_xml_xpath(NULL, &xpath_ctxt); 
     386  pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); 
     387  if(!pobj || pobj->type != XPATH_NODESET || 
     388     xmlXPathNodeSetIsEmpty(pobj->nodesetval)) { 
     389    if(exists) FAIL("uuid not yours"); 
     390    else { 
     391      char *target = NULL, *name = NULL, *module = NULL; 
     392      noit_module_t *m; 
     393      xmlNodePtr newcheck, a; 
     394      /* make sure this isn't a dup */ 
     395      for(a = attr; a; a = a->next) { 
     396        if(!strcmp((char *)a->name, "target")) 
     397          target = (char *)xmlNodeGetContent(a); 
     398        if(!strcmp((char *)a->name, "name")) 
     399          name = (char *)xmlNodeGetContent(a); 
     400        if(!strcmp((char *)a->name, "module")) 
     401          module = (char *)xmlNodeGetContent(a); 
     402      } 
     403      exists = (noit_poller_lookup_by_name(target, name) != NULL); 
     404      m = noit_module_lookup(module); 
     405      xmlFree(target); 
     406      xmlFree(name); 
     407      xmlFree(module); 
     408      if(exists) FAIL("target`name already registered"); 
     409      if(!m) FAIL("module does not exist"); 
     410      /* create a check here */ 
     411      newcheck = xmlNewNode(NULL, (xmlChar *)"check"); 
     412      xmlSetProp(newcheck, (xmlChar *)"uuid", (xmlChar *)pats[1]); 
     413      configure_xml_check(newcheck, attr, config); 
     414      parent = make_conf_path(pats[0]); 
     415      if(!parent) FAIL("invalid path"); 
     416      xmlAddChild(parent, newcheck); 
     417    } 
     418  } 
     419  if(exists) { 
     420    int module_change; 
     421    char *target, *name, *module; 
     422    xmlNodePtr a; 
     423    noit_check_t *ocheck; 
     424    cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); 
     425    if(cnt != 1) FAIL("internal error, |checkid| > 1"); 
     426    node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); 
     427    uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); 
     428    if(!uuid_conf || strcasecmp(uuid_conf, pats[1])) 
     429      FAIL("internal error uuid"); 
     430    /* update check here */ 
     431 
     432    /* make sure this isn't a dup */ 
     433    for(a = attr; a; a = a->next) { 
     434      if(!strcmp((char *)a->name, "target")) 
     435        target = (char *)xmlNodeGetContent(a); 
     436      if(!strcmp((char *)a->name, "name")) 
     437        name = (char *)xmlNodeGetContent(a); 
     438      if(!strcmp((char *)a->name, "module")) 
     439        module = (char *)xmlNodeGetContent(a); 
     440    } 
     441    ocheck = noit_poller_lookup_by_name(target, name); 
     442    module_change = strcmp(check->module, module); 
     443    xmlFree(target); 
     444    xmlFree(name); 
     445    xmlFree(module); 
     446    if(ocheck && ocheck != check) FAIL("new target`name would collide"); 
     447    if(module_change) FAIL("cannot change module"); 
     448    configure_xml_check(node, attr, config); 
     449    parent = make_conf_path(pats[0]); 
     450    if(!parent) FAIL("invalid path"); 
     451    xmlUnlinkNode(node); 
     452    xmlAddChild(parent, node); 
     453  } 
     454 
     455  noit_conf_mark_changed(); 
     456  noit_poller_reload(xpath); 
     457  if(restc->call_closure_free) restc->call_closure_free(restc->call_closure); 
     458  restc->call_closure_free = NULL; 
     459  restc->call_closure = NULL; 
     460  if(pobj) xmlXPathFreeObject(pobj); 
     461  if(doc) xmlFreeDoc(doc); 
     462  if(indoc) xmlFreeDoc(indoc); 
     463  restc->fastpath = rest_show_check; 
     464  return restc->fastpath(restc, restc->nparams, restc->params); 
     465 
     466 error: 
     467  noit_http_response_server_error(ctx, "text/xml"); 
     468  doc = xmlNewDoc((xmlChar *)"1.0"); 
     469  root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL); 
     470  xmlDocSetRootElement(doc, root); 
     471  xmlNodeAddContent(root, (xmlChar *)error); 
     472  noit_http_response_xml(ctx, doc); 
     473  noit_http_response_end(ctx); 
     474  goto cleanup; 
     475 
     476 cleanup: 
     477  if(pobj) xmlXPathFreeObject(pobj); 
     478  if(doc) xmlFreeDoc(doc); 
     479  if(indoc) xmlFreeDoc(indoc); 
     480  return 0; 
     481} 
     482 
    221483void 
    222484noit_check_rest_init() { 
     
    224486    "GET", 
    225487    "/checks/", 
    226     "^show(/.*)(?<=/)([0-9a-fA-F]{4}(?:[0-9a-fA-F]{4}-){4}[0-9a-fA-F]{12})$", 
    227     rest_host_check 
     488    "^show(/.*)(?<=/)(" UUID_REGEX ")$", 
     489    rest_show_check 
    228490  ) == 0); 
    229 
    230  
     491  assert(noit_http_rest_register( 
     492    "POST", 
     493    "/checks/", 
     494    "^set(/.*)(?<=/)(" UUID_REGEX ")$", 
     495    rest_set_check 
     496  ) == 0); 
     497
     498 
  • src/noit_rest.c

    r0256945 r914f047  
    156156    free(restc->params); 
    157157  } 
     158  if(restc->call_closure_free) restc->call_closure_free(restc->call_closure); 
     159  restc->call_closure_free = NULL; 
     160  restc->call_closure = NULL; 
    158161  restc->nparams = 0; 
    159162  restc->params = NULL; 
     
    163166noit_http_rest_closure_free(noit_http_rest_closure_t *restc) { 
    164167  free(restc->remote_cn); 
    165   noit_http_rest_clean_request(restc); 
     168  noit_http_rest_clean_request(restc); 
    166169  free(restc); 
    167170} 
  • src/noit_rest.h

    r0256945 r914f047  
    5454  char **params; 
    5555  int wants_shutdown; 
     56  void *call_closure; 
     57  void (*call_closure_free)(void *); 
    5658}; 
    5759