openconnect-internal.h 35.5 KB
Newer Older
1 2 3
/*
 * OpenConnect (SSL + DTLS) VPN client
 *
David Woodhouse's avatar
David Woodhouse committed
4
 * Copyright © 2008-2015 Intel Corporation.
5
 * Copyright © 2008 Nick Andrew <nick@nick-andrew.net>
6
 * Copyright © 2013 John Morrissey <jwm@horde.net>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * Author: David Woodhouse <dwmw2@infradead.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

#ifndef __OPENCONNECT_INTERNAL_H__
#define __OPENCONNECT_INTERNAL_H__

23 24
#define __OPENCONNECT_PRIVATE__

25 26 27
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
28 29 30 31
#ifndef SECURITY_WIN32
#define SECURITY_WIN32 1
#endif
#include <security.h>
32
#else
David Woodhouse's avatar
David Woodhouse committed
33
#include <sys/types.h>
34 35 36 37 38 39 40 41
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif

42 43
#include "openconnect.h"

44
#if defined(OPENCONNECT_OPENSSL)
45
#include <openssl/ssl.h>
46
#include <openssl/err.h>
47 48 49 50 51
/* Ick */
#if OPENSSL_VERSION_NUMBER >= 0x00909000L
#define method_const const
#else
#define method_const
52
#endif
53 54
#endif /* OPENSSL */

55
#if defined(OPENCONNECT_GNUTLS)
56
#include <gnutls/gnutls.h>
57
#include <gnutls/abstract.h>
58
#include <gnutls/x509.h>
59
#include <gnutls/crypto.h>
60 61 62 63
#ifdef HAVE_TROUSERS
#include <trousers/tss.h>
#include <trousers/trousers.h>
#endif
64 65
#endif

66 67 68 69 70
#ifdef HAVE_ICONV
#include <langinfo.h>
#include <iconv.h>
#endif

71 72 73 74 75
#include <zlib.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
76
#include <string.h>
77

David Woodhouse's avatar
David Woodhouse committed
78
#ifdef LIBPROXY_HDR
79 80
#include LIBPROXY_HDR
#endif
81

82 83
#ifdef HAVE_LIBSTOKEN
#include <stoken.h>
84 85
#endif

David Woodhouse's avatar
David Woodhouse committed
86
#ifdef HAVE_GSSAPI
87
#include GSSAPI_HDR
David Woodhouse's avatar
David Woodhouse committed
88 89
#endif

David Woodhouse's avatar
David Woodhouse committed
90 91 92 93
#ifdef HAVE_LIBPSKC
#include <pskc/pskc.h>
#endif

94 95 96 97
#ifdef HAVE_LIBP11
#include <libp11.h>
#endif

98
#ifdef HAVE_LIBPCSCLITE
99 100 101 102
#ifdef __APPLE__
#include <PCSC/wintypes.h>
#include <PCSC/winscard.h>
#else
103 104
#include <winscard.h>
#endif
105
#endif
106

107 108
#ifdef ENABLE_NLS
#include <libintl.h>
109
#define _(s) dgettext("openconnect", s)
110
#else
111
#define _(s) ((char *)(s))
112
#endif
113
#define N_(s) s
114

115 116
#include <libxml/tree.h>

117
#define SHA256_SIZE 32
118
#define SHA1_SIZE 20
119
#define MD5_SIZE 16
120

121 122
/* FreeBSD provides this in <sys/param.h>  */
#ifndef MAX
123
#define MAX(x,y) ((x)>(y))?(x):(y)
124
#endif
125 126 127 128 129
/****************************************************************************/

struct pkt {
	int len;
	struct pkt *next;
130
	union {
131 132 133 134 135 136
		struct {
			uint32_t spi;
			uint32_t seq;
			unsigned char iv[16];
			unsigned char payload[];
		} esp;
137
		struct {
138
			unsigned char pad[2];
139 140
			unsigned char rec[2];
			unsigned char kmp[20];
141
		} oncp;
142 143
		struct {
			unsigned char pad[16];
144
			unsigned char hdr[8];
145
		} cstp;
146
	};
147 148 149
	unsigned char data[];
};

150 151 152 153
#define REKEY_NONE      0
#define REKEY_TUNNEL    1
#define REKEY_SSL       2

154 155 156 157 158 159
#define KA_NONE		0
#define KA_DPD		1
#define KA_DPD_DEAD	2
#define KA_KEEPALIVE	3
#define KA_REKEY	4

160 161 162
#define DTLS_NOSECRET	0	/* Random secret has not been generated yet */
#define DTLS_SECRET	1	/* Secret is present, ready to attempt DTLS */
#define DTLS_DISABLED	2	/* DTLS was disabled on the *client* side */
163 164 165
#define DTLS_SLEEPING	3	/* For ESP, sometimes sending probes */
#define DTLS_CONNECTING	4	/* ESP probe received; must tell server */
#define DTLS_CONNECTED	5	/* Server informed and should be sending ESP */
166

167
#define COMPR_DEFLATE	(1<<0)
168
#define COMPR_LZS	(1<<1)
169
#define COMPR_LZ4	(1<<2)
170
#define COMPR_MAX	COMPR_LZ4
171 172

#ifdef HAVE_LZ4
173
#define COMPR_STATELESS	(COMPR_LZS | COMPR_LZ4)
174
#else
175
#define COMPR_STATELESS	(COMPR_LZS)
176
#endif
177
#define COMPR_ALL	(COMPR_STATELESS | COMPR_DEFLATE)
178

179 180
#define DTLS_APP_ID_EXT 48018

181 182 183 184
struct keepalive_info {
	int dpd;
	int keepalive;
	int rekey;
185
	int rekey_method;
186 187 188 189 190 191
	time_t last_rekey;
	time_t last_tx;
	time_t last_rx;
	time_t last_dpd;
};

192 193 194 195 196 197
struct pin_cache {
	struct pin_cache *next;
	char *token;
	char *pin;
};

198 199 200 201 202 203 204
struct oc_text_buf {
	char *data;
	int pos;
	int buf_len;
	int error;
};

205 206 207
#define RECONNECT_INTERVAL_MIN	10
#define RECONNECT_INTERVAL_MAX	100

208 209 210 211
#define REDIR_TYPE_NONE		0
#define REDIR_TYPE_NEWHOST	1
#define REDIR_TYPE_LOCAL	2

212 213 214 215 216 217 218
#define AUTH_TYPE_GSSAPI	0
#define AUTH_TYPE_NTLM		1
#define AUTH_TYPE_DIGEST	2
#define AUTH_TYPE_BASIC		3

#define MAX_AUTH_TYPES		4

219
#define AUTH_DEFAULT_DISABLED	-3
220
#define AUTH_DISABLED		-2
221 222 223 224 225 226
#define AUTH_FAILED		-1	/* Failed */
#define AUTH_UNSEEN		0	/* Server has not offered it */
#define AUTH_AVAILABLE		1	/* Server has offered it, we have not tried it */
	/* Individual auth types may use 2 onwards for their own state */
#define AUTH_IN_PROGRESS	2	/* In-progress attempt */

227
struct http_auth_state {
228 229
	int state;
	char *challenge;
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
	union {
#ifdef HAVE_GSSAPI
		struct {
			gss_name_t gss_target_name;
			gss_ctx_id_t gss_context;
		};
#endif
#ifdef _WIN32
		struct {
			CredHandle ntlm_sspi_cred;
			CtxtHandle ntlm_sspi_ctx;
		};
		struct {
			CredHandle sspi_cred;
			CtxtHandle sspi_ctx;
			SEC_WCHAR *sspi_target_name;
		};
#else
		struct {
			int ntlm_helper_fd;
		};
#endif
	};
253 254
};

255
struct vpn_proto {
256
	const char *name;
257 258 259
	const char *pretty_name;
	const char *description;
	unsigned int flags;
260
	int (*vpn_close_session)(struct openconnect_info *vpninfo, const char *reason);
261

262 263 264
	/* This does the full authentication, calling back as appropriate */
	int (*obtain_cookie)(struct openconnect_info *vpninfo);

265 266 267 268 269
	/* Establish the TCP connection (and obtain configuration) */
	int (*tcp_connect)(struct openconnect_info *vpninfo);

	int (*tcp_mainloop)(struct openconnect_info *vpninfo, int *timeout);

270 271 272
	/* Add headers common to each HTTP request */
	void (*add_http_headers)(struct openconnect_info *vpninfo, struct oc_text_buf *buf);

273 274 275 276 277 278 279 280 281 282 283 284
	/* Set up the UDP (DTLS) connection. Doesn't actually *start* it. */
	int (*udp_setup)(struct openconnect_info *vpninfo, int attempt_period);

	/* This will actually complete the UDP connection setup/handshake on the wire,
	   as well as transporting packets */
	int (*udp_mainloop)(struct openconnect_info *vpninfo, int *timeout);

	/* Close the connection but leave the session setup so it restarts */
	void (*udp_close)(struct openconnect_info *vpninfo);

	/* Close and destroy the (UDP) session */
	void (*udp_shutdown)(struct openconnect_info *vpninfo);
285 286
};

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
struct pkt_q {
	struct pkt *head;
	struct pkt **tail;
	int count;
};

static inline struct pkt *dequeue_packet(struct pkt_q *q)
{
	struct pkt *ret = q->head;

	if (ret) {
		q->head = ret->next;
		if (!--q->count)
			q->tail = &q->head;
	}
	return ret;
}

static inline void requeue_packet(struct pkt_q *q, struct pkt *p)
{
	p->next = q->head;
	q->head = p;
	if (!q->count++)
		q->tail = &p->next;
}

static inline int queue_packet(struct pkt_q *q, struct pkt *p)
{
	*(q->tail) = p;
	p->next = NULL;
	q->tail = &p->next;
	return ++q->count;
}

static inline void init_pkt_queue(struct pkt_q *q)
{
	q->tail = &q->head;
}
325 326 327 328 329

#define DTLS_OVERHEAD (1 /* packet + header */ + 13 /* DTLS header */ + \
	 20 /* biggest supported MAC (SHA1) */ +  16 /* biggest supported IV (AES-128) */ + \
	 16 /* max padding */)

330
struct esp {
331
#if defined(OPENCONNECT_GNUTLS)
332 333
	gnutls_cipher_hd_t cipher;
	gnutls_hmac_hd_t hmac;
334
#elif defined(OPENCONNECT_OPENSSL)
David Woodhouse's avatar
David Woodhouse committed
335 336
	HMAC_CTX *hmac, *pkt_hmac;
	EVP_CIPHER_CTX *cipher;
337
#endif
338
	uint64_t seq_backlog;
339
	uint64_t seq;
340
	uint32_t spi; /* Stored network-endian */
341 342 343
	unsigned char secrets[0x40];
};

344
struct openconnect_info {
345
	const struct vpn_proto *proto;
346

347 348 349 350
#ifdef HAVE_ICONV
	iconv_t ic_legacy_to_utf8;
	iconv_t ic_utf8_to_legacy;
#endif
351
	char *redirect_url;
352
	int redirect_type;
353

354 355 356 357 358 359 360
	unsigned char esp_hmac;
	unsigned char esp_enc;
	unsigned char esp_compr;
	uint32_t esp_replay_protect;
	uint32_t esp_lifetime_bytes;
	uint32_t esp_lifetime_seconds;
	uint32_t esp_ssl_fallback;
361 362 363
	int current_esp_in;
	int old_esp_maxseq;
	struct esp esp_in[2];
364 365
	struct esp esp_out;

David Woodhouse's avatar
David Woodhouse committed
366
	int tncc_fd; /* For Juniper TNCC */
367
	const char *csd_xmltag;
368
	int csd_nostub;
369
	char *platname;
370 371 372
	char *mobile_platform_version;
	char *mobile_device_type;
	char *mobile_device_uniqueid;
373 374 375 376 377 378 379 380
	char *csd_token;
	char *csd_ticket;
	char *csd_stuburl;
	char *csd_starturl;
	char *csd_waiturl;
	char *csd_preurl;

	char *csd_scriptname;
381
	xmlNode *opaque_srvdata;
382

383 384 385
	char *profile_url;
	char *profile_sha1;

David Woodhouse's avatar
David Woodhouse committed
386
#ifdef LIBPROXY_HDR
387 388 389 390 391
	pxProxyFactory *proxy_factory;
#endif
	char *proxy_type;
	char *proxy;
	int proxy_port;
392
	int proxy_fd;
393 394
	char *proxy_user;
	char *proxy_pass;
395
	int proxy_close_during_auth;
396 397
	int retry_on_auth_fail;
	int try_http_auth;
398
	struct http_auth_state http_auth[MAX_AUTH_TYPES];
399
	struct http_auth_state proxy_auth[MAX_AUTH_TYPES];
400

401
	char *localname;
402
	char *hostname;
403
	char *unique_hostname;
404 405
	int port;
	char *urlpath;
406
	int cert_expire_warning;
407 408
	char *cert;
	char *sslkey;
409
	char *cert_password;
410
	char *cafile;
411
	unsigned no_system_trust;
412
	const char *xmlconfig;
413
	char xmlsha1[(SHA1_SIZE * 2) + 1];
414 415
	char *authgroup;
	int nopasswd;
416
	int xmlpost;
417 418 419
	char *dtls_ciphers;
	char *csd_wrapper;
	int no_http_keepalive;
420
	int dump_http_traffic;
421

422 423 424 425
	int token_mode;
	int token_bypassed;
	int token_tries;
	time_t token_time;
426
#ifdef HAVE_LIBSTOKEN
427 428
	struct stoken_ctx *stoken_ctx;
	char *stoken_pin;
429 430
	int stoken_concat_pin;
	int stoken_interval;
431
#endif
David Woodhouse's avatar
David Woodhouse committed
432 433 434 435
#ifdef HAVE_LIBPSKC
	pskc_t *pskc;
	pskc_key_t *pskc_key;
#endif
436 437
	char *oath_secret;
	size_t oath_secret_len;
438 439 440 441 442
	enum {
		OATH_ALG_HMAC_SHA1 = 0,
		OATH_ALG_HMAC_SHA256,
		OATH_ALG_HMAC_SHA512,
	} oath_hmac_alg;
443 444 445 446 447 448
	enum {
		HOTP_SECRET_BASE32 = 1,
		HOTP_SECRET_RAW,
		HOTP_SECRET_HEX,
		HOTP_SECRET_PSKC,
	} hotp_secret_format; /* We need to give it back in the same form */
449 450 451
#ifdef HAVE_LIBPCSCLITE
	SCARDHANDLE pcsc_ctx, pcsc_card;
	char *yubikey_objname;
452 453
	unsigned char yubikey_pwhash[16];
	int yubikey_pw_set;
454
	int yubikey_mode;
455
#endif
456 457 458
	openconnect_lock_token_vfn lock_token;
	openconnect_unlock_token_vfn unlock_token;
	void *tok_cbdata;
459

460
	void *peer_cert;
461 462 463 464 465
	/* The SHA1 and SHA256 hashes of the peer's public key */
	uint8_t peer_cert_sha1_raw[SHA1_SIZE];
	uint8_t peer_cert_sha256_raw[SHA256_SIZE];
	/* this value is cache for openconnect_get_peer_cert_hash */
	char *peer_cert_hash;
466 467
	void *cert_list_handle;
	int cert_list_size;
468

469
	char *cookie; /* Pointer to within cookies list */
470 471 472
	struct oc_vpn_option *cookies;
	struct oc_vpn_option *cstp_options;
	struct oc_vpn_option *dtls_options;
473

474
	struct oc_vpn_option *script_env;
475
	struct oc_vpn_option *csd_env;
476

477
	unsigned pfs;
478
#if defined(OPENCONNECT_OPENSSL)
479 480 481 482 483 484 485 486
#ifdef HAVE_LIBP11
	PKCS11_CTX *pkcs11_ctx;
	PKCS11_SLOT *pkcs11_slot_list;
	unsigned int pkcs11_slot_count;
	PKCS11_SLOT *pkcs11_cert_slot;
	unsigned char *pkcs11_cert_id;
	size_t pkcs11_cert_id_len;
 #endif
487
	X509 *cert_x509;
488 489
	SSL_CTX *https_ctx;
	SSL *https_ssl;
490 491 492
#elif defined(OPENCONNECT_GNUTLS)
	gnutls_session_t https_sess;
	gnutls_certificate_credentials_t https_cred;
493
	gnutls_psk_client_credentials_t psk_cred;
David Woodhouse's avatar
David Woodhouse committed
494
	char local_cert_md5[MD5_SIZE * 2 + 1]; /* For CSD */
495
	char gnutls_prio[256];
496 497 498 499 500
#ifdef HAVE_TROUSERS
	TSS_HCONTEXT tpm_context;
	TSS_HKEY srk;
	TSS_HPOLICY srk_policy;
	TSS_HKEY tpm_key;
501
	TSS_HPOLICY tpm_key_policy;
502
#endif
503 504 505
#ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
#ifdef HAVE_P11KIT
	gnutls_pkcs11_privkey_t my_p11key;
506
#endif
507 508
	gnutls_privkey_t my_pkey;
	gnutls_x509_crt_t *my_certs;
509
	uint8_t *free_my_certs;
510 511 512
	unsigned int nr_my_certs;
#endif
#endif /* OPENCONNECT_GNUTLS */
513
	struct pin_cache *pin_cache;
514 515 516
	struct keepalive_info ssl_times;
	int owe_ssl_dpd_response;

David Woodhouse's avatar
David Woodhouse committed
517 518 519 520
	int deflate_pkt_size;			/* It may need to be larger than MTU */
	struct pkt *deflate_pkt;		/* For compressing outbound packets into */
	struct pkt *pending_deflated_pkt;	/* The original packet associated with above */
	struct pkt *current_ssl_pkt;		/* Partially sent SSL packet */
521
	struct pkt_q oncp_control_queue;		/* Control packets to be sent on oNCP next */
522
	int oncp_rec_size;			/* For packetising incoming oNCP stream */
David Woodhouse's avatar
David Woodhouse committed
523
	/* Packet buffers for receiving into */
524
	struct pkt *cstp_pkt;
David Woodhouse's avatar
David Woodhouse committed
525
	struct pkt *dtls_pkt;
David Woodhouse's avatar
David Woodhouse committed
526
	struct pkt *tun_pkt;
527 528
	int pkt_trailer; /* How many bytes after payload for encryption (ESP HMAC) */

529 530 531 532 533 534 535 536 537 538
	z_stream inflate_strm;
	uint32_t inflate_adler32;
	z_stream deflate_strm;
	uint32_t deflate_adler32;

	int disable_ipv6;
	int reconnect_timeout;
	int reconnect_interval;
	int dtls_attempt_period;
	time_t new_dtls_started;
539
#if defined(OPENCONNECT_OPENSSL)
540 541
	SSL_CTX *dtls_ctx;
	SSL *dtls_ssl;
542
#elif defined(OPENCONNECT_GNUTLS)
543 544 545 546
	/* Call this dtls_ssl rather than dtls_sess because it's just a
	   pointer, and generic code in dtls.c wants to check if it's
	   NULL or not or pass it to DTLS_SEND/DTLS_RECV. This way we
	   have fewer ifdefs and accessor macros for it. */
547
	gnutls_session_t dtls_ssl;
548
	char *gnutls_dtls_cipher; /* cached for openconnect_get_dtls_cipher() */
549
#endif
550 551
	char *cstp_cipher;

552
	int dtls_state;
553
	int dtls_need_reconnect;
554 555 556
	struct keepalive_info dtls_times;
	unsigned char dtls_session_id[32];
	unsigned char dtls_secret[48];
557 558
	unsigned char dtls_app_id[32];
	unsigned dtls_app_id_size;
559 560

	char *dtls_cipher;
561
	char *vpnc_script;
562
#ifndef _WIN32
563 564 565
	int uid_csd_given;
	uid_t uid_csd;
	gid_t gid_csd;
566
	uid_t uid;
567
	gid_t gid;
568 569
#endif
	int use_tun_script;
570 571
	int script_tun;
	char *ifname;
572
	char *cmd_ifname;
573

574
	int reqmtu, basemtu; /* Local static configured values */
575
	const char *banner;
576 577

	struct oc_ip_info ip_info;
578
	int cstp_basemtu; /* Returned by server */
579

580 581
#ifdef _WIN32
	long dtls_monitored, ssl_monitored, cmd_monitored, tun_monitored;
582
	HANDLE dtls_event, ssl_event, cmd_event;
583
#else
584 585 586 587
	int _select_nfds;
	fd_set _select_rfds;
	fd_set _select_wfds;
	fd_set _select_efds;
588
#endif
589 590 591

#ifdef __sun__
	int ip_fd;
592
	int ip6_fd;
593 594 595
#endif
#ifdef _WIN32
	HANDLE tun_fh;
596
	OVERLAPPED tun_rd_overlap, tun_wr_overlap;
597
	int tun_idx, tun_rd_pending;
598
#else
599
	int tun_fd;
600
#endif
601 602
	int ssl_fd;
	int dtls_fd;
603

604 605 606 607
	int dtls_tos_current;
	int dtls_pass_tos;
	int dtls_tos_proto, dtls_tos_optname;

608
	int cmd_fd;
609
	int cmd_fd_write;
610
	int got_cancel_cmd;
611
	int got_pause_cmd;
612
	char cancel_type;
613

614 615
	struct pkt_q incoming_queue;
	struct pkt_q outgoing_queue;
616
	int max_qlen;
617 618
	struct oc_stats stats;
	openconnect_stats_vfn stats_handler;
619 620 621 622 623

	socklen_t peer_addrlen;
	struct sockaddr *peer_addr;
	struct sockaddr *dtls_addr;

624 625
	int dtls_local_port;

626 627 628 629
	int req_compr; /* What we requested */
	int cstp_compr; /* Accepted for CSTP */
	int dtls_compr; /* Accepted for DTLS */

630
	int is_dyndns; /* Attempt to redo DNS lookup on each CSTP reconnect */
631 632
	char *useragent;

633
	const char *quit_reason;
634

635
	int verbose;
636 637 638 639 640
	void *cbdata;
	openconnect_validate_peer_cert_vfn validate_peer_cert;
	openconnect_write_new_config_vfn write_new_config;
	openconnect_process_auth_form_vfn process_auth_form;
	openconnect_progress_vfn progress;
641
	openconnect_protect_socket_vfn protect_socket;
642
	openconnect_getaddrinfo_vfn getaddrinfo_override;
643
	openconnect_setup_tun_vfn setup_tun;
644
	openconnect_reconnected_vfn reconnected;
645 646 647 648

	int (*ssl_read)(struct openconnect_info *vpninfo, char *buf, size_t len);
	int (*ssl_gets)(struct openconnect_info *vpninfo, char *buf, size_t len);
	int (*ssl_write)(struct openconnect_info *vpninfo, char *buf, size_t len);
649 650
};

651 652 653 654 655 656 657 658 659 660 661 662
#ifdef _WIN32
#define monitor_read_fd(_v, _n) _v->_n##_monitored |= FD_READ
#define monitor_write_fd(_v, _n) _v->_n##_monitored |= FD_WRITE
#define monitor_except_fd(_v, _n) _v->_n##_monitored |= FD_CLOSE
#define unmonitor_read_fd(_v, _n) _v->_n##_monitored &= ~FD_READ
#define unmonitor_write_fd(_v, _n) _v->_n##_monitored &= ~FD_WRITE
#define unmonitor_except_fd(_v, _n) _v->_n##_monitored &= ~FD_CLOSE

#define monitor_fd_new(_v, _n) do { if (!_v->_n##_event) _v->_n##_event = CreateEvent(NULL, FALSE, FALSE, NULL); } while (0)
#define read_fd_monitored(_v, _n) (_v->_n##_monitored & FD_READ)

#else
663 664 665 666 667 668 669 670 671 672 673 674 675
#define monitor_read_fd(_v, _n) FD_SET(_v-> _n##_fd, &vpninfo->_select_rfds)
#define unmonitor_read_fd(_v, _n) FD_CLR(_v-> _n##_fd, &vpninfo->_select_rfds)
#define monitor_write_fd(_v, _n) FD_SET(_v-> _n##_fd, &vpninfo->_select_wfds)
#define unmonitor_write_fd(_v, _n) FD_CLR(_v-> _n##_fd, &vpninfo->_select_wfds)
#define monitor_except_fd(_v, _n) FD_SET(_v-> _n##_fd, &vpninfo->_select_efds)
#define unmonitor_except_fd(_v, _n) FD_CLR(_v-> _n##_fd, &vpninfo->_select_efds)

#define monitor_fd_new(_v, _n) do { \
		if (_v->_select_nfds <= vpninfo->_n##_fd) \
			vpninfo->_select_nfds = vpninfo->_n##_fd + 1; \
	} while (0)

#define read_fd_monitored(_v, _n) FD_ISSET(_v->_n##_fd, &_v->_select_rfds)
676
#endif
677

678 679 680 681 682
/* Key material for DTLS-PSK */
#define PSK_LABEL "EXPORTER-openconnect-psk"
#define PSK_LABEL_SIZE sizeof(PSK_LABEL)-1
#define PSK_KEY_SIZE 32

683 684 685 686 687 688 689 690 691 692
/* Packet types */

#define AC_PKT_DATA		0	/* Uncompressed data */
#define AC_PKT_DPD_OUT		3	/* Dead Peer Detection */
#define AC_PKT_DPD_RESP		4	/* DPD response */
#define AC_PKT_DISCONN		5	/* Client disconnection notice */
#define AC_PKT_KEEPALIVE	7	/* Keepalive */
#define AC_PKT_COMPRESSED	8	/* Compressed data */
#define AC_PKT_TERM_SERVER	9	/* Server kick */

693 694
#define vpn_progress(_v, lvl, ...) do {					\
	if ((_v)->verbose >= (lvl))					\
David Woodhouse's avatar
David Woodhouse committed
695
		(_v)->progress((_v)->cbdata, lvl, __VA_ARGS__);	\
696
	} while(0)
697
#define vpn_perror(vpninfo, msg) vpn_progress((vpninfo), PRG_ERR, "%s: %s\n", (msg), strerror(errno))
698

699 700
/****************************************************************************/
/* Oh Solaris how we hate thee! */
701
#ifdef HAVE_SUNOS_BROKEN_TIME
702 703 704
#define time(x) openconnect__time(x)
time_t openconnect__time(time_t *t);
#endif
705 706 707 708
#ifndef HAVE_VASPRINTF
#define vasprintf openconnect__vasprintf
int openconnect__vasprintf(char **strp, const char *fmt, va_list ap);
#endif
709 710 711 712
#ifndef HAVE_ASPRINTF
#define asprintf openconnect__asprintf
int openconnect__asprintf(char **strp, const char *fmt, ...);
#endif
713 714 715 716
#ifndef HAVE_GETLINE
#define getline openconnect__getline
ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream);
#endif
717 718 719 720
#ifndef HAVE_STRCASESTR
#define strcasestr openconnect__strcasestr
char *openconnect__strcasestr(const char *haystack, const char *needle);
#endif
721 722 723 724 725
#ifndef HAVE_STRNDUP
#undef strndup
#define strndup openconnect__strndup
char *openconnect__strndup(const char *s, size_t n);
#endif
726

727 728 729 730 731
#ifndef HAVE_INET_ATON
#define inet_aton openconnect__inet_aton
int openconnect__inet_aton(const char *cp, struct in_addr *addr);
#endif

732 733 734
static inline int set_sock_nonblock(int fd)
{
#ifdef _WIN32
735
	unsigned long mode = 1;
736 737 738 739 740 741 742 743 744 745 746 747 748
	return ioctlsocket(fd, FIONBIO, &mode);
#else
	return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
#endif
}
static inline int set_fd_cloexec(int fd)
{
#ifdef _WIN32
	return 0; /* Windows has O_INHERIT but... */
#else
	return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
#endif
}
749 750 751 752 753 754 755 756
static inline int tun_is_up(struct openconnect_info *vpninfo)
{
#ifdef _WIN32
	return vpninfo->tun_fh != NULL;
#else
	return vpninfo->tun_fd != -1;
#endif
}
757

758
#ifdef _WIN32
759
#define pipe(fds) _pipe(fds, 4096, O_BINARY)
760
int openconnect__win32_sock_init();
761
char *openconnect__win32_strerror(DWORD err);
762 763 764
#undef inet_pton
#define inet_pton openconnect__win32_inet_pton
int openconnect__win32_inet_pton(int af, const char *src, void *dst);
765 766
#define OPENCONNECT_CMD_SOCKET SOCKET
OPENCONNECT_CMD_SOCKET dumb_socketpair(OPENCONNECT_CMD_SOCKET socks[2], int make_overlapped);
767 768
#else
#define closesocket close
769
#define OPENCONNECT_CMD_SOCKET int
770 771 772
#ifndef O_BINARY
#define O_BINARY 0
#endif
773 774
#endif

775 776 777 778 779 780
/* For systems that don't support O_CLOEXEC, just don't bother.
   We don't keep files open for long anyway. */
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif

781 782 783 784 785 786 787 788
/* I always coded as if it worked like this. Now it does. */
#define realloc_inplace(p, size) do {			\
	void *__realloc_old = p;			\
	p = realloc(p, size);				\
	if (size && !p)					\
		free(__realloc_old);			\
    } while (0)

789 790
/****************************************************************************/

791 792 793 794 795 796 797 798 799
/* iconv.c */
#ifdef HAVE_ICONV
char *openconnect_utf8_to_legacy(struct openconnect_info *vpninfo, const char *utf8);
char *openconnect_legacy_to_utf8(struct openconnect_info *vpninfo, const char *legacy);
#else
#define openconnect_utf8_to_legacy(v, str) ((char *)str)
#define openconnect_legacy_to_utf8(v, str) ((char *)str)
#endif

800
/* script.c */
David Woodhouse's avatar
David Woodhouse committed
801
unsigned char unhex(const char *data);
802 803 804
int script_setenv(struct openconnect_info *vpninfo, const char *opt, const char *val, int append);
int script_setenv_int(struct openconnect_info *vpninfo, const char *opt, int value);
void prepare_script_env(struct openconnect_info *vpninfo);
805
int script_config_tun(struct openconnect_info *vpninfo, const char *reason);
806
int apply_script_env(struct oc_vpn_option *envs);
807
void free_split_routes(struct openconnect_info *vpninfo);
808

809
/* tun.c / tun-win32.c */
810
void os_shutdown_tun(struct openconnect_info *vpninfo);
811
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt);
812
int os_write_tun(struct openconnect_info *vpninfo, struct pkt *pkt);
813
intptr_t os_setup_tun(struct openconnect_info *vpninfo);
814

815 816 817 818
/* {gnutls,openssl}-dtls.c */
int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd);
int dtls_try_handshake(struct openconnect_info *vpninfo);
unsigned dtls_set_mtu(struct openconnect_info *vpninfo, unsigned mtu);
David Woodhouse's avatar
David Woodhouse committed
819
void dtls_ssl_free(struct openconnect_info *vpninfo);
820

821
/* dtls.c */
822
int dtls_setup(struct openconnect_info *vpninfo, int dtls_attempt_period);
823
int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout);
824
void dtls_close(struct openconnect_info *vpninfo);
825
void dtls_shutdown(struct openconnect_info *vpninfo);
826
void append_dtls_ciphers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
827
void dtls_detect_mtu(struct openconnect_info *vpninfo);
828 829
int openconnect_dtls_read(struct openconnect_info *vpninfo, void *buf, size_t len, unsigned ms);
int openconnect_dtls_write(struct openconnect_info *vpninfo, void *buf, size_t len);
830
char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len);
831

832
/* cstp.c */
833
void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
834
int cstp_connect(struct openconnect_info *vpninfo);
835
int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout);
836
int cstp_bye(struct openconnect_info *vpninfo, const char *reason);
837
int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type,
838
				unsigned char *buf, int len);
839
int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt *this);
840

841 842 843 844
/* auth-juniper.c */
int oncp_obtain_cookie(struct openconnect_info *vpninfo);
void oncp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);

845
/* oncp.c */
846
int queue_esp_control(struct openconnect_info *vpninfo, int enable);
847 848
int oncp_connect(struct openconnect_info *vpninfo);
int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout);
849
int oncp_bye(struct openconnect_info *vpninfo, const char *reason);
850

851 852
/* lzs.c */
int lzs_decompress(unsigned char *dst, int dstlen, const unsigned char *src, int srclen);
853
int lzs_compress(unsigned char *dst, int dstlen, const unsigned char *src, int srclen);
854

855
/* ssl.c */
856
unsigned string_is_hostname(const char* str);
857
int connect_https_socket(struct openconnect_info *vpninfo);
858 859
int __attribute__ ((format(printf, 4, 5)))
    request_passphrase(struct openconnect_info *vpninfo, const char *label,
860
		       char **response, const char *fmt, ...);
861
int  __attribute__ ((format (printf, 2, 3)))
862
    openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...);
863 864
int openconnect_print_err_cb(const char *str, size_t len, void *ptr);
#define openconnect_report_ssl_errors(v) ERR_print_errors_cb(openconnect_print_err_cb, (v))
865
#if defined(FAKE_ANDROID_KEYSTORE) || defined(__ANDROID__)
866 867 868
#define ANDROID_KEYSTORE
#endif
#ifdef ANDROID_KEYSTORE
869
const char *keystore_strerror(int err);
870 871
int keystore_fetch(const char *key, unsigned char **result);
#endif
872
void cmd_fd_set(struct openconnect_info *vpninfo, fd_set *fds, int *maxfd);
873
void check_cmd_fd(struct openconnect_info *vpninfo, fd_set *fds);
874
int is_cancel_pending(struct openconnect_info *vpninfo, fd_set *fds);
875
void poll_cmd_fd(struct openconnect_info *vpninfo, int timeout);
876 877 878 879
int openconnect_open_utf8(struct openconnect_info *vpninfo,
			  const char *fname, int mode);
FILE *openconnect_fopen_utf8(struct openconnect_info *vpninfo,
			     const char *fname, const char *mode);
880
int udp_sockaddr(struct openconnect_info *vpninfo, int port);
881
int udp_connect(struct openconnect_info *vpninfo);
882
int ssl_reconnect(struct openconnect_info *vpninfo);
883 884
void openconnect_clear_cookies(struct openconnect_info *vpninfo);

885 886 887 888
/* openssl-pkcs11.c */
int load_pkcs11_key(struct openconnect_info *vpninfo);
int load_pkcs11_certificate(struct openconnect_info *vpninfo);

889 890 891
/* esp.c */
int verify_packet_seqno(struct openconnect_info *vpninfo,
			struct esp *esp, uint32_t seq);
892 893 894 895
int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period);
int esp_mainloop(struct openconnect_info *vpninfo, int *timeout);
void esp_close(struct openconnect_info *vpninfo);
void esp_shutdown(struct openconnect_info *vpninfo);
David Woodhouse's avatar
David Woodhouse committed
896
int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct esp *esp);
897

898
/* {gnutls,openssl}-esp.c */
899 900
int setup_esp_keys(struct openconnect_info *vpninfo);
void destroy_esp_ciphers(struct esp *esp);
901
int decrypt_esp_packet(struct openconnect_info *vpninfo, struct esp *esp, struct pkt *pkt);
902
int encrypt_esp_packet(struct openconnect_info *vpninfo, struct pkt *pkt);
903

904
/* {gnutls,openssl}.c */
905 906
int ssl_nonblock_read(struct openconnect_info *vpninfo, void *buf, int maxlen);
int ssl_nonblock_write(struct openconnect_info *vpninfo, void *buf, int buflen);
907
int openconnect_open_https(struct openconnect_info *vpninfo);
908
void openconnect_close_https(struct openconnect_info *vpninfo, int final);
909
int cstp_handshake(struct openconnect_info *vpninfo, unsigned init);
910
int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, void *cert,
911
			     char *buf);
912
int openconnect_sha1(unsigned char *result, void *data, int len);
913
int openconnect_sha256(unsigned char *result, void *data, int len);
914
int openconnect_md5(unsigned char *result, void *data, int len);
915
int openconnect_random(void *bytes, int len);
916 917
int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
			       char *buf);
918 919 920
int openconnect_yubikey_chalresp(struct openconnect_info *vpninfo,
				 const void *challenge, int chall_len, void *result);
int openconnect_hash_yubikey_password(struct openconnect_info *vpninfo,
921 922
				      const char *password, int pwlen,
				      const void *ident, int id_len);
923
int hotp_hmac(struct openconnect_info *vpninfo, const void *challenge);
924 925 926 927 928
#if defined(OPENCONNECT_OPENSSL)
#define openconnect_https_connected(_v) ((_v)->https_ssl)
#elif defined (OPENCONNECT_GNUTLS)
#define openconnect_https_connected(_v) ((_v)->https_sess)
#endif
929

930
/* mainloop.c */
931
int tun_mainloop(struct openconnect_info *vpninfo, int *timeout);
932
int queue_new_packet(struct pkt_q *q, void *buf, int len);
933
int keepalive_action(struct keepalive_info *ka, int *timeout);
934
int ka_stalled_action(struct keepalive_info *ka, int *timeout);
935 936

/* xml.c */
937 938
ssize_t read_file_into_string(struct openconnect_info *vpninfo, const char *fname,
			      char **ptr);
939 940
int config_lookup_host(struct openconnect_info *vpninfo, const char *host);

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
/* oath.c */
int set_totp_mode(struct openconnect_info *vpninfo, const char *token_str);
int set_hotp_mode(struct openconnect_info *vpninfo, const char *token_str);
int can_gen_totp_code(struct openconnect_info *vpninfo,
		      struct oc_auth_form *form,
		      struct oc_form_opt *opt);
int can_gen_hotp_code(struct openconnect_info *vpninfo,
		      struct oc_auth_form *form,
		      struct oc_form_opt *opt);
int do_gen_totp_code(struct openconnect_info *vpninfo,
		     struct oc_auth_form *form,
		     struct oc_form_opt *opt);
int do_gen_hotp_code(struct openconnect_info *vpninfo,
		     struct oc_auth_form *form,
		     struct oc_form_opt *opt);

957 958 959 960 961 962 963 964 965 966
/* stoken.c */
int prepare_stoken(struct openconnect_info *vpninfo);
int set_libstoken_mode(struct openconnect_info *vpninfo, const char *token_str);
int can_gen_stoken_code(struct openconnect_info *vpninfo,
			struct oc_auth_form *form,
			struct oc_form_opt *opt);
int do_gen_stoken_code(struct openconnect_info *vpninfo,
		       struct oc_auth_form *form,
		       struct oc_form_opt *opt);

967 968 969 970 971 972 973 974 975
/* yubikey.c */
int set_yubikey_mode(struct openconnect_info *vpninfo, const char *token_str);
int can_gen_yubikey_code(struct openconnect_info *vpninfo,
			 struct oc_auth_form *form,
			 struct oc_form_opt *opt);
int do_gen_yubikey_code(struct openconnect_info *vpninfo,
			struct oc_auth_form *form,
			struct oc_form_opt *opt);

976
/* auth.c */
977
int cstp_obtain_cookie(struct openconnect_info *vpninfo);
978

979 980 981 982
/* auth-common.c */
int xmlnode_is_named(xmlNode *xml_node, const char *name);
int xmlnode_get_prop(xmlNode *xml_node, const char *name, char **var);
int xmlnode_match_prop(xmlNode *xml_node, const char *name, const char *match);
983
int append_opt(struct oc_text_buf *body, const char *opt, const char *name);
984 985 986 987
int append_form_opts(struct openconnect_info *vpninfo,
		     struct oc_auth_form *form, struct oc_text_buf *body);
void free_opt(struct oc_form_opt *opt);
void free_auth_form(struct oc_auth_form *form);
988 989 990 991 992
int do_gen_tokencode(struct openconnect_info *vpninfo,
		     struct oc_auth_form *form);
int can_gen_tokencode(struct openconnect_info *vpninfo,
		      struct oc_auth_form *form,
		      struct oc_form_opt *opt);
993

994
/* http.c */
995
struct oc_text_buf *buf_alloc(void);
996
void dump_buf(struct openconnect_info *vpninfo, char prefix, char *buf);
997
int buf_ensure_space(struct oc_text_buf *buf, int len);
998 999
void  __attribute__ ((format (printf, 2, 3)))
	buf_append(struct oc_text_buf *buf, const char *fmt, ...);
1000
void buf_append_bytes(struct oc_text_buf *buf, const void *bytes, int len);
1001
void buf_append_hex(struct oc_text_buf *buf, const void *str, unsigned len);
1002
int buf_append_utf16le(struct oc_text_buf *buf, const char *utf8);
1003
int get_utf8char(const char **utf8);
1004
void buf_append_from_utf16le(struct oc_text_buf *buf, const void *utf16);
1005
void buf_truncate(struct oc_text_buf *buf);
1006
void buf_append_urlencoded(struct oc_text_buf *buf, const char *str);
1007 1008
int buf_error(struct oc_text_buf *buf);
int buf_free(struct oc_text_buf *buf);
1009
char *openconnect_create_useragent(const char *base);
1010
int process_proxy(struct openconnect_info *vpninfo, int ssl_sock);
1011
int internal_parse_url(const char *url, char **res_proto, char **res_host,
1012
		       int *res_port, char **res_path, int default_port);
1013 1014 1015
int do_https_request(struct openconnect_info *vpninfo, const char *method,
		     const char *request_body_type, struct oc_text_buf *request_body,
		     char **form_buf, int fetch_redirect);
1016 1017
int http_add_cookie(struct openconnect_info *vpninfo, const char *option,
		    const char *value, int replace);
1018 1019 1020 1021
int process_http_response(struct openconnect_info *vpninfo, int connect,
			  int (*header_cb)(struct openconnect_info *, char *, char *),
			  struct oc_text_buf *body);
int handle_redirect(struct openconnect_info *vpninfo);
1022
void http_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
1023

1024 1025 1026 1027 1028 1029
/* http-auth.c */
void buf_append_base64(struct oc_text_buf *buf, const void *bytes, int len);
void *openconnect_base64_decode(int *len, const char *in);
void clear_auth_states(struct openconnect_info *vpninfo,
		       struct http_auth_state *auth_states, int reset);
int proxy_auth_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val);
1030
int http_auth_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val);
1031 1032
int gen_authorization_hdr(struct openconnect_info *vpninfo, int proxy,
			  struct oc_text_buf *buf);
1033
/* ntlm.c */
1034
int ntlm_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
1035
void cleanup_ntlm_auth(struct openconnect_info *vpninfo, struct http_auth_state *auth_state);
1036

1037
/* gssapi.c */
1038
int gssapi_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
1039
void cleanup_gssapi_auth(struct openconnect_info *vpninfo, struct http_auth_state *auth_state);
David Woodhouse's avatar
David Woodhouse committed
1040
int socks_gssapi_auth(struct openconnect_info *vpninfo);
1041

1042
/* digest.c */
1043
int digest_authorization(struct openconnect_info *vpninfo, int proxy, struct http_auth_state *auth_state, struct oc_text_buf *buf);
1044

1045 1046 1047
/* library.c */
void nuke_opt_values(struct oc_form_opt *opt);
int process_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form);
1048 1049
/* This is private for now since we haven't yet worked out what the API will be */
void openconnect_set_juniper(struct openconnect_info *vpninfo);
1050

1051
/* version.c */
1052
extern const char *openconnect_version_str;
1053

1054 1055 1056 1057 1058 1059 1060 1061
/* strncasecmp() just checks that the first n characters match. This
   function ensures that the first n characters of the left-hand side
   are a *precise* match for the right-hand side. */
static inline int strprefix_match(const char *str, int len, const char *match)
{
	return len == strlen(match) && !strncasecmp(str, match, len);
}

1062
#define STRDUP(res, arg) \
1063
	if (res != arg) {					\
1064 1065 1066 1067 1068 1069
		free(res);					\
		if (arg) {					\
			res = strdup(arg);			\
			if (res == NULL) return -ENOMEM;	\
		} else res = NULL;				\
	} while(0)
1070

1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
#define UTF8CHECK(arg) \
	if ((arg) && buf_append_utf16le(NULL, (arg))) { \
		vpn_progress(vpninfo, PRG_ERR,				\
			     _("ERROR: %s() called with invalid UTF-8 for '%s' argument\n"),\
			     __func__, #arg);				\
		return -EILSEQ;						\
	}

#define UTF8CHECK_VOID(arg) \
	if ((arg) && buf_append_utf16le(NULL, (arg))) { \
		vpn_progress(vpninfo, PRG_ERR,				\
			     _("ERROR: %s() called with invalid UTF-8 for '%s' argument\n"),\
			     __func__, #arg);				\
		return;							\
	}

1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
/* Let's stop open-coding big-endian and little-endian loads/stores.
 *
 * Start with a packed structure so that we can let the compiler
 * decide whether the target CPU can cope with unaligned load/stores
 * or not. Then there are three cases to handle:
 *  - For big-endian loads/stores, just use htons() et al.
 *  - For little-endian when we *know* the CPU is LE, just load/store
 *  - For little-endian otherwise, do the data acess byte-wise
 */
struct oc_packed_uint32_t {
	uint32_t d;
} __attribute__((packed));
struct oc_packed_uint16_t {
	uint16_t d;
} __attribute__((packed));

static inline uint32_t load_be32(const void *_p)
{
	const struct oc_packed_uint32_t *p = _p;
	return ntohl(p->d);
}

static inline uint16_t load_be16(const void *_p)
{
	const struct oc_packed_uint16_t *p = _p;
	return ntohs(p->d);
}

static inline void store_be32(void *_p, uint32_t d)
{
	struct oc_packed_uint32_t *p = _p;
	p->d = htonl(d);
}

static inline void store_be16(void *_p, uint16_t d)
{
	struct oc_packed_uint16_t *p = _p;
	p->d = htons(d);
}

/* It doesn't matter if we don't find one. It'll default to the
 * "not known to be little-endian" case, and do the bytewise
 * load/store. Modern compilers might even spot the pattern and
 * optimise it (see GCC PR#55177 around comment 15). */
#ifdef ENDIAN_HDR
#include ENDIAN_HDR
#endif

#if defined(_WIN32) ||							       \
   (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) /* Solaris */ ||	       \
   (defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) && defined(__BYTE_ORDER) \
    && __BYTE_ORDER == __LITTLE_ENDIAN) /* Linux */ ||			       \
   (defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) && defined(BYTE_ORDER)       \
    && BYTE_ORDER == LITTLE_ENDIAN) /* *BSD */
static inline uint32_t load_le32(const void *_p)
{
	const struct oc_packed_uint32_t *p = _p;
	return p->d;
}

static inline uint16_t load_le16(const void *_p)
{
	const struct oc_packed_uint16_t *p = _p;
	return p->d;
}

static inline void store_le32(void *_p, uint32_t d)
{
	struct oc_packed_uint32_t *p = _p;
	p->d = d;
}

static inline void store_le16(void *_p, uint16_t d)
{
	struct oc_packed_uint16_t *p = _p;
	p->d = d;
}
#else
static inline uint32_t load_le32(const void *_p)
{
	const unsigned char *p = _p;
	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}

static inline uint16_t load_le16(const void *_p)
{
	const unsigned char *p = _p;
	return p[0] | (p[1] << 8);
}

static inline void store_le32(void *_p, uint32_t d)
{
	unsigned char *p = _p;
	p[0] = d;
	p[1] = d >> 8;
}

static inline void store_le16(void *_p, uint16_t d)
{
	unsigned char *p = _p;
	p[0] = d;
	p[1] = d >> 8;
	p[2] = d >> 16;
	p[3] = d >> 24;
}
#endif /* !Not known to be little-endian */

1194
#endif /* __OPENCONNECT_INTERNAL_H__ */