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