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