Line data Source code
1 : /* assuan.c - Global interface (not specific to context).
2 : Copyright (C) 2009 Free Software Foundation, Inc.
3 : Copyright (C) 2001, 2002, 2012, 2013 g10 Code GmbH
4 :
5 : This file is part of Assuan.
6 :
7 : Assuan is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : Assuan is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 :
22 : #ifdef HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include <stdlib.h>
27 :
28 : #include "assuan-defs.h"
29 : #include "debug.h"
30 :
31 :
32 : #define digitp(a) ((a) >= '0' && (a) <= '9')
33 :
34 :
35 :
36 : /* Global default state. */
37 :
38 : /* The default error source gor generated error codes. */
39 : static gpg_err_source_t _assuan_default_err_source = GPG_ERR_SOURCE_USER_1;
40 :
41 : /* The default memory management functions. */
42 : static struct assuan_malloc_hooks _assuan_default_malloc_hooks =
43 : { malloc, realloc, free };
44 :
45 : /* The default logging handler. */
46 : static assuan_log_cb_t _assuan_default_log_cb = _assuan_log_handler;
47 : static void *_assuan_default_log_cb_data = NULL;
48 :
49 :
50 : /* Set the default gpg error source. */
51 : void
52 0 : assuan_set_gpg_err_source (gpg_err_source_t errsource)
53 : {
54 0 : _assuan_default_err_source = errsource;
55 0 : }
56 :
57 :
58 : /* Get the default gpg error source. */
59 : gpg_err_source_t
60 0 : assuan_get_gpg_err_source (void)
61 : {
62 0 : return _assuan_default_err_source;
63 : }
64 :
65 :
66 : /* Set the default malloc hooks. */
67 : void
68 0 : assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks)
69 : {
70 0 : _assuan_default_malloc_hooks = *malloc_hooks;
71 0 : }
72 :
73 :
74 : /* Get the default malloc hooks. */
75 : assuan_malloc_hooks_t
76 0 : assuan_get_malloc_hooks (void)
77 : {
78 0 : return &_assuan_default_malloc_hooks;
79 : }
80 :
81 :
82 : /* Set the default log callback handler. */
83 : void
84 0 : assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data)
85 : {
86 0 : _assuan_default_log_cb = log_cb;
87 0 : _assuan_default_log_cb_data = log_cb_data;
88 0 : _assuan_init_log_envvars ();
89 0 : }
90 :
91 :
92 : /* Get the default log callback handler. */
93 : void
94 0 : assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data)
95 : {
96 0 : *log_cb = _assuan_default_log_cb;
97 0 : *log_cb_data = _assuan_default_log_cb_data;
98 0 : }
99 :
100 :
101 : void
102 0 : assuan_set_system_hooks (assuan_system_hooks_t system_hooks)
103 : {
104 0 : _assuan_system_hooks_copy (&_assuan_system_hooks, system_hooks);
105 0 : }
106 :
107 :
108 : /* Create a new Assuan context. The initial parameters are all needed
109 : in the creation of the context. */
110 : gpg_error_t
111 6 : assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source,
112 : assuan_malloc_hooks_t malloc_hooks, assuan_log_cb_t log_cb,
113 : void *log_cb_data)
114 : {
115 : struct assuan_context_s wctx;
116 : assuan_context_t ctx;
117 :
118 : /* Set up a working context so we can use standard functions. */
119 6 : memset (&wctx, 0, sizeof (wctx));
120 6 : wctx.err_source = err_source;
121 6 : wctx.malloc_hooks = *malloc_hooks;
122 6 : wctx.log_cb = log_cb;
123 6 : wctx.log_cb_data = log_cb_data;
124 :
125 : /* Need a new block for the trace macros to work. */
126 : {
127 6 : TRACE_BEG8 (&wctx, ASSUAN_LOG_CTX, "assuan_new_ext", r_ctx,
128 : "err_source = %i (%s), malloc_hooks = %p (%p, %p, %p), "
129 : "log_cb = %p, log_cb_data = %p", err_source,
130 : gpg_strsource (err_source), malloc_hooks, malloc_hooks->malloc,
131 : malloc_hooks->realloc, malloc_hooks->free, log_cb, log_cb_data);
132 :
133 6 : *r_ctx = NULL;
134 6 : ctx = _assuan_malloc (&wctx, sizeof (*ctx));
135 6 : if (!ctx)
136 0 : return TRACE_ERR (gpg_err_code_from_syserror ());
137 :
138 6 : memcpy (ctx, &wctx, sizeof (*ctx));
139 6 : ctx->system = _assuan_system_hooks;
140 :
141 : /* FIXME: Delegate to subsystems/engines, as the FDs are not our
142 : responsibility (we don't deallocate them, for example). */
143 6 : ctx->input_fd = ASSUAN_INVALID_FD;
144 6 : ctx->output_fd = ASSUAN_INVALID_FD;
145 6 : ctx->inbound.fd = ASSUAN_INVALID_FD;
146 6 : ctx->outbound.fd = ASSUAN_INVALID_FD;
147 6 : ctx->listen_fd = ASSUAN_INVALID_FD;
148 :
149 6 : *r_ctx = ctx;
150 :
151 6 : return TRACE_SUC1 ("ctx=%p", ctx);
152 : }
153 : }
154 :
155 :
156 : /* Create a new context with default arguments. */
157 : gpg_error_t
158 6 : assuan_new (assuan_context_t *r_ctx)
159 : {
160 6 : return assuan_new_ext (r_ctx, _assuan_default_err_source,
161 : &_assuan_default_malloc_hooks,
162 : _assuan_default_log_cb,
163 : _assuan_default_log_cb_data);
164 : }
165 :
166 :
167 : /* Release all resources associated with an engine operation. */
168 : void
169 4 : _assuan_reset (assuan_context_t ctx)
170 : {
171 4 : if (ctx->engine.release)
172 : {
173 4 : (*ctx->engine.release) (ctx);
174 4 : ctx->engine.release = NULL;
175 : }
176 :
177 : /* FIXME: Clean standard commands */
178 4 : }
179 :
180 :
181 : /* Release all resources associated with the given context. */
182 : void
183 4 : assuan_release (assuan_context_t ctx)
184 : {
185 4 : if (! ctx)
186 4 : return;
187 :
188 4 : TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx);
189 :
190 4 : _assuan_reset (ctx);
191 : /* None of the members that are our responsibility requires
192 : deallocation. To avoid sensitive data in the line buffers we
193 : wipe them out, though. Note that we can't wipe the entire
194 : context because it also has a pointer to the actual free(). */
195 4 : wipememory (&ctx->inbound, sizeof ctx->inbound);
196 4 : wipememory (&ctx->outbound, sizeof ctx->outbound);
197 4 : _assuan_free (ctx, ctx);
198 : }
199 :
200 :
201 :
202 : /*
203 : Version number stuff.
204 : */
205 :
206 : static const char*
207 16 : parse_version_number (const char *s, int *number)
208 : {
209 16 : int val = 0;
210 :
211 16 : if (*s == '0' && digitp (s[1]))
212 0 : return NULL; /* Leading zeros are not allowed. */
213 34 : for (; digitp (*s); s++)
214 : {
215 18 : val *= 10;
216 18 : val += *s - '0';
217 : }
218 16 : *number = val;
219 16 : return val < 0 ? NULL : s;
220 : }
221 :
222 :
223 : static const char *
224 6 : parse_version_string (const char *s, int *major, int *minor, int *micro)
225 : {
226 6 : s = parse_version_number (s, major);
227 6 : if (!s || *s != '.')
228 1 : return NULL;
229 5 : s++;
230 5 : s = parse_version_number (s, minor);
231 5 : if (!s || *s != '.')
232 0 : return NULL;
233 5 : s++;
234 5 : s = parse_version_number (s, micro);
235 5 : if (!s)
236 0 : return NULL;
237 5 : return s; /* Patchlevel. */
238 : }
239 :
240 :
241 : static const char *
242 3 : compare_versions (const char *my_version, const char *req_version)
243 : {
244 : int my_major, my_minor, my_micro;
245 : int rq_major, rq_minor, rq_micro;
246 : const char *my_plvl, *rq_plvl;
247 :
248 3 : if (!req_version)
249 0 : return my_version;
250 3 : if (!my_version)
251 0 : return NULL;
252 :
253 3 : my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
254 3 : if (!my_plvl)
255 0 : return NULL; /* Very strange: our own version is bogus. */
256 3 : rq_plvl = parse_version_string(req_version,
257 : &rq_major, &rq_minor, &rq_micro);
258 3 : if (!rq_plvl)
259 1 : return NULL; /* Requested version string is invalid. */
260 :
261 2 : if (my_major > rq_major
262 2 : || (my_major == rq_major && my_minor > rq_minor)
263 1 : || (my_major == rq_major && my_minor == rq_minor
264 1 : && my_micro > rq_micro)
265 1 : || (my_major == rq_major && my_minor == rq_minor
266 1 : && my_micro == rq_micro))
267 : {
268 2 : return my_version;
269 : }
270 0 : return NULL;
271 : }
272 :
273 :
274 : /*
275 : * Check that the the version of the library is at minimum REQ_VERSION
276 : * and return the actual version string; return NULL if the condition
277 : * is not met. If NULL is passed to this function, no check is done
278 : * and the version string is simply returned.
279 : */
280 : const char *
281 3 : assuan_check_version (const char *req_version)
282 : {
283 3 : return compare_versions (PACKAGE_VERSION, req_version);
284 : }
|