1 /* $OpenBSD: eng_ctrl.c,v 1.9 2014/07/10 13:58:22 jsing 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 ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 129 ERR_R_PASSED_NULL_PARAMETER); 130 return -1; 131 } 132 } 133 /* Now handle cmd_name -> cmd_num conversion */ 134 if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) { 135 if ((e->cmd_defns == NULL) || 136 ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) { 137 ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 138 ENGINE_R_INVALID_CMD_NAME); 139 return -1; 140 } 141 return e->cmd_defns[idx].cmd_num; 142 } 143 /* For the rest of the commands, the 'long' argument must specify a 144 * valie command number - so we need to conduct a search. */ 145 if ((e->cmd_defns == NULL) || 146 ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) { 147 ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 148 ENGINE_R_INVALID_CMD_NUMBER); 149 return -1; 150 } 151 /* Now the logic splits depending on command type */ 152 switch (cmd) { 153 case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 154 idx++; 155 if (int_ctrl_cmd_is_null(e->cmd_defns + idx)) 156 /* end-of-list */ 157 return 0; 158 else 159 return e->cmd_defns[idx].cmd_num; 160 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 161 return strlen(e->cmd_defns[idx].cmd_name); 162 case ENGINE_CTRL_GET_NAME_FROM_CMD: 163 ret = snprintf(s, strlen(e->cmd_defns[idx].cmd_name) + 1, 164 "%s", e->cmd_defns[idx].cmd_name); 165 if (ret >= (strlen(e->cmd_defns[idx].cmd_name) + 1)) 166 ret = -1; 167 return ret; 168 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 169 if (e->cmd_defns[idx].cmd_desc) 170 return strlen(e->cmd_defns[idx].cmd_desc); 171 return strlen(int_no_description); 172 case ENGINE_CTRL_GET_DESC_FROM_CMD: 173 if (e->cmd_defns[idx].cmd_desc) { 174 ret = snprintf(s, 175 strlen(e->cmd_defns[idx].cmd_desc) + 1, 176 "%s", e->cmd_defns[idx].cmd_desc); 177 if (ret >= strlen(e->cmd_defns[idx].cmd_desc) + 1) 178 ret = -1; 179 return ret; 180 } 181 ret = snprintf(s, strlen(int_no_description) + 1, "%s", 182 int_no_description); 183 if (ret >= strlen(int_no_description) + 1) 184 ret = -1; 185 return ret; 186 case ENGINE_CTRL_GET_CMD_FLAGS: 187 return e->cmd_defns[idx].cmd_flags; 188 } 189 190 /* Shouldn't really be here ... */ 191 ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INTERNAL_LIST_ERROR); 192 return -1; 193 } 194 195 int 196 ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) 197 { 198 int ctrl_exists, ref_exists; 199 200 if (e == NULL) { 201 ENGINEerr(ENGINE_F_ENGINE_CTRL, ERR_R_PASSED_NULL_PARAMETER); 202 return 0; 203 } 204 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 205 ref_exists = ((e->struct_ref > 0) ? 1 : 0); 206 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 207 ctrl_exists = ((e->ctrl == NULL) ? 0 : 1); 208 if (!ref_exists) { 209 ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_REFERENCE); 210 return 0; 211 } 212 /* Intercept any "root-level" commands before trying to hand them on to 213 * ctrl() handlers. */ 214 switch (cmd) { 215 case ENGINE_CTRL_HAS_CTRL_FUNCTION: 216 return ctrl_exists; 217 case ENGINE_CTRL_GET_FIRST_CMD_TYPE: 218 case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 219 case ENGINE_CTRL_GET_CMD_FROM_NAME: 220 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 221 case ENGINE_CTRL_GET_NAME_FROM_CMD: 222 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 223 case ENGINE_CTRL_GET_DESC_FROM_CMD: 224 case ENGINE_CTRL_GET_CMD_FLAGS: 225 if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL)) 226 return int_ctrl_helper(e, cmd, i, p, f); 227 if (!ctrl_exists) { 228 ENGINEerr(ENGINE_F_ENGINE_CTRL, 229 ENGINE_R_NO_CONTROL_FUNCTION); 230 /* For these cmd-related functions, failure is indicated 231 * by a -1 return value (because 0 is used as a valid 232 * return in some places). */ 233 return -1; 234 } 235 default: 236 break; 237 } 238 /* Anything else requires a ctrl() handler to exist. */ 239 if (!ctrl_exists) { 240 ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION); 241 return 0; 242 } 243 return e->ctrl(e, cmd, i, p, f); 244 } 245 246 int 247 ENGINE_cmd_is_executable(ENGINE *e, int cmd) 248 { 249 int flags; 250 251 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, 252 NULL, NULL)) < 0) { 253 ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE, 254 ENGINE_R_INVALID_CMD_NUMBER); 255 return 0; 256 } 257 if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) && 258 !(flags & ENGINE_CMD_FLAG_NUMERIC) && 259 !(flags & ENGINE_CMD_FLAG_STRING)) 260 return 0; 261 return 1; 262 } 263 264 int 265 ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, long i, void *p, 266 void (*f)(void), int cmd_optional) 267 { 268 int num; 269 270 if ((e == NULL) || (cmd_name == NULL)) { 271 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, 272 ERR_R_PASSED_NULL_PARAMETER); 273 return 0; 274 } 275 if ((e->ctrl == NULL) || 276 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 277 0, (void *)cmd_name, NULL)) <= 0)) { 278 /* If the command didn't *have* to be supported, we fake 279 * success. This allows certain settings to be specified for 280 * multiple ENGINEs and only require a change of ENGINE id 281 * (without having to selectively apply settings). Eg. changing 282 * from a hardware device back to the regular software ENGINE 283 * without editing the config file, etc. */ 284 if (cmd_optional) { 285 ERR_clear_error(); 286 return 1; 287 } 288 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ENGINE_R_INVALID_CMD_NAME); 289 return 0; 290 } 291 292 /* Force the result of the control command to 0 or 1, for the reasons 293 * mentioned before. */ 294 if (ENGINE_ctrl(e, num, i, p, f) > 0) 295 return 1; 296 297 return 0; 298 } 299 300 int 301 ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, 302 int cmd_optional) 303 { 304 int num, flags; 305 long l; 306 char *ptr; 307 308 if ((e == NULL) || (cmd_name == NULL)) { 309 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 310 ERR_R_PASSED_NULL_PARAMETER); 311 return 0; 312 } 313 if ((e->ctrl == NULL) || 314 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME, 0, 315 (void *)cmd_name, NULL)) <= 0)) { 316 /* If the command didn't *have* to be supported, we fake 317 * success. This allows certain settings to be specified for 318 * multiple ENGINEs and only require a change of ENGINE id 319 * (without having to selectively apply settings). Eg. changing 320 * from a hardware device back to the regular software ENGINE 321 * without editing the config file, etc. */ 322 if (cmd_optional) { 323 ERR_clear_error(); 324 return 1; 325 } 326 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 327 ENGINE_R_INVALID_CMD_NAME); 328 return 0; 329 } 330 if (!ENGINE_cmd_is_executable(e, num)) { 331 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 332 ENGINE_R_CMD_NOT_EXECUTABLE); 333 return 0; 334 } 335 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, 336 NULL, NULL)) < 0) { 337 /* Shouldn't happen, given that ENGINE_cmd_is_executable() 338 * returned success. */ 339 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 340 ENGINE_R_INTERNAL_LIST_ERROR); 341 return 0; 342 } 343 /* If the command takes no input, there must be no input. And vice 344 * versa. */ 345 if (flags & ENGINE_CMD_FLAG_NO_INPUT) { 346 if (arg != NULL) { 347 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 348 ENGINE_R_COMMAND_TAKES_NO_INPUT); 349 return 0; 350 } 351 /* We deliberately force the result of ENGINE_ctrl() to 0 or 1 352 * rather than returning it as "return data". This is to ensure 353 * usage of these commands is consistent across applications and 354 * that certain applications don't understand it one way, and 355 * others another. */ 356 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 357 return 1; 358 return 0; 359 } 360 /* So, we require input */ 361 if (arg == NULL) { 362 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 363 ENGINE_R_COMMAND_TAKES_INPUT); 364 return 0; 365 } 366 /* If it takes string input, that's easy */ 367 if (flags & ENGINE_CMD_FLAG_STRING) { 368 /* Same explanation as above */ 369 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 370 return 1; 371 return 0; 372 } 373 /* If it doesn't take numeric either, then it is unsupported for use in 374 * a config-setting situation, which is what this function is for. This 375 * should never happen though, because ENGINE_cmd_is_executable() was 376 * used. */ 377 if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) { 378 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 379 ENGINE_R_INTERNAL_LIST_ERROR); 380 return 0; 381 } 382 l = strtol(arg, &ptr, 10); 383 if ((arg == ptr) || (*ptr != '\0')) { 384 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 385 ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER); 386 return 0; 387 } 388 /* Force the result of the control command to 0 or 1, for the reasons 389 * mentioned before. */ 390 if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0) 391 return 1; 392 return 0; 393 } 394