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 | | /** @} */ |