trp/trp_upd.c
trp/trpc.c
trp/trps.c include/tr_name_internal.h mon/mon_req.c mon/mon_req_encode.c mon/mon_req_decode.c
- mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c)
+ mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c)
# Does not actually build!
add_executable(trust_router ${SOURCE_FILES})
-add_executable(trmon mon/monc.c tr/trmon_main.c)
+add_executable(trmon mon/monc.c tr/trmon_main.c common/tr_gss_client.c include/tr_gss_client.h)
# Test build targets - for debugging
add_executable(test_mon_req_encode mon/mon_common.c mon/mon_req.c mon/tests/test_mon_req_encode.c mon/mon_req_encode.c)
mon/mon_req_encode.c \
mon/mon_req_decode.c \
mon/mon_resp.c \
+ mon/mon_resp_decode.c \
mon/mon_resp_encode.c
check_PROGRAMS = common/t_constraint
tr/tr_trp.c \
tr/tr_mon.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(mon_srcs) \
tr_trpc_SOURCES =tr/trpc_main.c \
tr/tr_trp.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(trp_srcs) \
$(tid_srcs) \
$(common_srcs)
tr_trmon_SOURCES = tr/trmon_main.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(mon_srcs) \
trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(common_srcs)
tid_example_tidc_SOURCES = tid/example/tidc_main.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
+$(mon_srcs) \
$(common_srcs)
tid_example_tidc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
tid_example_tidc_LDFLAGS = $(AM_LDFLAGS) -pthread
tid_example_tids_SOURCES = tid/example/tids_main.c \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(common_srcs)
common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \
$(common_srcs) \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_cfg_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_commtest_SOURCES = common/tests/commtest.c \
$(common_srcs) \
common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_commtest_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_name_test_SOURCES = common/tests/name_test.c \
$(common_srcs) \
common/tr_gss.c \
+ common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_filt_test_SOURCES = common/tests/filt_test.c \
$(common_srcs) \
common/tr_gss.c \
+ common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_filt_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
json_decref(decoded);
assert(encoded);
- assert(msg=tr_msg_decode(encoded, strlen(encoded)));
+ assert(msg= tr_msg_decode(NULL, encoded, strlen(encoded)));
assert(upd=tr_msg_get_trp_upd(msg));
assert(inforec=trp_upd_get_inforec(upd));
/* now remove the inforec from the update context */
msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
assert(msglen);
assert(feof(f));
- msg=tr_msg_decode(msgbuf, msglen);
+ msg= tr_msg_decode(NULL, msgbuf, msglen);
free(msgbuf);
msgbuf=NULL;
--- /dev/null
+/*
+ * Copyright (c) 2012, 2014-2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <talloc.h>
+
+#include <trust_router/tr_dh.h>
+#include <tr_msg.h>
+#include <gsscon.h>
+#include <tr_debug.h>
+#include <tr_gss_client.h>
+
+static int tr_gssc_destructor(void *obj)
+{
+ TR_GSSC_INSTANCE *tr_gssc=talloc_get_type_abort(obj, TR_GSSC_INSTANCE);
+ if (NULL!=tr_gssc) {
+ if (NULL!=tr_gssc->client_dh)
+ tr_destroy_dh_params(tr_gssc->client_dh);
+ }
+ return 0;
+}
+
+TR_GSSC_INSTANCE *tr_gssc_instance_new(TALLOC_CTX *mem_ctx)
+{
+ TR_GSSC_INSTANCE *gssc=talloc(NULL, TR_GSSC_INSTANCE);
+ if (gssc != NULL) {
+ gssc->service_name = NULL;
+ gssc->client_dh = NULL;
+ gssc->conn = -1;
+ gssc->gss_ctx = talloc(gssc, gss_ctx_id_t);
+ if (gssc->gss_ctx == NULL) {
+ talloc_free(gssc); /* before the destructor is set */
+ return NULL;
+ }
+ talloc_set_destructor((void *)gssc, tr_gssc_destructor);
+ }
+ return gssc;
+}
+
+void tr_gssc_instance_free(TR_GSSC_INSTANCE *tr_gssc)
+{
+ talloc_free(tr_gssc);
+}
+
+/**
+ * Open a connection to the requested server:port
+ *
+ * @param gssc client instance
+ * @param server server name/address
+ * @param port TCP port to connect
+ * @return 0 on success, -1 on failure
+ */
+int tr_gssc_open_connection(TR_GSSC_INSTANCE *gssc, const char *server, unsigned int port)
+{
+ tr_debug("tr_gssc_open_connection: opening connection to %s:%d", server, port);
+ if (0 != gsscon_connect(server, port, gssc->service_name, &(gssc->conn), gssc->gss_ctx))
+ return -1;
+
+ return 0; /* success */
+}
+
+/**
+ * Send a request message and retrieve a response message
+ *
+ * @param mem_ctx
+ * @param gssc
+ * @param req_msg
+ * @return decoded message, or null on error
+ */
+TR_MSG *tr_gssc_exchange_msgs(TALLOC_CTX *mem_ctx, TR_GSSC_INSTANCE *gssc, TR_MSG *req_msg)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ char *req_buf = NULL;
+ char *resp_buf = NULL;
+ size_t resp_buflen = 0;
+ TR_MSG *resp_msg = NULL; /* this is the return value */
+ int err;
+
+ /* Validate inputs */
+ if ((gssc == NULL) || (req_msg == NULL))
+ goto cleanup;
+
+ /* Encode the request into a json string */
+ if (!(req_buf = tr_msg_encode(tmp_ctx, req_msg))) {
+ tr_err("tr_gssc_exchange_msgs: Error encoding request message.\n");
+ goto cleanup;
+ }
+
+ tr_debug( "tr_gssc_exchange_msgs: Sending request message:\n%s\n", req_buf);
+
+ /* Send the request over the connection */
+ err = gsscon_write_encrypted_token(gssc->conn, *(gssc->gss_ctx), req_buf, strlen(req_buf));
+ if (err) {
+ tr_err( "tr_gssc_exchange_msgs: Error sending request.\n");
+ goto cleanup;
+ }
+
+ /* Read the response from the connection */
+ /* TBD -- timeout? */
+ if (gsscon_read_encrypted_token(gssc->conn, *(gssc->gss_ctx), &resp_buf, &resp_buflen))
+ goto cleanup;
+
+ tr_debug( "tr_gssc_exchange_msgs: Response Received (%u bytes).\n%s\n", (unsigned) resp_buflen, resp_buf);
+ resp_msg = tr_msg_decode(mem_ctx, resp_buf, resp_buflen);
+ free(resp_buf);
+
+ if (resp_msg == NULL) {
+ tr_err( "tr_gssc_exchange_msgs: Error decoding response.\n");
+ goto cleanup;
+ }
+
+ /* If we get here, then we decoded the message and resp_msg is not null. Nothing more to do. */
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return resp_msg;
+}
+
+DH * tr_gssc_get_dh(TR_GSSC_INSTANCE *inst)
+{
+ return inst->client_dh;
+}
+
+DH *tr_gssc_set_dh(TR_GSSC_INSTANCE *inst, DH *dh)
+{
+ inst->client_dh = dh;
+ return dh;
+}
tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody));
}
/* We do not currently handle monitoring responses */
-// else if (0 == strcmp(mtype, "mon_response")) {
-// msg->msg_type = MON_RESPONSE;
-// tr_msg_set_mon_resp(msg, mon_resp_decode(NULL, jbody));
-// }
+ else if (0 == strcmp(mtype, "mon_response")) {
+ msg->msg_type = MON_RESPONSE;
+ tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody));
+ }
else {
msg->msg_type = TR_UNKNOWN;
msg->msg_rep = NULL;
--- /dev/null
+/*
+ * Copyright (c) 2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef TRUST_ROUTER_MON_H
+#define TRUST_ROUTER_MON_H
+
+#include <gssapi.h>
+#include <trust_router/tr_name.h>
+
+/* Typedefs */
+typedef struct mon_req MON_REQ;
+typedef struct mon_resp MON_RESP;
+
+typedef enum mon_cmd MON_CMD;
+typedef enum mon_resp_code MON_RESP_CODE;
+
+typedef struct mon_opt MON_OPT;
+typedef enum mon_opt_type MON_OPT_TYPE;
+
+typedef enum mon_rc MON_RC;
+
+typedef struct mons_instance MONS_INSTANCE;
+typedef struct monc_instance MONC_INSTANCE;
+
+typedef int (MONS_REQ_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *);
+typedef int (MONS_AUTH_FUNC)(gss_name_t client_name, TR_NAME *display_name, void *cookie);
+typedef int (MONC_RESP_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *);
+
+#endif //TRUST_ROUTER_MON_H
#include <stdint.h>
#include <jansson.h>
#include <gmodule.h>
+#include <gssapi.h>
+
//#include <trp_internal.h>
#include <tr_gss_names.h>
+#include <tr_gss_client.h>
#include <tr_name_internal.h>
-#include <gssapi.h>
#include <trust_router/tr_dh.h>
+#include <mon.h>
/* Typedefs */
typedef struct mon_req MON_REQ;
};
struct mon_resp {
- MON_REQ *req; // request this responds to
MON_RESP_CODE code;
TR_NAME *message;
json_t *payload;
void *cookie;
};
-/* Monitoring client instance */
+/* Client instance */
struct monc_instance {
- DH *client_dh;
+ TR_GSSC_INSTANCE *gssc;
};
/* Prototypes */
/* mon_req_decode.c */
MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json);
+MON_REQ *mon_req_parse(TALLOC_CTX *mem_ctx, const char *input);
/* mon_resp.c */
-MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx,
- MON_REQ *req,
- MON_RESP_CODE code,
- const char *msg,
- json_t *payload);
+MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx, MON_RESP_CODE code, const char *msg, json_t *payload);
void mon_resp_free(MON_RESP *resp);
/* mon_resp_encode.c */
json_t *mon_resp_encode(MON_RESP *resp);
+/* mon_resp_decode.c */
+MON_RESP * mon_resp_decode(TALLOC_CTX *mem_ctx, json_t *resp_json);
+
/* mons.c */
MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx);
int mons_get_listener(MONS_INSTANCE *mons, MONS_REQ_FUNC *req_handler, MONS_AUTH_FUNC *auth_handler, const char *hostname,
int mons_accept(MONS_INSTANCE *mons, int listen);
/* monc.c */
-MONC_INSTANCE *monc_create(void);
-void monc_destroy(MONC_INSTANCE *monc);
-int monc_open_connection (MONC_INSTANCE *monc, const char *server, unsigned int port, gss_ctx_id_t *gssctx);
-int monc_send_request (MONC_INSTANCE *monc, int conn, gss_ctx_id_t gssctx, MONC_RESP_FUNC *resp_handler,
- void *cookie);
-int monc_fwd_request(MONC_INSTANCE *monc, int conn, gss_ctx_id_t gssctx, MON_REQ *mon_req,
- MONC_RESP_FUNC *resp_handler, void *cookie);
-DH * monc_get_dh(MONC_INSTANCE *inst);
+MONC_INSTANCE *monc_new(TALLOC_CTX *mem_ctx);
+void monc_free(MONC_INSTANCE *monc);
+DH *monc_get_dh(MONC_INSTANCE *inst);
DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh);
+int monc_open_connection(MONC_INSTANCE *monc, const char *server, unsigned int port);
+MON_RESP *monc_send_request(TALLOC_CTX *mem_ctx, MONC_INSTANCE *monc, MON_REQ *req);
#endif //TRUST_ROUTER_MON_REQ_H
#include <tr_rp.h>
#include <trust_router/tid.h>
#include <jansson.h>
+#include "tr_gss_client.h"
struct tid_srvr_blk {
TID_SRVR_BLK *next;
};
struct tidc_instance {
- // TID_REQ *req_list;
- // TBD -- Do we still need a separate private key */
- // char *priv_key;
- // int priv_len;
- DH *client_dh; /* Client's DH struct with priv and pub keys */
+ TR_GSSC_INSTANCE *gssc;
};
struct tids_instance {
--- /dev/null
+/*
+ * Copyright (c) 2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TRUST_ROUTER_TR_GSS_CLIENT_H
+#define TRUST_ROUTER_TR_GSS_CLIENT_H
+
+#include <gssapi.h>
+#include <trust_router/tr_dh.h>
+#include <tr_msg.h>
+
+typedef struct tr_gssc_instance TR_GSSC_INSTANCE;
+
+/* Client instance */
+struct tr_gssc_instance {
+ const char *service_name;
+ DH *client_dh;
+ gss_ctx_id_t *gss_ctx;
+ int conn;
+};
+
+/* tr_gss_client.c */
+TR_GSSC_INSTANCE *tr_gssc_instance_new(TALLOC_CTX *mem_ctx);
+void tr_gssc_instance_free(TR_GSSC_INSTANCE *tr_gssc);
+int tr_gssc_open_connection(TR_GSSC_INSTANCE *gssc, const char *server, unsigned int port);
+TR_MSG *tr_gssc_exchange_msgs(TALLOC_CTX *mem_ctx, TR_GSSC_INSTANCE *gssc, TR_MSG *req_msg);
+DH * tr_gssc_get_dh(TR_GSSC_INSTANCE *inst);
+DH *tr_gssc_set_dh(TR_GSSC_INSTANCE *inst, DH *dh);
+
+#endif //TRUST_ROUTER_TR_GSS_CLIENT_H
#include <jansson.h>
#include <trust_router/tid.h>
#include <trust_router/trp.h>
-#include <mon_internal.h>
+#include <mon.h>
typedef struct tr_msg TR_MSG;
}
/**
- * Parse JSON for a request
+ * Parse a JSON string into a request
*/
-//static json_t *mon_req_parse(const char *input)
-//{
-// json_t *parsed_json = NULL;
-// json_error_t json_error;
-//
-// parsed_json = json_loads(input, JSON_REJECT_DUPLICATES, &json_error);
-// return parsed_json;
-//}
+MON_REQ *mon_req_parse(TALLOC_CTX *mem_ctx, const char *input)
+{
+ json_t *parsed_json = NULL;
+ json_error_t json_error;
+
+ parsed_json = json_loads(input, JSON_REJECT_DUPLICATES, &json_error);
+ return mon_req_decode(mem_ctx, parsed_json);
+}
/**
* Decode a JSON request
* @param req_json reference to JSON request object
* @return decoded request struct or NULL on failure
*/
-MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json) //const char *req_str)
+MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json)
{
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
MON_REQ *req = NULL;
json_t *opts_json = NULL;
MON_CMD cmd = MON_CMD_UNKNOWN;
- //req_json = mon_req_parse(req_str); // TODO: Check errors
-
if (! json_is_object(req_json))
goto cleanup;
* Makes its own copy of the message, so caller can dispose of
* that after allocating the response.
*
- * Steals the reference to the payload JSON object. Does not modify the
- * object. Caller should not modify it after allocating the response or
- * undefined behavior will result. If allocation fails, the stolen reference
- * will be released --- if you need to keep a reference, use incref before
- * calling this.
+ * Increments the reference count of the payload if it is not null.
*
* @param mem_ctx talloc context for allocation
* @param req MON_REQ this response corresponds to
* @param payload JSON object to be send as payload, or null for no payload
* @return response allocated in the requested talloc context, null on failure
*/
-MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx,
- MON_REQ *req,
- MON_RESP_CODE code,
- const char *msg,
- json_t *payload)
+MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx, MON_RESP_CODE code, const char *msg, json_t *payload)
{
MON_RESP *resp = talloc(mem_ctx, MON_RESP);
if (resp) {
- resp->req = req;
resp->code = code;
resp->message = tr_new_name(msg);
+
resp->payload = payload;
+ if (resp->payload)
+ json_incref(resp->payload);
+
talloc_set_destructor((void *)resp, mon_resp_destructor);
if (resp->message == NULL) {
talloc_free(resp); // destructor will be called
--- /dev/null
+/*
+ * Copyright (c) 2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <talloc.h>
+#include <jansson.h>
+
+#include <mon_internal.h>
+
+// Monitoring response decoder
+
+/**
+ * Decode a JSON response
+ *
+ * Expected format:
+ * {
+ * "code": 0,
+ * "message": "success",
+ * "payload": {
+ * "serial": 12345,
+ * ...
+ * }
+ * }
+ *
+ * Caller must free the return value with MON_REQ_free().
+ *
+ * @param mem_ctx talloc context for the returned struct
+ * @param resp_json reference to JSON request object
+ * @return decoded request struct or NULL on failure
+ */
+MON_RESP *mon_resp_decode(TALLOC_CTX *mem_ctx, json_t *resp_json)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ MON_RESP *resp = NULL;
+ json_t *jcode = NULL;
+ json_t *jmessage = NULL;
+ json_t *jpayload = NULL;
+
+ if (! json_is_object(resp_json))
+ goto cleanup;
+
+ /* Get the response code, which is an integer */
+ jcode = json_object_get(resp_json, "code");
+ if (! json_is_integer(jcode))
+ goto cleanup;
+
+ /* Get the response message, which is a string */
+ jmessage = json_object_get(resp_json, "message");
+ if (! json_is_string(jmessage))
+ goto cleanup;
+
+ /* Get the payload if we have one */
+ jpayload = json_object_get(resp_json, "payload");
+
+ /* Get a response in the tmp_ctx context. The payload may be null. */
+ resp = mon_resp_new(tmp_ctx,
+ (MON_RESP_CODE) json_integer_value(jcode),
+ json_string_value(jmessage),
+ jpayload);
+ if (resp == NULL)
+ goto cleanup;
+
+ /* Success! Put the request in the caller's talloc context */
+ talloc_steal(mem_ctx, resp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ if (resp_json)
+ json_decref(resp_json);
+
+ return resp;
+}
{
json_t *resp_json = NULL;
json_t *jval = NULL;
- const char *cmd_str = NULL;
/* Get a JSON object */
resp_json = json_object();
/* If we have a payload, add it */
if (resp->payload) {
- cmd_str = mon_cmd_to_string(resp->req->command); // key for the response payload
- object_set_or_free_and_return(resp_json, jval, cmd_str, resp->payload);
+ object_set_or_free_and_return(resp_json, jval, "payload", resp->payload);
}
return resp_json;
#include <tr_debug.h>
-static int monc_destructor(void *obj)
+MONC_INSTANCE *monc_new(TALLOC_CTX *mem_ctx)
{
- MONC_INSTANCE *monc=talloc_get_type_abort(obj, MONC_INSTANCE);
- if (NULL!=monc) {
- if (NULL!=monc->client_dh)
- tr_destroy_dh_params(monc->client_dh);
- }
- return 0;
-}
-
-/* creates struct in talloc null context */
-MONC_INSTANCE *monc_create(void)
-{
- MONC_INSTANCE *monc=talloc(NULL, MONC_INSTANCE);
+ MONC_INSTANCE *monc=talloc(mem_ctx, MONC_INSTANCE);
if (monc!=NULL) {
- monc->client_dh=NULL;
- talloc_set_destructor((void *)monc, monc_destructor);
+ monc->gssc = tr_gssc_instance_new(monc);
+ if (monc->gssc == NULL) {
+ talloc_free(monc);
+ return NULL;
+ }
+
+ monc->gssc->service_name = "trustmonitor";
}
return monc;
}
-void monc_destroy(MONC_INSTANCE *monc)
+void monc_free(MONC_INSTANCE *monc)
{
talloc_free(monc);
}
-int monc_open_connection (MONC_INSTANCE *monc,
- const char *server,
- unsigned int port,
- gss_ctx_id_t *gssctx)
+int monc_open_connection(MONC_INSTANCE *monc,
+ const char *server,
+ unsigned int port)
{
- int err = 0;
- int conn = -1;
-
- tr_debug("monc_open_connection: opening monc connection to %s:%d", server, port);
- err = gsscon_connect(server, port, "trustmonitor", &conn, gssctx);
-
- if (!err)
- return conn;
- else
- return -1;
+ return tr_gssc_open_connection(monc->gssc, server, port);
}
-int monc_send_request (MONC_INSTANCE *monc,
- int conn,
- gss_ctx_id_t gssctx,
- MONC_RESP_FUNC *resp_handler,
- void *cookie)
+MON_RESP *monc_send_request(TALLOC_CTX *mem_ctx, MONC_INSTANCE *monc, MON_REQ *req)
{
- MON_REQ *mon_req = NULL;
- int rc;
-
- /* Create and populate a MON req structure */
- if (!(mon_req = mon_req_new(NULL, MON_CMD_SHOW))) // TODO accept command as a parameter
- goto error;
-
- rc = monc_fwd_request(monc, conn, gssctx, mon_req, resp_handler, cookie);
- goto cleanup;
-error:
- rc = -1;
-cleanup:
- mon_req_free(mon_req);
- return rc;
-}
-
-int monc_fwd_request(MONC_INSTANCE *monc,
- int conn,
- gss_ctx_id_t gssctx,
- MON_REQ *mon_req,
- MONC_RESP_FUNC *resp_handler,
- void *cookie)
-{
- char *req_buf = NULL;
- char *resp_buf = NULL;
- size_t resp_buflen = 0;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
TR_MSG *msg = NULL;
TR_MSG *resp_msg = NULL;
- int err;
- int rc = 0;
+ MON_RESP *resp = NULL;
- /* Create and populate a MON msg structure */
- if (!(msg = talloc_zero(mon_req, TR_MSG)))
- goto error;
+ /* Create and populate a msg structure */
+ if (!(msg = talloc_zero(tmp_ctx, TR_MSG)))
+ goto cleanup;
msg->msg_type = MON_REQUEST;
- tr_msg_set_mon_req(msg, mon_req);
-
- /* store the response function and cookie */
- // mon_req->resp_func = resp_handler;
- // mon_req->cookie = cookie;
-
-
- /* Encode the request into a json string */
- if (!(req_buf = tr_msg_encode(NULL, msg))) {
- tr_err("monc_fwd_request: Error encoding MON request.\n");
- goto error;
- }
+ tr_msg_set_mon_req(msg, req);
- tr_debug( "monc_fwd_request: Sending MON request:\n");
- tr_debug( "%s\n", req_buf);
+ resp_msg = tr_gssc_exchange_msgs(tmp_ctx, monc->gssc, msg);
+ if (resp_msg == NULL)
+ goto cleanup;
- /* Send the request over the connection */
- err = gsscon_write_encrypted_token (conn, gssctx, req_buf, strlen(req_buf));
- if (err) {
- tr_err( "monc_fwd_request: Error sending request over connection.\n");
- goto error;
- }
+ resp = tr_msg_get_mon_resp(resp_msg);
- /* TBD -- queue request on instance, read resps in separate thread */
+ /* if we got a response, steal it from resp_msg's context so we can return it */
+ if (resp)
+ talloc_steal(mem_ctx, resp);
- /* Read the response from the connection */
- /* TBD -- timeout? */
- if (err = gsscon_read_encrypted_token(conn, gssctx, &resp_buf, &resp_buflen)) {
- if (resp_buf)
- free(resp_buf);
- goto error;
- }
-
- tr_debug( "monc_fwd_request: Response Received (%u bytes).\n", (unsigned) resp_buflen);
- tr_debug( "%s\n", resp_buf);
-
-// if (NULL == (resp_msg = tr_msg_decode(resp_buf, resp_buflen))) {
-// tr_err( "monc_fwd_request: Error decoding response.\n");
-// goto error;
-// }
-//
-// /* TBD -- Check if this is actually a valid response */
-// if (MON_RESPONSE != tr_msg_get_msg_type(resp_msg)) {
-// tr_err( "monc_fwd_request: Error, no response in the response!\n");
-// goto error;
-// }
-//
-// if (resp_handler) {
-// /* Call the caller's response function. It must copy any data it needs before returning. */
-// tr_debug("monc_fwd_request: calling response callback function.");
-// (*resp_handler)(monc, mon_req, tr_msg_get_resp(resp_msg), cookie);
-// }
-
- goto cleanup;
-
-error:
- rc = -1;
cleanup:
- if (msg)
- talloc_free(msg);
- if (req_buf)
- free(req_buf);
- if (resp_buf)
- free(resp_buf);
- if (resp_msg)
- tr_msg_free_decoded(resp_msg);
- return rc;
+ talloc_free(tmp_ctx);
+ return resp;
}
-
-DH * monc_get_dh(MONC_INSTANCE *inst)
+DH *monc_get_dh(MONC_INSTANCE *inst)
{
- return inst->client_dh;
+ return tr_gssc_get_dh(inst->gssc);
}
DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh)
{
- inst->client_dh = dh;
- return dh;
+ return tr_gssc_set_dh(inst->gssc, dh);
}
/* Create a TID client instance & the client DH */
tidc = tidc_create();
- if (NULL == (tidc->client_dh = tr_create_dh_params(NULL, 0))) {
+ tidc_set_dh(tidc, tr_create_dh_params(NULL, 0));
+ if (tidc_get_dh(tidc) == NULL) {
printf("Error creating client DH params.\n");
return 1;
}
#include <jansson.h>
#include <talloc.h>
+#include <gsscon.h>
#include <trust_router/tr_dh.h>
#include <tid_internal.h>
#include <tr_msg.h>
-#include <gsscon.h>
#include <tr_debug.h>
int tmp_len = 32;
-static int tidc_destructor(void *obj)
-{
- TIDC_INSTANCE *tidc=talloc_get_type_abort(obj, TIDC_INSTANCE);
- if (NULL!=tidc) {
- if (NULL!=tidc->client_dh)
- tr_destroy_dh_params(tidc->client_dh);
- }
- return 0;
-}
-
/* creates struct in talloc null context */
TIDC_INSTANCE *tidc_create(void)
{
TIDC_INSTANCE *tidc=talloc(NULL, TIDC_INSTANCE);
if (tidc!=NULL) {
- tidc->client_dh=NULL;
- talloc_set_destructor((void *)tidc, tidc_destructor);
+ tidc->gssc = tr_gssc_instance_new(tidc);
+ if (tidc->gssc == NULL) {
+ talloc_free(tidc);
+ return NULL;
+ }
+
+ tidc->gssc->service_name = "trustidentity";
}
return tidc;
}
}
int tidc_open_connection (TIDC_INSTANCE *tidc,
- const char *server,
- unsigned int port,
- gss_ctx_id_t *gssctx)
+ const char *server,
+ unsigned int port,
+ gss_ctx_id_t *gssctx)
{
- int err = 0;
- int conn = -1;
unsigned int use_port = 0;
+ tidc->gssc->gss_ctx = gssctx;
if (0 == port)
use_port = TID_PORT;
else
use_port = port;
- tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, port);
- err = gsscon_connect(server, use_port, "trustidentity", &conn, gssctx);
-
- if (!err)
- return conn;
+ tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, use_port);
+ if (0 == tr_gssc_open_connection(tidc->gssc, server, use_port))
+ return tidc->gssc->conn;
else
return -1;
}
int tidc_send_request (TIDC_INSTANCE *tidc,
- int conn,
- gss_ctx_id_t gssctx,
- const char *rp_realm,
- const char *realm,
- const char *comm,
- TIDC_RESP_FUNC *resp_handler,
- void *cookie)
+ int conn,
+ gss_ctx_id_t gssctx,
+ const char *rp_realm,
+ const char *realm,
+ const char *comm,
+ TIDC_RESP_FUNC *resp_handler,
+ void *cookie)
{
TID_REQ *tid_req = NULL;
int rc;
+ int orig_conn = 0;
+ gss_ctx_id_t *orig_gss_ctx = NULL;
+
+ /* For ABI compatibility, replace the generic GSS client parameters
+ * with the arguments we were passed. */
+ orig_conn = tidc->gssc->conn; /* save to restore later */
+ if (conn != tidc->gssc->conn) {
+ tr_warning("tidc_send_request: WARNING: socket connection FD does not match FD opened by tidc_open_connection()");
+ tidc->gssc->conn = conn;
+ }
+ orig_gss_ctx = tidc->gssc->gss_ctx; /* save to restore later */
+ if (gssctx != *(tidc->gssc->gss_ctx)) {
+ tr_warning("tidc_send_request: WARNING: sending request with different GSS context than used for tidc_open_connection()");
+ *tidc->gssc->gss_ctx = gssctx;
+ }
/* Create and populate a TID req structure */
if (!(tid_req = tid_req_new()))
- return -1;
+ goto error;
tid_req->conn = conn;
tid_req->gssctx = gssctx;
goto error;
}
- tid_req->tidc_dh = tr_dh_dup(tidc->client_dh);
+ tid_req->tidc_dh = tr_dh_dup(tidc->gssc->client_dh);
rc = tidc_fwd_request(tidc, tid_req, resp_handler, cookie);
goto cleanup;
error:
rc = -1;
cleanup:
- tid_req_free(tid_req);
+ if (tid_req)
+ tid_req_free(tid_req);
+
+ tidc->gssc->conn = orig_conn;
+ tidc->gssc->gss_ctx = orig_gss_ctx;
return rc;
}
int tidc_fwd_request(TIDC_INSTANCE *tidc,
TID_REQ *tid_req,
- TIDC_RESP_FUNC *resp_handler,
+ TIDC_RESP_FUNC *resp_handler,
void *cookie)
{
- char *req_buf = NULL;
- char *resp_buf = NULL;
- size_t resp_buflen = 0;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
TR_MSG *msg = NULL;
TR_MSG *resp_msg = NULL;
- int err;
int rc = 0;
/* Create and populate a TID msg structure */
- if (!(msg = talloc_zero(tid_req, TR_MSG)))
+ if (!(msg = talloc_zero(tmp_ctx, TR_MSG)))
goto error;
msg->msg_type = TID_REQUEST;
tr_msg_set_req(msg, tid_req);
- /* store the response function and cookie */
- // tid_req->resp_func = resp_handler;
- // tid_req->cookie = cookie;
-
- /* Encode the request into a json string */
- if (!(req_buf = tr_msg_encode(NULL, msg))) {
- tr_err("tidc_fwd_request: Error encoding TID request.\n");
- goto error;
- }
-
- tr_debug( "tidc_fwd_request: Sending TID request:\n");
- tr_debug( "%s\n", req_buf);
+ tr_debug( "tidc_fwd_request: Sending TID request\n");
/* Send the request over the connection */
- if (err = gsscon_write_encrypted_token (tid_req->conn, tid_req->gssctx, req_buf,
- strlen(req_buf))) {
- tr_err( "tidc_fwd_request: Error sending request over connection.\n");
+ resp_msg = tr_gssc_exchange_msgs(tmp_ctx, tidc->gssc, msg);
+ if (resp_msg == NULL)
goto error;
- }
-
- /* TBD -- queue request on instance, read resps in separate thread */
-
- /* Read the response from the connection */
- /* TBD -- timeout? */
- if (err = gsscon_read_encrypted_token(tid_req->conn, tid_req->gssctx, &resp_buf, &resp_buflen)) {
- if (resp_buf)
- free(resp_buf);
- goto error;
- }
-
- tr_debug( "tidc_fwd_request: Response Received (%u bytes).\n", (unsigned) resp_buflen);
- tr_debug( "%s\n", resp_buf);
-
- if (NULL == (resp_msg = tr_msg_decode(resp_buf, resp_buflen))) {
- tr_err( "tidc_fwd_request: Error decoding response.\n");
- goto error;
- }
/* TBD -- Check if this is actually a valid response */
if (TID_RESPONSE != tr_msg_get_msg_type(resp_msg)) {
error:
rc = -1;
cleanup:
- if (msg)
- talloc_free(msg);
- if (req_buf)
- free(req_buf);
- if (resp_buf)
- free(resp_buf);
- if (resp_msg)
- tr_msg_free_decoded(resp_msg);
+ talloc_free(tmp_ctx);
return rc;
}
DH * tidc_get_dh(TIDC_INSTANCE *inst)
{
- return inst->client_dh;
+ return tr_gssc_get_dh(inst->gssc);
}
DH *tidc_set_dh(TIDC_INSTANCE *inst, DH *dh)
{
- inst->client_dh = dh;
- return dh;
+ return tr_gssc_set_dh(inst->gssc, dh);
}
char *resp_str = NULL;
int rc = 0;
- mreq = tr_msg_decode(req_str, strlen(req_str)); // allocates memory on success!
+ mreq = tr_msg_decode(NULL, req_str, strlen(req_str)); // allocates memory on success!
if (mreq == NULL) {
tr_debug("tids_req_cb: Error decoding request.");
return NULL;
struct cmdline_args {
char *msg;
char *server;
- int port; /* optional */
+ unsigned int port; /* optional */
int repeat; /* how many times to repeat, or -1 for infinite */
};
/* parser for individual options - fills in a struct cmdline_args */
static error_t parse_option(int key, char *arg, struct argp_state *state)
{
+ long tmp_l = 0;
+
/* get a shorthand to the command line argument structure, part of state */
struct cmdline_args *arguments=state->input;
switch (key) {
- case 'r':
- if (arg==NULL)
- arguments->repeat=-1;
- else
- arguments->repeat=strtol(arg, NULL, 10);
- break;
-
- case ARGP_KEY_ARG: /* handle argument (not option) */
- switch (state->arg_num) {
- case 0:
- arguments->msg=arg;
+ case 'r':
+ if (arg==NULL)
+ arguments->repeat=-1;
+ else
+ tmp_l = strtol(arg, NULL, 10);
+ if ((errno == 0) && (tmp_l > 0) && (tmp_l < INT_MAX))
+ arguments->repeat = (int) tmp_l;
+ else
+ argp_usage(state);
break;
- case 1:
- arguments->server=arg;
+ case ARGP_KEY_ARG: /* handle argument (not option) */
+ switch (state->arg_num) {
+ case 0:
+ arguments->msg=arg;
+ break;
+
+ case 1:
+ arguments->server=arg;
+ break;
+
+ case 2:
+ tmp_l = strtol(arg, NULL, 10);
+ if (errno || (tmp_l < 0) || (tmp_l > 65535)) /* max valid port */
+ argp_usage(state);
+
+ arguments->port=(unsigned int) tmp_l;
+ break;
+
+ default:
+ /* too many arguments */
+ argp_usage(state);
+ }
break;
- case 2:
- arguments->port=strtol(arg, NULL, 10); /* optional */
+ case ARGP_KEY_END: /* no more arguments */
+ if (state->arg_num < 2) {
+ /* not enough arguments encountered */
+ argp_usage(state);
+ }
break;
default:
- /* too many arguments */
- argp_usage(state);
- }
- break;
-
- case ARGP_KEY_END: /* no more arguments */
- if (state->arg_num < 2) {
- /* not enough arguments encountered */
- argp_usage(state);
- }
- break;
-
- default:
- return ARGP_ERR_UNKNOWN;
+ 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[])
+int main(int argc, char *argv[])
{
TALLOC_CTX *main_ctx=talloc_new(NULL);
- MONC_INSTANCE *monc=NULL;
+ MONC_INSTANCE *monc = NULL;
+ MON_REQ *req = NULL;
+ MON_RESP *resp = NULL;
+
struct cmdline_args opts;
- int rc;
- int conn;
- gss_ctx_id_t gssctx;
+ int retval=1; /* exit with an error status unless this gets set to zero */
/* parse the command line*/
/* set defaults */
printf("TR Monitor:\nServer = %s, port = %i\n", opts.server, opts.port);
/* Create a MON client instance & the client DH */
- monc = monc_create();
- if (NULL == (monc->client_dh = tr_create_dh_params(main_ctx, 0))) {
+ monc = monc_new(main_ctx);
+ if (monc == NULL) {
+ printf("Error allocating client instance.\n");
+ goto cleanup;
+ }
+
+
+ /* fill in the DH parameters */
+ monc_set_dh(monc, tr_create_dh_params(NULL, 0));
+ if (monc_get_dh(monc) == NULL) {
printf("Error creating client DH params.\n");
- return 1;
+ goto cleanup;
}
/* Set-up MON connection */
- if (-1 == (conn = monc_open_connection(monc, opts.server, opts.port, &gssctx))) {
+ if (0 != monc_open_connection(monc, opts.server, opts.port)) {
/* Handle error */
- printf("Error in monc_open_connection.\n");
- return 1;
+ printf("Error opening connection to %s:%d.\n", opts.server, opts.port);
+ goto cleanup;
};
- /* Send a MON request */
- if (0 > (rc = monc_send_request(monc, conn, gssctx, NULL, NULL))) {
+ req = mon_req_new(main_ctx, MON_CMD_SHOW);
+
+ /* Send a MON request and get the response */
+ resp = monc_send_request(main_ctx, monc, req);
+
+ if (resp == NULL) {
/* Handle error */
- printf("Error in monc_send_request, rc = %d.\n", rc);
- return 1;
+ printf("Error executing monitoring request.\n");
+ goto cleanup;
}
+ /* success */
+ retval = 0;
+
/* Clean-up the MON client instance, and exit */
- monc_destroy(monc);
+cleanup:
talloc_free(main_ctx);
- return 0;
+ return retval;
}
if (buflen>=MAX_MSG_LEN)
printf("Warning: file may exceed maximum message length (%d bytes).\n", MAX_MSG_LEN);
- msg=tr_msg_decode(buf, buflen);
+ msg= tr_msg_decode(NULL, buf, buflen);
/* if (rc==TRP_SUCCESS)
trp_msg_print(msg);*/
tr_debug("trps_read_message: message received, %u bytes.", (unsigned) buflen);
tr_debug("trps_read_message: %.*s", buflen, buf);
- *msg=tr_msg_decode(buf, buflen);
+ *msg= tr_msg_decode(NULL, buf, buflen);
free(buf);
if (*msg==NULL)
return TRP_NOPARSE;