blob: 4ad30fd21e566b8f5c16589b6967d3b0343065b5 [file] [log] [blame]
David Sedlákddde4492018-09-30 21:34:38 +02001#include <stdio.h>
2#include <stdlib.h>
3#include <setjmp.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <errno.h>
7
8#include <cmocka.h>
9#include <libyang/libyang.h>
10#include <session_client.h>
11#include <log.h>
12#include <config.h>
13#include "tests/config.h"
14
15#include <libssh/libssh.h>
16#include <libssh/callbacks.h>
17#include <libssh/server.h>
18
19static int
20ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
21{
22 (void)hostname;
23 (void)session;
24 (void)priv;
25
26 return 0;
27}
28
29static int
30setup_f(void **state)
31{
32 (void)state;
33 int ret;
34
35 nc_verbosity(NC_VERB_VERBOSE);
36
37 ret = nc_client_ssh_set_username("username");
38 assert_int_equal(ret, 0);
39 nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
40
41 return 0;
42}
43
44static int
45teardown_f(void **state)
46{
47 (void)state;
48 return 0;
49}
50
51MOCK int
52__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
53{
54 (void)sockfd;
55 (void)addr;
56 (void)addrlen;
57
58 return (int)mock();
59}
60
61MOCK int
62__wrap_ssh_connect(ssh_session session)
63{
64 (void)session;
65
66 /* set support of all authentication methods by fake server */
67 ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
68 return (int)mock();
69}
70
71MOCK int
72__wrap_ssh_userauth_none(ssh_session session, const char *username)
73{
74 (void)session;
75 (void)username;
76
77 return (int)mock();
78}
79
80MOCK int
81__wrap_ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods)
82{
83 (void)session;
84 (void)user;
85 (void)submethods;
86
87 return (int)mock();
88}
89
90MOCK int
91__wrap_ssh_is_connected(ssh_session session)
92{
93 (void)session;
94
95 return (int)mock();
96}
97
98MOCK int
99__wrap_ssh_channel_open_session(ssh_channel channel)
100{
101 (void)channel;
102
103 return (int)mock();
104}
105
106MOCK int
107__wrap_ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem)
108{
109 (void)channel;
110 (void)subsystem;
111
112 return (int)mock();
113}
114
115MOCK int
116__wrap_ssh_channel_is_closed(ssh_channel channel)
117{
118 (void)channel;
119
120 return 0;
121}
122
123MOCK int
124__wrap_ssh_channel_write(ssh_channel channel, const void *data, uint32_t len)
125{
126 (void)channel;
127 (void)data;
128
129 return len;
130}
131
132MOCK int
133__wrap_ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr)
134{
135 (void)channel;
136 (void)timeout;
137 (void)is_stderr;
138
139 return (int)mock();
140}
141
142MOCK int
143__wrap_ssh_userauth_password(ssh_session session, const char *username, const char *password)
144{
145 (void)session;
146 check_expected(password);
147 check_expected(username);
148
149
150 return (int)mock();
151}
152
153MOCK int
154__wrap_nc_handshake_io(struct nc_session *session)
155{
156 (void)session;
157
158 return (int)mock();
159}
160
161MOCK int
162__wrap_nc_ctx_check_and_fill(struct nc_session *session)
163{
164 (void)session;
165
166 return (int)mock();
167}
168
David Sedlák77acc202018-10-08 21:44:14 +0200169MOCK int
170__wrap_ssh_userauth_try_publickey(ssh_session session, const char *username, const ssh_key pubkey)
171{
172 (void)session;
173 (void)username;
174 (void)pubkey;
175
176 return (int)mock();
177}
178
179MOCK int
180__wrap_ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey)
181{
182 (void)session;
183 (void)username;
184 (void)privkey;
185
186 return (int)mock();
187}
188
David Sedlákddde4492018-09-30 21:34:38 +0200189static int
190test_hostkey_clb(const char *hostname, ssh_session session, void *priv)
191{
192 (void)hostname;
193 (void)session;
194 (void)priv;
195
196 return 0;
197}
198
199static void
200test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state)
201{
202 (void)state;
203 int (*ret_f)(const char *hostname, ssh_session session, void *priv);
204 char *priv_data_ret;
205
206 /* ssh_hostkey_check_clb is set in setup_f */
207 nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
208 assert_ptr_equal(ret_f, ssh_hostkey_check_clb);
209 assert_null(priv_data_ret);
210
211 /* set different callback and private data */
212 nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA");
213 nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
214 assert_ptr_equal(ret_f, test_hostkey_clb);
215 assert_string_equal(priv_data_ret, "DATA");
216}
217
218char *
219test_pwd_clb1(const char *username, const char *hostname, void *priv)
220{
221 char *pass, *pass_to_return;
222
223 check_expected(username);
224 check_expected(hostname);
225 check_expected(priv);
226
227 pass = (char *)mock();
228 pass_to_return = malloc(sizeof *pass * (strlen(pass) + 1));
229 strcpy(pass_to_return, pass);
230
231 return pass_to_return;
232}
233
234char *
235test_pwd_clb2(const char *username, const char *hostname, void *priv)
236{
237 (void)username;
238 (void)hostname;
239 (void)priv;
240
241 return 0;
242}
243
244static void
245test_nc_client_ssh_setting_auth_password_clb(void **state)
246{
247 (void)state;
248 char *(*ret_f)(const char *username, const char *hostname, void *priv);
249 char *priv_data_ret;
250
251 /* set callback */
252 nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "DATA");
253 nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
254 assert_ptr_equal(test_pwd_clb1, ret_f);
255 assert_string_equal("DATA", priv_data_ret);
256
257 /* set different callback */
258 nc_client_ssh_set_auth_password_clb(test_pwd_clb2, "NEW DATA");
259 nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
260 assert_ptr_equal(test_pwd_clb2, ret_f);
261 assert_string_equal("NEW DATA", priv_data_ret);
262}
263
264char *
265test_inter_clb1(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
266{
267 (void)auth_name;
268 (void)instruction;
269 (void)prompt;
270 (void)echo;
271 (void)priv;
272
273 return 0;
274}
275
276char *
277test_inter_clb2(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
278{
279 (void)auth_name;
280 (void)instruction;
281 (void)prompt;
282 (void)echo;
283 (void)priv;
284
285 return 0;
286}
287
288static void
289test_nc_client_ssh_setting_auth_interactive_clb(void **state)
290{
291 (void)state;
292 char *(*ret_f)(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv);
293 char *priv_data_ret;
294
295 /* set callback */
296 nc_client_ssh_set_auth_interactive_clb(test_inter_clb1, "DATA");
297 nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
298 assert_ptr_equal(test_inter_clb1, ret_f);
299 assert_string_equal("DATA", priv_data_ret);
300
301 /* set diferent callback */
302 nc_client_ssh_set_auth_interactive_clb(test_inter_clb2, "NEW DATA");
303 nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
304 assert_ptr_equal(test_inter_clb2, ret_f);
305 assert_string_equal("NEW DATA", priv_data_ret);
306}
307
308char *
309test_passphrase_clb1(const char *privkey_path, void *priv)
310{
311 (void)privkey_path;
312 (void)priv;
313
314 return 0;
315}
316
317char *
318test_passphrase_clb2(const char *privkey_path, void *priv)
319{
320 (void)privkey_path;
321 (void)priv;
322
323 return 0;
324}
325
326static void
327test_nc_client_ssh_setting_auth_privkey_passphrase_clb(void **state)
328{
329 (void)state;
330 char *(*ret_f)(const char *privkey_path, void *priv);
331 char *priv_data_ret;
332 /* set first callback */
333 nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb1, "DATA");
334 nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
335 assert_ptr_equal(ret_f, test_passphrase_clb1);
336 assert_string_equal("DATA", priv_data_ret);
337
338 /* set different callback */
339 nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb2, "NEW DATA");
340 nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
341 assert_ptr_equal(ret_f, test_passphrase_clb2);
342 assert_string_equal("NEW DATA", priv_data_ret);
343}
344
345static void
346test_nc_client_ssh_adding_keypair(void **state)
347{
348 (void)state;
349 int ret;
350 const char *pubkey1, *pubkey2;
351 /* at the beginning keypair count should be 0 */
352 ret = nc_client_ssh_get_keypair_count();
353 assert_int_equal(ret, 0);
354
355 /* add first key pair */
356 ret = nc_client_ssh_add_keypair(TESTS_DIR"/data/key_dsa.pub", TESTS_DIR"/data/key_dsa");
357 assert_int_equal(ret, 0);
358 ret = nc_client_ssh_get_keypair_count();
359 assert_int_equal(ret, 1);
360
361 /* add second keypair */
362 ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
363 assert_int_equal(ret, 0);
364 ret = nc_client_ssh_get_keypair_count();
365 assert_int_equal(ret, 2);
366 ret = nc_client_ssh_get_keypair(1, &pubkey1, &pubkey2);
367 assert_int_equal(ret, 0);
368 assert_string_equal(pubkey1, "key_pub");
369 assert_string_equal(pubkey2, "key_priv");
370
371 /* delete first keypair */
372 ret = nc_client_ssh_del_keypair(0);
373 assert_int_equal(ret, 0);
374 ret = nc_client_ssh_get_keypair_count();
375 assert_int_equal(ret, 1);
376 /* try to get deleted keypair */
377 ret = nc_client_ssh_get_keypair(5, &pubkey1, &pubkey2);
378 assert_int_equal(ret, -1);
379
380 /* try to add keypair that is already set */
381 ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
382 assert_int_equal(ret, -1);
383 ret = nc_client_ssh_get_keypair_count();
384 assert_int_equal(ret, 1);
385
386 /* try to delete keypair with id that is not used */
387 ret = nc_client_ssh_del_keypair(42);
388 assert_int_equal(ret, -1);
389 ret = nc_client_ssh_get_keypair_count();
390 assert_int_equal(ret, 1);
391
392 /* remove remaining keypairs */
393 ret = nc_client_ssh_del_keypair(0);
394 assert_int_equal(ret, 0);
395 ret = nc_client_ssh_get_keypair_count();
396 assert_int_equal(ret, 0);
397}
398
399static void
400test_nc_client_ssh_setting_auth_pref(void **state)
401{
402 (void)state;
403 int ret;
404
David Sedlákaae4df32018-10-08 22:27:22 +0200405 /* initiate client, must be called in first test */
David Sedlákddde4492018-09-30 21:34:38 +0200406 nc_client_init();
407
408 /* check default prefference settings according to documentation */
409 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
410 assert_int_equal(ret, 3);
411 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
412 assert_int_equal(ret, 2);
413 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
414 assert_int_equal(ret, 1);
415
416 /* try to set prefetence of non existing method */
417 nc_client_ssh_set_auth_pref(42, 22);
418
419 /* try to get preference of non existing method */
420 ret = nc_client_ssh_get_auth_pref(42);
421 assert_int_equal(ret, 0);
422
423 /* change values of all methods and check if they actually changed */
424 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 9);
425 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
426 assert_int_equal(ret, 9);
427
428 /* negative value should be set as -1 */
429 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -5);
430 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
431 assert_int_equal(ret, -1);
432
433 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 11);
434 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
435 assert_int_equal(ret, 11);
436}
437
438static void
439test_nc_client_ssh_setting_username(void **state)
440{
441 (void)state;
442 int ret;
443 const char *username_ret;
444 username_ret = nc_client_ssh_get_username();
445 /* username is set to "username" in setup_f */
446 assert_string_equal(username_ret, "username");
447
448 /* set new username and check if it changes */
449 ret = nc_client_ssh_set_username("new_username");
450 assert_int_equal(ret, 0);
451 username_ret = nc_client_ssh_get_username();
452 assert_string_equal(username_ret, "new_username");
453}
454
455static void
456test_nc_connect_ssh_interactive_succesfull(void **state)
457{
458 (void)state;
459 struct nc_session *session;
460
461 /* set authentication method to use interactive authentication */
462 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
463 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
464 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
465
466 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 20);
467
468 /* prepare return values for functions used by nc_connect_ssh */
469 will_return(__wrap_connect, 0);
470 will_return(__wrap_ssh_connect, 0);
471 will_return(__wrap_ssh_userauth_none, 1);
472
473 will_return(__wrap_ssh_userauth_kbdint, 0);
474 will_return(__wrap_ssh_is_connected, 1);
475 will_return(__wrap_ssh_is_connected, 1);
476
477 will_return(__wrap_ssh_channel_open_session, 0);
478 will_return(__wrap_ssh_channel_request_subsystem, 0);
479
480 will_return(__wrap_nc_handshake_io, 3);
481 will_return(__wrap_nc_ctx_check_and_fill, 0);
482
483 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
484 assert_non_null(session);
485
486 nc_session_free(session, NULL);
487}
488
489static void
490test_nc_connect_ssh_password_succesfull(void **state)
491{
492 (void)state;
493 struct nc_session *session;
494
495 /* set authentication method to use password authentication */
496 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 1);
497 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
498 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
499
500 /* set authentication callback */
501 nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "private_data");
502 will_return(test_pwd_clb1, "secret password");
503 /* set values that are expected as parameters for authentication callback */
504 expect_string(test_pwd_clb1, username, "username");
505 expect_string(test_pwd_clb1, hostname, "127.0.0.1");
506 expect_string(test_pwd_clb1, priv, "private_data");
507
508 /* fake succesfull connection */
509 will_return(__wrap_connect, 0);
510 will_return(__wrap_ssh_connect, 0);
511 /* do not authenticate using no authentication method */
512 will_return(__wrap_ssh_userauth_none, 1);
513
514 /* succesfully authenticate via password authentication */
515 expect_string(__wrap_ssh_userauth_password, password, "secret password");
516 expect_string(__wrap_ssh_userauth_password, username, "username");
517 will_return(__wrap_ssh_userauth_password, 0);
518
519 /* fake ssh functions that are used to open netconf channel */
520 will_return(__wrap_ssh_channel_open_session, 0);
521 will_return(__wrap_ssh_channel_request_subsystem, 0);
522
523 /* fake that connection is still alive*/
524 will_return(__wrap_ssh_is_connected, 1);
525
526 /* fake ssh function for recieving hello message */
527 will_return(__wrap_ssh_is_connected, 1);
528
529 will_return(__wrap_nc_handshake_io, 3);
530 will_return(__wrap_nc_ctx_check_and_fill, 0);
531
532 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
533 assert_non_null(session);
534
535 /* disconnect */
536 nc_session_free(session, NULL);
537}
538
539static void
David Sedlák77acc202018-10-08 21:44:14 +0200540test_nc_connect_ssh_pubkey_succesfull(void **state)
541{
542 (void)state;
543 struct nc_session *session;
544 int ret = 0;
545
546 /* set authentication method to use password authentication */
547 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
548 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
549 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
550
551 /* add keypair for authentication */
552 ret = nc_client_ssh_add_keypair(TESTS_DIR"/data/key_dsa.pub", TESTS_DIR"/data/key_dsa");
553 assert_int_equal(ret, 0);
554
555 /* fake succesfull connection */
556 will_return(__wrap_connect, 0);
557 will_return(__wrap_ssh_connect, 0);
558 /* do not authenticate using no authentication method */
559 will_return(__wrap_ssh_userauth_none, 1);
560 will_return(__wrap_ssh_userauth_try_publickey, 0);
561 will_return(__wrap_ssh_userauth_publickey, 0);
562 will_return(__wrap_ssh_is_connected, 1);
563 will_return(__wrap_ssh_channel_open_session, 0);
564 will_return(__wrap_ssh_channel_request_subsystem, 0);
565
566 /* fake ssh function for recieving hello message */
567 will_return(__wrap_ssh_is_connected, 1);
568
569 will_return(__wrap_nc_handshake_io, 3);
570 will_return(__wrap_nc_ctx_check_and_fill, 0);
571 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
572 assert_non_null(session);
573
574 /* disconnect */
575 nc_session_free(session, NULL);
576}
577
578static void
David Sedlákddde4492018-09-30 21:34:38 +0200579test_nc_connect_connection_failed(void **state)
580{
581 (void)state;
582 struct nc_session *session;
583
584 errno = ECONNREFUSED;
585 will_return(__wrap_connect, -1);
586 will_return(__wrap_ssh_is_connected, 0);
587
588 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
589 assert_null(session);
590}
591
592static void
593test_nc_connect_ssh_bad_hello(void **state)
594{
595 (void)state;
596 struct nc_session *session;
597
598 /* set authentication method to use interactive authentication */
599 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
600 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
601 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
602
603 nc_client_ssh_set_auth_password_clb(test_pwd_clb2, NULL);
604
605 will_return(__wrap_connect, 0);
606 will_return(__wrap_ssh_connect, 0);
607 will_return(__wrap_ssh_userauth_none, 1);
608
609 will_return(__wrap_ssh_userauth_kbdint, 0);
610 will_return(__wrap_ssh_is_connected, 1);
611 will_return(__wrap_ssh_is_connected, 1);
612
613 will_return(__wrap_ssh_channel_open_session, 0);
614 will_return(__wrap_ssh_channel_request_subsystem, 0);
615 will_return(__wrap_nc_handshake_io, 4);
616
617 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
618 assert_null(session);
619
David Sedlákaae4df32018-10-08 22:27:22 +0200620 /* destroy client, must be called in last test */
David Sedlákddde4492018-09-30 21:34:38 +0200621 nc_client_destroy();
622}
623
624int
625main(void)
626{
627 const struct CMUnitTest tests[] = {
628 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_pref, setup_f, teardown_f),
629 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_hostkey_check_clb, setup_f, teardown_f),
630 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_password_clb, setup_f, teardown_f),
631 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_interactive_clb, setup_f, teardown_f),
632 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_privkey_passphrase_clb, setup_f, teardown_f),
633 cmocka_unit_test_setup_teardown(test_nc_client_ssh_adding_keypair, setup_f, teardown_f),
634 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f),
635 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f),
636 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f),
David Sedlák77acc202018-10-08 21:44:14 +0200637 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f),
David Sedlákddde4492018-09-30 21:34:38 +0200638 cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f),
639 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f),
640 };
641
642 return cmocka_run_group_tests(tests, NULL, NULL);
643}