blob: fd3684f409749e2c1930c0f2e0e87bb95be35aed [file] [log] [blame]
roman41a11e42022-06-22 09:27:08 +02001/**
2 * @file test_pam.c
3 * @author Roman Janota <xjanot04@fit.vutbr.cz>
4 * @brief libnetconf2 Linux PAM keyboard-interactive authentication test
5 *
6 * @copyright
7 * Copyright (c) 2022 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#include <pthread.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <libyang/libyang.h>
22#include <log.h>
23#include <session_client.h>
24#include <session_server.h>
25
26#include "tests/config.h"
27
28#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); abort(); }
29
30#define NC_ACCEPT_TIMEOUT 5000
31#define NC_PS_POLL_TIMEOUT 5000
32
33struct ly_ctx *ctx;
34
35static void *
36server_thread(void *arg)
37{
38 int ret;
39 NC_MSG_TYPE msgtype;
40 struct nc_session *session;
41 struct nc_pollsession *ps;
42
43 (void) arg;
44 ps = nc_ps_new();
45 nc_assert(ps);
46
47 /* accept a session and add it to the poll session structure */
48 msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session);
49 nc_assert(msgtype == NC_MSG_HELLO);
50 ret = nc_ps_add_session(ps, session);
51 nc_assert(!ret);
52 ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
53 nc_assert(ret & NC_PSPOLL_RPC);
54 nc_ps_clear(ps, 0, NULL);
55
56 nc_ps_free(ps);
57 nc_thread_destroy();
58 return NULL;
59}
60
61static int
62clb_hostkeys(const char *name, void *user_data, char **privkey_path, char **privkey_data,
63 NC_SSH_KEY_TYPE *privkey_type)
64{
65 (void) user_data;
66 (void) privkey_data;
67 (void) privkey_type;
68
69 /* set the path to the testing private keys */
70 if (!strcmp(name, "key_rsa")) {
71 *privkey_path = strdup(TESTS_DIR "/data/key_rsa");
72 return 0;
73 } else if (!strcmp(name, "key_dsa")) {
74 *privkey_path = strdup(TESTS_DIR "/data/key_dsa");
75 return 0;
76 }
77
78 return 1;
79}
80
81static char *
82auth_interactive(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
83{
84 (void) instruction;
85 (void) echo;
86 (void) auth_name;
87 (void) priv;
88
89 /* send the replies to keyboard-interactive authentication */
90 if (strstr(prompt, "backwards")) {
91 return strdup("tset");
92 } else if (strstr(prompt, "1+1")) {
93 return strdup("2");
94 } else {
95 return NULL;
96 }
97}
98
99static int
100ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
101{
102 (void)hostname;
103 (void)session;
104 (void)priv;
105 /* redundant in this test, nonetheless this callback has to be set */
106
107 return 0;
108}
109
110static void *
111client_thread(void *arg)
112{
113 (void) arg;
114 int ret;
115 struct nc_session *session = NULL;
116
117 printf("SSH client started.\n");
118
119 /* initialize client */
120 nc_client_init();
121 ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules");
122 nc_assert(!ret);
123 /* skip the knownhost check */
124 nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
125
126 ret = nc_client_ssh_set_username("test");
127 nc_assert(!ret);
128
129 /* set keyboard-interactive authentication callback */
130 nc_client_ssh_set_auth_interactive_clb(auth_interactive, NULL);
131 session = nc_connect_ssh("0.0.0.0", 6001, NULL);
132 nc_assert(session);
133
134 printf("SSH client finished.\n");
135 nc_client_destroy();
136
137 nc_session_free(session, NULL);
138 nc_thread_destroy();
139 return NULL;
140}
141
142int
143main(void)
144{
145 int ret, i;
146 pthread_t tids[2];
147
148 ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx);
149 nc_assert(ctx);
150 ly_ctx_load_module(ctx, "ietf-netconf", NULL, NULL);
151
152 nc_verbosity(NC_VERB_VERBOSE);
153 nc_server_init();
154
155 /* set callback */
156 nc_server_ssh_set_hostkey_clb(clb_hostkeys, NULL, NULL);
157
158 /* do first, so that client can connect on SSH */
159 ret = nc_server_add_endpt("main_ssh", NC_TI_LIBSSH);
160 nc_assert(!ret);
161 ret = nc_server_endpt_set_address("main_ssh", "0.0.0.0");
162 nc_assert(!ret);
163 ret = nc_server_endpt_set_port("main_ssh", 6001);
164 nc_assert(!ret);
165 ret = nc_server_ssh_endpt_add_hostkey("main_ssh", "key_rsa", -1);
166 nc_assert(!ret);
167
168 /* in order to use the Linux PAM keyboard-interactive method,
169 * the PAM module has to know where to find the desired configuration file */
170 ret = nc_server_ssh_set_pam_conf_path("netconf.conf", TESTS_DIR "/pam");
171 nc_assert(!ret);
172
173 /* only want to test keyboard-interactive auth method */
174 ret = nc_server_ssh_endpt_set_auth_methods("main_ssh", NC_SSH_AUTH_INTERACTIVE);
175 nc_assert(!ret);
176
177 ret = pthread_create(&tids[0], NULL, client_thread, NULL);
178 nc_assert(!ret);
179 ret = pthread_create(&tids[1], NULL, server_thread, NULL);
180 nc_assert(!ret);
181
182 for (i = 0; i < 2; i++) {
183 pthread_join(tids[i], NULL);
184 }
185
186 nc_server_destroy();
187 ly_ctx_destroy(ctx);
188 return 0;
189}