/******************************************************************** * FUNCTION yangapi_free_rcb * * Free a YANGAPI control block * * INPUTS: * rcb == Yuma REST-API control block to free * RETURNS: * none *********************************************************************/ void yangapi_free_rcb (yangapi_cb_t *rcb) { if (rcb == NULL) { return; } while (!dlq_empty(&rcb->paramQ)) { yangapi_param_t *param = (yangapi_param_t *)dlq_deque(&rcb->paramQ); if (param) { yangapi_free_param(param); } } yangapi_clean_keyvalQ(rcb); m__free(rcb->accept); m__free(rcb->request_method); m__free(rcb->request_uri); xpath_free_pcb(rcb->request_xpath); xpath_free_result(rcb->request_xpath_result); xpath_free_pcb(rcb->query_select_xpath); xpath_free_result(rcb->query_select_xpath_result); xpath_free_pcb(rcb->query_test_xpath); xpath_free_result(rcb->query_test_xpath_result); m__free(rcb->content_type); m__free(rcb->content_length); m__free(rcb->if_modified_since); m__free(rcb->if_unmodified_since); m__free(rcb->if_match); m__free(rcb->if_none_match); m__free(rcb); } /* yangapi_free_rcb */
/******************************************************************** * FUNCTION agt_cfg_free_commit_test * * Free a previously malloced agt_cfg_commit_test_t struct * * INPUTS: * commit_test == commit test record to free * *********************************************************************/ void agt_cfg_free_commit_test (agt_cfg_commit_test_t *commit_test) { if (commit_test == NULL) { return; } if (commit_test->objpcb) { xpath_free_pcb(commit_test->objpcb); } if (commit_test->result) { xpath_free_result(commit_test->result); } m__free(commit_test); } /* agt_cfg_free_commit_test */
/******************************************************************** * FUNCTION get_all_attrs * * Copy all the attributes from the current node to * the xml_attrs_t queue * * INPUTS: * scb == session control block * errnode == element node to use for reporting errors * msghdr == msg hdr w/ Q to get any rpc-errors as found, * NULL if not used * nserr == TRUE if unknown namespace should cause the * function to fail and the attr not to be saved * This is the normal mode. * == FALSE and the namespace will be marked INVALID * but an error will not be returned * * OUTPUTS: * attrs Q contains 0 or more entries * *msghdr.errQ may have rpc-errors added to it * * RETURNS: * status of the operation * returns NO_ERR if all copied okay or even zero copied *********************************************************************/ static status_t get_all_attrs (ses_cb_t *scb, xml_node_t *errnode, xml_attrs_t *attrs, ncx_layer_t layer, xml_msg_hdr_t *msghdr, boolean nserr) { /* check the attribute count first */ int cnt = xmlTextReaderAttributeCount(scb->reader); if (cnt==0) { return NO_ERR; } const xmlChar *name = NULL; status_t res = NO_ERR; boolean xpatherror = FALSE; int ret = 0; /* move through the list of attributes */ int i = 0; boolean done = FALSE; for (; i < cnt && !done; i++) { xmlChar *value = NULL; const xmlChar *badns = NULL; uint32 plen = 0; xmlns_id_t nsid = 0; res = NO_ERR; name = NULL; /* get the next attribute */ if (i==0) { ret = xmlTextReaderMoveToFirstAttribute(scb->reader); } else { ret = xmlTextReaderMoveToNextAttribute(scb->reader); } if (ret != 1) { res = ERR_XML_READER_INTERNAL; done = TRUE; } else { /* get the attribute name */ name = xmlTextReaderConstName(scb->reader); if (!name) { res = ERR_XML_READER_NULLNAME; } else { res = xml_check_ns(scb->reader, name, &nsid, &plen, &badns); if (!nserr && res != NO_ERR) { /* mask invalid namespace as requested */ nsid = xmlns_inv_id(); plen = 0; res = NO_ERR; } /* get the attribute value even if a NS error */ value = xmlTextReaderValue(scb->reader); if (!value) { res = ERR_XML_READER_NULLVAL; } else { /* save the values as received, may be QName * only error that can occur is a malloc fail */ xml_attr_t *attr = xml_add_qattr(attrs, nsid, name, plen, value, &res); if (!attr) { res = ERR_INTERNAL_MEM; } else { /* special hack: do not know which * attributes within an XML node * are tagged as XPath strings at this point * To save resources, only the 'select' and * 'key' attributes are supported at this time. */ if (!xml_strcmp(&name[plen], NCX_EL_SELECT)) { res = NO_ERR; attr->attr_xpcb = agt_new_xpath_pcb(scb, value, &res); if (!attr->attr_xpcb) { ; /* res already set */ } else { /* do a first pass parsing to resolve all * the prefixes and check well-formed XPath */ xpath_result_t *result = xpath1_eval_xmlexpr(scb->reader, attr->attr_xpcb, NULL, NULL, FALSE, FALSE, &res); if (res != NO_ERR) { xpatherror = TRUE; } xpath_free_result(result); } } else if (!xml_strcmp(&name[plen], NCX_EL_KEY)) { res = NO_ERR; attr->attr_xpcb = agt_new_xpath_pcb(scb, value, &res); if (!attr->attr_xpcb) { ; /* res already set */ } else { res = xpath_yang_validate_xmlkey (scb->reader, attr->attr_xpcb, NULL, FALSE); if (res != NO_ERR) { xpatherror = TRUE; } } } } } } } /* check the result */ if (res != NO_ERR && msghdr) { /* need a dummy attribute struct to report this error */ xml_attr_t errattr; memset(&errattr, 0x0, sizeof(xml_attr_t)); errattr.attr_ns = xmlns_nc_id(); errattr.attr_qname = name; errattr.attr_name = name; errattr.attr_val = value; /* save the error info */ if (xpatherror) { res = ERR_NCX_INVALID_XPATH_EXPR; /* generate an invalid-value error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, NULL, NCX_NT_NONE, NULL); } else if (res==ERR_XML_READER_NULLVAL || res==ERR_NCX_UNKNOWN_NAMESPACE) { /* generate a bad namespace error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, badns, NCX_NT_NONE, NULL); } else { /* generate a generic error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, NULL, NCX_NT_NONE, NULL); } } if (value) { xmlFree(value); } } /* reset the current node to where we started */ ret = xmlTextReaderMoveToElement(scb->reader); if (ret != 1) { if (msghdr) { res = ERR_XML_READER_INTERNAL; agt_record_error(scb, msghdr, layer, res, errnode, NCX_NT_STRING, name, NCX_NT_NONE, NULL); } } return res; } /* get_all_attrs */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_lock_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; cfg_template_t *running; val_value_t *select_val, *testval; xpath_result_t *result; xpath_resnode_t *resnode; status_t res, retres; ses_id_t lockowner; res = NO_ERR; retres = NO_ERR; plcb = NULL; result = NULL; running = cfg_get_config_id(NCX_CFGID_RUNNING); /* make sure the running config state is READY */ res = cfg_ok_to_partial_lock(running); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); return res; } /* the stack has already made sure at least 1 of these * is present because min-elements=1 */ select_val = val_find_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select); if (select_val == NULL || select_val->res != NO_ERR) { /* should not happen */ return SET_ERROR(ERR_INTERNAL_VAL); } /* allocate a new lock cb * the plcb pointer will be NULL if the result is not NO_ERR */ res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); if (res == ERR_NCX_RESOURCE_DENIED && !plcb && !cfg_is_partial_locked(running)) { /* no partial locks so it is safe to reset the lock index */ plock_cb_reset_id(); res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); } if (res != NO_ERR || !plcb ) { if ( res==NO_ERR && !plcb ) { res = ERR_INTERNAL_MEM; } agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); if ( plcb ) { plock_cb_free(plcb); } return res; } /* get all the select parm instances and save them * in the partial lock cb */ while (select_val != NULL) { result = xpath1_eval_xmlexpr(scb->reader, select_val->xpathpcb, running->root, running->root, FALSE, /* logerrors */ TRUE, /* config-only */ &res); if (result == NULL || res != NO_ERR) { /* should not get invalid XPath expression * but maybe something was valid in the * object tree but not in the value tree */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else if (result->restype != XP_RT_NODESET) { res = ERR_NCX_XPATH_NOT_NODESET; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else { /* save these pointers; the result will be * pruned for redundant nodes after all the * select expressions have been processed; * transfer the memory straight across */ plock_add_select(plcb, select_val->xpathpcb, result); select_val->xpathpcb = NULL; result = NULL; } /* set up the next select value even if errors so far */ select_val = val_find_next_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select, select_val); } /* check the result for non-empty only if all * the select stmts were valid */ if (retres == NO_ERR) { res = plock_make_final_result(plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, select_val); retres = res; } } /* make sure all the nodeptrs identify subtrees in the * running config that can really be locked right now * only if the final result is a non-empty nodeset */ if (retres == NO_ERR) { result = plock_get_final_result(plcb); for (resnode = xpath_get_first_resnode(result); resnode != NULL; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); /* !!! Update 2011-09-27 * Just talked to the RFC author; Martin and I * agree RFC 5717 does not specify that write * access be required to create a partial lock * In fact -- a user may want to lock a node * to do a stable read **** deleted agt_acm check ***/ /* make sure there is a plock slot available * and no part of this subtree is already locked * do not check lock conflicts if this subtree * is unauthorized for writing */ lockowner = 0; res = val_ok_to_partial_lock(testval, SES_MY_SID(scb), &lockowner); if (res != NO_ERR) { if (res == ERR_NCX_LOCK_DENIED) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_UINT32_PTR, &lockowner, NCX_NT_VAL, testval); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } retres = res; } } // for loop } // if retres == NO_ERR /* make sure there is no partial commit in progress */ if (agt_ncx_cc_active()) { res = ERR_NCX_IN_USE_COMMIT; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); retres = res; } /* save the plock CB only if there were no errors; * otherwise the invoke function will not get called */ if (retres == NO_ERR) { /* the invoke function must free this pointer */ msg->rpc_user1 = plcb; } else { plock_cb_free(plcb); } return retres; } /* y_ietf_netconf_partial_lock_partial_lock_validate */
/******************************************************************** * FUNCTION do_elif (local RPC) * * Handle the if command; start a new ifcb context * * elif expr='xpath-str' [docroot=$foo] * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * isif == TRUE for if, FALSE for elif * RETURNS: * status *********************************************************************/ static status_t do_if_elif (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len, boolean isif) { val_value_t *valset, *docroot, *expr, *dummydoc; xpath_pcb_t *pcb; xpath_result_t *result; status_t res; boolean cond; docroot = NULL; expr = NULL; pcb = NULL; dummydoc = NULL; cond = FALSE; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset == NULL) { return res; } if (res != NO_ERR) { val_free_value(valset); return res; } if (valset->res != NO_ERR) { res = valset->res; val_free_value(valset); return res; } /* get the expr parameter */ expr = val_find_child(valset, YANGCLI_MOD, YANGCLI_EXPR); if (expr == NULL) { res = ERR_NCX_MISSING_PARM; } else if (expr->res != NO_ERR) { res = expr->res; } if (res == NO_ERR) { /* get the optional docroot parameter */ docroot = val_find_child(valset, YANGCLI_MOD, YANGCLI_DOCROOT); if (docroot && docroot->res != NO_ERR) { res = docroot->res; } } if (res == NO_ERR && docroot == NULL) { dummydoc = xml_val_new_struct(NCX_EL_DATA, xmlns_nc_id()); if (dummydoc == NULL) { res = ERR_INTERNAL_MEM; } else { docroot = dummydoc; } } if (res == NO_ERR) { /* got all the parameters, and setup the XPath control block */ pcb = xpath_new_pcb_ex(VAL_STR(expr), xpath_getvar_fn, server_cb->runstack_context); if (pcb == NULL) { res = ERR_INTERNAL_MEM; } else if ((isif && runstack_get_cond_state(server_cb->runstack_context)) || (!isif && !runstack_get_if_used(server_cb->runstack_context))) { /* figure out if this if or elif block is enabled or not */ result = xpath1_eval_expr(pcb, docroot, /* context */ docroot, TRUE, FALSE, &res); if (result != NULL && res == NO_ERR) { /* get new condition state for this loop */ cond = xpath_cvt_boolean(result); } xpath_free_result(result); } if (res == NO_ERR) { if (isif) { res = runstack_handle_if(server_cb->runstack_context, cond); } else { res = runstack_handle_elif(server_cb->runstack_context, cond); } } } /* cleanup and exit */ if (valset) { val_free_value(valset); } if (pcb) { xpath_free_pcb(pcb); } if (dummydoc) { val_free_value(dummydoc); } return res; } /* do_if_elif */