blob: 8b860f7110ccdcf33ceb15790e1f8954d60dc550 [file] [log] [blame]
Radek Krejci206fcd62015-10-07 15:42:48 +02001/**
2 * \file session.c
Michal Vasko086311b2016-01-08 09:53:11 +01003 * \author Michal Vasko <mvasko@cesnet.cz>
4 * \brief libnetconf2 - general session functions
Radek Krejci206fcd62015-10-07 15:42:48 +02005 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 */
22
Radek Krejci206fcd62015-10-07 15:42:48 +020023#include <errno.h>
Radek Krejci952eb862016-01-08 14:22:55 +010024#include <stdlib.h>
Michal Vasko3512e402016-01-28 16:22:34 +010025#include <string.h>
Radek Krejciac6d3472015-10-22 15:47:18 +020026#include <pthread.h>
Michal Vasko58f31552016-01-19 12:39:15 +010027#include <time.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020028#include <libyang/libyang.h>
29
Michal Vasko5e228792016-02-03 15:30:24 +010030#include "session.h"
Michal Vaskob48aa812016-01-18 14:13:09 +010031#include "libnetconf.h"
Michal Vasko11d142a2016-01-19 15:58:24 +010032#include "session_server.h"
Michal Vaskob48aa812016-01-18 14:13:09 +010033
Michal Vasko086311b2016-01-08 09:53:11 +010034#ifdef ENABLE_SSH
Radek Krejci206fcd62015-10-07 15:42:48 +020035
Michal Vasko086311b2016-01-08 09:53:11 +010036# include <libssh/libssh.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020037
Michal Vasko086311b2016-01-08 09:53:11 +010038#endif /* ENABLE_SSH */
Radek Krejci695d4fa2015-10-22 13:23:54 +020039
Michal Vasko5e228792016-02-03 15:30:24 +010040#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
Michal Vaskoc14e3c82016-01-11 16:14:30 +010041
Michal Vasko5e228792016-02-03 15:30:24 +010042# include <openssl/engine.h>
43# include <openssl/conf.h>
Michal Vaskoc14e3c82016-01-11 16:14:30 +010044# include <openssl/err.h>
45
Michal Vasko5e228792016-02-03 15:30:24 +010046#endif /* ENABLE_SSH || ENABLE_TLS */
Michal Vaskoc14e3c82016-01-11 16:14:30 +010047
Michal Vasko086311b2016-01-08 09:53:11 +010048/* in seconds */
49#define NC_CLIENT_HELLO_TIMEOUT 60
Radek Krejci695d4fa2015-10-22 13:23:54 +020050
Michal Vasko05ba9df2016-01-13 14:40:27 +010051/* in milliseconds */
52#define NC_CLOSE_REPLY_TIMEOUT 200
53
Michal Vasko086311b2016-01-08 09:53:11 +010054extern struct nc_server_opts server_opts;
55
Michal Vasko96164bf2016-01-21 15:41:58 +010056/*
57 * @return 1 - success
58 * 0 - timeout
59 * -1 - error
60 */
61int
62nc_timedlock(pthread_mutex_t *lock, int timeout, int *elapsed)
63{
64 int ret;
65 struct timespec ts_timeout, ts_old, ts_new;
66
67 if (timeout > 0) {
68 clock_gettime(CLOCK_REALTIME, &ts_timeout);
69
70 if (elapsed) {
71 ts_old = ts_timeout;
72 }
73
74 ts_timeout.tv_sec += timeout / 1000;
75 ts_timeout.tv_nsec += (timeout % 1000) * 1000000;
76
77 ret = pthread_mutex_timedlock(lock, &ts_timeout);
78
79 if (elapsed) {
80 clock_gettime(CLOCK_REALTIME, &ts_new);
81
82 *elapsed += (ts_new.tv_sec - ts_old.tv_sec) * 1000;
83 *elapsed += (ts_new.tv_nsec - ts_old.tv_nsec) / 1000000;
84 }
85 } else if (!timeout) {
86 ret = pthread_mutex_trylock(lock);
87 } else { /* timeout == -1 */
88 ret = pthread_mutex_lock(lock);
89 }
90
91 if (ret == ETIMEDOUT) {
92 /* timeout */
93 return 0;
94 } else if (ret) {
95 /* error */
96 ERR("Mutex lock failed (%s).", strerror(errno));
97 return -1;
98 }
99
100 /* ok */
101 return 1;
102}
103
104void
105nc_subtract_elapsed(int *timeout, struct timespec *old_ts)
106{
107 struct timespec new_ts;
108
109 clock_gettime(CLOCK_MONOTONIC_RAW, &new_ts);
110
111 *timeout -= (new_ts.tv_sec - old_ts->tv_sec) * 1000;
112 *timeout -= (new_ts.tv_nsec - old_ts->tv_nsec) / 1000000;
113
114 *old_ts = new_ts;
115}
116
Michal Vasko8dadf782016-01-15 10:29:36 +0100117API NC_STATUS
118nc_session_get_status(const struct nc_session *session)
119{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100120 if (!session) {
121 ERRARG;
122 return 0;
123 }
124
Michal Vasko8dadf782016-01-15 10:29:36 +0100125 return session->status;
126}
127
128API uint32_t
129nc_session_get_id(const struct nc_session *session)
130{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100131 if (!session) {
132 ERRARG;
133 return 0;
134 }
135
Michal Vasko8dadf782016-01-15 10:29:36 +0100136 return session->id;
137}
138
Michal Vasko174fe8e2016-02-17 15:38:09 +0100139API int
140nc_session_get_version(const struct nc_session *session)
141{
142 if (!session) {
143 ERRARG;
144 return -1;
145 }
146
147 return (session->version == NC_VERSION_10 ? 0 : 1);
148}
149
Michal Vasko8dadf782016-01-15 10:29:36 +0100150API NC_TRANSPORT_IMPL
151nc_session_get_ti(const struct nc_session *session)
152{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100153 if (!session) {
154 ERRARG;
155 return 0;
156 }
157
Michal Vasko8dadf782016-01-15 10:29:36 +0100158 return session->ti_type;
159}
160
161API const char *
162nc_session_get_username(const struct nc_session *session)
163{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100164 if (!session) {
165 ERRARG;
166 return NULL;
167 }
168
Michal Vasko8dadf782016-01-15 10:29:36 +0100169 return session->username;
170}
171
172API const char *
173nc_session_get_host(const struct nc_session *session)
174{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100175 if (!session) {
176 ERRARG;
177 return NULL;
178 }
179
Michal Vasko8dadf782016-01-15 10:29:36 +0100180 return session->host;
181}
182
183API uint16_t
184nc_session_get_port(const struct nc_session *session)
185{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100186 if (!session) {
187 ERRARG;
188 return 0;
189 }
190
Michal Vasko8dadf782016-01-15 10:29:36 +0100191 return session->port;
192}
193
Michal Vasko9a25e932016-02-01 10:36:42 +0100194API struct ly_ctx *
195nc_session_get_ctx(const struct nc_session *session)
196{
197 if (!session) {
198 ERRARG;
199 return NULL;
200 }
201
202 return session->ctx;
203}
204
Michal Vasko8dadf782016-01-15 10:29:36 +0100205API const char **
206nc_session_get_cpblts(const struct nc_session *session)
207{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100208 if (!session) {
209 ERRARG;
210 return NULL;
211 }
212
Michal Vasko8dadf782016-01-15 10:29:36 +0100213 return session->cpblts;
214}
215
216API const char *
217nc_session_cpblt(const struct nc_session *session, const char *capab)
218{
219 int i, len;
220
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100221 if (!session || !capab) {
222 ERRARG;
223 return NULL;
224 }
225
Michal Vasko8dadf782016-01-15 10:29:36 +0100226 len = strlen(capab);
227 for (i = 0; session->cpblts[i]; ++i) {
228 if (!strncmp(session->cpblts[i], capab, len)) {
229 return session->cpblts[i];
230 }
231 }
232
233 return NULL;
234}
235
Michal Vasko086311b2016-01-08 09:53:11 +0100236NC_MSG_TYPE
237nc_send_msg(struct nc_session *session, struct lyd_node *op)
Radek Krejci695d4fa2015-10-22 13:23:54 +0200238{
Michal Vasko086311b2016-01-08 09:53:11 +0100239 int r;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200240
Michal Vasko086311b2016-01-08 09:53:11 +0100241 if (session->ctx != op->schema->module->ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +0100242 ERR("Session %u: RPC \"%s\" was created in different context than that of the session.",
243 session->id, op->schema->name);
Michal Vasko086311b2016-01-08 09:53:11 +0100244 return NC_MSG_ERROR;
Michal Vasko7df39ec2015-12-09 15:26:24 +0100245 }
246
Michal Vasko086311b2016-01-08 09:53:11 +0100247 r = nc_write_msg(session, NC_MSG_RPC, op, NULL);
248
249 if (r) {
250 return NC_MSG_ERROR;
251 }
252
253 return NC_MSG_RPC;
Michal Vasko7df39ec2015-12-09 15:26:24 +0100254}
255
Radek Krejci695d4fa2015-10-22 13:23:54 +0200256API void
257nc_session_free(struct nc_session *session)
258{
259 int r, i;
Michal Vasko428087d2016-01-14 16:04:28 +0100260 int connected; /* flag to indicate whether the transport socket is still connected */
Michal Vaskob48aa812016-01-18 14:13:09 +0100261 int multisession = 0; /* flag for more NETCONF sessions on a single SSH session */
Michal Vaskoa8ad4482016-01-28 14:25:54 +0100262 pthread_t tid;
Michal Vasko4589bbe2016-01-29 09:41:30 +0100263 struct nc_session *siter;
Michal Vaskoad611702015-12-03 13:41:51 +0100264 struct nc_msg_cont *contiter;
Michal Vaskoadd4c792015-10-26 15:36:58 +0100265 struct lyxml_elem *rpl, *child;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200266 struct lyd_node *close_rpc;
Michal Vaskoad611702015-12-03 13:41:51 +0100267 const struct lys_module *ietfnc;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200268 void *p;
269
Michal Vasko428087d2016-01-14 16:04:28 +0100270 if (!session || (session->status == NC_STATUS_CLOSING)) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200271 return;
272 }
273
274 /* mark session for closing */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100275 if (session->ti_lock) {
Michal Vasko4589bbe2016-01-29 09:41:30 +0100276 r = nc_timedlock(session->ti_lock, -1, NULL);
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100277 if (r == -1) {
Michal Vaskoadd4c792015-10-26 15:36:58 +0100278 return;
279 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200280 }
281
282 /* stop notifications loop if any */
Michal Vaskoa8ad4482016-01-28 14:25:54 +0100283 if (session->ntf_tid) {
284 tid = *session->ntf_tid;
285 free((pthread_t *)session->ntf_tid);
286 session->ntf_tid = NULL;
287 /* the thread now knows it should quit */
288
289 pthread_join(tid, NULL);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200290 }
291
Michal Vasko428087d2016-01-14 16:04:28 +0100292 if ((session->side == NC_CLIENT) && (session->status == NC_STATUS_RUNNING)) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200293 /* cleanup message queues */
294 /* notifications */
Michal Vaskoad611702015-12-03 13:41:51 +0100295 for (contiter = session->notifs; contiter; ) {
296 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200297
Michal Vaskoad611702015-12-03 13:41:51 +0100298 p = contiter;
299 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200300 free(p);
301 }
302
303 /* rpc replies */
Michal Vaskoad611702015-12-03 13:41:51 +0100304 for (contiter = session->replies; contiter; ) {
305 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200306
Michal Vaskoad611702015-12-03 13:41:51 +0100307 p = contiter;
308 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200309 free(p);
310 }
311
312 /* send closing info to the other side */
313 ietfnc = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL);
314 if (!ietfnc) {
Michal Vasko428087d2016-01-14 16:04:28 +0100315 WRN("Session %u: missing ietf-netconf schema in context, unable to send <close-session>.", session->id);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200316 } else {
317 close_rpc = lyd_new(NULL, ietfnc, "close-session");
Michal Vaskoad611702015-12-03 13:41:51 +0100318 nc_send_msg(session, close_rpc);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200319 lyd_free(close_rpc);
Michal Vasko05ba9df2016-01-13 14:40:27 +0100320 switch (nc_read_msg_poll(session, NC_CLOSE_REPLY_TIMEOUT, &rpl)) {
Michal Vaskofad6e912015-10-26 15:37:22 +0100321 case NC_MSG_REPLY:
322 LY_TREE_FOR(rpl->child, child) {
323 if (!strcmp(child->name, "ok") && child->ns && !strcmp(child->ns->value, NC_NS_BASE)) {
324 break;
325 }
326 }
327 if (!child) {
Michal Vasko428087d2016-01-14 16:04:28 +0100328 WRN("Session %u: the reply to <close-session> was not <ok> as expected.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100329 }
Michal Vaskoad611702015-12-03 13:41:51 +0100330 lyxml_free(session->ctx, rpl);
Michal Vaskofad6e912015-10-26 15:37:22 +0100331 break;
332 case NC_MSG_WOULDBLOCK:
Michal Vasko428087d2016-01-14 16:04:28 +0100333 WRN("Session %u: timeout for receiving a reply to <close-session> elapsed.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100334 break;
335 case NC_MSG_ERROR:
Michal Vaskod083db62016-01-19 10:31:29 +0100336 ERR("Session %u: failed to receive a reply to <close-session>.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100337 break;
338 default:
339 /* cannot happen */
340 break;
341 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200342 }
343
344 /* list of server's capabilities */
345 if (session->cpblts) {
346 for (i = 0; session->cpblts[i]; i++) {
347 lydict_remove(session->ctx, session->cpblts[i]);
348 }
349 free(session->cpblts);
350 }
351 }
352
353 session->status = NC_STATUS_CLOSING;
Michal Vasko428087d2016-01-14 16:04:28 +0100354 connected = nc_session_is_connected(session);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200355
356 /* transport implementation cleanup */
357 switch (session->ti_type) {
358 case NC_TI_FD:
359 /* nothing needed - file descriptors were provided by caller,
360 * so it is up to the caller to close them correctly
361 * TODO use callbacks
362 */
Michal Vasko3512e402016-01-28 16:22:34 +0100363 /* just to avoid compiler warning */
364 (void)connected;
Michal Vasko4589bbe2016-01-29 09:41:30 +0100365 (void)siter;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200366 break;
367
Michal Vaskofb2fb762015-10-27 11:44:32 +0100368#ifdef ENABLE_SSH
Radek Krejci695d4fa2015-10-22 13:23:54 +0200369 case NC_TI_LIBSSH:
Michal Vasko428087d2016-01-14 16:04:28 +0100370 if (connected) {
371 ssh_channel_free(session->ti.libssh.channel);
372 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200373 /* There can be multiple NETCONF sessions on the same SSH session (NETCONF session maps to
374 * SSH channel). So destroy the SSH session only if there is no other NETCONF session using
375 * it.
376 */
Michal Vasko96164bf2016-01-21 15:41:58 +0100377 multisession = 0;
378 if (session->ti.libssh.next) {
379 for (siter = session->ti.libssh.next; siter != session; siter = siter->ti.libssh.next) {
380 if (siter->status != NC_STATUS_STARTING) {
381 multisession = 1;
382 break;
383 }
384 }
385 }
386
387 if (!multisession) {
388 /* it's not multisession yet, but we still need to free the starting sessions */
389 if (session->ti.libssh.next) {
390 do {
391 siter = session->ti.libssh.next;
392 session->ti.libssh.next = siter->ti.libssh.next;
393
394 /* free starting SSH NETCONF session (channel will be freed in ssh_free()) */
Michal Vasko96164bf2016-01-21 15:41:58 +0100395 lydict_remove(session->ctx, session->username);
396 lydict_remove(session->ctx, session->host);
Michal Vasko96164bf2016-01-21 15:41:58 +0100397 if (!(session->flags & NC_SESSION_SHAREDCTX)) {
Radek Krejci4ba285b2016-02-04 17:34:06 +0100398 ly_ctx_destroy(session->ctx, NULL);
Michal Vasko96164bf2016-01-21 15:41:58 +0100399 }
400
401 free(siter);
402 } while (session->ti.libssh.next != session);
403 }
Michal Vasko428087d2016-01-14 16:04:28 +0100404 if (connected) {
405 ssh_disconnect(session->ti.libssh.session);
406 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200407 ssh_free(session->ti.libssh.session);
408 } else {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200409 /* remove the session from the list */
410 for (siter = session->ti.libssh.next; siter->ti.libssh.next != session; siter = siter->ti.libssh.next);
Michal Vaskoaec4f212015-10-26 15:37:45 +0100411 if (session->ti.libssh.next == siter) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200412 /* there will be only one session */
413 siter->ti.libssh.next = NULL;
414 } else {
415 /* there are still multiple sessions, keep the ring list */
416 siter->ti.libssh.next = session->ti.libssh.next;
417 }
Michal Vasko96164bf2016-01-21 15:41:58 +0100418 /* change nc_sshcb_msg() argument, we need a RUNNING session and this one will be freed */
419 if (session->flags & NC_SESSION_SSH_MSG_CB) {
420 for (siter = session->ti.libssh.next; siter->status != NC_STATUS_RUNNING; siter = siter->ti.libssh.next) {
421 if (siter->ti.libssh.next == session) {
422 ERRINT;
423 break;
424 }
425 }
426 ssh_set_message_callback(session->ti.libssh.session, nc_sshcb_msg, siter);
427 siter->flags |= NC_SESSION_SSH_MSG_CB;
428 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200429 }
430 break;
431#endif
432
433#ifdef ENABLE_TLS
434 case NC_TI_OPENSSL:
Michal Vasko428087d2016-01-14 16:04:28 +0100435 if (connected) {
436 SSL_shutdown(session->ti.tls);
437 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200438 SSL_free(session->ti.tls);
Michal Vasko06e22432016-01-15 10:30:06 +0100439
440 X509_free(session->tls_cert);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200441 break;
442#endif
Michal Vasko428087d2016-01-14 16:04:28 +0100443 case NC_TI_NONE:
444 ERRINT;
445 break;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200446 }
Michal Vasko428087d2016-01-14 16:04:28 +0100447
Radek Krejciac6d3472015-10-22 15:47:18 +0200448 lydict_remove(session->ctx, session->username);
449 lydict_remove(session->ctx, session->host);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200450
451 /* final cleanup */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100452 if (session->ti_lock) {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100453 pthread_mutex_unlock(session->ti_lock);
Michal Vaskob48aa812016-01-18 14:13:09 +0100454 if (!multisession) {
Michal Vaskoadd4c792015-10-26 15:36:58 +0100455 pthread_mutex_destroy(session->ti_lock);
456 free(session->ti_lock);
457 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200458 }
459
460 if (!(session->flags & NC_SESSION_SHAREDCTX)) {
Radek Krejci4ba285b2016-02-04 17:34:06 +0100461 ly_ctx_destroy(session->ctx, NULL);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200462 }
463
464 free(session);
465}
466
Michal Vasko086311b2016-01-08 09:53:11 +0100467static void
468add_cpblt(struct ly_ctx *ctx, const char *capab, const char ***cpblts, int *size, int *count)
469{
470 if (*count == *size) {
471 *size += 5;
472 *cpblts = realloc(*cpblts, *size * sizeof **cpblts);
473 }
474
475 if (capab) {
476 (*cpblts)[*count] = lydict_insert(ctx, capab, 0);
477 } else {
478 (*cpblts)[*count] = NULL;
479 }
480 ++(*count);
481}
482
483static const char **
484create_cpblts(struct ly_ctx *ctx)
485{
486 struct lyd_node *child, *child2, *yanglib;
487 struct lyd_node_leaf_list **features = NULL, *ns = NULL, *rev = NULL, *name = NULL;
488 const char **cpblts;
489 const struct lys_module *mod;
Michal Vasko11d142a2016-01-19 15:58:24 +0100490 int size = 10, count, feat_count = 0, i, str_len;
Michal Vasko086311b2016-01-08 09:53:11 +0100491 char str[512];
492
493 yanglib = ly_ctx_info(ctx);
494 if (!yanglib) {
495 return NULL;
496 }
497
498 cpblts = malloc(size * sizeof *cpblts);
499 cpblts[0] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.0", 0);
500 cpblts[1] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.1", 0);
501 count = 2;
502
503 /* capabilities */
504
505 mod = ly_ctx_get_module(ctx, "ietf-netconf", NULL);
506 if (mod) {
507 if (lys_features_state(mod, "writable-running") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100508 add_cpblt(ctx, "urn:ietf:params:netconf:capability:writable-running:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100509 }
510 if (lys_features_state(mod, "candidate") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100511 add_cpblt(ctx, "urn:ietf:params:netconf:capability:candidate:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100512 if (lys_features_state(mod, "confirmed-commit") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100513 add_cpblt(ctx, "urn:ietf:params:netconf:capability:confirmed-commit:1.1", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100514 }
515 }
516 if (lys_features_state(mod, "rollback-on-error") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100517 add_cpblt(ctx, "urn:ietf:params:netconf:capability:rollback-on-error:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100518 }
519 if (lys_features_state(mod, "validate") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100520 add_cpblt(ctx, "urn:ietf:params:netconf:capability:validate:1.1", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100521 }
522 if (lys_features_state(mod, "startup") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100523 add_cpblt(ctx, "urn:ietf:params:netconf:capability:startup:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100524 }
525 if (lys_features_state(mod, "url") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100526 add_cpblt(ctx, "urn:ietf:params:netconf:capability:url:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100527 }
528 if (lys_features_state(mod, "xpath") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100529 add_cpblt(ctx, "urn:ietf:params:netconf:capability:xpath:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100530 }
531 }
532
533 mod = ly_ctx_get_module(ctx, "ietf-netconf-with-defaults", NULL);
534 if (mod) {
535 if (!server_opts.wd_basic_mode) {
536 VRB("with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode.");
537 } else {
Michal Vasko3031aae2016-01-27 16:07:18 +0100538 strcpy(str, "urn:ietf:params:netconf:capability:with-defaults:1.0");
Michal Vasko086311b2016-01-08 09:53:11 +0100539 switch (server_opts.wd_basic_mode) {
540 case NC_WD_ALL:
541 strcat(str, "?basic-mode=report-all");
542 break;
543 case NC_WD_TRIM:
544 strcat(str, "?basic-mode=trim");
545 break;
546 case NC_WD_EXPLICIT:
547 strcat(str, "?basic-mode=explicit");
548 break;
549 default:
Michal Vasko9e036d52016-01-08 10:49:26 +0100550 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100551 break;
552 }
553
554 if (server_opts.wd_also_supported) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100555 strcat(str, "&amp;also-supported=");
Michal Vasko086311b2016-01-08 09:53:11 +0100556 if (server_opts.wd_also_supported & NC_WD_ALL) {
557 strcat(str, "report-all,");
558 }
559 if (server_opts.wd_also_supported & NC_WD_ALL_TAG) {
560 strcat(str, "report-all-tagged,");
561 }
562 if (server_opts.wd_also_supported & NC_WD_TRIM) {
563 strcat(str, "trim,");
564 }
565 if (server_opts.wd_also_supported & NC_WD_EXPLICIT) {
566 strcat(str, "explicit,");
567 }
568 str[strlen(str) - 1] = '\0';
569
570 add_cpblt(ctx, str, &cpblts, &size, &count);
571 }
572 }
573 }
574
Michal Vasko1a38c862016-01-15 15:50:07 +0100575 mod = ly_ctx_get_module(ctx, "nc-notifications", NULL);
Michal Vasko086311b2016-01-08 09:53:11 +0100576 if (mod) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100577 add_cpblt(ctx, "urn:ietf:params:netconf:capability:notification:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100578 if (server_opts.interleave_capab) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100579 add_cpblt(ctx, "urn:ietf:params:netconf:capability:interleave:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100580 }
581 }
582
583 /* models */
584
585 LY_TREE_FOR(yanglib->child, child) {
586 if (!strcmp(child->schema->name, "module")) {
587 LY_TREE_FOR(child->child, child2) {
588 if (!strcmp(child2->schema->name, "namespace")) {
589 ns = (struct lyd_node_leaf_list *)child2;
590 } else if (!strcmp(child2->schema->name, "name")) {
591 name = (struct lyd_node_leaf_list *)child2;
592 } else if (!strcmp(child2->schema->name, "revision")) {
593 rev = (struct lyd_node_leaf_list *)child2;
594 } else if (!strcmp(child2->schema->name, "feature")) {
595 features = realloc(features, feat_count++ * sizeof *features);
596 features[feat_count - 1] = (struct lyd_node_leaf_list *)child2;
597 }
598 }
599
600 if (!ns || !name || !rev) {
Michal Vasko9e036d52016-01-08 10:49:26 +0100601 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100602 continue;
603 }
604
Michal Vasko11d142a2016-01-19 15:58:24 +0100605 str_len = sprintf(str, "%s?module=%s&amp;revision=%s", ns->value_str, name->value_str, rev->value_str);
Michal Vasko086311b2016-01-08 09:53:11 +0100606 if (feat_count) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100607 strcat(str, "&amp;features=");
Michal Vasko11d142a2016-01-19 15:58:24 +0100608 str_len += 14;
Michal Vasko086311b2016-01-08 09:53:11 +0100609 for (i = 0; i < feat_count; ++i) {
Michal Vasko11d142a2016-01-19 15:58:24 +0100610 if (str_len + 1 + strlen(features[i]->value_str) >= 512) {
611 ERRINT;
612 break;
613 }
Michal Vasko086311b2016-01-08 09:53:11 +0100614 if (i) {
615 strcat(str, ",");
Michal Vasko11d142a2016-01-19 15:58:24 +0100616 ++str_len;
Michal Vasko086311b2016-01-08 09:53:11 +0100617 }
618 strcat(str, features[i]->value_str);
Michal Vasko11d142a2016-01-19 15:58:24 +0100619 str_len += strlen(features[i]->value_str);
Michal Vasko086311b2016-01-08 09:53:11 +0100620 }
621 }
622
623 add_cpblt(ctx, str, &cpblts, &size, &count);
624
625 ns = NULL;
626 name = NULL;
627 rev = NULL;
628 free(features);
629 features = NULL;
630 feat_count = 0;
631 }
632 }
633
634 lyd_free(yanglib);
635
636 /* ending NULL capability */
637 add_cpblt(ctx, NULL, &cpblts, &size, &count);
638
639 return cpblts;
640}
641
Radek Krejci695d4fa2015-10-22 13:23:54 +0200642static int
643parse_cpblts(struct lyxml_elem *xml, const char ***list)
644{
645 struct lyxml_elem *cpblt;
646 int ver = -1;
647 int i = 0;
648
649 if (list) {
650 /* get the storage for server's capabilities */
651 LY_TREE_FOR(xml->child, cpblt) {
652 i++;
653 }
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100654 /* last item remains NULL */
655 *list = calloc(i + 1, sizeof **list);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200656 if (!*list) {
657 ERRMEM;
658 return -1;
659 }
660 i = 0;
661 }
662
663 LY_TREE_FOR(xml->child, cpblt) {
664 if (strcmp(cpblt->name, "capability") && cpblt->ns && cpblt->ns->value &&
665 !strcmp(cpblt->ns->value, NC_NS_BASE)) {
666 ERR("Unexpected <%s> element in client's <hello>.", cpblt->name);
667 return -1;
668 } else if (!cpblt->ns || !cpblt->ns->value || strcmp(cpblt->ns->value, NC_NS_BASE)) {
669 continue;
670 }
671
672 /* detect NETCONF version */
673 if (ver < 0 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.0")) {
674 ver = 0;
675 } else if (ver < 1 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.1")) {
676 ver = 1;
677 }
678
679 /* store capabilities */
680 if (list) {
681 (*list)[i] = cpblt->content;
682 cpblt->content = NULL;
683 i++;
684 }
685 }
686
687 if (ver == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100688 ERR("Peer does not support a compatible NETCONF version.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200689 }
690
691 return ver;
692}
693
694static NC_MSG_TYPE
Michal Vasko11d142a2016-01-19 15:58:24 +0100695nc_send_client_hello(struct nc_session *session)
Michal Vasko086311b2016-01-08 09:53:11 +0100696{
697 int r, i;
698 const char **cpblts;
699
Michal Vasko11d142a2016-01-19 15:58:24 +0100700 /* client side hello - send only NETCONF base capabilities */
701 cpblts = malloc(3 * sizeof *cpblts);
702 cpblts[0] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.0", 0);
703 cpblts[1] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.1", 0);
704 cpblts[2] = NULL;
Michal Vasko05ba9df2016-01-13 14:40:27 +0100705
Michal Vasko11d142a2016-01-19 15:58:24 +0100706 r = nc_write_msg(session, NC_MSG_HELLO, cpblts, NULL);
Michal Vasko086311b2016-01-08 09:53:11 +0100707
Michal Vasko086311b2016-01-08 09:53:11 +0100708 for (i = 0; cpblts[i]; ++i) {
709 lydict_remove(session->ctx, cpblts[i]);
710 }
711 free(cpblts);
712
713 if (r) {
714 return NC_MSG_ERROR;
Michal Vasko086311b2016-01-08 09:53:11 +0100715 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100716
717 return NC_MSG_HELLO;
Michal Vasko086311b2016-01-08 09:53:11 +0100718}
719
720static NC_MSG_TYPE
Michal Vasko11d142a2016-01-19 15:58:24 +0100721nc_send_server_hello(struct nc_session *session)
722{
723 int r, i;
724 const char **cpblts;
725
726 cpblts = create_cpblts(session->ctx);
727
728 r = nc_write_msg(session, NC_MSG_HELLO, cpblts, &session->id);
729
Michal Vasko11d142a2016-01-19 15:58:24 +0100730 for (i = 0; cpblts[i]; ++i) {
731 lydict_remove(session->ctx, cpblts[i]);
732 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100733 free(cpblts);
734
735 if (r) {
736 return NC_MSG_ERROR;
737 }
738
739 return NC_MSG_HELLO;
740}
741
742static NC_MSG_TYPE
743nc_recv_client_hello(struct nc_session *session)
Radek Krejci695d4fa2015-10-22 13:23:54 +0200744{
745 struct lyxml_elem *xml = NULL, *node;
746 NC_MSG_TYPE msgtype = 0; /* NC_MSG_ERROR */
747 int ver = -1;
748 char *str;
749 long long int id;
750 int flag = 0;
751
Michal Vasko05ba9df2016-01-13 14:40:27 +0100752 msgtype = nc_read_msg_poll(session, NC_CLIENT_HELLO_TIMEOUT * 1000, &xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200753
754 switch(msgtype) {
755 case NC_MSG_HELLO:
756 /* parse <hello> data */
Michal Vasko11d142a2016-01-19 15:58:24 +0100757 LY_TREE_FOR(xml->child, node) {
758 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
759 continue;
760 } else if (!strcmp(node->name, "session-id")) {
761 if (!node->content || !strlen(node->content)) {
762 ERR("No value of <session-id> element in server's <hello>.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200763 goto error;
764 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100765 str = NULL;
766 id = strtoll(node->content, &str, 10);
767 if (*str || id < 1 || id > UINT32_MAX) {
768 ERR("Invalid value of <session-id> element in server's <hello>.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200769 goto error;
770 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100771 session->id = (uint32_t)id;
772 continue;
773 } else if (strcmp(node->name, "capabilities")) {
774 ERR("Unexpected <%s> element in client's <hello>.", node->name);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200775 goto error;
776 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100777
778 if (flag) {
779 /* multiple capabilities elements */
780 ERR("Invalid <hello> message (multiple <capabilities> elements).");
781 goto error;
782 }
783 flag = 1;
784
785 if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
786 goto error;
787 }
788 session->version = ver;
789 }
790
791 if (!session->id) {
792 ERR("Missing <session-id> in server's <hello>.");
793 goto error;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200794 }
795 break;
796 case NC_MSG_ERROR:
797 /* nothing special, just pass it out */
798 break;
799 default:
800 ERR("Unexpected message received instead of <hello>.");
801 msgtype = NC_MSG_ERROR;
802 }
803
804 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100805 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200806
807 return msgtype;
808
809error:
810 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100811 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200812
813 return NC_MSG_ERROR;
Radek Krejci5686ff72015-10-09 13:33:56 +0200814}
815
Michal Vasko11d142a2016-01-19 15:58:24 +0100816static NC_MSG_TYPE
817nc_recv_server_hello(struct nc_session *session)
818{
819 struct lyxml_elem *xml = NULL, *node;
820 NC_MSG_TYPE msgtype = 0; /* NC_MSG_ERROR */
821 int ver = -1;
822 int flag = 0;
823
Michal Vaskoadb850e2016-01-20 14:06:32 +0100824 msgtype = nc_read_msg_poll(session, (server_opts.hello_timeout ? server_opts.hello_timeout * 1000 : -1), &xml);
Michal Vasko11d142a2016-01-19 15:58:24 +0100825
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100826 switch (msgtype) {
Michal Vasko11d142a2016-01-19 15:58:24 +0100827 case NC_MSG_HELLO:
828 /* get know NETCONF version */
829 LY_TREE_FOR(xml->child, node) {
830 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
831 continue;
832 } else if (strcmp(node->name, "capabilities")) {
833 ERR("Unexpected <%s> element in client's <hello>.", node->name);
834 msgtype = NC_MSG_ERROR;
835 goto cleanup;
836 }
837
838 if (flag) {
839 /* multiple capabilities elements */
840 ERR("Invalid <hello> message (multiple <capabilities> elements).");
841 msgtype = NC_MSG_ERROR;
842 goto cleanup;
843 }
844 flag = 1;
845
846 if ((ver = parse_cpblts(node, NULL)) < 0) {
847 msgtype = NC_MSG_ERROR;
848 goto cleanup;
849 }
850 session->version = ver;
851 }
852 break;
853 case NC_MSG_ERROR:
854 /* nothing special, just pass it out */
855 break;
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100856 case NC_MSG_WOULDBLOCK:
857 ERR("Client's <hello> timeout elapsed.");
858 msgtype = NC_MSG_ERROR;
859 break;
Michal Vasko11d142a2016-01-19 15:58:24 +0100860 default:
861 ERR("Unexpected message received instead of <hello>.");
862 msgtype = NC_MSG_ERROR;
863 }
864
865cleanup:
Michal Vasko11d142a2016-01-19 15:58:24 +0100866 lyxml_free(session->ctx, xml);
Michal Vasko11d142a2016-01-19 15:58:24 +0100867
868 return msgtype;
869}
870
Michal Vasko80cad7f2015-12-08 14:42:27 +0100871int
Michal Vasko086311b2016-01-08 09:53:11 +0100872nc_handshake(struct nc_session *session)
Michal Vasko80cad7f2015-12-08 14:42:27 +0100873{
Michal Vasko086311b2016-01-08 09:53:11 +0100874 NC_MSG_TYPE type;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100875
Michal Vasko11d142a2016-01-19 15:58:24 +0100876 if (session->side == NC_CLIENT) {
877 type = nc_send_client_hello(session);
878 } else {
879 type = nc_send_server_hello(session);
880 }
881
Michal Vasko086311b2016-01-08 09:53:11 +0100882 if (type != NC_MSG_HELLO) {
883 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100884 }
885
Michal Vasko11d142a2016-01-19 15:58:24 +0100886 if (session->side == NC_CLIENT) {
887 type = nc_recv_client_hello(session);
888 } else {
889 type = nc_recv_server_hello(session);
890 }
891
Michal Vasko086311b2016-01-08 09:53:11 +0100892 if (type != NC_MSG_HELLO) {
893 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100894 }
895
Michal Vasko086311b2016-01-08 09:53:11 +0100896 return 0;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100897}
Michal Vasko086311b2016-01-08 09:53:11 +0100898
899#ifdef ENABLE_SSH
900
901API void
902nc_ssh_init(void)
903{
904 ssh_threads_set_callbacks(ssh_threads_get_pthread());
905 ssh_init();
906 ssh_set_log_level(verbose_level);
907}
908
909API void
910nc_ssh_destroy(void)
911{
Michal Vasko5e228792016-02-03 15:30:24 +0100912 ENGINE_cleanup();
913 CONF_modules_unload(1);
914 ERR_remove_state(0);
Michal Vasko086311b2016-01-08 09:53:11 +0100915 ssh_finalize();
916}
917
918#endif /* ENABLE_SSH */
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100919
920#ifdef ENABLE_TLS
921
922static pthread_mutex_t *tls_locks;
923
Michal Vaskof0c92c02016-01-29 09:41:45 +0100924struct CRYPTO_dynlock_value {
925 pthread_mutex_t lock;
926};
927
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100928static void
Michal Vaskob48aa812016-01-18 14:13:09 +0100929tls_thread_locking_func(int mode, int n, const char *UNUSED(file), int UNUSED(line))
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100930{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100931 if (mode & CRYPTO_LOCK) {
932 pthread_mutex_lock(tls_locks + n);
933 } else {
934 pthread_mutex_unlock(tls_locks + n);
935 }
936}
937
Michal Vaskof0c92c02016-01-29 09:41:45 +0100938static void
939tls_thread_id_func(CRYPTO_THREADID *tid)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100940{
Michal Vaskof0c92c02016-01-29 09:41:45 +0100941 CRYPTO_THREADID_set_numeric(tid, (unsigned long)pthread_self());
942}
943
944static struct CRYPTO_dynlock_value *
945tls_dyn_create_func(const char *UNUSED(file), int UNUSED(line))
946{
947 struct CRYPTO_dynlock_value *value;
948
949 value = malloc(sizeof *value);
950 if (!value) {
951 ERRMEM;
952 return NULL;
953 }
954 pthread_mutex_init(&value->lock, NULL);
955
956 return value;
957}
958
959static void
960tls_dyn_lock_func(int mode, struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line))
961{
962 /* mode can also be CRYPTO_READ or CRYPTO_WRITE, but all the examples
963 * I found ignored this fact, what do I know... */
964 if (mode & CRYPTO_LOCK) {
965 pthread_mutex_lock(&l->lock);
966 } else {
967 pthread_mutex_unlock(&l->lock);
968 }
969}
970
971static void
972tls_dyn_destroy_func(struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line))
973{
974 pthread_mutex_destroy(&l->lock);
975 free(l);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100976}
977
978API void
979nc_tls_init(void)
980{
981 int i;
982
983 SSL_load_error_strings();
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100984 ERR_load_BIO_strings();
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100985 SSL_library_init();
986
987 tls_locks = malloc(CRYPTO_num_locks() * sizeof *tls_locks);
988 for (i = 0; i < CRYPTO_num_locks(); ++i) {
989 pthread_mutex_init(tls_locks + i, NULL);
990 }
991
Michal Vaskof0c92c02016-01-29 09:41:45 +0100992 CRYPTO_THREADID_set_callback(tls_thread_id_func);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100993 CRYPTO_set_locking_callback(tls_thread_locking_func);
Michal Vaskof0c92c02016-01-29 09:41:45 +0100994
995 CRYPTO_set_dynlock_create_callback(tls_dyn_create_func);
996 CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func);
997 CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100998}
999
1000API void
1001nc_tls_destroy(void)
1002{
1003 int i;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001004
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001005 CRYPTO_cleanup_all_ex_data();
Michal Vasko5e228792016-02-03 15:30:24 +01001006 ERR_remove_state(0);
1007 EVP_cleanup();
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001008 ERR_free_strings();
1009 sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001010
1011 CRYPTO_set_id_callback(NULL);
1012 CRYPTO_set_locking_callback(NULL);
1013 for (i = 0; i < CRYPTO_num_locks(); ++i) {
1014 pthread_mutex_destroy(tls_locks + i);
1015 }
1016 free(tls_locks);
Michal Vaskof0c92c02016-01-29 09:41:45 +01001017
1018 CRYPTO_set_dynlock_create_callback(NULL);
1019 CRYPTO_set_dynlock_lock_callback(NULL);
1020 CRYPTO_set_dynlock_destroy_callback(NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001021}
1022
1023#endif /* ENABLE_TLS */
Michal Vasko5e228792016-02-03 15:30:24 +01001024
1025#if defined(ENABLE_SSH) || defined(ENABLE_TLS)
1026
1027API void
1028nc_thread_destroy(void) {
1029 CRYPTO_THREADID crypto_tid;
1030
Michal Vasko0be5dff2016-02-08 15:26:37 +01001031 /* caused data-races and seems not neccessary for avoiding valgrind reachable memory */
1032 //CRYPTO_cleanup_all_ex_data();
Michal Vasko5e228792016-02-03 15:30:24 +01001033
1034 CRYPTO_THREADID_current(&crypto_tid);
1035 ERR_remove_thread_state(&crypto_tid);
1036}
1037
1038#endif /* ENABLE_SSH || ENABLE_TLS */
1039
1040#if defined(ENABLE_SSH) && defined(ENABLE_TLS)
1041
1042API void
1043nc_ssh_tls_init(void)
1044{
1045 SSL_load_error_strings();
1046 ERR_load_BIO_strings();
1047 SSL_library_init();
1048
1049 nc_ssh_init();
1050
1051 CRYPTO_set_dynlock_create_callback(tls_dyn_create_func);
1052 CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func);
1053 CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func);
1054}
1055
1056API void
1057nc_ssh_tls_destroy(void)
1058{
1059 ERR_free_strings();
1060 sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
1061
1062 nc_ssh_destroy();
1063
1064 CRYPTO_set_dynlock_create_callback(NULL);
1065 CRYPTO_set_dynlock_lock_callback(NULL);
1066 CRYPTO_set_dynlock_destroy_callback(NULL);
1067}
1068
1069#endif /* ENABLE_SSH && ENABLE_TLS */