1109998Smarkm/* crypto/engine/eng_ctrl.c */ 2109998Smarkm/* ==================================================================== 3109998Smarkm * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 4109998Smarkm * 5109998Smarkm * Redistribution and use in source and binary forms, with or without 6109998Smarkm * modification, are permitted provided that the following conditions 7109998Smarkm * are met: 8109998Smarkm * 9109998Smarkm * 1. Redistributions of source code must retain the above copyright 10280297Sjkim * notice, this list of conditions and the following disclaimer. 11109998Smarkm * 12109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 13109998Smarkm * notice, this list of conditions and the following disclaimer in 14109998Smarkm * the documentation and/or other materials provided with the 15109998Smarkm * distribution. 16109998Smarkm * 17109998Smarkm * 3. All advertising materials mentioning features or use of this 18109998Smarkm * software must display the following acknowledgment: 19109998Smarkm * "This product includes software developed by the OpenSSL Project 20109998Smarkm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 21109998Smarkm * 22109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23109998Smarkm * endorse or promote products derived from this software without 24109998Smarkm * prior written permission. For written permission, please contact 25109998Smarkm * licensing@OpenSSL.org. 26109998Smarkm * 27109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 28109998Smarkm * nor may "OpenSSL" appear in their names without prior written 29109998Smarkm * permission of the OpenSSL Project. 30109998Smarkm * 31109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 32109998Smarkm * acknowledgment: 33109998Smarkm * "This product includes software developed by the OpenSSL Project 34109998Smarkm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 35109998Smarkm * 36109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 48109998Smarkm * ==================================================================== 49109998Smarkm * 50109998Smarkm * This product includes cryptographic software written by Eric Young 51109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 52109998Smarkm * Hudson (tjh@cryptsoft.com). 53109998Smarkm * 54109998Smarkm */ 55109998Smarkm 56109998Smarkm#include "eng_int.h" 57109998Smarkm 58280297Sjkim/* 59280297Sjkim * When querying a ENGINE-specific control command's 'description', this 60280297Sjkim * string is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. 61280297Sjkim */ 62109998Smarkmstatic const char *int_no_description = ""; 63109998Smarkm 64280297Sjkim/* 65280297Sjkim * These internal functions handle 'CMD'-related control commands when the 66109998Smarkm * ENGINE in question has asked us to take care of it (ie. the ENGINE did not 67280297Sjkim * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. 68280297Sjkim */ 69109998Smarkm 70109998Smarkmstatic int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn) 71280297Sjkim{ 72280297Sjkim if ((defn->cmd_num == 0) || (defn->cmd_name == NULL)) 73280297Sjkim return 1; 74280297Sjkim return 0; 75280297Sjkim} 76109998Smarkm 77109998Smarkmstatic int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s) 78280297Sjkim{ 79280297Sjkim int idx = 0; 80280297Sjkim while (!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) { 81280297Sjkim idx++; 82280297Sjkim defn++; 83280297Sjkim } 84280297Sjkim if (int_ctrl_cmd_is_null(defn)) 85280297Sjkim /* The given name wasn't found */ 86280297Sjkim return -1; 87280297Sjkim return idx; 88280297Sjkim} 89109998Smarkm 90109998Smarkmstatic int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num) 91280297Sjkim{ 92280297Sjkim int idx = 0; 93280297Sjkim /* 94280297Sjkim * NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So 95280297Sjkim * our searches don't need to take any longer than necessary. 96280297Sjkim */ 97280297Sjkim while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) { 98280297Sjkim idx++; 99280297Sjkim defn++; 100280297Sjkim } 101280297Sjkim if (defn->cmd_num == num) 102280297Sjkim return idx; 103280297Sjkim /* The given cmd_num wasn't found */ 104280297Sjkim return -1; 105280297Sjkim} 106109998Smarkm 107160814Ssimonstatic int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, 108280297Sjkim void (*f) (void)) 109280297Sjkim{ 110280297Sjkim int idx; 111280297Sjkim char *s = (char *)p; 112280297Sjkim /* Take care of the easy one first (eg. it requires no searches) */ 113280297Sjkim if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) { 114280297Sjkim if ((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns)) 115280297Sjkim return 0; 116280297Sjkim return e->cmd_defns->cmd_num; 117280297Sjkim } 118280297Sjkim /* One or two commands require that "p" be a valid string buffer */ 119280297Sjkim if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) || 120280297Sjkim (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) || 121280297Sjkim (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) { 122280297Sjkim if (s == NULL) { 123280297Sjkim ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ERR_R_PASSED_NULL_PARAMETER); 124280297Sjkim return -1; 125280297Sjkim } 126280297Sjkim } 127280297Sjkim /* Now handle cmd_name -> cmd_num conversion */ 128280297Sjkim if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) { 129280297Sjkim if ((e->cmd_defns == NULL) 130280297Sjkim || ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) { 131280297Sjkim ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NAME); 132280297Sjkim return -1; 133280297Sjkim } 134280297Sjkim return e->cmd_defns[idx].cmd_num; 135280297Sjkim } 136280297Sjkim /* 137280297Sjkim * For the rest of the commands, the 'long' argument must specify a valie 138280297Sjkim * command number - so we need to conduct a search. 139280297Sjkim */ 140280297Sjkim if ((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns, 141280297Sjkim (unsigned int) 142280297Sjkim i)) < 0)) { 143280297Sjkim ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INVALID_CMD_NUMBER); 144280297Sjkim return -1; 145280297Sjkim } 146280297Sjkim /* Now the logic splits depending on command type */ 147280297Sjkim switch (cmd) { 148280297Sjkim case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 149280297Sjkim idx++; 150280297Sjkim if (int_ctrl_cmd_is_null(e->cmd_defns + idx)) 151280297Sjkim /* end-of-list */ 152280297Sjkim return 0; 153280297Sjkim else 154280297Sjkim return e->cmd_defns[idx].cmd_num; 155280297Sjkim case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 156280297Sjkim return strlen(e->cmd_defns[idx].cmd_name); 157280297Sjkim case ENGINE_CTRL_GET_NAME_FROM_CMD: 158280297Sjkim return BIO_snprintf(s, strlen(e->cmd_defns[idx].cmd_name) + 1, 159280297Sjkim "%s", e->cmd_defns[idx].cmd_name); 160280297Sjkim case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 161280297Sjkim if (e->cmd_defns[idx].cmd_desc) 162280297Sjkim return strlen(e->cmd_defns[idx].cmd_desc); 163280297Sjkim return strlen(int_no_description); 164280297Sjkim case ENGINE_CTRL_GET_DESC_FROM_CMD: 165280297Sjkim if (e->cmd_defns[idx].cmd_desc) 166280297Sjkim return BIO_snprintf(s, 167280297Sjkim strlen(e->cmd_defns[idx].cmd_desc) + 1, 168280297Sjkim "%s", e->cmd_defns[idx].cmd_desc); 169280297Sjkim return BIO_snprintf(s, strlen(int_no_description) + 1, "%s", 170280297Sjkim int_no_description); 171280297Sjkim case ENGINE_CTRL_GET_CMD_FLAGS: 172280297Sjkim return e->cmd_defns[idx].cmd_flags; 173280297Sjkim } 174280297Sjkim /* Shouldn't really be here ... */ 175280297Sjkim ENGINEerr(ENGINE_F_INT_CTRL_HELPER, ENGINE_R_INTERNAL_LIST_ERROR); 176280297Sjkim return -1; 177280297Sjkim} 178109998Smarkm 179280297Sjkimint ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 180280297Sjkim{ 181280297Sjkim int ctrl_exists, ref_exists; 182280297Sjkim if (e == NULL) { 183280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL, ERR_R_PASSED_NULL_PARAMETER); 184280297Sjkim return 0; 185280297Sjkim } 186280297Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 187280297Sjkim ref_exists = ((e->struct_ref > 0) ? 1 : 0); 188280297Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 189280297Sjkim ctrl_exists = ((e->ctrl == NULL) ? 0 : 1); 190280297Sjkim if (!ref_exists) { 191280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_REFERENCE); 192280297Sjkim return 0; 193280297Sjkim } 194280297Sjkim /* 195280297Sjkim * Intercept any "root-level" commands before trying to hand them on to 196280297Sjkim * ctrl() handlers. 197280297Sjkim */ 198280297Sjkim switch (cmd) { 199280297Sjkim case ENGINE_CTRL_HAS_CTRL_FUNCTION: 200280297Sjkim return ctrl_exists; 201280297Sjkim case ENGINE_CTRL_GET_FIRST_CMD_TYPE: 202280297Sjkim case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 203280297Sjkim case ENGINE_CTRL_GET_CMD_FROM_NAME: 204280297Sjkim case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 205280297Sjkim case ENGINE_CTRL_GET_NAME_FROM_CMD: 206280297Sjkim case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 207280297Sjkim case ENGINE_CTRL_GET_DESC_FROM_CMD: 208280297Sjkim case ENGINE_CTRL_GET_CMD_FLAGS: 209280297Sjkim if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL)) 210280297Sjkim return int_ctrl_helper(e, cmd, i, p, f); 211280297Sjkim if (!ctrl_exists) { 212280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION); 213280297Sjkim /* 214280297Sjkim * For these cmd-related functions, failure is indicated by a -1 215280297Sjkim * return value (because 0 is used as a valid return in some 216280297Sjkim * places). 217280297Sjkim */ 218280297Sjkim return -1; 219280297Sjkim } 220280297Sjkim default: 221280297Sjkim break; 222280297Sjkim } 223280297Sjkim /* Anything else requires a ctrl() handler to exist. */ 224280297Sjkim if (!ctrl_exists) { 225280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_NO_CONTROL_FUNCTION); 226280297Sjkim return 0; 227280297Sjkim } 228280297Sjkim return e->ctrl(e, cmd, i, p, f); 229280297Sjkim} 230109998Smarkm 231109998Smarkmint ENGINE_cmd_is_executable(ENGINE *e, int cmd) 232280297Sjkim{ 233280297Sjkim int flags; 234280297Sjkim if ((flags = 235280297Sjkim ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) { 236280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE, 237280297Sjkim ENGINE_R_INVALID_CMD_NUMBER); 238280297Sjkim return 0; 239280297Sjkim } 240280297Sjkim if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) && 241280297Sjkim !(flags & ENGINE_CMD_FLAG_NUMERIC) && 242280297Sjkim !(flags & ENGINE_CMD_FLAG_STRING)) 243280297Sjkim return 0; 244280297Sjkim return 1; 245280297Sjkim} 246109998Smarkm 247109998Smarkmint ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, 248280297Sjkim long i, void *p, void (*f) (void), int cmd_optional) 249280297Sjkim{ 250280297Sjkim int num; 251109998Smarkm 252280297Sjkim if ((e == NULL) || (cmd_name == NULL)) { 253280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ERR_R_PASSED_NULL_PARAMETER); 254109998Smarkm return 0; 255280297Sjkim } 256280297Sjkim if ((e->ctrl == NULL) || ((num = ENGINE_ctrl(e, 257280297Sjkim ENGINE_CTRL_GET_CMD_FROM_NAME, 258280297Sjkim 0, (void *)cmd_name, 259280297Sjkim NULL)) <= 0)) { 260280297Sjkim /* 261280297Sjkim * If the command didn't *have* to be supported, we fake success. 262280297Sjkim * This allows certain settings to be specified for multiple ENGINEs 263280297Sjkim * and only require a change of ENGINE id (without having to 264280297Sjkim * selectively apply settings). Eg. changing from a hardware device 265280297Sjkim * back to the regular software ENGINE without editing the config 266280297Sjkim * file, etc. 267280297Sjkim */ 268280297Sjkim if (cmd_optional) { 269280297Sjkim ERR_clear_error(); 270280297Sjkim return 1; 271109998Smarkm } 272280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, ENGINE_R_INVALID_CMD_NAME); 273280297Sjkim return 0; 274280297Sjkim } 275280297Sjkim /* 276280297Sjkim * Force the result of the control command to 0 or 1, for the reasons 277280297Sjkim * mentioned before. 278280297Sjkim */ 279280297Sjkim if (ENGINE_ctrl(e, num, i, p, f) > 0) 280280297Sjkim return 1; 281280297Sjkim return 0; 282280297Sjkim} 283109998Smarkm 284109998Smarkmint ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, 285280297Sjkim int cmd_optional) 286280297Sjkim{ 287280297Sjkim int num, flags; 288280297Sjkim long l; 289280297Sjkim char *ptr; 290280297Sjkim if ((e == NULL) || (cmd_name == NULL)) { 291280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 292280297Sjkim ERR_R_PASSED_NULL_PARAMETER); 293280297Sjkim return 0; 294280297Sjkim } 295280297Sjkim if ((e->ctrl == NULL) || ((num = ENGINE_ctrl(e, 296280297Sjkim ENGINE_CTRL_GET_CMD_FROM_NAME, 297280297Sjkim 0, (void *)cmd_name, 298280297Sjkim NULL)) <= 0)) { 299280297Sjkim /* 300280297Sjkim * If the command didn't *have* to be supported, we fake success. 301280297Sjkim * This allows certain settings to be specified for multiple ENGINEs 302280297Sjkim * and only require a change of ENGINE id (without having to 303280297Sjkim * selectively apply settings). Eg. changing from a hardware device 304280297Sjkim * back to the regular software ENGINE without editing the config 305280297Sjkim * file, etc. 306280297Sjkim */ 307280297Sjkim if (cmd_optional) { 308280297Sjkim ERR_clear_error(); 309280297Sjkim return 1; 310280297Sjkim } 311280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, ENGINE_R_INVALID_CMD_NAME); 312280297Sjkim return 0; 313280297Sjkim } 314280297Sjkim if (!ENGINE_cmd_is_executable(e, num)) { 315280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 316280297Sjkim ENGINE_R_CMD_NOT_EXECUTABLE); 317280297Sjkim return 0; 318280297Sjkim } 319280297Sjkim if ((flags = 320280297Sjkim ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0) { 321280297Sjkim /* 322280297Sjkim * Shouldn't happen, given that ENGINE_cmd_is_executable() returned 323280297Sjkim * success. 324280297Sjkim */ 325280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 326280297Sjkim ENGINE_R_INTERNAL_LIST_ERROR); 327280297Sjkim return 0; 328280297Sjkim } 329280297Sjkim /* 330280297Sjkim * If the command takes no input, there must be no input. And vice versa. 331280297Sjkim */ 332280297Sjkim if (flags & ENGINE_CMD_FLAG_NO_INPUT) { 333280297Sjkim if (arg != NULL) { 334280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 335280297Sjkim ENGINE_R_COMMAND_TAKES_NO_INPUT); 336280297Sjkim return 0; 337280297Sjkim } 338280297Sjkim /* 339280297Sjkim * We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather 340280297Sjkim * than returning it as "return data". This is to ensure usage of 341280297Sjkim * these commands is consistent across applications and that certain 342280297Sjkim * applications don't understand it one way, and others another. 343280297Sjkim */ 344280297Sjkim if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 345280297Sjkim return 1; 346280297Sjkim return 0; 347280297Sjkim } 348280297Sjkim /* So, we require input */ 349280297Sjkim if (arg == NULL) { 350280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 351280297Sjkim ENGINE_R_COMMAND_TAKES_INPUT); 352280297Sjkim return 0; 353280297Sjkim } 354280297Sjkim /* If it takes string input, that's easy */ 355280297Sjkim if (flags & ENGINE_CMD_FLAG_STRING) { 356280297Sjkim /* Same explanation as above */ 357280297Sjkim if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0) 358280297Sjkim return 1; 359280297Sjkim return 0; 360280297Sjkim } 361280297Sjkim /* 362280297Sjkim * If it doesn't take numeric either, then it is unsupported for use in a 363280297Sjkim * config-setting situation, which is what this function is for. This 364280297Sjkim * should never happen though, because ENGINE_cmd_is_executable() was 365280297Sjkim * used. 366280297Sjkim */ 367280297Sjkim if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) { 368280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 369280297Sjkim ENGINE_R_INTERNAL_LIST_ERROR); 370280297Sjkim return 0; 371280297Sjkim } 372280297Sjkim l = strtol(arg, &ptr, 10); 373280297Sjkim if ((arg == ptr) || (*ptr != '\0')) { 374280297Sjkim ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 375280297Sjkim ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER); 376280297Sjkim return 0; 377280297Sjkim } 378280297Sjkim /* 379280297Sjkim * Force the result of the control command to 0 or 1, for the reasons 380280297Sjkim * mentioned before. 381280297Sjkim */ 382280297Sjkim if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0) 383280297Sjkim return 1; 384280297Sjkim return 0; 385280297Sjkim} 386