/******************************************************************** * FUNCTION mgr_not_init * * Initialize the mgr_not module * call once to init module * Adds the mgr_not_dispatch function as the handler * for the NETCONF <rpc> top-level element. * * INPUTS: * none * RETURNS: * NO_ERR if all okay, the minimum spare requests will be malloced *********************************************************************/ status_t mgr_not_init (void) { if (mgr_not_init_done) { return ERR_INTERNAL_INIT_SEQ; } /* get the notification template */ notification_obj = NULL; callbackfn = NULL; ncx_module_t *mod = ncx_find_module(NCN_MODULE, NULL); if (mod == NULL) { return ERR_NCX_MOD_NOT_FOUND; } notification_obj = ncx_find_object(mod, NCX_EL_NOTIFICATION); if (notification_obj == NULL) { return ERR_NCX_DEF_NOT_FOUND; } status_t res = top_register_node(NCN_MODULE, NCX_EL_NOTIFICATION, mgr_not_dispatch); if (res != NO_ERR) { return res; } mgr_not_init_done = TRUE; return NO_ERR; } /* mgr_not_init */
/******************************************************************** * FUNCTION agt_cap_set_modules * * Initialize the NETCONF agent capabilities modules list * MUST call after agt_cap_set_caps * * INPUTS: * profile == agent profile control block to use * * RETURNS: * status *********************************************************************/ status_t agt_cap_set_modules (agt_profile_t *profile) { if (!agt_caps || !my_agt_caps) { return SET_ERROR(ERR_INTERNAL_INIT_SEQ); } /* add the ietf-netconf module first */ status_t res = cap_add_netconf_modval(agt_caps); if (res != NO_ERR) { log_error("\nError: could not add ietf-netconf " "capability val (%s)\n", get_error_string(res)); return res; } ncx_module_t *mod = ncx_get_first_module(); /* add capability for each module loaded in ncxmod */ while (mod && res == NO_ERR) { /* keep internal modules out of the capabilities */ if (agt_advertise_module_needed(mod->name)) { res = cap_add_modval(agt_caps, mod); if (res == NO_ERR) { res = cap_add_mod(my_agt_caps, mod); } } mod = (ncx_module_t *)dlq_nextEntry(mod); } /* add capability for each deviation module, not already * listed in the module capabilities so far */ ncx_save_deviations_t *savedev; for (savedev = (ncx_save_deviations_t *) dlq_firstEntry(&profile->agt_savedevQ); savedev != NULL && res == NO_ERR; savedev = (ncx_save_deviations_t *) dlq_nextEntry(savedev)) { if (agt_advertise_module_needed(savedev->devmodule)) { /* make sure this is not a hard-wired internal module * or a duplicate already loaded as a regular module */ mod = ncx_find_module(savedev->devmodule, savedev->devrevision); if (mod == NULL) { /* not already announced in the capabilities */ res = cap_add_devmodval(agt_caps, savedev); } } } return res; } /* agt_cap_set_modules */
/******************************************************************** * FUNCTION ncx_feature_enabled_str * * Check if the specified feature and any referenced * if-features are enabled * * INPUTS: * modname == name of module to search * revision == module revision string (may be NULL) * name == feature name to find * RETURNS: * TRUE if feature is completely enabled * FALSE if feature is not enabled, or partially enabled *********************************************************************/ boolean ncx_feature_enabled_str (const xmlChar *modname, const xmlChar *revision, const xmlChar *name) { #ifdef DEBUG if (!modname || !name) { SET_ERROR(ERR_INTERNAL_PTR); return FALSE; } #endif ncx_module_t *mod = ncx_find_module(modname, revision); if (mod == NULL) { return FALSE; } const ncx_feature_t *feature = ncx_find_feature(mod, name); if (feature == NULL) { return FALSE; } return ncx_feature_enabled(feature); } /* ncx_feature_enabled_str */
/******************************************************************** * FUNCTION help_program_module * * Print the full help text for an entire program module to STDOUT * * INPUTS: * modname == module name without file suffix * cliname == name of CLI parmset within the modname module * *********************************************************************/ void help_program_module (const xmlChar *modname, const xmlChar *cliname, help_mode_t mode) { ncx_module_t *mod; obj_template_t *cli; uint32 nestlevel; help_mode_t usemode; #ifdef DEBUG if (!modname) { SET_ERROR(ERR_INTERNAL_PTR); return; } if (mode == HELP_MODE_NONE || mode > HELP_MODE_FULL) { SET_ERROR(ERR_INTERNAL_VAL); return; } #endif nestlevel = get_nestlevel(mode); mod = ncx_find_module(modname, NULL); if (!mod) { log_error("\nhelp: Module '%s' not found", modname); SET_ERROR(ERR_NCX_MOD_NOT_FOUND); return; } log_stdout("\n\n Program %s", mod->name); log_stdout("\n\n Usage:"); log_stdout("\n\n %s [parameters]", mod->name); if (mode != HELP_MODE_BRIEF) { log_stdout("\n\n Parameters can be entered in any order, and have "); log_stdout("the form:"); log_stdout("\n\n [start] name separator [value]"); log_stdout("\n\n where:"); log_stdout("\n\n start == 0, 1, or 2 dashes (foo, -foo, --foo)"); log_stdout("\n\n name == parameter name (foo)" "\n\n Parameter name completion " "will be attempted " "\n if a partial name is entered."); log_stdout("\n\n separator == whitespace or equals sign " "(foo=bar, foo bar)"); log_stdout("\n\n value == string value for the parameter"); log_stdout("\n\n Strings with whitespace need to be " "double quoted." "\n (--foo=\"some string\")"); } if (mode == HELP_MODE_FULL && mod->descr) { log_stdout("\n\n Description:"); help_write_lines(mod->descr, 4, TRUE); } if (cliname) { cli = ncx_find_object(mod, cliname); if (!cli) { log_error("\nhelp: CLI Object %s not found", cliname); SET_ERROR(ERR_NCX_DEF_NOT_FOUND); return; } else if (cli->objtype == OBJ_TYP_CONTAINER) { log_stdout("\n\n Command Line Parameters"); log_stdout("\n\n Key: parm-name [built-in-type] [d:default]\n"); if (mode == HELP_MODE_BRIEF) { usemode = HELP_MODE_NORMAL; } else { usemode = HELP_MODE_FULL; } obj_dump_datadefQ(obj_get_datadefQ(cli), usemode, nestlevel, 4); log_stdout("\n"); } } if (obj_any_rpcs(&mod->datadefQ) && mode == HELP_MODE_FULL) { log_stdout("\n\n Local Commands\n"); dump_rpcQ(&mod->datadefQ, mode, 4); } } /* help_program_module */
/******************************************************************** * FUNCTION mgr_hello_dispatch * * Handle an incoming <hello> message from the client * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void mgr_hello_dispatch (ses_cb_t *scb, xml_node_t *top) { val_value_t *val; ncx_module_t *mod; obj_template_t *obj; mgr_scb_t *mscb; xml_msg_hdr_t msg; status_t res; #ifdef DEBUG if (!scb || !top) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif #ifdef MGR_HELLO_DEBUG if (LOGDEBUG) { log_debug("\nmgr_hello got node"); } if (LOGDEBUG2) { xml_dump_node(top); } #endif mscb = mgr_ses_get_mscb(scb); /* only process this message in hello wait state */ if (scb->state != SES_ST_HELLO_WAIT) { /* TBD: stats update */ if (LOGINFO) { log_info("\nmgr_hello dropped, wrong state for session %d", scb->sid); } return; } /* init local vars */ res = NO_ERR; val = NULL; obj = NULL; xml_msg_init_hdr(&msg); /* get a value struct to hold the server hello msg */ val = val_new_value(); if (!val) { res = ERR_INTERNAL_MEM; } /* get the type definition from the registry */ if (res == NO_ERR) { mod = ncx_find_module(NC_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, MGR_SERVER_HELLO_OBJ); } if (!obj) { /* netconf module should have loaded this definition */ res = SET_ERROR(ERR_INTERNAL_PTR); } } /* parse an server hello message */ if (res == NO_ERR) { res = mgr_val_parse(scb, obj, top, val); } /* examine the server capability list * and it matches the server protocol version */ if (res == NO_ERR) { res = process_server_hello(scb, val); } /* report first error and close session */ if (res != NO_ERR) { if (LOGINFO) { log_info("\nmgr_connect error (%s)\n dropping session %u (a:%u)", get_error_string(res), scb->sid, mscb->agtsid, res); } } else { scb->state = SES_ST_IDLE; if (LOGDEBUG) { log_debug("\nmgr_hello manager hello ok"); } } if (val) { val_free_value(val); } } /* mgr_hello_dispatch */
/******************************************************************** * FUNCTION agt_hello_dispatch * * Handle an incoming <hello> message from the client * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void agt_hello_dispatch (ses_cb_t *scb, xml_node_t *top) { assert( scb && "scb is NULL!" ); assert( top && "top is NULL!" ); if (LOGDEBUG2) { log_debug2("\nagt_hello: got node"); if (LOGDEBUG3) { xml_dump_node(top); } } /* only process this message in hello wait state */ if (scb->state != SES_ST_HELLO_WAIT) { log_info("\nagt_hello dropped, wrong state " "(%d) for session %d", scb->state, scb->sid); mytotals->inBadHellos++; mytotals->droppedSessions++; agt_ses_request_close(scb, scb->sid, SES_TR_BAD_HELLO); return; } /* init local vars */ status_t res = NO_ERR; obj_template_t *obj = NULL; xml_msg_hdr_t msg; xml_msg_init_hdr(&msg); /* get a value struct to hold the client hello msg */ val_value_t *val = val_new_value(); if (!val) { res = ERR_INTERNAL_MEM; } /* get the type definition from the registry */ if (res == NO_ERR) { ncx_module_t *mod = ncx_find_module(NC_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, CLIENT_HELLO_CON); } if (!obj) { /* netconf module should have loaded this definition */ res = SET_ERROR(ERR_INTERNAL_PTR); } } /* parse a manager hello message */ if (res == NO_ERR) { res = agt_val_parse_nc(scb, &msg, obj, top, NCX_DC_STATE, val); } /* check that the NETCONF base capability is included * and it matches the server protocol version */ if (res == NO_ERR) { res = check_manager_hello(scb, val); } /* report first error and close session */ if (res != NO_ERR) { if (LOGINFO) { log_info("\nagt_connect error (%s), dropping session %d", get_error_string(res), scb->sid); } mytotals->inBadHellos++; mytotals->droppedSessions++; agt_ses_request_close(scb, scb->sid, SES_TR_BAD_HELLO); } else { scb->state = SES_ST_IDLE; scb->active = TRUE; /* start the timer for the first rpc request */ (void)time(&scb->last_rpc_time); if (LOGDEBUG) { log_debug("\nSession %d for %s@%s now active", scb->sid, scb->username, scb->peeraddr); if (ses_get_protocol(scb) == NCX_PROTO_NETCONF11) { log_debug_append(" (base:1.1)"); } else { log_debug_append(" (base:1.0)"); } } } if (val) { val_free_value(val); } } /* agt_hello_dispatch */
/******************************************************************** * FUNCTION agt_cli_process_input * * Process the param line parameters against the hardwired * parmset for the netconfd program * * INPUTS: * argc == argument count * argv == array of command line argument strings * agt_profile == agent profile struct to fill in * showver == address of version return quick-exit status * showhelpmode == address of help return quick-exit status * * OUTPUTS: * *agt_profile is filled in, with parms gathered or defaults * *showver == TRUE if user requsted version quick-exit mode * *showhelpmode == requested help mode * (none, breief, normal, full) * * RETURNS: * NO_ERR if all goes well *********************************************************************/ status_t agt_cli_process_input (int argc, char *argv[], agt_profile_t *agt_profile, boolean *showver, help_mode_t *showhelpmode) { ncx_module_t *mod; obj_template_t *obj; val_value_t *valset, *val; FILE *fp; status_t res; boolean test; #ifdef DEBUG if (!argv || !agt_profile || !showver || !showhelpmode) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif *showver = FALSE; *showhelpmode = HELP_MODE_NONE; /* find the parmset definition in the registry */ obj = NULL; mod = ncx_find_module(AGT_CLI_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, AGT_CLI_CONTAINER); } if (!obj) { log_error("\nError: netconfd module with CLI definitions not loaded"); return ERR_NCX_NOT_FOUND; } /* parse the command line against the object template */ res = NO_ERR; valset = NULL; if (argc > 0) { valset = cli_parse(NULL, argc, argv, obj, FULLTEST, PLAINMODE, TRUE, CLI_MODE_PROGRAM, &res); if (res != NO_ERR) { if (valset) { val_free_value(valset); } return res; } } if (valset != NULL) { /* transfer the parmset values */ set_server_profile(valset, agt_profile); /* next get any params from the conf file */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_CONFIG); if (val) { if (val->res == NO_ERR) { /* try the specified config location */ agt_profile->agt_conffile = VAL_STR(val); res = conf_parse_val_from_filespec(VAL_STR(val), valset, TRUE, TRUE); if (res != NO_ERR) { val_free_value(valset); return res; } else { /* transfer the parmset values again */ set_server_profile(valset, agt_profile); } } } else { fp = fopen((const char *)AGT_DEF_CONF_FILE, "r"); if (fp != NULL) { fclose(fp); /* use default config location */ res = conf_parse_val_from_filespec(AGT_DEF_CONF_FILE, valset, TRUE, TRUE); if (res != NO_ERR) { val_free_value(valset); return res; } else { /* transfer the parmset values again */ set_server_profile(valset, agt_profile); } } } /* set the logging control parameters */ val_set_logging_parms(valset); /* audit-log-append param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_AUDIT_LOG_APPEND); if (val && val->res == NO_ERR) { test = TRUE; } else { test = FALSE; } /* audit-log param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_AUDIT_LOG); if (val && val->res == NO_ERR) { xmlChar *filespec = ncx_get_source(VAL_STR(val), &res); if (filespec == NULL) { log_error("\nError: get source for audit log failed"); return res; } res = log_audit_open((const char *)filespec, test, TRUE); if (res == NO_ERR) { if (LOGDEBUG) { log_debug("\nAudit log '%s' opened for %s", filespec, (test) ? "append" : "write"); } } else { log_error("\nError: open audit log '%s' failed", filespec); } m__free(filespec); if (res != NO_ERR) { return res; } } /* set the file search path parms */ res = val_set_path_parms(valset); if (res != NO_ERR) { return res; } /* set the warning control parameters */ res = val_set_warning_parms(valset); if (res != NO_ERR) { return res; } /* set the feature code generation parameters */ res = val_set_feature_parms(valset); if (res != NO_ERR) { return res; } /* check the subdirs parameter */ res = val_set_subdirs_parm(valset); if (res != NO_ERR) { return res; } /* check the protocols parameter */ res = val_set_protocols_parm(valset); if (res != NO_ERR) { return res; } /* check the system-sorted param */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_SYSTEM_SORTED); if (val && val->res == NO_ERR) { agt_profile->agt_system_sorted = VAL_BOOL(val); } /* version param handled externally */ /* check if version mode requested */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_VERSION); *showver = (val) ? TRUE : FALSE; /* check if help mode requested */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_HELP); if (val) { *showhelpmode = HELP_MODE_NORMAL; /* help submode parameter (brief/normal/full) */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_BRIEF); if (val) { *showhelpmode = HELP_MODE_BRIEF; } else { /* full parameter */ val = val_find_child(valset, AGT_CLI_MODULE, NCX_EL_FULL); if (val) { *showhelpmode = HELP_MODE_FULL; } } } } /* cleanup and exit * handoff the malloced 'valset' memory here */ cli_val = valset; return res; } /* agt_cli_process_input */
/******************************************************************** * FUNCTION mgr_rpc_dispatch * * Dispatch an incoming <rpc-reply> response * handle the <rpc-reply> element * called by mgr_top.c: * This function is registered with top_register_node * for the module 'netconf', top-node 'rpc-reply' * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void mgr_rpc_dispatch (ses_cb_t *scb, xml_node_t *top) { obj_template_t *rpyobj; mgr_rpc_rpy_t *rpy; mgr_rpc_req_t *req; xml_attr_t *attr; xmlChar *msg_id; ncx_module_t *mod; mgr_rpc_cbfn_t handler; ncx_num_t num; status_t res; #ifdef DEBUG if (!scb || !top) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif /* init local vars */ res = NO_ERR; msg_id = NULL; req = NULL; /* make sure any real session has been properly established */ if (scb->type != SES_TYP_DUMMY && scb->state != SES_ST_IDLE) { log_error("\nError: mgr_rpc: skipping incoming message '%s'", top->qname); mgr_xml_skip_subtree(scb->reader, top); return; } /* check if the reply template is already cached */ rpyobj = NULL; mod = ncx_find_module(NC_MODULE, NULL); if (mod != NULL) { rpyobj = ncx_find_object(mod, NC_RPC_REPLY_TYPE); } if (rpyobj == NULL) { SET_ERROR(ERR_NCX_DEF_NOT_FOUND); mgr_xml_skip_subtree(scb->reader, top); return; } /* get the NC RPC message-id attribute; should be present * because the send-rpc function put a message-id in <rpc> */ attr = xml_find_attr(top, 0, NCX_EL_MESSAGE_ID); if (attr && attr->attr_val) { msg_id = xml_strdup(attr->attr_val); } if (msg_id == NULL) { mgr_xml_skip_subtree(scb->reader, top); log_info("\nmgr_rpc: incoming message with no message-id"); return; } /* the current node is 'rpc-reply' in the netconf namespace * First get a new RPC reply struct */ rpy = new_reply(); if (rpy == NULL) { m__free(msg_id); log_error("\nError: mgr_rpc: skipping incoming message"); mgr_xml_skip_subtree(scb->reader, top); return; } else { rpy->msg_id = msg_id; } /* get the NCX RPC group-id attribute if present */ attr = xml_find_attr(top, xmlns_ncx_id(), NCX_EL_GROUP_ID); if (attr && attr->attr_val) { res = ncx_decode_num(attr->attr_val, NCX_BT_UINT32, &num); if (res == NO_ERR) { rpy->group_id = num.u; } } /* find the request that goes with this reply */ if (rpy->msg_id != NULL) { req = find_request(scb, rpy->msg_id); if (req == NULL) { #ifdef MGR_RPC_DEBUG log_debug("\nmgr_rpc: got request found for msg (%s) " "on session %d", rpy->msg_id, scb->sid); #endif mgr_xml_skip_subtree(scb->reader, top); mgr_rpc_free_reply(rpy); return; } else { dlq_remove(req); } } /* have a request/reply pair, so parse the reply * as a val_value_t tree, stored in rpy->reply */ rpy->res = mgr_val_parse_reply(scb, rpyobj, (req != NULL) ? req->rpc : ncx_get_gen_anyxml(), top, rpy->reply); if (rpy->res != NO_ERR && LOGINFO) { log_info("\nmgr_rpc: got invalid reply on session %d (%s)", scb->sid, get_error_string(rpy->res)); } /* check that there is nothing after the <rpc-reply> element */ if (rpy->res==NO_ERR && !xml_docdone(scb->reader) && LOGINFO) { log_info("\nmgr_rpc: got extra nodes in reply on session %d", scb->sid); } /* invoke the reply handler */ if (req != NULL) { handler = (mgr_rpc_cbfn_t)req->replycb; (*handler)(scb, req, rpy); } /* only reset the session state to idle if was not changed * to SES_ST_SHUTDOWN_REQ during this RPC call */ if (scb->state == SES_ST_IN_MSG) { scb->state = SES_ST_IDLE; } #ifdef MGR_RPC_DEBUG print_errors(); clear_errors(); #endif } /* mgr_rpc_dispatch */