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