Coverage Report

Created: 2026-07-05 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/src/init.c
Line
Count
Source
1
/*
2
 * init.c - initialization and finalization of the library
3
 *
4
 * This file is part of the SSH Library
5
 *
6
 * Copyright (c) 2003-2009 by Aris Adamantiadis
7
 *
8
 * The SSH Library is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or (at your
11
 * option) any later version.
12
 *
13
 * The SSH Library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16
 * License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with the SSH Library; see the file COPYING.  If not, write to
20
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21
 * MA 02111-1307, USA.
22
 */
23
24
#include "config.h"
25
26
#include <stdio.h>
27
28
#include "libssh/priv.h"
29
#include "libssh/socket.h"
30
#include "libssh/dh.h"
31
#include "libssh/poll.h"
32
#include "libssh/threads.h"
33
34
#ifdef _WIN32
35
#include <winsock2.h>
36
#endif
37
38
#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
39
#define CONSTRUCTOR_ATTRIBUTE __attribute__((constructor))
40
#else
41
#define CONSTRUCTOR_ATTRIBUTE
42
#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
43
44
#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
45
#define DESTRUCTOR_ATTRIBUTE __attribute__((destructor))
46
#else
47
#define DESTRUCTOR_ATTRIBUTE
48
#endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
49
50
/* Declare static mutex */
51
static SSH_MUTEX ssh_init_mutex = SSH_MUTEX_STATIC_INIT;
52
53
/* Counter for initializations */
54
static int _ssh_initialized = 0;
55
56
/* Cache the returned value */
57
static int _ssh_init_ret = 0;
58
59
void libssh_constructor(void) CONSTRUCTOR_ATTRIBUTE;
60
void libssh_destructor(void) DESTRUCTOR_ATTRIBUTE;
61
62
2
static int _ssh_init(unsigned constructor) {
63
64
2
    int rc = 0;
65
66
2
    if (!constructor) {
67
1
        ssh_mutex_lock(&ssh_init_mutex);
68
1
    }
69
70
2
    _ssh_initialized++;
71
72
2
    if (_ssh_initialized > 1) {
73
1
        rc = _ssh_init_ret;
74
1
        goto _ret;
75
1
    }
76
77
1
    rc = ssh_threads_init();
78
1
    if (rc) {
79
0
        goto _ret;
80
0
    }
81
82
1
    rc = ssh_crypto_init();
83
1
    if (rc) {
84
0
        goto _ret;
85
0
    }
86
87
1
    rc = ssh_dh_init();
88
1
    if (rc) {
89
0
        goto _ret;
90
0
    }
91
92
1
    rc = ssh_socket_init();
93
1
    if (rc) {
94
0
        goto _ret;
95
0
    }
96
97
2
_ret:
98
2
    _ssh_init_ret = rc;
99
100
2
    if (!constructor) {
101
1
        ssh_mutex_unlock(&ssh_init_mutex);
102
1
    }
103
104
2
    return rc;
105
1
}
106
107
/**
108
 * @brief Initialize global cryptographic data structures.
109
 *
110
 * This function is automatically called when the library is loaded.
111
 *
112
 */
113
void libssh_constructor(void)
114
1
{
115
116
1
    int rc;
117
118
1
    rc = _ssh_init(1);
119
120
1
    if (rc < 0) {
121
0
        fprintf(stderr, "Error in auto_init()\n");
122
0
    }
123
124
1
    return;
125
1
}
126
127
/**
128
 * @defgroup libssh The libssh API
129
 *
130
 * The libssh library is implementing the SSH protocols and some of its
131
 * extensions. This group of functions is mostly used to implement an SSH
132
 * client.
133
 * Some functions are needed to implement an SSH server too.
134
 *
135
 * @{
136
 */
137
138
/**
139
 * @brief Initialize global cryptographic data structures.
140
 *
141
 * Since version 0.8.0, when libssh is dynamically linked, it is not necessary
142
 * to call this function on systems that fully support threading (that is,
143
 * systems with pthreads available).
144
 *
145
 * If libssh is statically linked, it is necessary to explicitly call ssh_init()
146
 * before calling any other provided API, and it is necessary to explicitly call
147
 * ssh_finalize() to free the allocated resources before exiting.
148
 *
149
 * If the library is already initialized, increments the _ssh_initialized
150
 * counter and return the error code cached in _ssh_init_ret.
151
 *
152
 * @returns             SSH_OK on success, SSH_ERROR if an error occurred.
153
 *
154
 * @see ssh_finalize()
155
 */
156
1
int ssh_init(void) {
157
1
    return _ssh_init(0);
158
1
}
159
160
1
static int _ssh_finalize(unsigned destructor) {
161
162
1
    if (!destructor) {
163
1
        ssh_mutex_lock(&ssh_init_mutex);
164
165
1
        if (_ssh_initialized > 1) {
166
1
            _ssh_initialized--;
167
1
            ssh_mutex_unlock(&ssh_init_mutex);
168
1
            return 0;
169
1
        }
170
171
0
        if (_ssh_initialized == 1) {
172
0
            if (_ssh_init_ret < 0) {
173
0
                ssh_mutex_unlock(&ssh_init_mutex);
174
0
                return 0;
175
0
            }
176
0
        }
177
0
    }
178
179
    /* If the counter reaches zero or it is the destructor calling, finalize */
180
0
    ssh_dh_finalize();
181
0
    ssh_crypto_finalize();
182
0
    ssh_socket_cleanup();
183
    /* It is important to finalize threading after CRYPTO because
184
     * it still depends on it */
185
0
    ssh_threads_finalize();
186
187
0
    _ssh_initialized = 0;
188
189
0
    if (!destructor) {
190
0
        ssh_mutex_unlock(&ssh_init_mutex);
191
0
    }
192
193
#if (defined(_WIN32) && !defined(HAVE_PTHREAD))
194
    if (ssh_init_mutex != NULL) {
195
        DeleteCriticalSection(ssh_init_mutex);
196
        SAFE_FREE(ssh_init_mutex);
197
    }
198
#endif
199
200
0
    return 0;
201
1
}
202
203
/**
204
 * @brief Finalize and clean up all libssh and cryptographic data structures.
205
 *
206
 * This function is automatically called when the library is unloaded.
207
 *
208
 */
209
void libssh_destructor(void)
210
0
{
211
0
    int rc;
212
213
0
    rc = _ssh_finalize(1);
214
215
0
    if (rc < 0) {
216
0
        fprintf(stderr, "Error in libssh_destructor()\n");
217
0
    }
218
0
}
219
220
/**
221
 * @brief Finalize and clean up all libssh and cryptographic data structures.
222
 *
223
 * Since version 0.8.0, when libssh is dynamically linked, it is not necessary
224
 * to call this function, since it is automatically called when the library is
225
 * unloaded.
226
 *
227
 * If libssh is statically linked, it is necessary to explicitly call ssh_init()
228
 * before calling any other provided API, and it is necessary to explicitly call
229
 * ssh_finalize() to free the allocated resources before exiting.
230
 *
231
 * If ssh_init() is called explicitly, then ssh_finalize() must be called
232
 * explicitly.
233
 *
234
 * When called, decrements the counter _ssh_initialized. If the counter reaches
235
 * zero, then the libssh and cryptographic data structures are cleaned up.
236
 *
237
 * @returns             0 on success, -1 if an error occurred.
238
 *
239
 * @see ssh_init()
240
 */
241
1
int ssh_finalize(void) {
242
1
    return _ssh_finalize(0);
243
1
}
244
245
#ifdef _WIN32
246
247
#if defined(_MSC_VER) && !defined(LIBSSH_STATIC)
248
/* Library constructor and destructor */
249
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
250
                    DWORD fdwReason,
251
                    LPVOID lpvReserved)
252
{
253
    int rc = 0;
254
255
    switch(fdwReason) {
256
    case DLL_PROCESS_ATTACH:
257
        rc = _ssh_init(1);
258
        if (rc != 0) {
259
            fprintf(stderr, "DllMain: ssh_init failed!");
260
            return FALSE;
261
        }
262
        break;
263
    case DLL_PROCESS_DETACH:
264
        _ssh_finalize(1);
265
        break;
266
    default:
267
        break;
268
    }
269
270
    return TRUE;
271
}
272
#endif /* _MSC_VER && !LIBSSH_STATIC */
273
274
#endif /* _WIN32 */
275
276
/**
277
 * @internal
278
 * @brief Return whether the library is initialized
279
 *
280
 * @returns true if the library is initialized; false otherwise.
281
 *
282
 * @see ssh_init()
283
 */
284
0
bool is_ssh_initialized(void) {
285
286
0
    bool is_initialized = false;
287
288
0
    ssh_mutex_lock(&ssh_init_mutex);
289
0
    is_initialized = _ssh_initialized > 0;
290
0
    ssh_mutex_unlock(&ssh_init_mutex);
291
292
0
    return is_initialized;
293
0
}
294
295
/** @} */