1295016Sjkim/* dso_lib.c */
2280304Sjkim/*
3280304Sjkim * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
4280304Sjkim * 2000.
568651Skris */
668651Skris/* ====================================================================
768651Skris * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
868651Skris *
968651Skris * Redistribution and use in source and binary forms, with or without
1068651Skris * modification, are permitted provided that the following conditions
1168651Skris * are met:
1268651Skris *
1368651Skris * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
1568651Skris *
1668651Skris * 2. Redistributions in binary form must reproduce the above copyright
1768651Skris *    notice, this list of conditions and the following disclaimer in
1868651Skris *    the documentation and/or other materials provided with the
1968651Skris *    distribution.
2068651Skris *
2168651Skris * 3. All advertising materials mentioning features or use of this
2268651Skris *    software must display the following acknowledgment:
2368651Skris *    "This product includes software developed by the OpenSSL Project
2468651Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2568651Skris *
2668651Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2768651Skris *    endorse or promote products derived from this software without
2868651Skris *    prior written permission. For written permission, please contact
2968651Skris *    licensing@OpenSSL.org.
3068651Skris *
3168651Skris * 5. Products derived from this software may not be called "OpenSSL"
3268651Skris *    nor may "OpenSSL" appear in their names without prior written
3368651Skris *    permission of the OpenSSL Project.
3468651Skris *
3568651Skris * 6. Redistributions of any form whatsoever must retain the following
3668651Skris *    acknowledgment:
3768651Skris *    "This product includes software developed by the OpenSSL Project
3868651Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3968651Skris *
4068651Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4168651Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4268651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4368651Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4468651Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4568651Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4668651Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4768651Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4968651Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5068651Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5168651Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5268651Skris * ====================================================================
5368651Skris *
5468651Skris * This product includes cryptographic software written by Eric Young
5568651Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5668651Skris * Hudson (tjh@cryptsoft.com).
5768651Skris *
5868651Skris */
5968651Skris
6068651Skris#include <stdio.h>
6168651Skris#include <openssl/crypto.h>
6268651Skris#include "cryptlib.h"
6368651Skris#include <openssl/dso.h>
6468651Skris
6568651Skrisstatic DSO_METHOD *default_DSO_meth = NULL;
6668651Skris
6768651SkrisDSO *DSO_new(void)
68280304Sjkim{
69280304Sjkim    return (DSO_new_method(NULL));
70280304Sjkim}
7168651Skris
7268651Skrisvoid DSO_set_default_method(DSO_METHOD *meth)
73280304Sjkim{
74280304Sjkim    default_DSO_meth = meth;
75280304Sjkim}
7668651Skris
7768651SkrisDSO_METHOD *DSO_get_default_method(void)
78280304Sjkim{
79280304Sjkim    return (default_DSO_meth);
80280304Sjkim}
8168651Skris
8268651SkrisDSO_METHOD *DSO_get_method(DSO *dso)
83280304Sjkim{
84280304Sjkim    return (dso->meth);
85280304Sjkim}
8668651Skris
8768651SkrisDSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth)
88280304Sjkim{
89280304Sjkim    DSO_METHOD *mtmp;
90280304Sjkim    mtmp = dso->meth;
91280304Sjkim    dso->meth = meth;
92280304Sjkim    return (mtmp);
93280304Sjkim}
9468651Skris
9568651SkrisDSO *DSO_new_method(DSO_METHOD *meth)
96280304Sjkim{
97280304Sjkim    DSO *ret;
9868651Skris
99280304Sjkim    if (default_DSO_meth == NULL)
100280304Sjkim        /*
101280304Sjkim         * We default to DSO_METH_openssl() which in turn defaults to
102280304Sjkim         * stealing the "best available" method. Will fallback to
103280304Sjkim         * DSO_METH_null() in the worst case.
104280304Sjkim         */
105280304Sjkim        default_DSO_meth = DSO_METHOD_openssl();
106280304Sjkim    ret = (DSO *)OPENSSL_malloc(sizeof(DSO));
107280304Sjkim    if (ret == NULL) {
108280304Sjkim        DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
109280304Sjkim        return (NULL);
110280304Sjkim    }
111280304Sjkim    memset(ret, 0, sizeof(DSO));
112280304Sjkim    ret->meth_data = sk_void_new_null();
113280304Sjkim    if (ret->meth_data == NULL) {
114280304Sjkim        /* sk_new doesn't generate any errors so we do */
115280304Sjkim        DSOerr(DSO_F_DSO_NEW_METHOD, ERR_R_MALLOC_FAILURE);
116280304Sjkim        OPENSSL_free(ret);
117280304Sjkim        return (NULL);
118280304Sjkim    }
119280304Sjkim    if (meth == NULL)
120280304Sjkim        ret->meth = default_DSO_meth;
121280304Sjkim    else
122280304Sjkim        ret->meth = meth;
123280304Sjkim    ret->references = 1;
124280304Sjkim    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
125280304Sjkim        OPENSSL_free(ret);
126280304Sjkim        ret = NULL;
127280304Sjkim    }
128280304Sjkim    return (ret);
129280304Sjkim}
13068651Skris
13168651Skrisint DSO_free(DSO *dso)
132280304Sjkim{
133280304Sjkim    int i;
134280304Sjkim
135280304Sjkim    if (dso == NULL) {
136280304Sjkim        DSOerr(DSO_F_DSO_FREE, ERR_R_PASSED_NULL_PARAMETER);
137280304Sjkim        return (0);
138280304Sjkim    }
139280304Sjkim
140280304Sjkim    i = CRYPTO_add(&dso->references, -1, CRYPTO_LOCK_DSO);
14168651Skris#ifdef REF_PRINT
142280304Sjkim    REF_PRINT("DSO", dso);
14368651Skris#endif
144280304Sjkim    if (i > 0)
145280304Sjkim        return (1);
14668651Skris#ifdef REF_CHECK
147280304Sjkim    if (i < 0) {
148280304Sjkim        fprintf(stderr, "DSO_free, bad reference count\n");
149280304Sjkim        abort();
150280304Sjkim    }
15168651Skris#endif
15268651Skris
153280304Sjkim    if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
154280304Sjkim        DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
155280304Sjkim        return (0);
156280304Sjkim    }
15768651Skris
158280304Sjkim    if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
159280304Sjkim        DSOerr(DSO_F_DSO_FREE, DSO_R_FINISH_FAILED);
160280304Sjkim        return (0);
161280304Sjkim    }
162280304Sjkim
163280304Sjkim    sk_void_free(dso->meth_data);
164280304Sjkim    if (dso->filename != NULL)
165280304Sjkim        OPENSSL_free(dso->filename);
166280304Sjkim    if (dso->loaded_filename != NULL)
167280304Sjkim        OPENSSL_free(dso->loaded_filename);
168280304Sjkim
169280304Sjkim    OPENSSL_free(dso);
170280304Sjkim    return (1);
171280304Sjkim}
172280304Sjkim
17368651Skrisint DSO_flags(DSO *dso)
174280304Sjkim{
175280304Sjkim    return ((dso == NULL) ? 0 : dso->flags);
176280304Sjkim}
17768651Skris
178109998Smarkmint DSO_up_ref(DSO *dso)
179280304Sjkim{
180280304Sjkim    if (dso == NULL) {
181280304Sjkim        DSOerr(DSO_F_DSO_UP_REF, ERR_R_PASSED_NULL_PARAMETER);
182280304Sjkim        return (0);
183280304Sjkim    }
18468651Skris
185280304Sjkim    CRYPTO_add(&dso->references, 1, CRYPTO_LOCK_DSO);
186280304Sjkim    return (1);
187280304Sjkim}
18868651Skris
18968651SkrisDSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
190280304Sjkim{
191280304Sjkim    DSO *ret;
192280304Sjkim    int allocated = 0;
19368651Skris
194280304Sjkim    if (dso == NULL) {
195280304Sjkim        ret = DSO_new_method(meth);
196280304Sjkim        if (ret == NULL) {
197280304Sjkim            DSOerr(DSO_F_DSO_LOAD, ERR_R_MALLOC_FAILURE);
198280304Sjkim            goto err;
199280304Sjkim        }
200280304Sjkim        allocated = 1;
201280304Sjkim        /* Pass the provided flags to the new DSO object */
202280304Sjkim        if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
203280304Sjkim            DSOerr(DSO_F_DSO_LOAD, DSO_R_CTRL_FAILED);
204280304Sjkim            goto err;
205280304Sjkim        }
206280304Sjkim    } else
207280304Sjkim        ret = dso;
208280304Sjkim    /* Don't load if we're currently already loaded */
209280304Sjkim    if (ret->filename != NULL) {
210280304Sjkim        DSOerr(DSO_F_DSO_LOAD, DSO_R_DSO_ALREADY_LOADED);
211280304Sjkim        goto err;
212280304Sjkim    }
213280304Sjkim    /*
214280304Sjkim     * filename can only be NULL if we were passed a dso that already has one
215280304Sjkim     * set.
216280304Sjkim     */
217280304Sjkim    if (filename != NULL)
218280304Sjkim        if (!DSO_set_filename(ret, filename)) {
219280304Sjkim            DSOerr(DSO_F_DSO_LOAD, DSO_R_SET_FILENAME_FAILED);
220280304Sjkim            goto err;
221280304Sjkim        }
222280304Sjkim    filename = ret->filename;
223280304Sjkim    if (filename == NULL) {
224280304Sjkim        DSOerr(DSO_F_DSO_LOAD, DSO_R_NO_FILENAME);
225280304Sjkim        goto err;
226280304Sjkim    }
227280304Sjkim    if (ret->meth->dso_load == NULL) {
228280304Sjkim        DSOerr(DSO_F_DSO_LOAD, DSO_R_UNSUPPORTED);
229280304Sjkim        goto err;
230280304Sjkim    }
231280304Sjkim    if (!ret->meth->dso_load(ret)) {
232280304Sjkim        DSOerr(DSO_F_DSO_LOAD, DSO_R_LOAD_FAILED);
233280304Sjkim        goto err;
234280304Sjkim    }
235280304Sjkim    /* Load succeeded */
236280304Sjkim    return (ret);
237280304Sjkim err:
238280304Sjkim    if (allocated)
239280304Sjkim        DSO_free(ret);
240280304Sjkim    return (NULL);
241280304Sjkim}
24268651Skris
24368651Skrisvoid *DSO_bind_var(DSO *dso, const char *symname)
244280304Sjkim{
245280304Sjkim    void *ret = NULL;
24668651Skris
247280304Sjkim    if ((dso == NULL) || (symname == NULL)) {
248280304Sjkim        DSOerr(DSO_F_DSO_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
249280304Sjkim        return (NULL);
250280304Sjkim    }
251280304Sjkim    if (dso->meth->dso_bind_var == NULL) {
252280304Sjkim        DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_UNSUPPORTED);
253280304Sjkim        return (NULL);
254280304Sjkim    }
255280304Sjkim    if ((ret = dso->meth->dso_bind_var(dso, symname)) == NULL) {
256280304Sjkim        DSOerr(DSO_F_DSO_BIND_VAR, DSO_R_SYM_FAILURE);
257280304Sjkim        return (NULL);
258280304Sjkim    }
259280304Sjkim    /* Success */
260280304Sjkim    return (ret);
261280304Sjkim}
26268651Skris
26368651SkrisDSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
264280304Sjkim{
265280304Sjkim    DSO_FUNC_TYPE ret = NULL;
26668651Skris
267280304Sjkim    if ((dso == NULL) || (symname == NULL)) {
268280304Sjkim        DSOerr(DSO_F_DSO_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
269280304Sjkim        return (NULL);
270280304Sjkim    }
271280304Sjkim    if (dso->meth->dso_bind_func == NULL) {
272280304Sjkim        DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_UNSUPPORTED);
273280304Sjkim        return (NULL);
274280304Sjkim    }
275280304Sjkim    if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
276280304Sjkim        DSOerr(DSO_F_DSO_BIND_FUNC, DSO_R_SYM_FAILURE);
277280304Sjkim        return (NULL);
278280304Sjkim    }
279280304Sjkim    /* Success */
280280304Sjkim    return (ret);
281280304Sjkim}
28268651Skris
283280304Sjkim/*
284280304Sjkim * I don't really like these *_ctrl functions very much to be perfectly
285280304Sjkim * honest. For one thing, I think I have to return a negative value for any
286280304Sjkim * error because possible DSO_ctrl() commands may return values such as
287280304Sjkim * "size"s that can legitimately be zero (making the standard
288284285Sjkim * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
289280304Sjkim * times. I'd prefer "output" values to be passed by reference and the return
290280304Sjkim * value as success/failure like usual ... but we conform when we must... :-)
291280304Sjkim */
29268651Skrislong DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
293280304Sjkim{
294280304Sjkim    if (dso == NULL) {
295280304Sjkim        DSOerr(DSO_F_DSO_CTRL, ERR_R_PASSED_NULL_PARAMETER);
296280304Sjkim        return (-1);
297280304Sjkim    }
298280304Sjkim    /*
299280304Sjkim     * We should intercept certain generic commands and only pass control to
300280304Sjkim     * the method-specific ctrl() function if it's something we don't handle.
301280304Sjkim     */
302280304Sjkim    switch (cmd) {
303280304Sjkim    case DSO_CTRL_GET_FLAGS:
304280304Sjkim        return dso->flags;
305280304Sjkim    case DSO_CTRL_SET_FLAGS:
306280304Sjkim        dso->flags = (int)larg;
307280304Sjkim        return (0);
308280304Sjkim    case DSO_CTRL_OR_FLAGS:
309280304Sjkim        dso->flags |= (int)larg;
310280304Sjkim        return (0);
311280304Sjkim    default:
312280304Sjkim        break;
313280304Sjkim    }
314280304Sjkim    if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
315280304Sjkim        DSOerr(DSO_F_DSO_CTRL, DSO_R_UNSUPPORTED);
316280304Sjkim        return (-1);
317280304Sjkim    }
318280304Sjkim    return (dso->meth->dso_ctrl(dso, cmd, larg, parg));
319280304Sjkim}
320109998Smarkm
321109998Smarkmint DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
322280304Sjkim                           DSO_NAME_CONVERTER_FUNC *oldcb)
323280304Sjkim{
324280304Sjkim    if (dso == NULL) {
325280304Sjkim        DSOerr(DSO_F_DSO_SET_NAME_CONVERTER, ERR_R_PASSED_NULL_PARAMETER);
326280304Sjkim        return (0);
327280304Sjkim    }
328280304Sjkim    if (oldcb)
329280304Sjkim        *oldcb = dso->name_converter;
330280304Sjkim    dso->name_converter = cb;
331280304Sjkim    return (1);
332280304Sjkim}
333109998Smarkm
334109998Smarkmconst char *DSO_get_filename(DSO *dso)
335280304Sjkim{
336280304Sjkim    if (dso == NULL) {
337280304Sjkim        DSOerr(DSO_F_DSO_GET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
338280304Sjkim        return (NULL);
339280304Sjkim    }
340280304Sjkim    return (dso->filename);
341280304Sjkim}
342109998Smarkm
343109998Smarkmint DSO_set_filename(DSO *dso, const char *filename)
344280304Sjkim{
345280304Sjkim    char *copied;
346109998Smarkm
347280304Sjkim    if ((dso == NULL) || (filename == NULL)) {
348280304Sjkim        DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
349280304Sjkim        return (0);
350280304Sjkim    }
351280304Sjkim    if (dso->loaded_filename) {
352280304Sjkim        DSOerr(DSO_F_DSO_SET_FILENAME, DSO_R_DSO_ALREADY_LOADED);
353280304Sjkim        return (0);
354280304Sjkim    }
355280304Sjkim    /* We'll duplicate filename */
356280304Sjkim    copied = OPENSSL_malloc(strlen(filename) + 1);
357280304Sjkim    if (copied == NULL) {
358280304Sjkim        DSOerr(DSO_F_DSO_SET_FILENAME, ERR_R_MALLOC_FAILURE);
359280304Sjkim        return (0);
360280304Sjkim    }
361280304Sjkim    BUF_strlcpy(copied, filename, strlen(filename) + 1);
362280304Sjkim    if (dso->filename)
363280304Sjkim        OPENSSL_free(dso->filename);
364280304Sjkim    dso->filename = copied;
365280304Sjkim    return (1);
366280304Sjkim}
367109998Smarkm
368160814Ssimonchar *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
369280304Sjkim{
370280304Sjkim    char *result = NULL;
371160814Ssimon
372280304Sjkim    if (dso == NULL || filespec1 == NULL) {
373280304Sjkim        DSOerr(DSO_F_DSO_MERGE, ERR_R_PASSED_NULL_PARAMETER);
374280304Sjkim        return (NULL);
375280304Sjkim    }
376280304Sjkim    if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
377280304Sjkim        if (dso->merger != NULL)
378280304Sjkim            result = dso->merger(dso, filespec1, filespec2);
379280304Sjkim        else if (dso->meth->dso_merger != NULL)
380280304Sjkim            result = dso->meth->dso_merger(dso, filespec1, filespec2);
381280304Sjkim    }
382280304Sjkim    return (result);
383280304Sjkim}
384160814Ssimon
385109998Smarkmchar *DSO_convert_filename(DSO *dso, const char *filename)
386280304Sjkim{
387280304Sjkim    char *result = NULL;
388109998Smarkm
389280304Sjkim    if (dso == NULL) {
390280304Sjkim        DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
391280304Sjkim        return (NULL);
392280304Sjkim    }
393280304Sjkim    if (filename == NULL)
394280304Sjkim        filename = dso->filename;
395280304Sjkim    if (filename == NULL) {
396280304Sjkim        DSOerr(DSO_F_DSO_CONVERT_FILENAME, DSO_R_NO_FILENAME);
397280304Sjkim        return (NULL);
398280304Sjkim    }
399280304Sjkim    if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
400280304Sjkim        if (dso->name_converter != NULL)
401280304Sjkim            result = dso->name_converter(dso, filename);
402280304Sjkim        else if (dso->meth->dso_name_converter != NULL)
403280304Sjkim            result = dso->meth->dso_name_converter(dso, filename);
404280304Sjkim    }
405280304Sjkim    if (result == NULL) {
406280304Sjkim        result = OPENSSL_malloc(strlen(filename) + 1);
407280304Sjkim        if (result == NULL) {
408280304Sjkim            DSOerr(DSO_F_DSO_CONVERT_FILENAME, ERR_R_MALLOC_FAILURE);
409280304Sjkim            return (NULL);
410280304Sjkim        }
411280304Sjkim        BUF_strlcpy(result, filename, strlen(filename) + 1);
412280304Sjkim    }
413280304Sjkim    return (result);
414280304Sjkim}
415109998Smarkm
416109998Smarkmconst char *DSO_get_loaded_filename(DSO *dso)
417280304Sjkim{
418280304Sjkim    if (dso == NULL) {
419280304Sjkim        DSOerr(DSO_F_DSO_GET_LOADED_FILENAME, ERR_R_PASSED_NULL_PARAMETER);
420280304Sjkim        return (NULL);
421280304Sjkim    }
422280304Sjkim    return (dso->loaded_filename);
423280304Sjkim}
424238405Sjkim
425280304Sjkimint DSO_pathbyaddr(void *addr, char *path, int sz)
426280304Sjkim{
427280304Sjkim    DSO_METHOD *meth = default_DSO_meth;
428280304Sjkim    if (meth == NULL)
429280304Sjkim        meth = DSO_METHOD_openssl();
430280304Sjkim    if (meth->pathbyaddr == NULL) {
431280304Sjkim        DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
432280304Sjkim        return -1;
433280304Sjkim    }
434280304Sjkim    return (*meth->pathbyaddr) (addr, path, sz);
435280304Sjkim}
436238405Sjkim
437238405Sjkimvoid *DSO_global_lookup(const char *name)
438280304Sjkim{
439280304Sjkim    DSO_METHOD *meth = default_DSO_meth;
440280304Sjkim    if (meth == NULL)
441280304Sjkim        meth = DSO_METHOD_openssl();
442280304Sjkim    if (meth->globallookup == NULL) {
443280304Sjkim        DSOerr(DSO_F_DSO_GLOBAL_LOOKUP, DSO_R_UNSUPPORTED);
444280304Sjkim        return NULL;
445280304Sjkim    }
446280304Sjkim    return (*meth->globallookup) (name);
447280304Sjkim}
448