return rc;
}
-TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, int n, struct dirent **cfg_files) {
+/* Join two paths and return a pointer to the result. This should be freed
+ * via talloc_free. Returns NULL on failure. */
+static char *join_paths(const char *p1, const char *p2) {
+ return talloc_asprintf(NULL, "%s/%s", p1, p2); /* returns NULL on a failure */
+}
+
+/* Reads configuration files in config_dir ("" or "./" will use the current directory) */
+TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, const char *config_dir, int n, struct dirent **cfg_files) {
json_t *jcfg;
json_t *jser;
json_error_t rc;
+ char *file_with_path;
- if ((!tr) || (!cfg_files))
+ if ((!tr) || (!cfg_files) || (n<=0))
return TR_CFG_BAD_PARAMS;
/* If there is a partial/abandoned config lying around, free it */
/* Parse configuration information from each config file */
while (n--) {
- tr_debug("tr_read_config: Parsing %s.", cfg_files[n]->d_name);
- if (NULL == (jcfg = json_load_file(cfg_files[n]->d_name,
- JSON_DISABLE_EOF_CHECK, &rc))) {
- tr_debug("tr_read_config: Error parsing config file %s.",
- cfg_files[n]->d_name);
+ file_with_path=join_paths(config_dir, cfg_files[n]->d_name); /* must free result with talloc_free */
+ if(file_with_path == NULL) {
+ tr_crit("tr_parse_config: error joining path.");
+ return TR_CFG_NOMEM;
+ }
+ tr_debug("tr_parse_config: Parsing %s.", cfg_files[n]->d_name); /* print the filename without the path */
+ if (NULL == (jcfg = json_load_file(file_with_path,
+ JSON_DISABLE_EOF_CHECK, &rc))) {
+ tr_debug("tr_parse_config: Error parsing config file %s.",
+ cfg_files[n]->d_name);
+ talloc_free(file_with_path);
return TR_CFG_NOPARSE;
}
+ talloc_free(file_with_path); /* done with filename */
// Look for serial number and log it if it exists
if (NULL != (jser = json_object_get(jcfg, "serial_number"))) {
}
if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_rp_clients(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_idp_realms(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_comms(tr->new_cfg, jcfg))) {
+ (TR_CFG_SUCCESS != tr_cfg_parse_rp_clients(tr->new_cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_idp_realms(tr->new_cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(tr->new_cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_comms(tr->new_cfg, jcfg))) {
tr_cfg_free(tr->new_cfg);
return TR_CFG_ERROR;
}
static int is_cfg_file(const struct dirent *dent) {
int n;
- /* if the last four letters of the filename are .cfg, return true. */
- if ((4 <= (n = strlen(dent->d_name))) &&
- (0 == strcmp(&(dent->d_name[n-4]), ".cfg"))) {
+ /* Only accept filenames ending in ".cfg" and starting with a character
+ * other than an ASCII '.' */
+
+ /* filename must be at least 4 characters long to be acceptable */
+ n=strlen(dent->d_name);
+ if (n < 4) {
+ return 0;
+ }
+
+ /* filename must not start with '.' */
+ if ('.' == dent->d_name[0]) {
+ return 0;
+ }
+
+ /* If the above passed and the last four characters of the filename are .cfg, accept.
+ * (n.b., assumes an earlier test checked that the name is >= 4 chars long.) */
+ if (0 == strcmp(&(dent->d_name[n-4]), ".cfg")) {
return 1;
}
return 0;
}
-int tr_find_config_files (struct dirent ***cfg_files) {
+/* Find configuration files in a particular directory. Returns the
+ * number of entries found, 0 if none are found, or <0 for some
+ * errors. If n>=0, the cfg_files parameter will contain a newly
+ * allocated array of pointers to struct dirent entries, as returned
+ * by scandir(). These can be freed with tr_free_config_file_list().
+ */
+int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) {
int n = 0, i = 0;
- n = scandir(".", cfg_files, &is_cfg_file, 0);
+ n = scandir(config_dir, cfg_files, &is_cfg_file, 0);
if (n < 0) {
perror("scandir");
- tr_debug("tr_find_config: scandir error.");
- return 0;
- }
-
- if (n == 0) {
+ tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir);
+ } else if (n == 0) {
tr_debug("tr_find_config: No config files found.");
- return 0;
+ } else {
+ i = n;
+ while(i--) {
+ tr_debug("tr_find_config: Config file found (%s).", (*cfg_files)[i]->d_name);
+ }
}
- i = n;
- while(i--) {
- tr_debug("tr_find_config: Config file found (%s).", (*cfg_files)[i]->d_name);
- }
-
return n;
}
+
+/* Free memory allocated for configuration file list returned from tr_find_config_files().
+ * This can be called regardless of the return value of tr_find_config_values(). */
+void tr_free_config_file_list(int n, struct dirent ***cfg_files) {
+ int ii;
+
+ /* if n < 0, then scandir did not allocate anything because it failed */
+ if((n>=0) && (*cfg_files != NULL)) {
+ for(ii=0; ii<n; ii++) {
+ free((*cfg_files)[ii]);
+ }
+ free(*cfg_files); /* safe even if n==0 */
+ *cfg_files=NULL; /* this will help prevent accidentally freeing twice */
+ }
+}
{
if (one->len != two->len)
return 1;
- else
- /* TBD -- should really do a length-based comparison */
- return strcmp(one->buf, two->buf);
+ else {
+ /* lengths equal */
+ return strncmp(one->buf, two->buf, one->len);
+ }
}
void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len)
* or implied warranty.
*/
+#include <signal.h>
+
#include <gsscon.h>
/* --------------------------------------------------------------------------- */
if (!err) {
const char *ptr = inBuffer;
do {
- ssize_t count = write (inSocket, ptr, inBufferLength - bytesWritten);
+ ssize_t count;
+
+ /* disable the SIGPIPE signal while we write so that we can handle a
+ * broken pipe error gracefully */
+ signal(SIGPIPE, SIG_IGN); /* temporarily disable */
+ count = write (inSocket, ptr, inBufferLength - bytesWritten);
+ signal(SIGPIPE, SIG_DFL); /* reenable */
+
if (count < 0) {
/* Try again on EINTR */
if (errno != EINTR) { err = errno; }
} while (!err && (bytesWritten < inBufferLength));
}
- if (err) { gsscon_print_error (err, "WritBuffer failed"); }
+ if (err) { gsscon_print_error (err, "WriteBuffer failed"); }
return err;
}
/* TBD -- Trust Links */
} TR_CFG;
-int tr_find_config_files (struct dirent ***cfg_files);
-TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, int n, struct dirent **cfg_files);
+int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files);
+void tr_free_config_file_list(int n, struct dirent ***cfg_files);
+TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, const char *config_dir, int n, struct dirent **cfg_files);
TR_CFG_RC tr_apply_new_config (TR_INSTANCE *tr);
TR_CFG_RC tr_cfg_validate (TR_CFG *trc);
void tr_cfg_free(TR_CFG *cfg);
#include <stdlib.h>
#include <stdio.h>
#include <talloc.h>
+#include <argp.h>
#include <gsscon.h>
#include <tr_debug.h>
#include <tid_internal.h>
#include <trust_router/tr_dh.h>
-void static tidc_print_usage (const char *name)
-{
- printf("Usage: %s <server> <RP-realm> <target-realm> <community> [<port>]\n", name);
-}
-
static void tidc_resp_handler (TIDC_INSTANCE * tidc,
TID_REQ *req,
TID_RESP *resp,
return;
}
+
+/* command-line option setup */
+
+/* argp global parameters */
+const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
+
+/* doc strings */
+static const char doc[]=PACKAGE_NAME " - TID Client";
+static const char arg_doc[]="<server> <RP-realm> <target-realm> <community> [<port>]"; /* 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[] = {
+ { NULL }
+};
+
+/* structure for communicating with option parser */
+struct cmdline_args {
+ char *server;
+ char *rp_realm;
+ char *target_realm;
+ char *community;
+ int port; /* optional */
+};
+
+/* 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 ARGP_KEY_ARG: /* handle argument (not option) */
+ switch (state->arg_num) {
+ case 0:
+ arguments->server=arg;
+ break;
+
+ case 1:
+ arguments->rp_realm=arg;
+ break;
+
+ case 2:
+ arguments->target_realm=arg;
+ break;
+
+ case 3:
+ arguments->community=arg;
+ break;
+
+ case 4:
+ arguments->port=strtol(arg, NULL, 10); /* optional */
+ break;
+
+ default:
+ /* too many arguments */
+ argp_usage(state);
+ }
+ break;
+
+ case ARGP_KEY_END: /* no more arguments */
+ if (state->arg_num < 4) {
+ /* not enough arguments encountered */
+ argp_usage(state);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0; /* success */
+}
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
+
int main (int argc,
- const char *argv[])
+ char *argv[])
{
TIDC_INSTANCE *tidc;
- char *server = NULL;
- char *rp_realm = NULL;
- char *realm = NULL;
- char *coi = NULL;
- int port = TID_PORT;
int conn = 0;
int rc;
gss_ctx_id_t gssctx;
+ struct cmdline_args opts;
+
+ /* parse the command line*/
+ /* set defaults */
+ opts.server=NULL;
+ opts.rp_realm=NULL;
+ opts.target_realm=NULL;
+ opts.community=NULL;
+ opts.port=TID_PORT;
+
+ argp_parse(&argp, argc, argv, 0, 0, &opts);
+ /* TBD -- validity checking, dealing with quotes, etc. */
/* Use standalone logging */
tr_log_open();
tr_log_threshold(LOG_CRIT);
tr_console_threshold(LOG_DEBUG);
- /* Parse command-line arguments */
- if (argc < 5 || argc > 6) {
- tidc_print_usage(argv[0]);
- exit(1);
- }
-
- /* TBD -- validity checking, dealing with quotes, etc. */
- server = (char *)argv[1];
- rp_realm = (char *) argv[2];
- realm = (char *)argv[3];
- coi = (char *)argv[4];
-
- if (argc > 5) {
- port = strtol(argv[5], NULL, 10);
- }
-
- printf("TIDC Client:\nServer = %s, rp_realm = %s, target_realm = %s, community = %s, port = %i\n", server, rp_realm, realm, coi, port);
+ printf("TIDC Client:\nServer = %s, rp_realm = %s, target_realm = %s, community = %s, port = %i\n", opts.server, opts.rp_realm, opts.target_realm, opts.community, opts.port);
/* Create a TID client instance & the client DH */
tidc = tidc_create();
}
/* Set-up TID connection */
- if (-1 == (conn = tidc_open_connection(tidc, server, port, &gssctx))) {
+ if (-1 == (conn = tidc_open_connection(tidc, opts.server, opts.port, &gssctx))) {
/* Handle error */
printf("Error in tidc_open_connection.\n");
return 1;
};
/* Send a TID request */
- if (0 > (rc = tidc_send_request(tidc, conn, gssctx, rp_realm, realm, coi,
+ if (0 > (rc = tidc_send_request(tidc, conn, gssctx, opts.rp_realm, opts.target_realm, opts.community,
&tidc_resp_handler, NULL))) {
/* Handle error */
printf("Error in tidc_send_request, rc = %d.\n", rc);
#include <stdlib.h>
#include <talloc.h>
#include <sqlite3.h>
+#include <argp.h>
#include <tr_debug.h>
#include <tid_internal.h>
return s_keylen;
}
+
static int auth_handler(gss_name_t gss_name, TR_NAME *client,
void *expected_client)
{
TR_NAME *expected_client_trname = (TR_NAME*) expected_client;
- return tr_name_cmp(client, expected_client_trname);
+ int result=tr_name_cmp(client, expected_client_trname);
+ if (result != 0) {
+ tr_notice("Auth denied for incorrect gss-name ('%.*s' requested, expected '%.*s').",
+ client->len, client->buf,
+ expected_client_trname->len, expected_client_trname->buf);
+ }
+ return result;
}
+/* command-line option setup */
+
+/* argp global parameters */
+const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
+
+/* doc strings */
+static const char doc[]=PACKAGE_NAME " - TID Server";
+static const char arg_doc[]="<ip-address> <gss-name> <hostname> <database-name>"; /* 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[] = {
+ { NULL }
+};
+
+/* structure for communicating with option parser */
+struct cmdline_args {
+ char *ip_address;
+ char *gss_name;
+ char *hostname;
+ char *database_name;
+};
+
+/* 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 ARGP_KEY_ARG: /* handle argument (not option) */
+ switch (state->arg_num) {
+ case 0:
+ arguments->ip_address=arg;
+ break;
+
+ case 1:
+ arguments->gss_name=arg;
+ break;
+
+ case 2:
+ arguments->hostname=arg;
+ break;
+
+ case 3:
+ arguments->database_name=arg;
+ break;
+
+ default:
+ /* too many arguments */
+ argp_usage(state);
+ }
+ break;
+
+ case ARGP_KEY_END: /* no more arguments */
+ if (state->arg_num < 4) {
+ /* not enough arguments encountered */
+ argp_usage(state);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0; /* success */
+}
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
int main (int argc,
- const char *argv[])
+ char *argv[])
{
TIDS_INSTANCE *tids;
int rc = 0;
- char *ipaddr = NULL;
- const char *hostname = NULL;
TR_NAME *gssname = NULL;
+ struct cmdline_args opts={NULL};
+
+ /* parse the command line*/
+ argp_parse(&argp, argc, argv, 0, 0, &opts);
talloc_set_log_stderr();
- /* Parse command-line arguments */
- if (argc != 5) {
- fprintf(stdout, "Usage: %s <ip-address> <gss-name> <hostname> <database-name>\n", argv[0]);
- exit(1);
- }
/* Use standalone logging */
tr_log_open();
tr_log_threshold(LOG_CRIT);
tr_console_threshold(LOG_DEBUG);
- ipaddr = (char *)argv[1];
- gssname = tr_new_name((char *) argv[2]);
- hostname = argv[3];
- if (SQLITE_OK != sqlite3_open(argv[4], &db)) {
- tr_crit("Error opening database %s", argv[4]);
+ gssname = tr_new_name(opts.gss_name);
+ if (SQLITE_OK != sqlite3_open(opts.database_name, &db)) {
+ tr_crit("Error opening database %s", opts.database_name);
exit(1);
}
sqlite3_busy_timeout( db, 1000);
return 1;
}
- tids->ipaddr = ipaddr;
+ tids->ipaddr = opts.ip_address;
/* Start-up the server, won't return unless there is an error. */
- rc = tids_start(tids, &tids_req_handler , auth_handler, hostname, TID_PORT, gssname);
+ rc = tids_start(tids, &tids_req_handler , auth_handler, opts.hostname, TID_PORT, gssname);
tr_crit("Error in tids_start(), rc = %d. Exiting.", rc);
return conn;
}
+/* returns EACCES if authorization is denied */
static int tids_auth_cb(gss_name_t clientName, gss_buffer_t displayName,
void *data)
{
struct tids_instance *inst = (struct tids_instance *) data;
TR_NAME name ={(char *) displayName->value,
displayName->length};
- return inst->auth_handler(clientName, &name, inst->cookie);
+ int result=0;
+
+ if (0!=inst->auth_handler(clientName, &name, inst->cookie)) {
+ tr_debug("tids_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
+ result=EACCES; /* denied */
+ }
+
+ return result;
}
+/* returns 0 on authorization success, 1 on failure, or -1 in case of error */
static int tids_auth_connection (struct tids_instance *inst,
int conn, gss_ctx_id_t *gssctx)
{
return tids;
}
+/* Process tids requests forever. Should not return except on error. */
int tids_start (TIDS_INSTANCE *tids,
TIDS_REQ_FUNC *req_handler,
tids_auth_func *auth_handler,
close(listen);
tids_handle_connection(tids, conn);
close(conn);
- return 0;
+ exit(0); /* exit to kill forked child process */
} else {
close(conn);
}
#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>
+#include <argp.h>
#include <tr.h>
#include <tr_filter.h>
return 0;
}
+/* Strip trailing / from a path name.*/
+static void remove_trailing_slash(char *s) {
+ size_t n;
-int main (int argc, const char *argv[])
+ n=strlen(s);
+ if(s[n-1]=='/') {
+ s[n-1]='\0';
+ }
+}
+
+/* command-line option setup */
+
+/* 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";
+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)"},
+ { NULL }
+};
+
+/* structure for communicating with option parser */
+struct cmdline_args {
+ 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;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0; /* success */
+}
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
+
+
+int main (int argc, char *argv[])
{
TR_INSTANCE *tr = NULL;
struct dirent **cfg_files = NULL;
TR_CFG_RC rc = TR_CFG_SUCCESS; /* presume success */
- int err = 0, n = 0;;
-
- /* parse command-line arguments? -- TBD */
+ int err = 0, n = 0;
+ struct cmdline_args opts;
/* Use standalone logging */
tr_log_open();
+ /* parse command-line arguments */
+ /* set defaults */
+ opts.config_dir=".";
+
+ /* parse the command line*/
+ argp_parse(&argp, argc, argv, 0, 0, &opts);
+
+ /* process options */
+ remove_trailing_slash(opts.config_dir);
+
/* create a Trust Router instance */
if (NULL == (tr = tr_create())) {
tr_crit("Unable to create Trust Router instance, exiting.");
return 1;
}
- /* find the configuration files */
- if (0 == (n = tr_find_config_files(&cfg_files))) {
+ /* find the configuration files -- n.b., tr_find_config_files()
+ * allocates memory to cfg_files which we must later free */
+ tr_debug("Reading configuration files from %s/", opts.config_dir);
+ n = tr_find_config_files(opts.config_dir, &cfg_files);
+ if (n <= 0) {
tr_crit("Can't locate configuration files, exiting.");
+ tr_free_config_file_list(n, &cfg_files);
exit(1);
}
- if (TR_CFG_SUCCESS != tr_parse_config(tr, n, cfg_files)) {
+ if (TR_CFG_SUCCESS != tr_parse_config(tr, opts.config_dir, n, cfg_files)) {
tr_crit("Error decoding configuration information, exiting.");
+ tr_free_config_file_list(n, &cfg_files);
exit(1);
}
+
+ /* we are now done with the config filenames, free those */
+ tr_free_config_file_list(n, &cfg_files);
/* apply initial configuration */
if (TR_CFG_SUCCESS != (rc = tr_apply_new_config(tr))) {