1 /* $OpenBSD: eng_ctrl.c,v 1.11 2017/01/29 17:49:23 beck Exp $ */ 2 /* ==================================================================== 3 * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this 18 * software must display the following acknowledgment: 19 * "This product includes software developed by the OpenSSL Project 20 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 21 * 22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For written permission, please contact 25 * licensing@OpenSSL.org. 26 * 27 * 5. Products derived from this software may not be called "OpenSSL" 28 * nor may "OpenSSL" appear in their names without prior written 29 * permission of the OpenSSL Project. 30 * 31 * 6. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This product includes cryptographic software written by Eric Young 51 * (eay@cryptsoft.com). This product includes software written by Tim 52 * Hudson (tjh@cryptsoft.com). 53 * 54 */ 55 56 #include <string.h> 57 58 #include <openssl/err.h> 59 60 #include "eng_int.h" 61 62 /* When querying a ENGINE-specific control command's 'description', this string 63 * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */ 64 static const char *int_no_description = ""; 65 66 /* These internal functions handle 'CMD'-related control commands when the 67 * ENGINE in question has asked us to take care of it (ie. the ENGINE did not 68 * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */ 69 70 static int 71 int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn) 72 { 73 if ((defn->cmd_num == 0) || (defn->cmd_name == NULL)) 74 return 1; 75 return 0; 76 } 77 78 static int 79 int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s) 80 { 81 int idx = 0; 82 while (!int_ctrl_cmd_is_null(defn) && 83 (strcmp(defn->cmd_name, s) != 0)) { 84 idx++; 85 defn++; 86 } 87 if (int_ctrl_cmd_is_null(defn)) 88 /* The given name wasn't found */ 89 return -1; 90 return idx; 91 } 92 93 static int 94 int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num) 95 { 96 int idx = 0; 97 /* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So 98 * our searches don't need to take any longer than necessary. */ 99 while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) { 100 idx++; 101 defn++; 102 } 103 if (defn->cmd_num == num) 104 return idx; 105 /* The given cmd_num wasn't found */ 106 return -1; 107 } 108 109 static int 110 int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) 111 { 112 int idx; 113 int ret; 114 char *s = (char *)p; 115 116 /* Take care of the easy one first (eg. it requires no searches) */ 117 if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) { 118 if ((e->cmd_defns == NULL) || 119 int_ctrl_cmd_is_null(e->cmd_defns)) 120 return 0; 121 return e->cmd_defns->cmd_num; 122 } 123 /* One or two commands require that "p" be a valid string buffer */ 124 if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) || 125 (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) || 126 (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) { 127 if (s == NULL) { 128 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 129 return -1; 130 } 131 } 132 /* Now handle cmd_name -> cmd_num conversion */ 133 if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) { 134 if ((e->cmd_defns == NULL) || 135 ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) { 136 ENGINEerror(ENGINE_R_INVALID_CMD_NAME); 137 return -1; 138 } 139 return e->cmd_defns[idx].cmd_num; 140 } 141 /* For the rest of the commands, the 'long' argument must specify a 142 * valie command number - so we need to conduct a search. */ 143 if ((e->cmd_defns == NULL) || 144 ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) { 145 ENGINEerror(ENGINE_R_INVALID_CMD_NUMBER); 146 return -1; 147 } 148 /* Now the logic splits depending on command type */ 149 switch (cmd) { 150 case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 151 idx++; 152 if (int_ctrl_cmd_is_null(e->cmd_defns + idx)) 153 /* end-of-list */ 154 return 0; 155 else 156 return e->cmd_defns[idx].cmd_num; 157 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 158 return strlen(e->cmd_defns[idx].cmd_name); 159 case ENGINE_CTRL_GET_NAME_FROM_CMD: 160 ret = snprintf(s, strlen(e->cmd_defns[idx].cmd_name) + 1, 161 "%s", e->cmd_defns[idx].cmd_name); 162 if (ret >= (strlen(e->cmd_defns[idx].cmd_name) + 1)) 163 ret = -1; 164 return ret; 165 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 166 if (e->cmd_defns[idx].cmd_desc) 167 return strlen(e->cmd_defns[idx].cmd_desc); 168 return strlen(int_no_description); 169 case ENGINE_CTRL_GET_DESC_FROM_CMD: 170 if (e->cmd_defns[idx].cmd_desc) { 171 ret = snprintf(s, 172 strlen(e->cmd_defns[idx].cmd_desc) + 1, 173 "%s", e->cmd_defns[idx].cmd_desc); 174 if (ret >= strlen(e->cmd_defns[idx].cmd_desc) + 1) 175 ret = -1; 176 return ret; 177 } 178 ret = snprintf(s, strlen(int_no_description) + 1, "%s", 179 int_no_description); 180 if (ret >= strlen(int_no_description) + 1) 181 ret = -1; 182 return ret; 183 case ENGINE_CTRL_GET_CMD_FLAGS: 184 return e->cmd_defns[idx].cmd_flags; 185 } 186 187 /* Shouldn't really be here ... */ 188 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 189 return -1; 190 } 191 192 int 193 ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) 194 { 195 int ctrl_exists, ref_exists; 196 197 if (e == NULL) { 198 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 199 return 0; 200 } 201 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 202 ref_exists = ((e->struct_ref > 0) ? 1 : 0); 203 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 204 ctrl_exists = ((e->ctrl == NULL) ? 0 : 1); 205 if (!ref_exists) { 206 ENGINEerror(ENGINE_R_NO_REFERENCE); 207 return 0; 208 } 209 /* Intercept any "root-level" commands before trying to hand them on to 210 * ctrl() handlers. */ 211 switch (cmd) { 212 case ENGINE_CTRL_HAS_CTRL_FUNCTION: 213 return ctrl_exists; 214 case ENGINE_CTRL_GET_FIRST_CMD_TYPE: 215 case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 216 case ENGINE_CTRL_GET_CMD_FROM_NAME: 217 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 218 case ENGINE_CTRL_GET_NAME_FROM_CMD: 219 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 220 case ENGINE_CTRL_GET_DESC_FROM_CMD: 221 case ENGINE_CTRL_GET_CMD_FLAGS: 222 if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL)) 223 return int_ctrl_helper(e, cmd, i, p, f); 224 if (!ctrl_exists) { 225 ENGINEerror(ENGINE_R_NO_CONTROL_FUNCTION); 226 /* For these cmd-related functions, failure is indicated 227 * by a -1 return value (because 0 is used as a valid 228 * return in some places). */ 229 return -1; 230 } 231 default: 232 break; 233 } 234 /* Anything else requires a ctrl() handler to exist. */ 235 if (!ctrl_exists) { 236 ENGINEerror(ENGINE_R_NO_CONTROL_FUNCTION); 237 return 0; 238 } 239 return e->ctrl(e, cmd, i, p, f); 240 } 241 242 int 243 ENGINE_cmd_is_executable(ENGINE *e, int cmd) 244 { 245 int flags; 246 247 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, 248 NULL, NULL)) < 0) { 249 ENGINEerror(ENGINE_R_INVALID_CMD_NUMBER); 250 return 0; 251 } 252 if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) && 253 !(flags & ENGINE_CMD_FLAG_NUMERIC) && 254 !(flags & ENGINE_CMD_FLAG_STRING)) 255 return 0; 256 return 1; 257 } 258 259 int 260 ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, long i, void *p, 261 void (*f)(void), int cmd_optional) 262 { 263 int num; 264 265 if ((e == NULL) || (cmd_name == NULL)) { 266 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 267 return 0; 268 } 269 if ((e->ctrl == NULL) || 270 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 271 0, (void *)cmd_name, NULL)) <= 0)) { 272 /* If the command didn't *have* to be supported, we fake 273 * success. This allows certain settings to be specified for 274 * multiple ENGINEs and only require a change of ENGINE id 275 * (without having to selectively apply settings). Eg. changing 276 * from a hardware device back to the regular software ENGINE 277 * without editing the config file, etc. */ 278 if (cmd_optional) { 279 ERR_clear_error(); 280 return 1; 281 } 282 ENGINEerror(ENGINE_R_INVALID_CMD_NAME); 283 return 0; 284 } 285 286 /* Force the result of the control command to 0 or 1, for the reasons 287 * mentioned before. */ 288 if (ENGINE_ctrl(e, num, i, p, f) > 0) 289 return 1; 290 291 return 0; 292 } 293 294 int 295 ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, 296 int cmd_optional) 297 { 298 int num, flags; 299 long l; 300 char *ptr; 301 302 if ((e == NULL) || (cmd_name == NULL)) { 303 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 304 return 0; 305 } 306 if ((e->ctrl == NULL) || 307 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, 308 (void *)cmd_name, NULL)) <= 0)) { 309 /* If the command didn't *have* to be supported, we fake 310 * success. This allows certain settings to be specified for 311 * multiple ENGINEs and only require a change of ENGINE id 312 * (without having to selectively apply settings). Eg. changing 313 * from a hardware device back to the regular software ENGINE 314 * without editing the config file, etc. */ 315 if (cmd_optional) { 316 ERR_clear_error(); 317 return 1; 318 } 319 ENGINEerror(ENGINE_R_INVALID_CMD_NAME); 320 return 0; 321 } 322 if (!ENGINE_cmd_is_executable(e, num)) { 323 ENGINEerror(ENGINE_R_CMD_NOT_EXECUTABLE); 324 return 0; 325 } 326 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, 327 NULL, NULL)) < 0) { 328 /* Shouldn't happen, given that ENGINE_cmd_is_executable() 329 * returned success. */ 330 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 331 return 0; 332 } 333 /* If the command takes no input, there must be no input. And vice 334 * versa. */ 335 if (flags & ENGINE_CMD_FLAG_NO_INPUT) { 336 if (arg != NULL) { 337 ENGINEerror(ENGINE_R_COMMAND_TAKES_NO_INPUT); 338 return 0; 339 } 340 /* We deliberately force the result of ENGINE_ctrl() to 0 or 1 341 * rather than returning it as "return data". This is to ensure 342 * usage of these commands is consistent across applications and 343 * that certain applications don't understand it one way, and 344 * others another. */ 345 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 346 return 1; 347 return 0; 348 } 349 /* So, we require input */ 350 if (arg == NULL) { 351 ENGINEerror(ENGINE_R_COMMAND_TAKES_INPUT); 352 return 0; 353 } 354 /* If it takes string input, that's easy */ 355 if (flags & ENGINE_CMD_FLAG_STRING) { 356 /* Same explanation as above */ 357 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 358 return 1; 359 return 0; 360 } 361 /* If it doesn't take numeric either, then it is unsupported for use in 362 * a config-setting situation, which is what this function is for. This 363 * should never happen though, because ENGINE_cmd_is_executable() was 364 * used. */ 365 if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) { 366 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 367 return 0; 368 } 369 l = strtol(arg, &ptr, 10); 370 if ((arg == ptr) || (*ptr != '\0')) { 371 ENGINEerror(ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER); 372 return 0; 373 } 374 /* Force the result of the control command to 0 or 1, for the reasons 375 * mentioned before. */ 376 if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0) 377 return 1; 378 return 0; 379 } 380