]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/dso/dso_dl.c
Add a CHANGES entry for the unrecognised record type change
[thirdparty/openssl.git] / crypto / dso / dso_dl.c
CommitLineData
0f113f3e 1/*
d2e9e320 2 * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
8f4fac7f 3 *
d2e9e320
RS
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8f4fac7f
GT
8 */
9
73decf59 10#include "dso_locl.h"
8f4fac7f 11
38186bfd 12#ifdef DSO_DL
8f4fac7f 13
0f113f3e 14# include <dl.h>
8f4fac7f 15
b9e63915 16/* Part of the hack in "dl_load" ... */
0f113f3e 17# define DSO_MAX_TRANSLATED_SIZE 256
b9e63915 18
51c8dc37 19static int dl_load(DSO *dso);
8f4fac7f 20static int dl_unload(DSO *dso);
e9a68cfb 21static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname);
51c8dc37 22static char *dl_name_converter(DSO *dso, const char *filename);
0f113f3e
MC
23static char *dl_merger(DSO *dso, const char *filespec1,
24 const char *filespec2);
c6cb42e4 25static void *dl_globallookup(const char *name);
8f4fac7f
GT
26
27static DSO_METHOD dso_meth_dl = {
0f113f3e
MC
28 "OpenSSL 'dl' shared library method",
29 dl_load,
30 dl_unload,
0f113f3e 31 dl_bind_func,
0f113f3e
MC
32 NULL, /* ctrl */
33 dl_name_converter,
34 dl_merger,
35 NULL, /* init */
36 NULL, /* finish */
0f113f3e
MC
37 dl_globallookup
38};
8f4fac7f 39
38186bfd 40DSO_METHOD *DSO_METHOD_openssl(void)
0f113f3e 41{
38186bfd 42 return &dso_meth_dl;
0f113f3e 43}
8f4fac7f 44
0f113f3e
MC
45/*
46 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
47 * (shl_t) returned from shl_load(). NB: I checked on HPUX11 and shl_t is
48 * itself a pointer type so the cast is safe.
8f4fac7f
GT
49 */
50
51c8dc37 51static int dl_load(DSO *dso)
0f113f3e
MC
52{
53 shl_t ptr = NULL;
54 /*
55 * We don't do any fancy retries or anything, just take the method's (or
56 * DSO's if it has the callback set) best translation of the
57 * platform-independent filename and try once with that.
58 */
59 char *filename = DSO_convert_filename(dso, NULL);
8f4fac7f 60
0f113f3e
MC
61 if (filename == NULL) {
62 DSOerr(DSO_F_DL_LOAD, DSO_R_NO_FILENAME);
63 goto err;
64 }
65 ptr = shl_load(filename, BIND_IMMEDIATE |
66 (dso->flags & DSO_FLAG_NO_NAME_TRANSLATION ? 0 :
67 DYNAMIC_PATH), 0L);
68 if (ptr == NULL) {
7d37818d 69 char errbuf[160];
0f113f3e 70 DSOerr(DSO_F_DL_LOAD, DSO_R_LOAD_FAILED);
7d37818d
MC
71 if (openssl_strerror_r(errno, errbuf, sizeof(errbuf)))
72 ERR_add_error_data(4, "filename(", filename, "): ", errbuf);
0f113f3e
MC
73 goto err;
74 }
75 if (!sk_push(dso->meth_data, (char *)ptr)) {
76 DSOerr(DSO_F_DL_LOAD, DSO_R_STACK_ERROR);
77 goto err;
78 }
79 /*
80 * Success, stick the converted filename we've loaded under into the DSO
81 * (it also serves as the indicator that we are currently loaded).
82 */
83 dso->loaded_filename = filename;
84 return (1);
85 err:
86 /* Cleanup! */
b548a1f1 87 OPENSSL_free(filename);
0f113f3e
MC
88 if (ptr != NULL)
89 shl_unload(ptr);
90 return (0);
91}
8f4fac7f
GT
92
93static int dl_unload(DSO *dso)
0f113f3e
MC
94{
95 shl_t ptr;
96 if (dso == NULL) {
97 DSOerr(DSO_F_DL_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
98 return (0);
99 }
100 if (sk_num(dso->meth_data) < 1)
101 return (1);
102 /* Is this statement legal? */
103 ptr = (shl_t) sk_pop(dso->meth_data);
104 if (ptr == NULL) {
105 DSOerr(DSO_F_DL_UNLOAD, DSO_R_NULL_HANDLE);
106 /*
107 * Should push the value back onto the stack in case of a retry.
108 */
109 sk_push(dso->meth_data, (char *)ptr);
110 return (0);
111 }
112 shl_unload(ptr);
113 return (1);
114}
8f4fac7f 115
e9a68cfb 116static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname)
0f113f3e
MC
117{
118 shl_t ptr;
119 void *sym;
e9a68cfb 120
0f113f3e
MC
121 if ((dso == NULL) || (symname == NULL)) {
122 DSOerr(DSO_F_DL_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
123 return (NULL);
124 }
125 if (sk_num(dso->meth_data) < 1) {
126 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_STACK_ERROR);
127 return (NULL);
128 }
129 ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
130 if (ptr == NULL) {
131 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_NULL_HANDLE);
132 return (NULL);
133 }
134 if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) {
7d37818d 135 char errbuf[160];
0f113f3e 136 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_SYM_FAILURE);
7d37818d
MC
137 if (openssl_strerror_r(errno, errbuf, sizeof(errbuf)))
138 ERR_add_error_data(4, "symname(", symname, "): ", errbuf);
0f113f3e
MC
139 return (NULL);
140 }
141 return ((DSO_FUNC_TYPE)sym);
142}
8f4fac7f 143
cbecb3ac 144static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2)
0f113f3e
MC
145{
146 char *merged;
cbecb3ac 147
0f113f3e
MC
148 if (!filespec1 && !filespec2) {
149 DSOerr(DSO_F_DL_MERGER, ERR_R_PASSED_NULL_PARAMETER);
150 return (NULL);
151 }
152 /*
153 * If the first file specification is a rooted path, it rules. same goes
154 * if the second file specification is missing.
155 */
156 if (!filespec2 || filespec1[0] == '/') {
a89c9a0d 157 merged = OPENSSL_strdup(filespec1);
90945fa3 158 if (merged == NULL) {
0f113f3e
MC
159 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
160 return (NULL);
161 }
0f113f3e
MC
162 }
163 /*
164 * If the first file specification is missing, the second one rules.
165 */
166 else if (!filespec1) {
a89c9a0d 167 merged = OPENSSL_strdup(filespec2);
90945fa3 168 if (merged == NULL) {
0f113f3e
MC
169 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
170 return (NULL);
171 }
0f113f3e
MC
172 } else
173 /*
174 * This part isn't as trivial as it looks. It assumes that the
175 * second file specification really is a directory, and makes no
176 * checks whatsoever. Therefore, the result becomes the
177 * concatenation of filespec2 followed by a slash followed by
178 * filespec1.
179 */
180 {
181 int spec2len, len;
cbecb3ac 182
0f113f3e
MC
183 spec2len = (filespec2 ? strlen(filespec2) : 0);
184 len = spec2len + (filespec1 ? strlen(filespec1) : 0);
cbecb3ac 185
947f9da1 186 if (spec2len && filespec2[spec2len - 1] == '/') {
0f113f3e
MC
187 spec2len--;
188 len--;
189 }
190 merged = OPENSSL_malloc(len + 2);
90945fa3 191 if (merged == NULL) {
0f113f3e
MC
192 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE);
193 return (NULL);
194 }
195 strcpy(merged, filespec2);
196 merged[spec2len] = '/';
197 strcpy(&merged[spec2len + 1], filespec1);
198 }
199 return (merged);
200}
cbecb3ac 201
0f113f3e
MC
202/*
203 * This function is identical to the one in dso_dlfcn.c, but as it is highly
204 * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at
205 * the same time, there's no great duplicating the code. Figuring out an
206 * elegant way to share one copy of the code would be more difficult and
207 * would not leave the implementations independent.
208 */
51c8dc37 209static char *dl_name_converter(DSO *dso, const char *filename)
0f113f3e
MC
210{
211 char *translated;
212 int len, rsize, transform;
51c8dc37 213
0f113f3e
MC
214 len = strlen(filename);
215 rsize = len + 1;
216 transform = (strstr(filename, "/") == NULL);
217 {
218 /* We will convert this to "%s.s?" or "lib%s.s?" */
e987f9f2 219 rsize += strlen(DSO_EXTENSION); /* The length of ".s?" */
0f113f3e
MC
220 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
221 rsize += 3; /* The length of "lib" */
222 }
223 translated = OPENSSL_malloc(rsize);
224 if (translated == NULL) {
225 DSOerr(DSO_F_DL_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
226 return (NULL);
227 }
228 if (transform) {
229 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
e987f9f2 230 sprintf(translated, "lib%s%s", filename, DSO_EXTENSION);
0f113f3e 231 else
e987f9f2 232 sprintf(translated, "%s%s", filename, DSO_EXTENSION);
0f113f3e
MC
233 } else
234 sprintf(translated, "%s", filename);
235 return (translated);
236}
51c8dc37 237
c6cb42e4 238static void *dl_globallookup(const char *name)
0f113f3e
MC
239{
240 void *ret;
241 shl_t h = NULL;
68b64fb6 242
0f113f3e
MC
243 return shl_findsym(&h, name, TYPE_UNDEFINED, &ret) ? NULL : ret;
244}
245#endif /* DSO_DL */