1 /*
2  * radd, radtool, and sratool common client code
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 #include <axa/client.h>
20 #include <axa/socket.h>
21 #include <axa/strbuf.h>
22 #include <axa/json.h>
23 #include <axa/yajl_shortcuts.h>
24 
25 #include <libmy/ubuf-pb.h>		/* query protobuf version */
26 
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #ifdef __linux
33 #include <bsd/string.h>			/* for strlcpy() */
34 #endif
35 #include <sysexits.h>
36 #include <sys/utsname.h>
37 #include <unistd.h>
38 #include <wdns.h>
39 
40 #include <yajl/yajl_version.h>
41 #include <yajl/yajl_gen.h>
42 
43 #define	MIN_BACKOFF_MS	(1*1000)
44 #define	MAX_BACKOFF_MS	(60*1000)
45 
46 #ifndef HOST_NAME_MAX
47 #define HOST_NAME_MAX 255
48 #endif
49 
50 void
axa_client_init(axa_client_t * client)51 axa_client_init(axa_client_t *client)
52 {
53 	time_t backoff;
54 	struct timeval retry;
55 
56 	/* Do not change the back-off clock. */
57 	backoff = client->backoff;
58 	retry = client->retry;
59 
60 	memset(client, 0, sizeof(*client));
61 	axa_io_init(&client->io);
62 
63 	client->retry = retry;
64 	client->backoff = backoff;
65 }
66 
67 void
axa_client_backoff(axa_client_t * client)68 axa_client_backoff(axa_client_t *client)
69 {
70 	axa_client_close(client);
71 
72 	gettimeofday(&client->retry, NULL);
73 	client->backoff = max(MIN_BACKOFF_MS, client->backoff*2);
74 	if (client->backoff > MAX_BACKOFF_MS)
75 		client->backoff = MAX_BACKOFF_MS;
76 }
77 
78 void
axa_client_backoff_max(axa_client_t * client)79 axa_client_backoff_max(axa_client_t *client)
80 {
81 	axa_client_close(client);
82 
83 	gettimeofday(&client->retry, NULL);
84 	client->backoff = MAX_BACKOFF_MS;
85 }
86 
87 void
axa_client_backoff_reset(axa_client_t * client)88 axa_client_backoff_reset(axa_client_t *client)
89 {
90 	client->retry.tv_sec = 0;
91 	client->backoff = 0;
92 }
93 
94 time_t					/* ms until retry or < 0 */
axa_client_again(axa_client_t * client,struct timeval * now)95 axa_client_again(axa_client_t *client, struct timeval *now)
96 {
97 	struct timeval tv;
98 
99 	if (client->retry.tv_sec == 0)
100 		return (-1);
101 
102 	if (now == NULL)
103 		now = &tv;
104 	gettimeofday(now, NULL);
105 
106 	return (client->backoff - axa_elapsed_ms(now, &client->retry));
107 }
108 
109 void
axa_client_close(axa_client_t * client)110 axa_client_close(axa_client_t *client)
111 {
112 	/* Everything except the reconnection timers must be set again
113 	 * if and when it is re-opened. */
114 
115 	axa_io_close(&client->io);
116 
117 	if (client->hello != NULL) {
118 		free(client->hello);
119 		client->hello = NULL;
120 	}
121 
122 	client->have_id = false;
123 	client->clnt_id = 0;
124 }
125 
126 static bool
connect_ssh(axa_emsg_t * emsg,axa_client_t * client,bool nonblock,bool ssh_debug)127 connect_ssh(axa_emsg_t *emsg, axa_client_t *client,
128 	    bool nonblock, bool ssh_debug)
129 {
130 	int in_fildes[2], out_fildes[2], err_fildes[2];
131 
132 	if (0 > pipe(in_fildes)) {
133 		axa_pemsg(emsg, "pipe(%s): %s",
134 			  client->io.label, strerror(errno));
135 		return (false);
136 	}
137 	if (0 > pipe(out_fildes)) {
138 		axa_pemsg(emsg, "pipe(%s): %s",
139 			  client->io.label, strerror(errno));
140 		close(in_fildes[0]);
141 		close(in_fildes[1]);
142 		return (false);
143 	}
144 	if (0 > pipe(err_fildes)) {
145 		axa_pemsg(emsg, "pipe(%s): %s",
146 			  client->io.label, strerror(errno));
147 		close(in_fildes[0]);
148 		close(in_fildes[1]);
149 		close(out_fildes[0]);
150 		close(out_fildes[1]);
151 		return (false);
152 	}
153 	client->io.tun_pid = fork();
154 	if (client->io.tun_pid == -1) {
155 		axa_pemsg(emsg, "ssh fork(%s): %s",
156 			  client->io.label, strerror(errno));
157 		close(in_fildes[0]);
158 		close(in_fildes[1]);
159 		close(out_fildes[0]);
160 		close(out_fildes[1]);
161 		close(err_fildes[0]);
162 		close(err_fildes[1]);
163 		return (false);
164 	}
165 	if (client->io.tun_pid == 0) {
166 		/* Run ssh in the child process. */
167 		signal(SIGPIPE, SIG_IGN);
168 		signal(SIGHUP, SIG_IGN);
169 		signal(SIGTERM, SIG_IGN);
170 		signal(SIGINT, SIG_IGN);
171 #ifdef SIGXFSZ
172 		signal(SIGXFSZ, SIG_IGN);
173 #endif
174 
175 		if (0 > dup2(in_fildes[1], STDOUT_FILENO)
176 		    || 0 > dup2(out_fildes[0], STDIN_FILENO)
177 		    || 0 > dup2(err_fildes[1], STDERR_FILENO)) {
178 			axa_error_msg("ssh dup2(%s): %s",
179 				      client->io.label, strerror(errno));
180 			exit(EX_OSERR);
181 		}
182 		close(in_fildes[0]);
183 		close(out_fildes[1]);
184 		close(err_fildes[0]);
185 
186 		/*
187 		 * -v	only when debugging is enabled
188 		 * -T	no pseudo-tty
189 		 * -a	disable forwarding of the authentication agent
190 		 *	    connection
191 		 * -x	no X11 forwarding
192 		 * -oBatchMode=yes  no interactive passphrase/password querying
193 		 * -oStrictHostKeyChecking=no do not look for the server's key
194 		 *	    in the known_hosts file and so do not worry about
195 		 *	    men in the middle to prevent user interaction when
196 		 *	    the server's key changes
197 		 * -oCheckHostIP=no do not check for the server's IP address
198 		 *	    in the known_hosts file
199 		 * -enone for no escape character because we are moving binary
200 		 */
201 		if (ssh_debug)
202 			execlp("ssh", "ssh", "-v",
203 			       "-Tax", "-oBatchMode=yes",
204 			       "-oStrictHostKeyChecking=no",
205 			       "-oCheckHostIP=no",
206 			       "-enone",
207 			       client->io.addr, NULL);
208 		else
209 			execlp("ssh", "ssh",
210 			       "-Tax", "-oBatchMode=yes",
211 			       "-oStrictHostKeyChecking=no",
212 			       "-oCheckHostIP=no",
213 			       "-enone",
214 			       client->io.addr, NULL);
215 		axa_error_msg("exec(ssh %s): %s",
216 			      client->io.addr, strerror(errno));
217 		exit(EX_OSERR);
218 	}
219 
220 	/* Finish setting up links to the ssh child in this the parent. */
221 	client->io.i_fd = in_fildes[0];
222 	client->io.i_events = AXA_POLL_IN;
223 	client->io.o_fd = out_fildes[1];
224 	client->io.o_events = 0;
225 	client->io.tun_fd = err_fildes[0];
226 	close(in_fildes[1]);
227 	close(out_fildes[0]);
228 	close(err_fildes[1]);
229 
230 	if (!axa_set_sock(emsg, client->io.i_fd, client->io.label,
231 			  0, nonblock)
232 	    || !axa_set_sock(emsg, client->io.o_fd, client->io.label,
233 			     0, nonblock)
234 	    || !axa_set_sock(emsg, client->io.tun_fd, client->io.label,
235 			     0, true))  {
236 		return (false);
237 	}
238 
239 	return (true);
240 }
241 
242 static axa_connect_result_t
socket_connect(axa_emsg_t * emsg,axa_client_t * client)243 socket_connect(axa_emsg_t *emsg, axa_client_t *client)
244 {
245 	int i;
246 
247 	if (!AXA_CLIENT_OPENED(client)) {
248 		client->io.o_fd = socket(client->io.su.sa.sa_family,
249 					 SOCK_STREAM, 0);
250 		if (client->io.o_fd < 0) {
251 			axa_pemsg(emsg, "socket(%s): %s",
252 				  client->io.label, strerror(errno));
253 			axa_client_backoff_max(client);
254 			return (AXA_CONNECT_ERR);
255 		}
256 		client->io.i_fd = client->io.o_fd;
257 
258 		if (!axa_set_sock(emsg, client->io.o_fd, client->io.label,
259 				  client->io.bufsize, client->io.nonblock))  {
260 			axa_client_backoff_max(client);
261 			return (AXA_CONNECT_ERR);
262 		}
263 	}
264 
265 	if (!client->io.connected_tcp) {
266 		i = connect(client->io.o_fd, &client->io.su.sa,
267 			    AXA_SU_LEN(&client->io.su));
268 		if (0 <= i || errno == EISCONN) {
269 			/* We finished a new connection or a previously
270 			 * started non-blocking connection. */
271 			client->io.connected_tcp = true;
272 			client->io.i_events = AXA_POLL_IN;
273 			client->io.o_events = 0;
274 
275 		} else if (client->io.nonblock && AXA_CONN_WAIT_ERRORS()) {
276 			/* Non-blocking connection unfinished. */
277 			client->io.i_events = AXA_POLL_OUT;
278 			client->io.o_events = 0;
279 			return (AXA_CONNECT_INCOM);
280 
281 		} else {
282 			/* Failed to connect. */
283 			axa_pemsg(emsg, "connect(%s): %s",
284 				  client->io.label, strerror(errno));
285 			axa_client_backoff(client);
286 			return (AXA_CONNECT_TEMP);
287 		}
288 	}
289 
290 	return (AXA_CONNECT_DONE);
291 }
292 
293 axa_connect_result_t
axa_client_connect(axa_emsg_t * emsg,axa_client_t * client)294 axa_client_connect(axa_emsg_t *emsg, axa_client_t *client)
295 {
296 	axa_p_hdr_t hdr;
297 	axa_connect_result_t connect_result;
298 	uint8_t pvers_save;
299 
300 	if (AXA_CLIENT_CONNECTED(client))
301 		return (AXA_CONNECT_DONE);
302 
303 	/* Clamp the AXA protocol version to 1 (guaranteed to be spoken by all
304 	 * AXA clients and servers. This is done just before the identification
305 	 * and authentication (I&A) message exchange and subsequent  spin-up of
306 	 * the encrypted tunnel. We do this for two reasons:
307 	 *
308 	 * 1. A client's preferred AXA protocol version (AXA_PVERS) may be
309 	 *    higher than what the server can understand (such would be the
310 	 *    case when a newer client connects to an older server).
311 	 * 2. AXA protocol version negotiation is performed during the HELLO
312 	 *    handshake. This happens after I&A, allowing it to be
313 	 *    performed inside an encrypted tunnel and prevent information
314 	 *    leakage to an observer. The issue is the I&A process involves the
315 	 *    exchange of AXA messages (AXA_P_OP_USER and/or AXA_P_OP_NOP). If
316 	 *    the AXA protocol version were too new, the server wouldn't
317 	 *    understand (but also wouldn't have had the option to tell the
318 	 *    client to downgrade its AXA protocol version).
319 	 *
320 	 *    The downside here is that the AXA I&A message exchange protocol
321 	 *    cannot change. New I&A methods can be added or removed but the
322 	 *    structure of the messages must remain the same.
323 	 *
324 	 *    After I&A, the AXA protocol may be set to a version the client
325 	 *    prefers, and the HELLO handshake should proceed.
326 	 */
327 	axa_io_pvers_get(&client->io, &pvers_save);
328 	axa_io_pvers_set(&client->io, AXA_P_PVERS1);
329 
330 	switch (client->io.type) {
331 	case AXA_IO_TYPE_UNIX:
332 	case AXA_IO_TYPE_TCP:
333 		connect_result = socket_connect(emsg, client);
334 		if (connect_result != AXA_CONNECT_DONE) {
335 			axa_io_pvers_set(&client->io, pvers_save);
336 			return (connect_result);
337 		}
338 		client->io.connected = true;
339 
340 		/* TCP and UNIX domain sockets need a user name */
341 		if (client->io.user.name[0] != '\0') {
342 			if (!axa_client_send(emsg, client,
343 					     AXA_TAG_NONE, AXA_P_OP_USER, &hdr,
344 					     &client->io.user,
345 					     sizeof(client->io.user))) {
346 				axa_client_backoff(client);
347 				axa_io_pvers_set(&client->io, pvers_save);
348 				return (AXA_CONNECT_ERR);
349 			}
350 			axa_p_to_str(emsg->c, sizeof(emsg->c),
351 				     true, &hdr,
352 				     (axa_p_body_t *)&client->io.user);
353 			axa_io_pvers_set(&client->io, pvers_save);
354 			return (AXA_CONNECT_USER);
355 		}
356 		break;
357 
358 	case AXA_IO_TYPE_SSH:
359 		if (!AXA_CLIENT_OPENED(client)) {
360 			if (!connect_ssh(emsg, client, client->io.nonblock,
361 					 client->io.tun_debug)) {
362 				axa_client_backoff_max(client);
363 				axa_io_pvers_set(&client->io, pvers_save);
364 				return (AXA_CONNECT_ERR);
365 			}
366 			client->io.connected_tcp = true;
367 			client->io.connected = true;
368 		}
369 		break;
370 
371 	case AXA_IO_TYPE_TLS:
372 		connect_result = socket_connect(emsg, client);
373 		if (connect_result != AXA_CONNECT_DONE) {
374 			axa_io_pvers_set(&client->io, pvers_save);
375 			return (connect_result);
376 		}
377 		switch (axa_tls_start(emsg, &client->io)) {
378 		case AXA_IO_OK:
379 			break;
380 		case AXA_IO_ERR:
381 			axa_client_backoff_max(client);
382 			axa_io_pvers_set(&client->io, pvers_save);
383 			return (AXA_CONNECT_ERR);
384 		case AXA_IO_BUSY:
385 			AXA_ASSERT(client->io.nonblock);
386 			axa_io_pvers_set(&client->io, pvers_save);
387 			return (connect_result);
388 		case AXA_IO_TUNERR:
389 		case AXA_IO_KEEPALIVE:
390 			AXA_FAIL("impossible axa_tls_start() result");
391 		}
392 		break;
393 
394 	case AXA_IO_TYPE_APIKEY:
395 		connect_result = socket_connect(emsg, client);
396 		if (connect_result != AXA_CONNECT_DONE) {
397 			axa_io_pvers_set(&client->io, pvers_save);
398 			return (connect_result);
399 		}
400 		switch (axa_apikey_start(emsg, &client->io)) {
401 		case AXA_IO_OK:
402 			/* username field holds apikey */
403 			if (!axa_client_send(emsg, client,
404 					     AXA_TAG_NONE, AXA_P_OP_USER, &hdr,
405 					     &client->io.user,
406 					     sizeof(client->io.user))) {
407 				axa_client_backoff(client);
408 				axa_io_pvers_set(&client->io, pvers_save);
409 				return (AXA_CONNECT_ERR);
410 			}
411 			axa_p_to_str(emsg->c, sizeof(emsg->c),
412 				     true, &hdr,
413 				     (axa_p_body_t *)&client->io.user);
414 			axa_io_pvers_set(&client->io, pvers_save);
415 			return (AXA_CONNECT_USER);
416 			break;
417 		case AXA_IO_ERR:
418 			axa_client_backoff_max(client);
419 			axa_io_pvers_set(&client->io, pvers_save);
420 			return (AXA_CONNECT_ERR);
421 		case AXA_IO_BUSY:
422 			AXA_ASSERT(client->io.nonblock);
423 			axa_io_pvers_set(&client->io, pvers_save);
424 			return (connect_result);
425 		case AXA_IO_TUNERR:
426 		case AXA_IO_KEEPALIVE:
427 			AXA_FAIL("impossible axa_apikey_start() result");
428 		}
429 		break;
430 
431 	case AXA_IO_TYPE_UNKN:
432 	default:
433 		axa_pemsg(emsg, "impossible client type");
434 		axa_client_backoff_max(client);
435 		axa_io_pvers_set(&client->io, pvers_save);
436 		return (AXA_CONNECT_ERR);
437 	}
438 
439 	/* Send a NOP if we didn't send the user name. */
440 	if (!axa_client_send(emsg, client, AXA_TAG_NONE, AXA_P_OP_NOP,
441 			     &hdr, NULL, 0)) {
442 		axa_client_backoff(client);
443 		axa_io_pvers_set(&client->io, pvers_save);
444 		return (AXA_CONNECT_ERR);
445 	}
446 	axa_p_to_str(emsg->c, sizeof(emsg->c), true,
447 		     &hdr, (axa_p_body_t *)&client->io.user);
448 	return (AXA_CONNECT_NOP);
449 }
450 
451 axa_connect_result_t
axa_client_open(axa_emsg_t * emsg,axa_client_t * client,const char * addr,bool is_rad,bool tun_debug,int bufsize,bool nonblock)452 axa_client_open(axa_emsg_t *emsg, axa_client_t *client, const char *addr,
453 		bool is_rad, bool tun_debug, int bufsize, bool nonblock)
454 {
455 	struct addrinfo *ai;
456 	const char *p;
457 	int i;
458 
459 	axa_client_close(client);
460 
461 	client->io.is_rad = is_rad;
462 	client->io.is_client = true;
463 	client->io.tun_debug = tun_debug;
464 	client->io.nonblock = nonblock;
465 	client->io.bufsize = bufsize;
466 	gettimeofday(&client->retry, NULL);
467 
468 	p = strpbrk(addr, AXA_WHITESPACE":");
469 	if (p == NULL) {
470 		axa_pemsg(emsg,
471 			"missing AXA transport delimiter in \"%s\"",
472 			addr);
473 		axa_client_backoff_max(client);
474 		return (AXA_CONNECT_ERR);
475 	}
476 
477 	client->io.type = axa_io_type_parse(&addr);
478 	if (client->io.type == AXA_IO_TYPE_UNKN) {
479 		axa_pemsg(emsg,
480 			"invalid AXA transport protocol or alias in \"%s\"",
481 			addr);
482 		axa_client_backoff_max(client);
483 		return (AXA_CONNECT_ERR);
484 	}
485 
486 	if (addr[0] == '-' || addr[0] == '\0') {
487 		axa_pemsg(emsg, "invalid server \"%s\"", addr);
488 		axa_client_backoff_max(client);
489 		return (AXA_CONNECT_ERR);
490 	}
491 
492 	p = strchr(addr, '@');
493 	if (p == NULL) {
494 		i = 0;
495 	} else {
496 		i = p - addr;
497 		/* Collect the user name from protocols that provide it. */
498 		if (client->io.type != AXA_IO_TYPE_TLS) {
499 			if (i >= (int)sizeof(client->io.user.name)) {
500 				axa_pemsg(emsg,
501 					  "server user name \"%.*s\" too long",
502 					  i, addr);
503 				axa_client_backoff_max(client);
504 				return (AXA_CONNECT_ERR);
505 			}
506 			memcpy(client->io.user.name, addr, i);
507 		}
508 		++i;
509 	}
510 	if (addr[0] == '-' || addr[0] == '\0'
511 	    || addr[i] == '-' || addr[i] == '\0') {
512 		axa_pemsg(emsg, "invalid server name \"%s\"", addr);
513 		axa_client_backoff_max(client);
514 		return (AXA_CONNECT_ERR);
515 	}
516 
517 	switch (client->io.type) {
518 	case AXA_IO_TYPE_UNIX:
519 		client->io.addr = axa_strdup(addr+i);
520 		client->io.label = axa_strdup(client->io.addr);
521 		client->io.su.sa.sa_family = AF_UNIX;
522 		strlcpy(client->io.su.sun.sun_path, client->io.addr,
523 			sizeof(client->io.su.sun.sun_path));
524 #ifdef HAVE_SA_LEN
525 		client->io.su.sun.sun_len = SUN_LEN(&client->io.su.sun);
526 #endif
527 		break;
528 
529 	case AXA_IO_TYPE_TCP:
530 		client->io.addr = axa_strdup(addr+i);
531 		client->io.label = axa_strdup(client->io.addr);
532 		if (!axa_get_srvr(emsg, client->io.addr, false, &ai)) {
533 			axa_client_backoff(client);
534 			return (AXA_CONNECT_ERR);
535 		}
536 		memcpy(&client->io.su.sa, ai->ai_addr, ai->ai_addrlen);
537 		freeaddrinfo(ai);
538 		break;
539 
540 	case AXA_IO_TYPE_SSH:
541 		client->io.addr = axa_strdup(addr);
542 		client->io.label = axa_strdup(addr);
543 		break;
544 
545 	case AXA_IO_TYPE_TLS:
546 		if (!axa_tls_parse(emsg, &client->io.cert_file,
547 				   &client->io.key_file,
548 				   &client->io.addr,
549 				   addr))
550 			return (AXA_CONNECT_ERR);
551 		client->io.label = axa_strdup(client->io.addr);
552 		if (!axa_get_srvr(emsg, client->io.addr, false, &ai)) {
553 			axa_client_backoff(client);
554 			return (AXA_CONNECT_ERR);
555 		}
556 		memcpy(&client->io.su.sa, ai->ai_addr, ai->ai_addrlen);
557 		freeaddrinfo(ai);
558 		break;
559 
560 	case AXA_IO_TYPE_APIKEY:
561 		if (!axa_apikey_parse(emsg, &client->io.addr,
562 					&client->io.user, addr))
563 			return (AXA_CONNECT_ERR);
564 		client->io.label = axa_strdup(client->io.addr);
565 		if (!axa_get_srvr(emsg, client->io.addr, false, &ai)) {
566 			axa_client_backoff(client);
567 			return (AXA_CONNECT_ERR);
568 		}
569 		memcpy(&client->io.su.sa, ai->ai_addr, ai->ai_addrlen);
570 		freeaddrinfo(ai);
571 		break;
572 
573 	case AXA_IO_TYPE_UNKN:
574 	default:
575 		AXA_FAIL("impossible client type");
576 	}
577 
578 	return (axa_client_connect(emsg, client));
579 }
580 
581 bool
axa_client_send(axa_emsg_t * emsg,axa_client_t * client,axa_tag_t tag,axa_p_op_t op,axa_p_hdr_t * hdr,const void * body,size_t body_len)582 axa_client_send(axa_emsg_t *emsg, axa_client_t *client,
583 		axa_tag_t tag, axa_p_op_t op, axa_p_hdr_t *hdr,
584 		const void *body, size_t body_len)
585 {
586 	axa_io_result_t io_result;
587 
588 	if (!AXA_CLIENT_CONNECTED(client)) {
589 		axa_pemsg(emsg, "not connected before output");
590 		return (false);
591 	}
592 	io_result = axa_send(emsg, &client->io, tag, op, hdr,
593 			     body, body_len, NULL, 0);
594 	switch (io_result) {
595 	case AXA_IO_OK:
596 		break;
597 	case AXA_IO_BUSY:
598 		strlcpy(emsg->c, "output busy", sizeof(emsg->c));
599 		return (false);
600 	case AXA_IO_ERR:
601 		return (false);
602 	case AXA_IO_TUNERR:
603 	case AXA_IO_KEEPALIVE:
604 	default:
605 		AXA_FAIL("impossible axa_send() result");
606 	}
607 
608 	return (true);
609 }
610 
611 bool
axa_client_get_hello_string(axa_emsg_t * emsg,const char * origin,axa_client_t * client,char ** out)612 axa_client_get_hello_string(axa_emsg_t *emsg, const char *origin,
613 		axa_client_t *client, char **out)
614 {
615 	int yajl_rc;
616 	yajl_gen g = NULL;
617 	struct axa_strbuf *sb = NULL;
618 	char hostname[HOST_NAME_MAX] = {0};
619 	struct utsname utsbuf;
620 
621 	sb = axa_strbuf_init();
622 	if (sb == NULL) {
623 		axa_pemsg(emsg, "could not allocate axa_strbuf");
624 		return (false);
625 	}
626 
627 	g = yajl_gen_alloc(NULL);
628 	AXA_ASSERT (g != NULL);
629 
630 	yajl_rc = yajl_gen_config(g,
631 			yajl_gen_print_callback,
632 			_callback_print_yajl_axa_strbuf,
633 			sb);
634 	AXA_ASSERT(yajl_rc != 0);
635 
636 	add_yajl_map(g);
637 
638 	if (0 > gethostname(hostname, sizeof(hostname) - 1)) {
639 		axa_pemsg(emsg, "gethostname(): %s", strerror(errno));
640 		goto err;
641 	}
642 	add_yajl_string(g, "hostname");
643 	add_yajl_string(g, hostname);
644 
645 	if (uname(&utsbuf) < 0) {
646 		axa_pemsg(emsg, "uname(): %s", strerror(errno));
647 		goto err;
648 	} else {
649 		add_yajl_string(g, "uname_sysname");
650 		add_yajl_string(g, utsbuf.sysname);
651 		add_yajl_string(g, "uname_release");
652 		add_yajl_string(g, utsbuf.release);
653 		add_yajl_string(g, "uname_version");
654 		add_yajl_string(g, utsbuf.version);
655 		add_yajl_string(g, "uname_machine");
656 		add_yajl_string(g, utsbuf.machine);
657 	}
658 
659 	add_yajl_string(g, "origin");
660 	if (origin == NULL) {
661 		add_yajl_string(g, "unknown");
662 	}
663 	else {
664 		add_yajl_string(g, origin);
665 	}
666 
667 	add_yajl_string(g, "libaxa");
668 	add_yajl_string(g, axa_get_version());
669 
670 	add_yajl_string(g, "libnmsg");
671 #ifdef NMSG_LIBRARY_VERSION
672 	add_yajl_string(g, nmsg_get_version());
673 #else
674 	add_yajl_string(g, "<=0.13.2");
675 #endif
676 	add_yajl_string(g, "libwdns");
677 #ifdef WDNS_LIBRARY_VERSION
678 	add_yajl_string(g, wdns_get_version());
679 #else
680 	add_yajl_string(g, "<=0.9.1");
681 #endif
682 	add_yajl_string(g, "libyajl");
683 	add_yajl_integer(g, yajl_version());
684 	add_yajl_string(g, "OpenSSL");
685 	add_yajl_string(g, SSLeay_version(SSLEAY_VERSION));
686 	add_yajl_string(g, "libprotobuf-c");
687 	add_yajl_string(g, PROTOBUF_C_VERSION);
688 
689 	add_yajl_string(g, "AXA protocol");
690 	add_yajl_integer(g, client->io.pvers);
691 
692 	close_yajl_map(g);
693 
694 	yajl_gen_reset(g, "");
695 	yajl_gen_free(g);
696 
697 	*out = sb->data;
698 	/* Don't call axa_strbuf_destroy() here, rather, free the wrapper
699 	 * structure now and leave it to the caller to release sb->data. */
700 	free(sb);
701 
702 	return (true);
703 err:
704 	if (g != NULL)
705 		yajl_gen_free(g);
706 	axa_strbuf_destroy(&sb);
707 	return (false);
708 }
709 
710 /* Process AXA_P_OP_HELLO from the server. */
711 bool
axa_client_hello(axa_emsg_t * emsg,axa_client_t * client,const axa_p_hello_t * hello,const char * origin)712 axa_client_hello(axa_emsg_t *emsg, axa_client_t *client,
713 		 const axa_p_hello_t *hello, const char *origin)
714 {
715 	axa_p_hdr_t hdr;
716 	axa_p_hello_t *cl_hello;
717 	size_t len;
718 	char op_buf[AXA_P_OP_STRLEN], *p, *out = NULL;
719 
720 	/* Assume by default that the incoming HELLO is the latest message
721 	 * in the client structure. */
722 	if (hello == NULL) {
723 		if (client->io.recv_body == NULL) {
724 			axa_pemsg(emsg, "no received AXA message ready");
725 			return (false);
726 		}
727 		hello = &client->io.recv_body->hello;
728 	}
729 
730 	/* There must be one HELLO per session. */
731 	if (client->hello != NULL) {
732 		axa_pemsg(emsg, "duplicate %s",
733 			  axa_op_to_str(op_buf, sizeof(op_buf),
734 					AXA_P_OP_HELLO));
735 		return (false);
736 	}
737 	client->hello = axa_strdup(hello->str);
738 
739 	/* Save bundle ID for AXA_P_OP_JOIN */
740 	client->clnt_id = hello->id;
741 	client->have_id = true;
742 
743 	/* Save the protocol version that the server requires. */
744 	client->io.pvers = AXA_P_PVERS;
745 	if (client->io.pvers < hello->pvers_min)
746 		client->io.pvers = hello->pvers_min;
747 	if (client->io.pvers > hello->pvers_max)
748 		client->io.pvers = hello->pvers_max;
749 
750 	/* Limit the version to one that we can understand.
751 	 * Just hope for the best if the server did not offer a version
752 	 * that we can use.  */
753 	if (client->io.pvers < AXA_P_PVERS_MIN)
754 		client->io.pvers = AXA_P_PVERS_MIN;
755 	if (client->io.pvers > AXA_P_PVERS_MAX)
756 		client->io.pvers = AXA_P_PVERS_MAX;
757 
758 	/* client -> server HELLO was introduced in AXA_P_VERS2 */
759 	if (hello->pvers_max < AXA_P_PVERS2)
760 		return (true);
761 
762         cl_hello = AXA_SALLOC(axa_p_hello_t);
763         cl_hello->id = hello->id;
764         cl_hello->pvers_min = AXA_P_PVERS_MIN;
765         cl_hello->pvers_max = AXA_P_PVERS_MAX;
766 
767 	p = cl_hello->str;
768 	len = sizeof (cl_hello->str);
769 	if (!axa_client_get_hello_string(emsg, origin, client, &out)) {
770 		axa_error_msg("error getting detailed HELLO info: %s",
771 				emsg->c);
772 		if (origin == NULL)
773 			origin = "[unknown]";
774 
775 		snprintf(cl_hello->str, sizeof (cl_hello->str) - 1,
776 				"%s %s AXA protocol %d",
777 				origin, axa_get_version(), AXA_P_PVERS);
778 	}
779 	else {
780 		/* Note, if strlen(out) is > sizeof (*p), the json blob will be
781 		 * fouled. */
782 		axa_buf_print(&p, &len, "%s", out);
783 		free(out);
784 	}
785 
786 	axa_client_send(emsg, client, AXA_TAG_NONE, AXA_P_OP_HELLO, &hdr,
787 			cl_hello, sizeof(*cl_hello) -
788 			sizeof(cl_hello->str) + strlen(cl_hello->str) + 1);
789 	free(cl_hello);
790 
791 	return (true);
792 }
793