1 /*
2  * Advanced Exchange Access (AXA) common code for RAD and SRA clients
3  *
4  *  Copyright (c) 2014-2018 by Farsight Security, Inc.
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 #ifndef AXA_CLIENT_H
20 #define AXA_CLIENT_H
21 
22 /**
23  *  \defgroup axa_client axa_client
24  *
25  *  `axa_client` contains AXA client macros, data type definitions, and
26  *  function prototypes.
27  *
28  * @{
29  */
30 
31 #include <axa/axa.h>
32 #include <axa/wire.h>
33 
34 /**
35  * maximum length of an AXA server specification such as "unix user@host"
36  */
37 #define AXA_MAX_SRVRLEN (4+64+1025+1)
38 
39 
40 /** @cond */
41 /* obsolete but retained for upward compatibility */
42 #define	AXA_CLIENT_TYPE_UNIX_STR    AXA_IO_TYPE_UNIX_STR
43 #define AXA_CLIENT_TYPE_TCP_STR	    AXA_IO_TYPE_TCP_STR
44 #define AXA_CLIENT_TYPE_SSH_STR	    AXA_IO_TYPE_SSH_STR
45 /** @endcond */
46 
47 /** AXA client state */
48 typedef struct {
49 	axa_io_t	io;		        /**< I/O context */
50 
51 	struct timeval	retry;		/**< connection retry timer */
52 	time_t		backoff;	    /**< connection back-off quantum */
53 
54 	char		*hello;		    /**< HELLO string from server */
55 
56 	bool		have_id;	    /**< for AXA_P_OP_JOIN */
57 	axa_p_clnt_id_t clnt_id;	/**< unique client ID */
58 } axa_client_t;
59 
60 /**
61  *  Check than an AXA client context is closed.
62  *
63  *  \param[in] client address of a client context
64  */
65 #define AXA_CLIENT_OPENED(client) AXA_IO_OPENED(&((client)->io))
66 
67 /**
68  *  Check that an AXA client context is open and connected.
69  *
70  *  \param[in] client address of a client context
71  */
72 #define AXA_CLIENT_CONNECTED(client) AXA_IO_CONNECTED(&((client)->io))
73 
74 /**
75  *  (Re-)initialize an AXA client context with default values.
76  *
77  *  \param[in] client address of a client context
78  */
79 extern void axa_client_init(axa_client_t *client);
80 
81 /**
82  *  Disconnect from the server and increase the delay before trying again.
83  *
84  *  \param[in] client address of a client context
85  */
86 extern void axa_client_backoff(axa_client_t *client);
87 
88 /**
89  *  Disconnect from the server and increase the delay before trying again to
90  *  the maximum.
91  *
92  *  \param[in] client address of a client context
93  */
94 extern void axa_client_backoff_max(axa_client_t *client);
95 
96 /**
97  *  Reset the delay before try to connect to zero.
98  *
99  *  \param[in] client address of a client context
100  */
101 extern void axa_client_backoff_reset(axa_client_t *client);
102 
103 /**
104  *  Get the number of milliseconds before the server connection should be
105  *  attempted again.
106  *
107  *  \param[in] client address of a client context
108  *  \param[out] now current wall clock time or NULL
109  *
110  *  \return <= 0 if yes
111  */
112 extern time_t axa_client_again(axa_client_t *client, struct timeval *now);
113 
114 /**
115  *  Close the server connection and release buffers.
116  *
117  *  \param[in] client address of a client context
118  */
119 extern void axa_client_close(axa_client_t *client);
120 
121 /** return codes for axa_client_open() and axa_client_connect() */
122 typedef enum {
123 	/**
124      * Permanent failure.  The connection has been closed and
125 	 * axa_client_backoff() called. Check emsg.
126      */
127 	AXA_CONNECT_ERR,
128 
129 	/**
130      * Temporary failure.  The connection has been closed and
131 	 * axa_client_backoff() called. Check emsg
132      */
133 	AXA_CONNECT_TEMP,
134 
135 	/** connection is complete */
136 	AXA_CONNECT_DONE,
137 
138 	/** non-blocking connection waiting for TCP syn-ack or TLS handshake */
139 	AXA_CONNECT_INCOM,
140 
141 	/**
142      *  Connection now completed including sending the initial AXA_P_OP_NOP.
143      *  emsg contains the result of
144      *  axa_p_to_str(emsg->c, sizeof(emsg->c), true, ...)
145      */
146 	AXA_CONNECT_NOP,
147 
148 	/**
149      *  Connection now completed including sending the initial AXA_P_OP_USER.
150      *  An AXA_P_OP_OK or AXA_P_OP_ERROR should be coming. emsg contains the
151      *  result of axa_p_to_str(emsg->c, sizeof(emsg->c), true, ...)
152      */
153 	AXA_CONNECT_USER
154 } axa_connect_result_t;
155 
156 /**
157  *  Create a new server connection perhaps after closing an existing
158  *	connection.  axa_client_connect() must be called after a result other
159  *	than AXA_CONNECT_DONE, AXA_CONNECT_NOP,	or AXA_CONNECT_USER.
160  *
161  *  \param[out] emsg if something goes wrong, this will contain the reason
162  *  \param[in] client address of a client context
163  *  \param[in] is_rad true if server is radd instead of srad
164  *  \param[in] addr connect to this AXA server specification
165  *  \param[in] tun_debug true to turn on ssh tunnel debugging
166  *  \param[in] bufsize 0 or desired socket buffer sizes
167  *  \param[in] nonblock true to start the connection without blocking and
168  *	to make the connection non-blocking
169  *
170  *  \retval one of #axa_connect_result_t
171  */
172 extern axa_connect_result_t axa_client_open(axa_emsg_t *emsg,
173 					    axa_client_t *client,
174 					    const char *addr, bool is_rad,
175 					    bool tun_debug,
176 					    int bufsize, bool nonblock);
177 
178 /**
179  *  Finish a new connection to an SRA or RAD server.
180  *  The connection must have been previously opened with axa_client_open(),
181  *  which must have returned #AXA_CONNECT_TEMP.
182  *  axa_client_connect() must be called again when it returns #AXA_CONNECT_TEMP.
183  *
184  *  \param[out] emsg if something goes wrong, this will contain the reason
185  *  \param[in] client address of a client context
186  *
187  *  \retval one of #axa_connect_result_t
188  */
189 extern axa_connect_result_t axa_client_connect(axa_emsg_t *emsg,
190 					       axa_client_t *client);
191 
192 /**
193  *  Send an AXA message to the server connected through a client context,
194  *  blocking until finished.
195  *
196  *  \param[out] emsg if something goes wrong, this will contain the reason
197  *  \param[in] client address of a client context
198  *  \param[in] tag AXA tag
199  *  \param[in] op AXA opcode
200  *  \param[out] hdr AXA protocol header to be built or NULL
201  *  \param[in] body NULL or optional body of the AXA message after the header
202  *  \param[in] body_len length of body
203  *
204  *  \retval true success
205  *  \retval false error.  Call axa_client_backoff() and check check emsg.
206  */
207 extern bool axa_client_send(axa_emsg_t *emsg, axa_client_t *client,
208 			    axa_tag_t tag, axa_p_op_t op, axa_p_hdr_t *hdr,
209 			    const void *body, size_t body_len);
210 
211 /**
212  *  Retrieve a detailed string describing the local host/config to pass to
213  *  the AXA server as part of a client HELLO message.
214  *
215  *  \param[out] emsg if something goes wrong, this will contain the reason
216  *  \param[in] origin null-terminated string containing the name of the
217  *  	requesting client application or service, i.e. radtool, sratunnel, etc.
218  *  \param[in] client address of the client context
219  *  \param[out] out pointer to a char * that is assigned on success. Must be
220  *  	freed by caller.
221  *
222  *  \retval true  version string was generated successfully
223  *  \retval false error occurred making client HELLO string
224  */
225 extern bool
226 axa_client_get_hello_string(axa_emsg_t *emsg, const char *origin,
227 		axa_client_t *client, char **out);
228 
229 /**
230  *  Examine HELLO message from server to pick a common protocol version
231  *  and save session information.
232  *
233  *  \param[out] emsg if something goes wrong, this will contain the reason
234  *  \param[in] client address of the client context
235  *	default to &client->recv_body->hello if NULL
236  *  \param[in] hello address of the received HELLO message or NULL, which
237  *	    implies client->recv_body->hello
238  *  \param[in] origin null-terminated string with name of requesting
239  *  	    application, which will be sent back in a client HELLO string
240  *
241  *  \retval true parameters saved
242  *  \retval false bad HELLO
243  */
244 extern bool axa_client_hello(axa_emsg_t *emsg, axa_client_t *client,
245 			     const axa_p_hello_t* hello, const char *origin);
246 /**@}*/
247 
248 #endif /* AXA_CLIENT_H */
249