Refactor tidc/monc to better share code
[trust_router.git] / common / tr_gss_client.c
1 /*
2  * Copyright (c) 2012, 2014-2018, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 #include <talloc.h>
36
37 #include <trust_router/tr_dh.h>
38 #include <tr_msg.h>
39 #include <gsscon.h>
40 #include <tr_debug.h>
41 #include <tr_gss_client.h>
42
43 static int tr_gssc_destructor(void *obj)
44 {
45   TR_GSSC_INSTANCE *tr_gssc=talloc_get_type_abort(obj, TR_GSSC_INSTANCE);
46   if (NULL!=tr_gssc) {
47     if (NULL!=tr_gssc->client_dh)
48       tr_destroy_dh_params(tr_gssc->client_dh);
49   }
50   return 0;
51 }
52
53 TR_GSSC_INSTANCE *tr_gssc_instance_new(TALLOC_CTX *mem_ctx)
54 {
55   TR_GSSC_INSTANCE *gssc=talloc(NULL, TR_GSSC_INSTANCE);
56   if (gssc != NULL) {
57     gssc->service_name = NULL;
58     gssc->client_dh = NULL;
59     gssc->conn = -1;
60     gssc->gss_ctx = talloc(gssc, gss_ctx_id_t);
61     if (gssc->gss_ctx == NULL) {
62       talloc_free(gssc); /* before the destructor is set */
63       return NULL;
64     }
65     talloc_set_destructor((void *)gssc, tr_gssc_destructor);
66   }
67   return gssc;
68 }
69
70 void tr_gssc_instance_free(TR_GSSC_INSTANCE *tr_gssc)
71 {
72   talloc_free(tr_gssc);
73 }
74
75 /**
76  * Open a connection to the requested server:port
77  *
78  * @param gssc client instance
79  * @param server server name/address
80  * @param port TCP port to connect
81  * @return 0 on success, -1 on failure
82  */
83 int tr_gssc_open_connection(TR_GSSC_INSTANCE *gssc, const char *server, unsigned int port)
84 {
85   tr_debug("tr_gssc_open_connection: opening connection to %s:%d", server, port);
86   if (0 != gsscon_connect(server, port, gssc->service_name, &(gssc->conn), gssc->gss_ctx))
87     return -1;
88
89   return 0; /* success */
90 }
91
92 /**
93  * Send a request message and retrieve a response message
94  *
95  * @param mem_ctx
96  * @param gssc
97  * @param req_msg
98  * @return decoded message, or null on error
99  */
100 TR_MSG *tr_gssc_exchange_msgs(TALLOC_CTX *mem_ctx, TR_GSSC_INSTANCE *gssc, TR_MSG *req_msg)
101 {
102   TALLOC_CTX *tmp_ctx = talloc_new(NULL);
103   char *req_buf = NULL;
104   char *resp_buf = NULL;
105   size_t resp_buflen = 0;
106   TR_MSG *resp_msg = NULL; /* this is the return value */
107   int err;
108
109   /* Validate inputs */
110   if ((gssc == NULL) || (req_msg == NULL))
111     goto cleanup;
112
113   /* Encode the request into a json string */
114   if (!(req_buf = tr_msg_encode(tmp_ctx, req_msg))) {
115     tr_err("tr_gssc_exchange_msgs: Error encoding request message.\n");
116     goto cleanup;
117   }
118
119   tr_debug( "tr_gssc_exchange_msgs: Sending request message:\n%s\n", req_buf);
120
121   /* Send the request over the connection */
122   err = gsscon_write_encrypted_token(gssc->conn, *(gssc->gss_ctx), req_buf, strlen(req_buf));
123   if (err) {
124     tr_err( "tr_gssc_exchange_msgs: Error sending request.\n");
125     goto cleanup;
126   }
127
128   /* Read the response from the connection */
129   /* TBD -- timeout? */
130   if (gsscon_read_encrypted_token(gssc->conn, *(gssc->gss_ctx), &resp_buf, &resp_buflen))
131     goto cleanup;
132
133   tr_debug( "tr_gssc_exchange_msgs: Response Received (%u bytes).\n%s\n", (unsigned) resp_buflen, resp_buf);
134   resp_msg = tr_msg_decode(mem_ctx, resp_buf, resp_buflen);
135   free(resp_buf);
136
137   if (resp_msg == NULL) {
138     tr_err( "tr_gssc_exchange_msgs: Error decoding response.\n");
139     goto cleanup;
140   }
141
142   /* If we get here, then we decoded the message and resp_msg is not null. Nothing more to do. */
143
144 cleanup:
145   talloc_free(tmp_ctx);
146   return resp_msg;
147 }
148
149 DH * tr_gssc_get_dh(TR_GSSC_INSTANCE *inst)
150 {
151   return inst->client_dh;
152 }
153
154 DH *tr_gssc_set_dh(TR_GSSC_INSTANCE *inst, DH *dh)
155 {
156   inst->client_dh = dh;
157   return dh;
158 }