blob: d1aef7f2a3c94ce79f35438fac6d4e7d7ccdef0c [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 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci206fcd62015-10-07 15:42:48 +020013 */
14
Radek Krejci206fcd62015-10-07 15:42:48 +020015#include <errno.h>
Radek Krejci952eb862016-01-08 14:22:55 +010016#include <stdlib.h>
Michal Vasko3512e402016-01-28 16:22:34 +010017#include <string.h>
Radek Krejciac6d3472015-10-22 15:47:18 +020018#include <pthread.h>
Michal Vasko58f31552016-01-19 12:39:15 +010019#include <time.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020020#include <libyang/libyang.h>
21
Michal Vasko5e228792016-02-03 15:30:24 +010022#include "session.h"
Michal Vaskob48aa812016-01-18 14:13:09 +010023#include "libnetconf.h"
Michal Vasko11d142a2016-01-19 15:58:24 +010024#include "session_server.h"
Michal Vaskob48aa812016-01-18 14:13:09 +010025
Radek Krejci53691be2016-02-22 13:58:37 +010026#ifdef NC_ENABLED_SSH
Radek Krejci206fcd62015-10-07 15:42:48 +020027
Michal Vasko086311b2016-01-08 09:53:11 +010028# include <libssh/libssh.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020029
Radek Krejci53691be2016-02-22 13:58:37 +010030#endif /* NC_ENABLED_SSH */
Radek Krejci695d4fa2015-10-22 13:23:54 +020031
Radek Krejci53691be2016-02-22 13:58:37 +010032#if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
Michal Vaskoc14e3c82016-01-11 16:14:30 +010033
Michal Vasko5e228792016-02-03 15:30:24 +010034# include <openssl/engine.h>
35# include <openssl/conf.h>
Michal Vaskoc14e3c82016-01-11 16:14:30 +010036# include <openssl/err.h>
37
Radek Krejci53691be2016-02-22 13:58:37 +010038#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
Michal Vaskoc14e3c82016-01-11 16:14:30 +010039
Michal Vasko086311b2016-01-08 09:53:11 +010040/* in seconds */
41#define NC_CLIENT_HELLO_TIMEOUT 60
Radek Krejci695d4fa2015-10-22 13:23:54 +020042
Michal Vasko05ba9df2016-01-13 14:40:27 +010043/* in milliseconds */
44#define NC_CLOSE_REPLY_TIMEOUT 200
45
Michal Vasko086311b2016-01-08 09:53:11 +010046extern struct nc_server_opts server_opts;
47
Michal Vasko96164bf2016-01-21 15:41:58 +010048/*
49 * @return 1 - success
50 * 0 - timeout
51 * -1 - error
52 */
53int
54nc_timedlock(pthread_mutex_t *lock, int timeout, int *elapsed)
55{
56 int ret;
57 struct timespec ts_timeout, ts_old, ts_new;
58
59 if (timeout > 0) {
60 clock_gettime(CLOCK_REALTIME, &ts_timeout);
61
62 if (elapsed) {
63 ts_old = ts_timeout;
64 }
65
66 ts_timeout.tv_sec += timeout / 1000;
67 ts_timeout.tv_nsec += (timeout % 1000) * 1000000;
68
69 ret = pthread_mutex_timedlock(lock, &ts_timeout);
70
71 if (elapsed) {
72 clock_gettime(CLOCK_REALTIME, &ts_new);
73
74 *elapsed += (ts_new.tv_sec - ts_old.tv_sec) * 1000;
75 *elapsed += (ts_new.tv_nsec - ts_old.tv_nsec) / 1000000;
76 }
77 } else if (!timeout) {
78 ret = pthread_mutex_trylock(lock);
79 } else { /* timeout == -1 */
80 ret = pthread_mutex_lock(lock);
81 }
82
83 if (ret == ETIMEDOUT) {
84 /* timeout */
85 return 0;
86 } else if (ret) {
87 /* error */
88 ERR("Mutex lock failed (%s).", strerror(errno));
89 return -1;
90 }
91
92 /* ok */
93 return 1;
94}
95
96void
97nc_subtract_elapsed(int *timeout, struct timespec *old_ts)
98{
99 struct timespec new_ts;
100
101 clock_gettime(CLOCK_MONOTONIC_RAW, &new_ts);
102
103 *timeout -= (new_ts.tv_sec - old_ts->tv_sec) * 1000;
104 *timeout -= (new_ts.tv_nsec - old_ts->tv_nsec) / 1000000;
105
106 *old_ts = new_ts;
107}
108
Michal Vasko8dadf782016-01-15 10:29:36 +0100109API NC_STATUS
110nc_session_get_status(const struct nc_session *session)
111{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100112 if (!session) {
113 ERRARG;
114 return 0;
115 }
116
Michal Vasko8dadf782016-01-15 10:29:36 +0100117 return session->status;
118}
119
120API uint32_t
121nc_session_get_id(const struct nc_session *session)
122{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100123 if (!session) {
124 ERRARG;
125 return 0;
126 }
127
Michal Vasko8dadf782016-01-15 10:29:36 +0100128 return session->id;
129}
130
Michal Vasko174fe8e2016-02-17 15:38:09 +0100131API int
132nc_session_get_version(const struct nc_session *session)
133{
134 if (!session) {
135 ERRARG;
136 return -1;
137 }
138
139 return (session->version == NC_VERSION_10 ? 0 : 1);
140}
141
Michal Vasko8dadf782016-01-15 10:29:36 +0100142API NC_TRANSPORT_IMPL
143nc_session_get_ti(const struct nc_session *session)
144{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100145 if (!session) {
146 ERRARG;
147 return 0;
148 }
149
Michal Vasko8dadf782016-01-15 10:29:36 +0100150 return session->ti_type;
151}
152
153API const char *
154nc_session_get_username(const struct nc_session *session)
155{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100156 if (!session) {
157 ERRARG;
158 return NULL;
159 }
160
Michal Vasko8dadf782016-01-15 10:29:36 +0100161 return session->username;
162}
163
164API const char *
165nc_session_get_host(const struct nc_session *session)
166{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100167 if (!session) {
168 ERRARG;
169 return NULL;
170 }
171
Michal Vasko8dadf782016-01-15 10:29:36 +0100172 return session->host;
173}
174
175API uint16_t
176nc_session_get_port(const struct nc_session *session)
177{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100178 if (!session) {
179 ERRARG;
180 return 0;
181 }
182
Michal Vasko8dadf782016-01-15 10:29:36 +0100183 return session->port;
184}
185
Michal Vasko9a25e932016-02-01 10:36:42 +0100186API struct ly_ctx *
187nc_session_get_ctx(const struct nc_session *session)
188{
189 if (!session) {
190 ERRARG;
191 return NULL;
192 }
193
194 return session->ctx;
195}
196
Michal Vasko8dadf782016-01-15 10:29:36 +0100197API const char **
198nc_session_get_cpblts(const struct nc_session *session)
199{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100200 if (!session) {
201 ERRARG;
202 return NULL;
203 }
204
Michal Vasko8dadf782016-01-15 10:29:36 +0100205 return session->cpblts;
206}
207
208API const char *
209nc_session_cpblt(const struct nc_session *session, const char *capab)
210{
211 int i, len;
212
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100213 if (!session || !capab) {
214 ERRARG;
215 return NULL;
216 }
217
Michal Vasko8dadf782016-01-15 10:29:36 +0100218 len = strlen(capab);
219 for (i = 0; session->cpblts[i]; ++i) {
220 if (!strncmp(session->cpblts[i], capab, len)) {
221 return session->cpblts[i];
222 }
223 }
224
225 return NULL;
226}
227
Michal Vasko086311b2016-01-08 09:53:11 +0100228NC_MSG_TYPE
229nc_send_msg(struct nc_session *session, struct lyd_node *op)
Radek Krejci695d4fa2015-10-22 13:23:54 +0200230{
Michal Vasko086311b2016-01-08 09:53:11 +0100231 int r;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200232
Michal Vasko086311b2016-01-08 09:53:11 +0100233 if (session->ctx != op->schema->module->ctx) {
Michal Vaskod083db62016-01-19 10:31:29 +0100234 ERR("Session %u: RPC \"%s\" was created in different context than that of the session.",
235 session->id, op->schema->name);
Michal Vasko086311b2016-01-08 09:53:11 +0100236 return NC_MSG_ERROR;
Michal Vasko7df39ec2015-12-09 15:26:24 +0100237 }
238
Michal Vasko086311b2016-01-08 09:53:11 +0100239 r = nc_write_msg(session, NC_MSG_RPC, op, NULL);
240
241 if (r) {
242 return NC_MSG_ERROR;
243 }
244
245 return NC_MSG_RPC;
Michal Vasko7df39ec2015-12-09 15:26:24 +0100246}
247
Radek Krejci695d4fa2015-10-22 13:23:54 +0200248API void
249nc_session_free(struct nc_session *session)
250{
251 int r, i;
Michal Vasko428087d2016-01-14 16:04:28 +0100252 int connected; /* flag to indicate whether the transport socket is still connected */
Michal Vaskob48aa812016-01-18 14:13:09 +0100253 int multisession = 0; /* flag for more NETCONF sessions on a single SSH session */
Michal Vaskoa8ad4482016-01-28 14:25:54 +0100254 pthread_t tid;
Michal Vasko4589bbe2016-01-29 09:41:30 +0100255 struct nc_session *siter;
Michal Vaskoad611702015-12-03 13:41:51 +0100256 struct nc_msg_cont *contiter;
Michal Vaskoadd4c792015-10-26 15:36:58 +0100257 struct lyxml_elem *rpl, *child;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200258 struct lyd_node *close_rpc;
Michal Vaskoad611702015-12-03 13:41:51 +0100259 const struct lys_module *ietfnc;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200260 void *p;
261
Michal Vasko428087d2016-01-14 16:04:28 +0100262 if (!session || (session->status == NC_STATUS_CLOSING)) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200263 return;
264 }
265
266 /* mark session for closing */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100267 if (session->ti_lock) {
Michal Vasko4589bbe2016-01-29 09:41:30 +0100268 r = nc_timedlock(session->ti_lock, -1, NULL);
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100269 if (r == -1) {
Michal Vaskoadd4c792015-10-26 15:36:58 +0100270 return;
271 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200272 }
273
274 /* stop notifications loop if any */
Michal Vaskoa8ad4482016-01-28 14:25:54 +0100275 if (session->ntf_tid) {
276 tid = *session->ntf_tid;
277 free((pthread_t *)session->ntf_tid);
278 session->ntf_tid = NULL;
279 /* the thread now knows it should quit */
280
281 pthread_join(tid, NULL);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200282 }
283
Michal Vasko428087d2016-01-14 16:04:28 +0100284 if ((session->side == NC_CLIENT) && (session->status == NC_STATUS_RUNNING)) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200285 /* cleanup message queues */
286 /* notifications */
Michal Vaskoad611702015-12-03 13:41:51 +0100287 for (contiter = session->notifs; contiter; ) {
288 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200289
Michal Vaskoad611702015-12-03 13:41:51 +0100290 p = contiter;
291 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200292 free(p);
293 }
294
295 /* rpc replies */
Michal Vaskoad611702015-12-03 13:41:51 +0100296 for (contiter = session->replies; contiter; ) {
297 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200298
Michal Vaskoad611702015-12-03 13:41:51 +0100299 p = contiter;
300 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200301 free(p);
302 }
303
304 /* send closing info to the other side */
305 ietfnc = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL);
306 if (!ietfnc) {
Michal Vasko428087d2016-01-14 16:04:28 +0100307 WRN("Session %u: missing ietf-netconf schema in context, unable to send <close-session>.", session->id);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200308 } else {
309 close_rpc = lyd_new(NULL, ietfnc, "close-session");
Michal Vaskoad611702015-12-03 13:41:51 +0100310 nc_send_msg(session, close_rpc);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200311 lyd_free(close_rpc);
Michal Vasko05ba9df2016-01-13 14:40:27 +0100312 switch (nc_read_msg_poll(session, NC_CLOSE_REPLY_TIMEOUT, &rpl)) {
Michal Vaskofad6e912015-10-26 15:37:22 +0100313 case NC_MSG_REPLY:
314 LY_TREE_FOR(rpl->child, child) {
315 if (!strcmp(child->name, "ok") && child->ns && !strcmp(child->ns->value, NC_NS_BASE)) {
316 break;
317 }
318 }
319 if (!child) {
Michal Vasko428087d2016-01-14 16:04:28 +0100320 WRN("Session %u: the reply to <close-session> was not <ok> as expected.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100321 }
Michal Vaskoad611702015-12-03 13:41:51 +0100322 lyxml_free(session->ctx, rpl);
Michal Vaskofad6e912015-10-26 15:37:22 +0100323 break;
324 case NC_MSG_WOULDBLOCK:
Michal Vasko428087d2016-01-14 16:04:28 +0100325 WRN("Session %u: timeout for receiving a reply to <close-session> elapsed.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100326 break;
327 case NC_MSG_ERROR:
Michal Vaskod083db62016-01-19 10:31:29 +0100328 ERR("Session %u: failed to receive a reply to <close-session>.", session->id);
Michal Vaskofad6e912015-10-26 15:37:22 +0100329 break;
330 default:
331 /* cannot happen */
332 break;
333 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200334 }
335
336 /* list of server's capabilities */
337 if (session->cpblts) {
338 for (i = 0; session->cpblts[i]; i++) {
339 lydict_remove(session->ctx, session->cpblts[i]);
340 }
341 free(session->cpblts);
342 }
343 }
344
345 session->status = NC_STATUS_CLOSING;
Michal Vasko428087d2016-01-14 16:04:28 +0100346 connected = nc_session_is_connected(session);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200347
348 /* transport implementation cleanup */
349 switch (session->ti_type) {
350 case NC_TI_FD:
351 /* nothing needed - file descriptors were provided by caller,
352 * so it is up to the caller to close them correctly
353 * TODO use callbacks
354 */
Michal Vasko3512e402016-01-28 16:22:34 +0100355 /* just to avoid compiler warning */
356 (void)connected;
Michal Vasko4589bbe2016-01-29 09:41:30 +0100357 (void)siter;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200358 break;
359
Radek Krejci53691be2016-02-22 13:58:37 +0100360#ifdef NC_ENABLED_SSH
Radek Krejci695d4fa2015-10-22 13:23:54 +0200361 case NC_TI_LIBSSH:
Michal Vasko428087d2016-01-14 16:04:28 +0100362 if (connected) {
363 ssh_channel_free(session->ti.libssh.channel);
364 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200365 /* There can be multiple NETCONF sessions on the same SSH session (NETCONF session maps to
366 * SSH channel). So destroy the SSH session only if there is no other NETCONF session using
367 * it.
368 */
Michal Vasko96164bf2016-01-21 15:41:58 +0100369 multisession = 0;
370 if (session->ti.libssh.next) {
371 for (siter = session->ti.libssh.next; siter != session; siter = siter->ti.libssh.next) {
372 if (siter->status != NC_STATUS_STARTING) {
373 multisession = 1;
374 break;
375 }
376 }
377 }
378
379 if (!multisession) {
380 /* it's not multisession yet, but we still need to free the starting sessions */
381 if (session->ti.libssh.next) {
382 do {
383 siter = session->ti.libssh.next;
384 session->ti.libssh.next = siter->ti.libssh.next;
385
386 /* free starting SSH NETCONF session (channel will be freed in ssh_free()) */
Michal Vasko96164bf2016-01-21 15:41:58 +0100387 lydict_remove(session->ctx, session->username);
388 lydict_remove(session->ctx, session->host);
Michal Vasko96164bf2016-01-21 15:41:58 +0100389 if (!(session->flags & NC_SESSION_SHAREDCTX)) {
Radek Krejci4ba285b2016-02-04 17:34:06 +0100390 ly_ctx_destroy(session->ctx, NULL);
Michal Vasko96164bf2016-01-21 15:41:58 +0100391 }
392
393 free(siter);
394 } while (session->ti.libssh.next != session);
395 }
Michal Vasko428087d2016-01-14 16:04:28 +0100396 if (connected) {
397 ssh_disconnect(session->ti.libssh.session);
398 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200399 ssh_free(session->ti.libssh.session);
400 } else {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200401 /* remove the session from the list */
402 for (siter = session->ti.libssh.next; siter->ti.libssh.next != session; siter = siter->ti.libssh.next);
Michal Vaskoaec4f212015-10-26 15:37:45 +0100403 if (session->ti.libssh.next == siter) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200404 /* there will be only one session */
405 siter->ti.libssh.next = NULL;
406 } else {
407 /* there are still multiple sessions, keep the ring list */
408 siter->ti.libssh.next = session->ti.libssh.next;
409 }
Michal Vasko96164bf2016-01-21 15:41:58 +0100410 /* change nc_sshcb_msg() argument, we need a RUNNING session and this one will be freed */
411 if (session->flags & NC_SESSION_SSH_MSG_CB) {
412 for (siter = session->ti.libssh.next; siter->status != NC_STATUS_RUNNING; siter = siter->ti.libssh.next) {
413 if (siter->ti.libssh.next == session) {
414 ERRINT;
415 break;
416 }
417 }
418 ssh_set_message_callback(session->ti.libssh.session, nc_sshcb_msg, siter);
419 siter->flags |= NC_SESSION_SSH_MSG_CB;
420 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200421 }
422 break;
423#endif
424
Radek Krejci53691be2016-02-22 13:58:37 +0100425#ifdef NC_ENABLED_TLS
Radek Krejci695d4fa2015-10-22 13:23:54 +0200426 case NC_TI_OPENSSL:
Michal Vasko428087d2016-01-14 16:04:28 +0100427 if (connected) {
428 SSL_shutdown(session->ti.tls);
429 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200430 SSL_free(session->ti.tls);
Michal Vasko06e22432016-01-15 10:30:06 +0100431
432 X509_free(session->tls_cert);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200433 break;
434#endif
Michal Vasko428087d2016-01-14 16:04:28 +0100435 case NC_TI_NONE:
436 ERRINT;
437 break;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200438 }
Michal Vasko428087d2016-01-14 16:04:28 +0100439
Radek Krejciac6d3472015-10-22 15:47:18 +0200440 lydict_remove(session->ctx, session->username);
441 lydict_remove(session->ctx, session->host);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200442
443 /* final cleanup */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100444 if (session->ti_lock) {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100445 pthread_mutex_unlock(session->ti_lock);
Michal Vaskob48aa812016-01-18 14:13:09 +0100446 if (!multisession) {
Michal Vaskoadd4c792015-10-26 15:36:58 +0100447 pthread_mutex_destroy(session->ti_lock);
448 free(session->ti_lock);
449 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200450 }
451
452 if (!(session->flags & NC_SESSION_SHAREDCTX)) {
Radek Krejci4ba285b2016-02-04 17:34:06 +0100453 ly_ctx_destroy(session->ctx, NULL);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200454 }
455
456 free(session);
457}
458
Michal Vasko086311b2016-01-08 09:53:11 +0100459static void
460add_cpblt(struct ly_ctx *ctx, const char *capab, const char ***cpblts, int *size, int *count)
461{
462 if (*count == *size) {
463 *size += 5;
464 *cpblts = realloc(*cpblts, *size * sizeof **cpblts);
465 }
466
467 if (capab) {
468 (*cpblts)[*count] = lydict_insert(ctx, capab, 0);
469 } else {
470 (*cpblts)[*count] = NULL;
471 }
472 ++(*count);
473}
474
475static const char **
476create_cpblts(struct ly_ctx *ctx)
477{
478 struct lyd_node *child, *child2, *yanglib;
479 struct lyd_node_leaf_list **features = NULL, *ns = NULL, *rev = NULL, *name = NULL;
480 const char **cpblts;
481 const struct lys_module *mod;
Michal Vasko11d142a2016-01-19 15:58:24 +0100482 int size = 10, count, feat_count = 0, i, str_len;
Michal Vasko086311b2016-01-08 09:53:11 +0100483 char str[512];
484
485 yanglib = ly_ctx_info(ctx);
486 if (!yanglib) {
487 return NULL;
488 }
489
490 cpblts = malloc(size * sizeof *cpblts);
491 cpblts[0] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.0", 0);
492 cpblts[1] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.1", 0);
493 count = 2;
494
495 /* capabilities */
496
497 mod = ly_ctx_get_module(ctx, "ietf-netconf", NULL);
498 if (mod) {
499 if (lys_features_state(mod, "writable-running") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100500 add_cpblt(ctx, "urn:ietf:params:netconf:capability:writable-running:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100501 }
502 if (lys_features_state(mod, "candidate") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100503 add_cpblt(ctx, "urn:ietf:params:netconf:capability:candidate:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100504 if (lys_features_state(mod, "confirmed-commit") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100505 add_cpblt(ctx, "urn:ietf:params:netconf:capability:confirmed-commit:1.1", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100506 }
507 }
508 if (lys_features_state(mod, "rollback-on-error") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100509 add_cpblt(ctx, "urn:ietf:params:netconf:capability:rollback-on-error:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100510 }
511 if (lys_features_state(mod, "validate") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100512 add_cpblt(ctx, "urn:ietf:params:netconf:capability:validate:1.1", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100513 }
514 if (lys_features_state(mod, "startup") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100515 add_cpblt(ctx, "urn:ietf:params:netconf:capability:startup:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100516 }
517 if (lys_features_state(mod, "url") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100518 add_cpblt(ctx, "urn:ietf:params:netconf:capability:url:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100519 }
520 if (lys_features_state(mod, "xpath") == 1) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100521 add_cpblt(ctx, "urn:ietf:params:netconf:capability:xpath:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100522 }
523 }
524
525 mod = ly_ctx_get_module(ctx, "ietf-netconf-with-defaults", NULL);
526 if (mod) {
527 if (!server_opts.wd_basic_mode) {
528 VRB("with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode.");
529 } else {
Michal Vasko3031aae2016-01-27 16:07:18 +0100530 strcpy(str, "urn:ietf:params:netconf:capability:with-defaults:1.0");
Michal Vasko086311b2016-01-08 09:53:11 +0100531 switch (server_opts.wd_basic_mode) {
532 case NC_WD_ALL:
533 strcat(str, "?basic-mode=report-all");
534 break;
535 case NC_WD_TRIM:
536 strcat(str, "?basic-mode=trim");
537 break;
538 case NC_WD_EXPLICIT:
539 strcat(str, "?basic-mode=explicit");
540 break;
541 default:
Michal Vasko9e036d52016-01-08 10:49:26 +0100542 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100543 break;
544 }
545
546 if (server_opts.wd_also_supported) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100547 strcat(str, "&amp;also-supported=");
Michal Vasko086311b2016-01-08 09:53:11 +0100548 if (server_opts.wd_also_supported & NC_WD_ALL) {
549 strcat(str, "report-all,");
550 }
551 if (server_opts.wd_also_supported & NC_WD_ALL_TAG) {
552 strcat(str, "report-all-tagged,");
553 }
554 if (server_opts.wd_also_supported & NC_WD_TRIM) {
555 strcat(str, "trim,");
556 }
557 if (server_opts.wd_also_supported & NC_WD_EXPLICIT) {
558 strcat(str, "explicit,");
559 }
560 str[strlen(str) - 1] = '\0';
561
562 add_cpblt(ctx, str, &cpblts, &size, &count);
563 }
564 }
565 }
566
Michal Vasko1a38c862016-01-15 15:50:07 +0100567 mod = ly_ctx_get_module(ctx, "nc-notifications", NULL);
Michal Vasko086311b2016-01-08 09:53:11 +0100568 if (mod) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100569 add_cpblt(ctx, "urn:ietf:params:netconf:capability:notification:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100570 if (server_opts.interleave_capab) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100571 add_cpblt(ctx, "urn:ietf:params:netconf:capability:interleave:1.0", &cpblts, &size, &count);
Michal Vasko086311b2016-01-08 09:53:11 +0100572 }
573 }
574
575 /* models */
576
577 LY_TREE_FOR(yanglib->child, child) {
578 if (!strcmp(child->schema->name, "module")) {
579 LY_TREE_FOR(child->child, child2) {
580 if (!strcmp(child2->schema->name, "namespace")) {
581 ns = (struct lyd_node_leaf_list *)child2;
582 } else if (!strcmp(child2->schema->name, "name")) {
583 name = (struct lyd_node_leaf_list *)child2;
584 } else if (!strcmp(child2->schema->name, "revision")) {
585 rev = (struct lyd_node_leaf_list *)child2;
586 } else if (!strcmp(child2->schema->name, "feature")) {
587 features = realloc(features, feat_count++ * sizeof *features);
588 features[feat_count - 1] = (struct lyd_node_leaf_list *)child2;
589 }
590 }
591
592 if (!ns || !name || !rev) {
Michal Vasko9e036d52016-01-08 10:49:26 +0100593 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100594 continue;
595 }
596
Michal Vasko11d142a2016-01-19 15:58:24 +0100597 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 +0100598 if (feat_count) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100599 strcat(str, "&amp;features=");
Michal Vasko11d142a2016-01-19 15:58:24 +0100600 str_len += 14;
Michal Vasko086311b2016-01-08 09:53:11 +0100601 for (i = 0; i < feat_count; ++i) {
Michal Vasko11d142a2016-01-19 15:58:24 +0100602 if (str_len + 1 + strlen(features[i]->value_str) >= 512) {
603 ERRINT;
604 break;
605 }
Michal Vasko086311b2016-01-08 09:53:11 +0100606 if (i) {
607 strcat(str, ",");
Michal Vasko11d142a2016-01-19 15:58:24 +0100608 ++str_len;
Michal Vasko086311b2016-01-08 09:53:11 +0100609 }
610 strcat(str, features[i]->value_str);
Michal Vasko11d142a2016-01-19 15:58:24 +0100611 str_len += strlen(features[i]->value_str);
Michal Vasko086311b2016-01-08 09:53:11 +0100612 }
613 }
614
615 add_cpblt(ctx, str, &cpblts, &size, &count);
616
617 ns = NULL;
618 name = NULL;
619 rev = NULL;
620 free(features);
621 features = NULL;
622 feat_count = 0;
623 }
624 }
625
626 lyd_free(yanglib);
627
628 /* ending NULL capability */
629 add_cpblt(ctx, NULL, &cpblts, &size, &count);
630
631 return cpblts;
632}
633
Radek Krejci695d4fa2015-10-22 13:23:54 +0200634static int
635parse_cpblts(struct lyxml_elem *xml, const char ***list)
636{
637 struct lyxml_elem *cpblt;
638 int ver = -1;
639 int i = 0;
640
641 if (list) {
642 /* get the storage for server's capabilities */
643 LY_TREE_FOR(xml->child, cpblt) {
644 i++;
645 }
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100646 /* last item remains NULL */
647 *list = calloc(i + 1, sizeof **list);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200648 if (!*list) {
649 ERRMEM;
650 return -1;
651 }
652 i = 0;
653 }
654
655 LY_TREE_FOR(xml->child, cpblt) {
656 if (strcmp(cpblt->name, "capability") && cpblt->ns && cpblt->ns->value &&
657 !strcmp(cpblt->ns->value, NC_NS_BASE)) {
658 ERR("Unexpected <%s> element in client's <hello>.", cpblt->name);
659 return -1;
660 } else if (!cpblt->ns || !cpblt->ns->value || strcmp(cpblt->ns->value, NC_NS_BASE)) {
661 continue;
662 }
663
664 /* detect NETCONF version */
665 if (ver < 0 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.0")) {
666 ver = 0;
667 } else if (ver < 1 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.1")) {
668 ver = 1;
669 }
670
671 /* store capabilities */
672 if (list) {
673 (*list)[i] = cpblt->content;
674 cpblt->content = NULL;
675 i++;
676 }
677 }
678
679 if (ver == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100680 ERR("Peer does not support a compatible NETCONF version.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200681 }
682
683 return ver;
684}
685
686static NC_MSG_TYPE
Michal Vasko11d142a2016-01-19 15:58:24 +0100687nc_send_client_hello(struct nc_session *session)
Michal Vasko086311b2016-01-08 09:53:11 +0100688{
689 int r, i;
690 const char **cpblts;
691
Michal Vasko11d142a2016-01-19 15:58:24 +0100692 /* client side hello - send only NETCONF base capabilities */
693 cpblts = malloc(3 * sizeof *cpblts);
694 cpblts[0] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.0", 0);
695 cpblts[1] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.1", 0);
696 cpblts[2] = NULL;
Michal Vasko05ba9df2016-01-13 14:40:27 +0100697
Michal Vasko11d142a2016-01-19 15:58:24 +0100698 r = nc_write_msg(session, NC_MSG_HELLO, cpblts, NULL);
Michal Vasko086311b2016-01-08 09:53:11 +0100699
Michal Vasko086311b2016-01-08 09:53:11 +0100700 for (i = 0; cpblts[i]; ++i) {
701 lydict_remove(session->ctx, cpblts[i]);
702 }
703 free(cpblts);
704
705 if (r) {
706 return NC_MSG_ERROR;
Michal Vasko086311b2016-01-08 09:53:11 +0100707 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100708
709 return NC_MSG_HELLO;
Michal Vasko086311b2016-01-08 09:53:11 +0100710}
711
712static NC_MSG_TYPE
Michal Vasko11d142a2016-01-19 15:58:24 +0100713nc_send_server_hello(struct nc_session *session)
714{
715 int r, i;
716 const char **cpblts;
717
718 cpblts = create_cpblts(session->ctx);
719
720 r = nc_write_msg(session, NC_MSG_HELLO, cpblts, &session->id);
721
Michal Vasko11d142a2016-01-19 15:58:24 +0100722 for (i = 0; cpblts[i]; ++i) {
723 lydict_remove(session->ctx, cpblts[i]);
724 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100725 free(cpblts);
726
727 if (r) {
728 return NC_MSG_ERROR;
729 }
730
731 return NC_MSG_HELLO;
732}
733
734static NC_MSG_TYPE
735nc_recv_client_hello(struct nc_session *session)
Radek Krejci695d4fa2015-10-22 13:23:54 +0200736{
737 struct lyxml_elem *xml = NULL, *node;
738 NC_MSG_TYPE msgtype = 0; /* NC_MSG_ERROR */
739 int ver = -1;
740 char *str;
741 long long int id;
742 int flag = 0;
743
Michal Vasko05ba9df2016-01-13 14:40:27 +0100744 msgtype = nc_read_msg_poll(session, NC_CLIENT_HELLO_TIMEOUT * 1000, &xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200745
746 switch(msgtype) {
747 case NC_MSG_HELLO:
748 /* parse <hello> data */
Michal Vasko11d142a2016-01-19 15:58:24 +0100749 LY_TREE_FOR(xml->child, node) {
750 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
751 continue;
752 } else if (!strcmp(node->name, "session-id")) {
753 if (!node->content || !strlen(node->content)) {
754 ERR("No value of <session-id> element in server's <hello>.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200755 goto error;
756 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100757 str = NULL;
758 id = strtoll(node->content, &str, 10);
759 if (*str || id < 1 || id > UINT32_MAX) {
760 ERR("Invalid value of <session-id> element in server's <hello>.");
Radek Krejci695d4fa2015-10-22 13:23:54 +0200761 goto error;
762 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100763 session->id = (uint32_t)id;
764 continue;
765 } else if (strcmp(node->name, "capabilities")) {
766 ERR("Unexpected <%s> element in client's <hello>.", node->name);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200767 goto error;
768 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100769
770 if (flag) {
771 /* multiple capabilities elements */
772 ERR("Invalid <hello> message (multiple <capabilities> elements).");
773 goto error;
774 }
775 flag = 1;
776
777 if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
778 goto error;
779 }
780 session->version = ver;
781 }
782
783 if (!session->id) {
784 ERR("Missing <session-id> in server's <hello>.");
785 goto error;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200786 }
787 break;
788 case NC_MSG_ERROR:
789 /* nothing special, just pass it out */
790 break;
791 default:
792 ERR("Unexpected message received instead of <hello>.");
793 msgtype = NC_MSG_ERROR;
794 }
795
796 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100797 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200798
799 return msgtype;
800
801error:
802 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100803 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200804
805 return NC_MSG_ERROR;
Radek Krejci5686ff72015-10-09 13:33:56 +0200806}
807
Michal Vasko11d142a2016-01-19 15:58:24 +0100808static NC_MSG_TYPE
809nc_recv_server_hello(struct nc_session *session)
810{
811 struct lyxml_elem *xml = NULL, *node;
812 NC_MSG_TYPE msgtype = 0; /* NC_MSG_ERROR */
813 int ver = -1;
814 int flag = 0;
815
Michal Vaskoadb850e2016-01-20 14:06:32 +0100816 msgtype = nc_read_msg_poll(session, (server_opts.hello_timeout ? server_opts.hello_timeout * 1000 : -1), &xml);
Michal Vasko11d142a2016-01-19 15:58:24 +0100817
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100818 switch (msgtype) {
Michal Vasko11d142a2016-01-19 15:58:24 +0100819 case NC_MSG_HELLO:
820 /* get know NETCONF version */
821 LY_TREE_FOR(xml->child, node) {
822 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
823 continue;
824 } else if (strcmp(node->name, "capabilities")) {
825 ERR("Unexpected <%s> element in client's <hello>.", node->name);
826 msgtype = NC_MSG_ERROR;
827 goto cleanup;
828 }
829
830 if (flag) {
831 /* multiple capabilities elements */
832 ERR("Invalid <hello> message (multiple <capabilities> elements).");
833 msgtype = NC_MSG_ERROR;
834 goto cleanup;
835 }
836 flag = 1;
837
838 if ((ver = parse_cpblts(node, NULL)) < 0) {
839 msgtype = NC_MSG_ERROR;
840 goto cleanup;
841 }
842 session->version = ver;
843 }
844 break;
845 case NC_MSG_ERROR:
846 /* nothing special, just pass it out */
847 break;
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100848 case NC_MSG_WOULDBLOCK:
849 ERR("Client's <hello> timeout elapsed.");
850 msgtype = NC_MSG_ERROR;
851 break;
Michal Vasko11d142a2016-01-19 15:58:24 +0100852 default:
853 ERR("Unexpected message received instead of <hello>.");
854 msgtype = NC_MSG_ERROR;
855 }
856
857cleanup:
Michal Vasko11d142a2016-01-19 15:58:24 +0100858 lyxml_free(session->ctx, xml);
Michal Vasko11d142a2016-01-19 15:58:24 +0100859
860 return msgtype;
861}
862
Michal Vasko80cad7f2015-12-08 14:42:27 +0100863int
Michal Vasko086311b2016-01-08 09:53:11 +0100864nc_handshake(struct nc_session *session)
Michal Vasko80cad7f2015-12-08 14:42:27 +0100865{
Michal Vasko086311b2016-01-08 09:53:11 +0100866 NC_MSG_TYPE type;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100867
Michal Vasko11d142a2016-01-19 15:58:24 +0100868 if (session->side == NC_CLIENT) {
869 type = nc_send_client_hello(session);
870 } else {
871 type = nc_send_server_hello(session);
872 }
873
Michal Vasko086311b2016-01-08 09:53:11 +0100874 if (type != NC_MSG_HELLO) {
875 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100876 }
877
Michal Vasko11d142a2016-01-19 15:58:24 +0100878 if (session->side == NC_CLIENT) {
879 type = nc_recv_client_hello(session);
880 } else {
881 type = nc_recv_server_hello(session);
882 }
883
Michal Vasko086311b2016-01-08 09:53:11 +0100884 if (type != NC_MSG_HELLO) {
885 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100886 }
887
Michal Vasko086311b2016-01-08 09:53:11 +0100888 return 0;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100889}
Michal Vasko086311b2016-01-08 09:53:11 +0100890
Radek Krejci53691be2016-02-22 13:58:37 +0100891#ifdef NC_ENABLED_SSH
Michal Vasko086311b2016-01-08 09:53:11 +0100892
893API void
894nc_ssh_init(void)
895{
896 ssh_threads_set_callbacks(ssh_threads_get_pthread());
897 ssh_init();
898 ssh_set_log_level(verbose_level);
899}
900
901API void
902nc_ssh_destroy(void)
903{
Michal Vasko5e228792016-02-03 15:30:24 +0100904 ENGINE_cleanup();
905 CONF_modules_unload(1);
Michal Vaskob6e37262016-02-25 14:49:00 +0100906 nc_thread_destroy();
Michal Vasko086311b2016-01-08 09:53:11 +0100907 ssh_finalize();
908}
909
Radek Krejci53691be2016-02-22 13:58:37 +0100910#endif /* NC_ENABLED_SSH */
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100911
Radek Krejci53691be2016-02-22 13:58:37 +0100912#ifdef NC_ENABLED_TLS
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100913
914static pthread_mutex_t *tls_locks;
915
Michal Vaskof0c92c02016-01-29 09:41:45 +0100916struct CRYPTO_dynlock_value {
917 pthread_mutex_t lock;
918};
919
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100920static void
Michal Vaskob48aa812016-01-18 14:13:09 +0100921tls_thread_locking_func(int mode, int n, const char *UNUSED(file), int UNUSED(line))
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100922{
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100923 if (mode & CRYPTO_LOCK) {
924 pthread_mutex_lock(tls_locks + n);
925 } else {
926 pthread_mutex_unlock(tls_locks + n);
927 }
928}
929
Michal Vaskof0c92c02016-01-29 09:41:45 +0100930static void
931tls_thread_id_func(CRYPTO_THREADID *tid)
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100932{
Michal Vaskof0c92c02016-01-29 09:41:45 +0100933 CRYPTO_THREADID_set_numeric(tid, (unsigned long)pthread_self());
934}
935
936static struct CRYPTO_dynlock_value *
937tls_dyn_create_func(const char *UNUSED(file), int UNUSED(line))
938{
939 struct CRYPTO_dynlock_value *value;
940
941 value = malloc(sizeof *value);
942 if (!value) {
943 ERRMEM;
944 return NULL;
945 }
946 pthread_mutex_init(&value->lock, NULL);
947
948 return value;
949}
950
951static void
952tls_dyn_lock_func(int mode, struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line))
953{
954 /* mode can also be CRYPTO_READ or CRYPTO_WRITE, but all the examples
955 * I found ignored this fact, what do I know... */
956 if (mode & CRYPTO_LOCK) {
957 pthread_mutex_lock(&l->lock);
958 } else {
959 pthread_mutex_unlock(&l->lock);
960 }
961}
962
963static void
964tls_dyn_destroy_func(struct CRYPTO_dynlock_value *l, const char *UNUSED(file), int UNUSED(line))
965{
966 pthread_mutex_destroy(&l->lock);
967 free(l);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100968}
969
970API void
971nc_tls_init(void)
972{
973 int i;
974
975 SSL_load_error_strings();
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100976 ERR_load_BIO_strings();
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100977 SSL_library_init();
978
979 tls_locks = malloc(CRYPTO_num_locks() * sizeof *tls_locks);
980 for (i = 0; i < CRYPTO_num_locks(); ++i) {
981 pthread_mutex_init(tls_locks + i, NULL);
982 }
983
Michal Vaskof0c92c02016-01-29 09:41:45 +0100984 CRYPTO_THREADID_set_callback(tls_thread_id_func);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100985 CRYPTO_set_locking_callback(tls_thread_locking_func);
Michal Vaskof0c92c02016-01-29 09:41:45 +0100986
987 CRYPTO_set_dynlock_create_callback(tls_dyn_create_func);
988 CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func);
989 CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func);
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100990}
991
992API void
993nc_tls_destroy(void)
994{
995 int i;
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100996
Michal Vaskoc14e3c82016-01-11 16:14:30 +0100997 CRYPTO_cleanup_all_ex_data();
Michal Vaskob6e37262016-02-25 14:49:00 +0100998 nc_thread_destroy();
Michal Vasko5e228792016-02-03 15:30:24 +0100999 EVP_cleanup();
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001000 ERR_free_strings();
1001 sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001002
Michal Vaskob6e37262016-02-25 14:49:00 +01001003 CRYPTO_THREADID_set_callback(NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001004 CRYPTO_set_locking_callback(NULL);
1005 for (i = 0; i < CRYPTO_num_locks(); ++i) {
1006 pthread_mutex_destroy(tls_locks + i);
1007 }
1008 free(tls_locks);
Michal Vaskof0c92c02016-01-29 09:41:45 +01001009
1010 CRYPTO_set_dynlock_create_callback(NULL);
1011 CRYPTO_set_dynlock_lock_callback(NULL);
1012 CRYPTO_set_dynlock_destroy_callback(NULL);
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001013}
1014
Radek Krejci53691be2016-02-22 13:58:37 +01001015#endif /* NC_ENABLED_TLS */
Michal Vasko5e228792016-02-03 15:30:24 +01001016
Radek Krejci53691be2016-02-22 13:58:37 +01001017#if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
Michal Vasko5e228792016-02-03 15:30:24 +01001018
1019API void
1020nc_thread_destroy(void) {
1021 CRYPTO_THREADID crypto_tid;
1022
Michal Vasko0be5dff2016-02-08 15:26:37 +01001023 /* caused data-races and seems not neccessary for avoiding valgrind reachable memory */
1024 //CRYPTO_cleanup_all_ex_data();
Michal Vasko5e228792016-02-03 15:30:24 +01001025
1026 CRYPTO_THREADID_current(&crypto_tid);
1027 ERR_remove_thread_state(&crypto_tid);
1028}
1029
Radek Krejci53691be2016-02-22 13:58:37 +01001030#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
Michal Vasko5e228792016-02-03 15:30:24 +01001031
Radek Krejci53691be2016-02-22 13:58:37 +01001032#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
Michal Vasko5e228792016-02-03 15:30:24 +01001033
1034API void
1035nc_ssh_tls_init(void)
1036{
1037 SSL_load_error_strings();
1038 ERR_load_BIO_strings();
1039 SSL_library_init();
1040
1041 nc_ssh_init();
1042
1043 CRYPTO_set_dynlock_create_callback(tls_dyn_create_func);
1044 CRYPTO_set_dynlock_lock_callback(tls_dyn_lock_func);
1045 CRYPTO_set_dynlock_destroy_callback(tls_dyn_destroy_func);
1046}
1047
1048API void
1049nc_ssh_tls_destroy(void)
1050{
1051 ERR_free_strings();
1052 sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
1053
1054 nc_ssh_destroy();
1055
1056 CRYPTO_set_dynlock_create_callback(NULL);
1057 CRYPTO_set_dynlock_lock_callback(NULL);
1058 CRYPTO_set_dynlock_destroy_callback(NULL);
1059}
1060
Radek Krejci53691be2016-02-22 13:58:37 +01001061#endif /* NC_ENABLED_SSH && NC_ENABLED_TLS */