X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=blobdiff_plain;f=tr%2Ftr_main.c;h=73c429e58dafeedfc4e1e103d5c82ae9f7bd63eb;hp=c1bf61931bc4e3b92aec2adca793e379ff4dec18;hb=HEAD;hpb=e2ab5cedf190c113faea82dda746199b4805b6c8 diff --git a/tr/tr_main.c b/tr/tr_main.c index c1bf619..73c429e 100644 --- a/tr/tr_main.c +++ b/tr/tr_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, JANET(UK) + * Copyright (c) 2012, 2015, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,263 +33,298 @@ */ #include -#include - -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include -/* Structure to hold TR instance and original request in one cookie */ -typedef struct tr_resp_cookie { - TR_INSTANCE *tr; - TID_REQ *orig_req; -} TR_RESP_COOKIE; +#define TALLOC_DEBUG_ENABLE 1 +/***** command-line option handling / setup *****/ -static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc, - TID_REQ *req, - TID_RESP *resp, - void *resp_cookie) +static void print_version_info(void) { - fprintf(stderr, "tr_tidc_resp_handler: Response received (conn = %d)! Realm = %s, Community = %s.\n", ((TR_RESP_COOKIE *)resp_cookie)->orig_req->conn, resp->realm->buf, resp->comm->buf); - req->resp_rcvd = 1; - - /* TBD -- handle concatentation of multiple responses to single req */ - tids_send_response(((TR_RESP_COOKIE *)resp_cookie)->tr->tids, - ((TR_RESP_COOKIE *)resp_cookie)->orig_req, - resp); - - return; + printf("Moonshot Trust Router %s\n\n", PACKAGE_VERSION); } -static int tr_tids_req_handler (TIDS_INSTANCE *tids, - TID_REQ *orig_req, - TID_RESP **resp, - void *tr) -{ - TIDC_INSTANCE *tidc = NULL; - TR_RESP_COOKIE resp_cookie; - TR_AAA_SERVER *aaa_servers = NULL; - TR_NAME *apc = NULL; - TID_REQ *fwd_req = NULL; - TR_COMM *cfg_comm = NULL; - TR_COMM *cfg_apc = NULL; - TR_CONSTRAINT_SET *ocons = NULL; - int oaction = TR_FILTER_ACTION_REJECT; - int rc = 0; - - if ((!tids) || (!orig_req) || (!resp) || (!(*resp)) || (!tr)) { - fprintf(stderr, "tids_req_handler: Bad parameters\n"); - return -1; - } - - fprintf(stdout, "tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s\n", orig_req->conn, - orig_req->realm->buf, orig_req->comm->buf); - if (tids) - tids->req_count++; +/* Strip trailing / from a path name.*/ +static void remove_trailing_slash(char *s) { + size_t n; - /* Duplicate the request, so we can modify and forward it */ - if (NULL == (fwd_req = tid_dup_req(orig_req))) { - fprintf(stderr, "tr_tids_req_handler: Unable to duplicate request.\n"); - return -1; + n=strlen(s); + if(s[n-1]=='/') { + s[n-1]='\0'; } +} - if (NULL == (cfg_comm = tr_comm_lookup((TR_INSTANCE *)tids->cookie, orig_req->comm))) { - fprintf(stderr, "tr_tids_req_hander: Request for unknown comm: %s.\n", orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "Unknown community"); - return -1; +/* argp global parameters */ +const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */ + +/* doc strings */ +static const char doc[]=PACKAGE_NAME " - Moonshot Trust Router " PACKAGE_VERSION; +static const char arg_doc[]=""; /* string describing arguments, if any */ + +/* define the options here. Fields are: + * { long-name, short-name, variable name, options, help description } */ +static const struct argp_option cmdline_options[] = { + { "config-dir", 'c', "DIR", 0, "Specify configuration file location (default is current directory)"}, + { "config-validate", 'C', NULL, 0, "Validate configuration files and exit"}, + { "version", 1, NULL, 0, "Print version information and exit"}, + { NULL } +}; + +/* structure for communicating with option parser */ +struct cmdline_args { + int version_requested; + int validate_config_and_exit; + char *config_dir; +}; + +/* parser for individual options - fills in a struct cmdline_args */ +static error_t parse_option(int key, char *arg, struct argp_state *state) +{ + /* get a shorthand to the command line argument structure, part of state */ + struct cmdline_args *arguments=state->input; + + switch (key) { + case 'c': + if (arg == NULL) { + /* somehow we got called without an argument */ + return ARGP_ERR_UNKNOWN; + } + arguments->config_dir=arg; + break; + + case 1: + arguments->version_requested=1; + break; + + case 'C': + arguments->validate_config_and_exit=1; + break; + + default: + return ARGP_ERR_UNKNOWN; } - /* Check that the rp_realm matches the filter for the GSS name that - * was received. */ + return 0; /* success */ +} - if ((!((TR_INSTANCE *)tr)->rp_gss) || - (!((TR_INSTANCE *)tr)->rp_gss->filter)) { - fprintf(stderr, "tr_tids_req_handler: No GSS name for incoming request.\n"); - tids_send_err_response(tids, orig_req, "No GSS name for request"); - return -1; - } +/* assemble the argp parser */ +static struct argp argp = {cmdline_options, parse_option, arg_doc, doc}; - if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm, ((TR_INSTANCE *)tr)->rp_gss->filter, NULL, &ocons, &oaction)) || - (TR_FILTER_ACTION_REJECT == oaction)) { - fprintf(stderr, "tr_tids_req_handler: RP realm (%s) does not match RP Realm filter for GSS name\n", orig_req->rp_realm->buf); - tids_send_err_response(tids, orig_req, "RP Realm filter error"); - return -1; - } - /* TBD -- add constraints to request for further forwarding. */ +/***** talloc error handling *****/ +/* called when talloc tries to abort */ +static void tr_abort(const char *reason) +{ + tr_crit("tr_abort: Critical error, talloc aborted. Reason: %s", reason); + abort(); +} - /* Check that the rp_realm and target_realm are members of the community in the request */ - if (NULL == (tr_find_comm_rp(cfg_comm, orig_req->rp_realm))) { - fprintf(stderr, "tr_tids_req_hander: RP Realm (%s) not member of community (%s).\n", orig_req->rp_realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "RP COI membership error"); - return -1; - } - if (NULL == (tr_find_comm_idp(cfg_comm, orig_req->realm))) { - fprintf(stderr, "tr_tids_req_hander: IDP Realm (%s) not member of APC (%s).\n", orig_req->realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "IDP COI membership error"); - return -1; - } +#if TALLOC_DEBUG_ENABLE +static void tr_talloc_log(const char *msg) +{ + tr_debug("talloc: %s", msg); +} +#endif /* TALLOC_DEBUG_ENABLE */ - /* Map the comm in the request from a COI to an APC, if needed */ - if (TR_COMM_COI == cfg_comm->type) { - fprintf(stderr, "tr_tids_req_handler: Community was a COI, switching.\n"); - /* TBD -- In theory there can be more than one? How would that work? */ - if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) { - fprintf(stderr, "No valid APC for COI %s.\n", orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "No valid APC for community"); - return -1; - } - apc = tr_dup_name(cfg_comm->apcs->id); - - /* Check that the APC is configured */ - if (NULL == (cfg_apc = tr_comm_lookup((TR_INSTANCE *)tids->cookie, apc))) { - fprintf(stderr, "tr_tids_req_hander: Request for unknown comm: %s.\n", apc->buf); - tids_send_err_response(tids, orig_req, "Unknown APC"); - return -1; - } - - fwd_req->comm = apc; - fwd_req->orig_coi = orig_req->comm; - - /* Check that rp_realm and target_realm are members of this APC */ - if (NULL == (tr_find_comm_rp(cfg_apc, orig_req->rp_realm))) { - fprintf(stderr, "tr_tids_req_hander: RP Realm (%s) not member of community (%s).\n", orig_req->rp_realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "RP APC membership error"); - return -1; - } - if (NULL == (tr_find_comm_idp(cfg_apc, orig_req->realm))) { - fprintf(stderr, "tr_tids_req_hander: IDP Realm (%s) not member of APC (%s).\n", orig_req->realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "IDP APC membership error"); - return -1; - } - } +static void configure_signals(void) +{ + sigset_t signals; + /* ignore SIGPIPE */ + sigemptyset(&signals); + sigaddset(&signals, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &signals, NULL); +} - /* Find the AAA server(s) for this request */ - if (NULL == (aaa_servers = tr_idp_aaa_server_lookup((TR_INSTANCE *)tids->cookie, - orig_req->realm, - orig_req->comm))) { - fprintf(stderr, "tr_tids_req_handler: No AAA Servers for realm %s.\n", orig_req->realm->buf); - tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm"); - return -1; - } - /* send a TID request to the AAA server(s), and get the answer(s) */ - /* TBD -- Handle multiple servers */ - - /* Create a TID client instance */ - if (NULL == (tidc = tidc_create())) { - fprintf(stderr, "tr_tids_req_hander: Unable to allocate TIDC instance.\n"); - tids_send_err_response(tids, orig_req, "Memory allocation failure"); - return -1; - } +/* Monitoring handlers */ +static MON_RC tr_handle_version(void *cookie, json_t **result_ptr) +{ + *result_ptr = json_string(PACKAGE_VERSION); + return (*result_ptr == NULL) ? MON_NOMEM : MON_SUCCESS; +} - /* Use the DH parameters from the original request */ - /* TBD -- this needs to be fixed when we handle more than one req per conn */ - tidc->client_dh = orig_req->tidc_dh; - - /* Save information about this request for the response */ - resp_cookie.tr = tr; - resp_cookie.orig_req = orig_req; - - /* Set-up TID connection */ - /* TBD -- handle IPv6 Addresses */ - if (-1 == (fwd_req->conn = tidc_open_connection(tidc, - inet_ntoa(aaa_servers->aaa_server_addr), - &(fwd_req->gssctx)))) { - fprintf(stderr, "tr_tids_req_handler: Error in tidc_open_connection.\n"); - tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS"); - return -1; - }; - - /* Send a TID request */ - if (0 > (rc = tidc_fwd_request(tidc, fwd_req, &tr_tidc_resp_handler, (void *)&resp_cookie))) { - fprintf(stderr, "Error from tidc_fwd_request, rc = %d.\n", rc); - tids_send_err_response(tids, orig_req, "Can't forward request to next hop TIDS"); - return -1; - } - - return 0; +static MON_RC tr_handle_uptime(void *cookie, json_t **result_ptr) +{ + time_t *start_time = cookie; + *result_ptr = json_integer(time(NULL) - (*start_time)); + return (*result_ptr == NULL) ? MON_NOMEM : MON_SUCCESS; } -static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name, - void *tr) +static MON_RC tr_handle_show_rp_clients(void *cookie, json_t **response_ptr) { - TR_RP_CLIENT *rp; + TR_CFG_MGR *cfg_mgr = talloc_get_type_abort(cookie, TR_CFG_MGR); - if ((!client_name) || (!gss_name) || (!tr)) { - fprintf(stderr, "tr_tidc_gss_handler: Bad parameters.\n"); - return -1; - } - - /* look up the RP client matching the GSS name */ - if ((NULL == (rp = tr_rp_client_lookup(tr, gss_name)))) { - fprintf(stderr, "tr_tids_gss_handler: Unknown GSS name %s\n", gss_name->buf); - return -1; - } + *response_ptr = tr_rp_clients_to_json(cfg_mgr->active->rp_clients); + return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS; +} - /* Store the rp client in the TR_INSTANCE structure for now... - * TBD -- fix me for new tasking model. */ - ((TR_INSTANCE *)tr)->rp_gss = rp; - fprintf( stderr, "Client's GSS Name: %s\n", gss_name->buf); - return 0; +static MON_RC tr_handle_show_cfg_serial(void *cookie, json_t **response_ptr) +{ + TR_CFG_MGR *cfg_mgr = talloc_get_type_abort(cookie, TR_CFG_MGR); + + *response_ptr = tr_cfg_files_to_json_array(cfg_mgr->active); + return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS; } -int main (int argc, const char *argv[]) + +int main(int argc, char *argv[]) { + TALLOC_CTX *main_ctx=NULL; + TR_INSTANCE *tr = NULL; - struct dirent **cfg_files = NULL; - json_t *jcfg = NULL; - TR_CFG_RC rc = TR_CFG_SUCCESS; /* presume success */ - int err = 0, n = 0;; + struct cmdline_args opts; + struct event_base *ev_base; + struct tr_socket_event tids_ev = {0}; + struct event *tids_sweep_ev; + struct tr_socket_event mon_ev = {0}; + struct event *cfgwatch_ev; + + time_t start_time = time(NULL); /* TODO move this? */ + + configure_signals(); + + /* we're going to be multithreaded, so disable null context tracking */ + talloc_set_abort_fn(tr_abort); + talloc_disable_null_tracking(); +#if TALLOC_DEBUG_ENABLE + talloc_set_log_fn(tr_talloc_log); +#endif /* TALLOC_DEBUG_ENABLE */ + main_ctx=talloc_new(NULL); + + /* Use standalone logging */ + tr_log_open(); + + /***** parse command-line arguments *****/ + /* set defaults */ + opts.version_requested=0; + opts.validate_config_and_exit=0; + opts.config_dir="."; + + /* parse the command line*/ + argp_parse(&argp, argc, argv, 0, 0, &opts); - /* parse command-line arguments? -- TBD */ + /* process options */ + remove_trailing_slash(opts.config_dir); + + + /***** Print version info *****/ + print_version_info(); + if (opts.version_requested) + return 0; /* requested that we print version and exit */ + + /***** create a Trust Router instance *****/ + if (NULL == (tr = tr_create(main_ctx))) { + tr_crit("Unable to create Trust Router instance, exiting."); + return 1; + } + + /***** initialize the trust path query server instance *****/ + if (NULL == (tr->tids = tids_new(tr))) { + tr_crit("Error initializing Trust Path Query Server instance."); + return 1; + } - /* create a Trust Router instance */ - if (NULL == (tr = tr_create())) { - fprintf(stderr, "Unable to create Trust Router instance, exiting.\n"); + /***** initialize the trust router protocol server instance *****/ + if (NULL == (tr->trps = trps_new(tr))) { + tr_crit("Error initializing Trust Router Protocol Server instance."); return 1; } - /* find the configuration files */ - if (0 == (n = tr_find_config_files(&cfg_files))) { - fprintf (stderr, "Can't locate configuration files, exiting.\n"); - exit(1); + /***** initialize the monitoring interface instance *****/ + if (NULL == (tr->mons = mons_new(tr))) { + tr_crit("Error initializing monitoring interface instance."); + return 1; + } + /* Monitor our tids/trps instances */ + tr->mons->tids = tr->tids; + tr->mons->trps = tr->trps; + + /* Register monitoring handlers */ + mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_VERSION, tr_handle_version, NULL); + mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_CONFIG_FILES, tr_handle_show_cfg_serial, tr->cfg_mgr); + mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_UPTIME, tr_handle_uptime, &start_time); + mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_RP_CLIENTS, tr_handle_show_rp_clients, tr->cfg_mgr); + tr_tid_register_mons_handlers(tr->tids, tr->mons); + tr_trp_register_mons_handlers(tr->trps, tr->mons); + + /***** process configuration *****/ + tr->cfgwatch=tr_cfgwatch_create(tr); + if (tr->cfgwatch == NULL) { + tr_crit("Unable to create configuration watcher object, exiting."); + return 1; + } + tr->cfgwatch->config_dir=opts.config_dir; + tr->cfgwatch->cfg_mgr=tr->cfg_mgr; + tr->cfgwatch->update_cb=tr_config_changed; /* handle configuration changes */ + tr->cfgwatch->update_cookie=(void *)tr; + if (0 != tr_read_and_apply_config(tr->cfgwatch)) { + tr_crit("Error reading configuration, exiting."); + return 1; } - /* read and parse initial configuration */ - if (NULL == (jcfg = tr_read_config (n, cfg_files))) { - fprintf (stderr, "Error reading or parsing configuration files, exiting.\n"); - exit(1); + /***** Exit here if we are just validating our configuration *****/ + if (opts.validate_config_and_exit) { + printf("Valid configuration found in %s.\n", opts.config_dir); + return 0; + } + /***** Set up the event loop *****/ + ev_base=tr_event_loop_init(); /* Set up the event loop */ + if (ev_base==NULL) { + tr_crit("Error initializing event loop."); + return 1; } - if (TR_CFG_SUCCESS != tr_parse_config(tr, jcfg)) { - fprintf (stderr, "Error decoding configuration information, exiting.\n"); - exit(1); + + /* already set config_dir, fstat_list and n_files earlier */ + if (0 != tr_cfgwatch_event_init(ev_base, tr->cfgwatch, &cfgwatch_ev)) { + tr_crit("Error initializing configuration file watcher."); + return 1; } - /* apply initial configuration */ - if (TR_CFG_SUCCESS != (rc = tr_apply_new_config(tr))) { - fprintf (stderr, "Error applying configuration, rc = %d.\n", rc); - exit(1); + /* install monitoring interface events */ + tr_debug("Initializing monitoring interface events."); + if (0 != tr_mons_event_init(ev_base, tr->mons, tr->cfg_mgr, &mon_ev)) { + tr_crit("Error initializing monitoring interface."); + return 1; } - /* initialize the trust path query server instance */ - if (0 == (tr->tids = tids_create ())) { - fprintf (stderr, "Error initializing Trust Path Query Server instance.\n"); - exit(1); + /* install TID server events */ + tr_debug("Initializing TID server events."); + if (0 != tr_tids_event_init(ev_base, tr->tids, tr->cfg_mgr, tr->trps, &tids_ev, &tids_sweep_ev)) { + tr_crit("Error initializing Trust Path Query Server instance."); + return 1; } - /* start the trust path query server, won't return unless fatal error. */ - if (0 != (err = tids_start(tr->tids, &tr_tids_req_handler, &tr_tids_gss_handler, tr->active_cfg->internal->hostname, (void *)tr))) { - fprintf (stderr, "Error from Trust Path Query Server, err = %d.\n", err); - exit(err); + /* tell the trps which port the tid server listens on */ + tr->trps->tids_port = tr->tids->tids_port; + + /* install TRP handler events */ + tr_debug("Initializing Dynamic Trust Router Protocol events."); + if (TRP_SUCCESS != tr_trps_event_init(ev_base, tr)) { + tr_crit("Error initializing Trust Path Query Server instance."); + return 1; } - tids_destroy(tr->tids); - tr_destroy(tr); - exit(0); + tr_debug("Starting event loop."); + tr_event_loop_run(ev_base); /* does not return until we are done */ + + tr_destroy(tr); /* thanks to talloc, should destroy everything */ + + talloc_free(main_ctx); + return 0; }