/******************************************************************** * 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 */