1 /*
2  *   stunnel       TLS offloading and load-balancing proxy
3  *   Copyright (C) 1998-2021 Michal Trojnara <Michal.Trojnara@stunnel.org>
4  *
5  *   This program is free software; you can redistribute it and/or modify it
6  *   under the terms of the GNU General Public License as published by the
7  *   Free Software Foundation; either version 2 of the License, or (at your
8  *   option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  *   See the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License along
16  *   with this program; if not, see <http://www.gnu.org/licenses>.
17  *
18  *   Linking stunnel statically or dynamically with other modules is making
19  *   a combined work based on stunnel. Thus, the terms and conditions of
20  *   the GNU General Public License cover the whole combination.
21  *
22  *   In addition, as a special exception, the copyright holder of stunnel
23  *   gives you permission to combine stunnel with free software programs or
24  *   libraries that are released under the GNU LGPL and with code included
25  *   in the standard release of OpenSSL under the OpenSSL License (or
26  *   modified versions of such code, with unchanged license). You may copy
27  *   and distribute such a system following the terms of the GNU GPL for
28  *   stunnel and the licenses of the other code concerned.
29  *
30  *   Note that people who make modified versions of stunnel are not obligated
31  *   to grant this special exception for their modified versions; it is their
32  *   choice whether to do so. The GNU General Public License gives permission
33  *   to release a modified version without this exception; this exception
34  *   also makes it possible to release a modified version which carries
35  *   forward this exception.
36  */
37 
38 #include "common.h"
39 #include "prototypes.h"
40 
41 volatile int tls_initialized=0;
42 
43 NOEXPORT void tls_platform_init();
44 #if OPENSSL_VERSION_NUMBER<0x10100000L
45 NOEXPORT void free_function(void *);
46 #endif
47 
48 /**************************************** thread local storage */
49 
50 /* this has to be the first function called from ui_*.c */
tls_init()51 void tls_init() {
52     tls_platform_init();
53     tls_initialized=1;
54     ui_tls=tls_alloc(NULL, NULL, "ui");
55 #if OPENSSL_VERSION_NUMBER>=0x10100000L
56     CRYPTO_set_mem_functions(str_alloc_detached_debug,
57         str_realloc_detached_debug, str_free_debug);
58 #else
59     CRYPTO_set_mem_ex_functions(str_alloc_detached_debug,
60         str_realloc_detached_debug, free_function);
61 #endif
62 }
63 
64 /* this has to be the first function called by a new thread */
tls_alloc(CLI * c,TLS_DATA * inherited,char * txt)65 TLS_DATA *tls_alloc(CLI *c, TLS_DATA *inherited, char *txt) {
66     TLS_DATA *tls_data;
67 
68     if(inherited) { /* reuse the thread-local storage after fork() */
69         tls_data=inherited;
70         str_free(tls_data->id);
71     } else {
72         tls_data=calloc(1, sizeof(TLS_DATA));
73         if(!tls_data)
74             fatal("Out of memory");
75         if(c)
76             c->tls=tls_data;
77         str_init(tls_data);
78         tls_data->c=c;
79         tls_data->opt=c?c->opt:&service_options;
80     }
81     tls_data->id="unconfigured";
82     tls_set(tls_data);
83 
84     /* str.c functions can be used below this point */
85     if(txt) {
86         tls_data->id=str_dup(txt);
87         str_detach(tls_data->id); /* it is deallocated after str_stats() */
88     } else if(c) {
89         tls_data->id=log_id(c);
90         str_detach(tls_data->id); /* it is deallocated after str_stats() */
91     }
92 
93     return tls_data;
94 }
95 
96 /* per-thread thread-local storage cleanup */
tls_cleanup()97 void tls_cleanup() {
98     TLS_DATA *tls_data;
99 
100     tls_data=tls_get();
101     if(!tls_data)
102         return;
103     str_cleanup(tls_data);
104     str_free(tls_data->id); /* detached allocation */
105     tls_set(NULL);
106     free(tls_data);
107 }
108 
109 #ifdef USE_UCONTEXT
110 
111 static TLS_DATA *global_tls=NULL;
112 
tls_platform_init()113 NOEXPORT void tls_platform_init() {
114 }
115 
tls_set(TLS_DATA * tls_data)116 void tls_set(TLS_DATA *tls_data) {
117     if(ready_head)
118         ready_head->tls=tls_data;
119     else /* ucontext threads not initialized */
120         global_tls=tls_data;
121 }
122 
tls_get()123 TLS_DATA *tls_get() {
124     if(ready_head)
125         return ready_head->tls;
126     else /* ucontext threads not initialized */
127         return global_tls;
128 }
129 
130 #endif /* USE_UCONTEXT */
131 
132 #ifdef USE_FORK
133 
134 static TLS_DATA *global_tls=NULL;
135 
tls_platform_init()136 NOEXPORT void tls_platform_init() {
137 }
138 
tls_set(TLS_DATA * tls_data)139 void tls_set(TLS_DATA *tls_data) {
140     global_tls=tls_data;
141 }
142 
tls_get()143 TLS_DATA *tls_get() {
144     return global_tls;
145 }
146 
147 #endif /* USE_FORK */
148 
149 #ifdef USE_PTHREAD
150 
151 static pthread_key_t pthread_key;
152 
tls_platform_init()153 NOEXPORT void tls_platform_init() {
154     pthread_key_create(&pthread_key, NULL);
155 }
156 
tls_set(TLS_DATA * tls_data)157 void tls_set(TLS_DATA *tls_data) {
158     pthread_setspecific(pthread_key, tls_data);
159 }
160 
tls_get()161 TLS_DATA *tls_get() {
162     return pthread_getspecific(pthread_key);
163 }
164 
165 #endif /* USE_PTHREAD */
166 
167 #ifdef USE_WIN32
168 
169 static DWORD tls_index;
170 
tls_platform_init()171 NOEXPORT void tls_platform_init() {
172     tls_index=TlsAlloc();
173 }
174 
tls_set(TLS_DATA * tls_data)175 void tls_set(TLS_DATA *tls_data) {
176     TlsSetValue(tls_index, tls_data);
177 }
178 
tls_get()179 TLS_DATA *tls_get() {
180     return TlsGetValue(tls_index);
181 }
182 
183 #endif /* USE_WIN32 */
184 
185 /**************************************** OpenSSL allocator hook */
186 
187 #if OPENSSL_VERSION_NUMBER<0x10100000L
free_function(void * ptr)188 NOEXPORT void free_function(void *ptr) {
189     /* CRYPTO_set_mem_ex_functions() needs a function rather than a macro */
190     /* unfortunately, OpenSSL provides no file:line information here */
191     str_free_debug(ptr, "OpenSSL", 0);
192 }
193 #endif
194 
195 /* end of tls.c */
196