1 /* crypto/engine/eng_ctrl.c */
   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 "eng_int.h"
  57 
  58 /* When querying a ENGINE-specific control command's 'description', this string
  59  * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */
  60 static const char *int_no_description = "";
  61 
  62 /* These internal functions handle 'CMD'-related control commands when the
  63  * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
  64  * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */
  65 
  66 static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
  67         {
  68         if((defn->cmd_num == 0) || (defn->cmd_name == NULL))
  69                 return 1;
  70         return 0;
  71         }
  72 
  73 static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
  74         {
  75         int idx = 0;
  76         while(!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0))
  77                 {
  78                 idx++;
  79                 defn++;
  80                 }
  81         if(int_ctrl_cmd_is_null(defn))
  82                 /* The given name wasn't found */
  83                 return -1;
  84         return idx;
  85         }
  86 
  87 static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
  88         {
  89         int idx = 0;
  90         /* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
  91          * our searches don't need to take any longer than necessary. */
  92         while(!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num))
  93                 {
  94                 idx++;
  95                 defn++;
  96                 }
  97         if(defn->cmd_num == num)
  98                 return idx;
  99         /* The given cmd_num wasn't found */
 100         return -1;
 101         }
 102 
 103 static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p,
 104                            void (*f)(void))
 105         {
 106         int idx;
 107         char *s = (char *)p;
 108         /* Take care of the easy one first (eg. it requires no searches) */
 109         if(cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE)
 110                 {
 111                 if((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
 112                         return 0;
 113                 return e->cmd_defns->cmd_num;
 114                 }
 115         /* One or two commands require that "p" be a valid string buffer */
 116         if((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
 117                         (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
 118                         (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD))
 119                 {
 120                 if(s == NULL)
 121                         {
 122                         ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
 123                                 ERR_R_PASSED_NULL_PARAMETER);
 124                         return -1;
 125                         }
 126                 }
 127         /* Now handle cmd_name -> cmd_num conversion */
 128         if(cmd == ENGINE_CTRL_GET_CMD_FROM_NAME)
 129                 {
 130                 if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_name(
 131                                                 e->cmd_defns, s)) < 0))
 132                         {
 133                         ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
 134                                 ENGINE_R_INVALID_CMD_NAME);
 135                         return -1;
 136                         }
 137                 return e->cmd_defns[idx].cmd_num;
 138                 }
 139         /* For the rest of the commands, the 'long' argument must specify a
 140          * valie command number - so we need to conduct a search. */
 141         if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns,
 142                                         (unsigned int)i)) < 0))
 143                 {
 144                 ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
 145                         ENGINE_R_INVALID_CMD_NUMBER);
 146                 return -1;
 147                 }
 148         /* Now the logic splits depending on command type */
 149         switch(cmd)
 150                 {
 151         case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
 152                 idx++;
 153                 if(int_ctrl_cmd_is_null(e->cmd_defns + idx))
 154                         /* end-of-list */
 155                         return 0;
 156                 else
 157                         return e->cmd_defns[idx].cmd_num;
 158         case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
 159                 return strlen(e->cmd_defns[idx].cmd_name);
 160         case ENGINE_CTRL_GET_NAME_FROM_CMD:
 161                 return BIO_snprintf(s,strlen(e->cmd_defns[idx].cmd_name) + 1,
 162                                     "%s", e->cmd_defns[idx].cmd_name);
 163         case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
 164                 if(e->cmd_defns[idx].cmd_desc)
 165                         return strlen(e->cmd_defns[idx].cmd_desc);
 166                 return strlen(int_no_description);
 167         case ENGINE_CTRL_GET_DESC_FROM_CMD:
 168                 if(e->cmd_defns[idx].cmd_desc)
 169                         return BIO_snprintf(s,
 170                                             strlen(e->cmd_defns[idx].cmd_desc) + 1,
 171                                             "%s", e->cmd_defns[idx].cmd_desc);
 172                 return BIO_snprintf(s, strlen(int_no_description) + 1,"%s",
 173                                     int_no_description);
 174         case ENGINE_CTRL_GET_CMD_FLAGS:
 175                 return e->cmd_defns[idx].cmd_flags;
 176                 }
 177         /* Shouldn't really be here ... */
 178         ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR);
 179         return -1;
 180         }
 181 
 182 int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
 183         {
 184         int ctrl_exists, ref_exists;
 185         if(e == NULL)
 186                 {
 187                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER);
 188                 return 0;
 189                 }
 190         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 191         ref_exists = ((e->struct_ref > 0) ? 1 : 0);
 192         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 193         ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
 194         if(!ref_exists)
 195                 {
 196                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE);
 197                 return 0;
 198                 }
 199         /* Intercept any "root-level" commands before trying to hand them on to
 200          * ctrl() handlers. */
 201         switch(cmd)
 202                 {
 203         case ENGINE_CTRL_HAS_CTRL_FUNCTION:
 204                 return ctrl_exists;
 205         case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
 206         case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
 207         case ENGINE_CTRL_GET_CMD_FROM_NAME:
 208         case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
 209         case ENGINE_CTRL_GET_NAME_FROM_CMD:
 210         case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
 211         case ENGINE_CTRL_GET_DESC_FROM_CMD:
 212         case ENGINE_CTRL_GET_CMD_FLAGS:
 213                 if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
 214                         return int_ctrl_helper(e,cmd,i,p,f);
 215                 if(!ctrl_exists)
 216                         {
 217                         ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
 218                         /* For these cmd-related functions, failure is indicated
 219                          * by a -1 return value (because 0 is used as a valid
 220                          * return in some places). */
 221                         return -1;
 222                         }
 223         default:
 224                 break;
 225                 }
 226         /* Anything else requires a ctrl() handler to exist. */
 227         if(!ctrl_exists)
 228                 {
 229                 ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
 230                 return 0;
 231                 }
 232         return e->ctrl(e, cmd, i, p, f);
 233         }
 234 
 235 int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
 236         {
 237         int flags;
 238         if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0)
 239                 {
 240                 ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
 241                         ENGINE_R_INVALID_CMD_NUMBER);
 242                 return 0;
 243                 }
 244         if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
 245                         !(flags & ENGINE_CMD_FLAG_NUMERIC) &&
 246                         !(flags & ENGINE_CMD_FLAG_STRING))
 247                 return 0;
 248         return 1;
 249         }
 250 
 251 int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
 252         long i, void *p, void (*f)(void), int cmd_optional)
 253         {
 254         int num;
 255 
 256         if((e == NULL) || (cmd_name == NULL))
 257                 {
 258                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
 259                         ERR_R_PASSED_NULL_PARAMETER);
 260                 return 0;
 261                 }
 262         if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
 263                                         ENGINE_CTRL_GET_CMD_FROM_NAME,
 264                                         0, (void *)cmd_name, NULL)) <= 0))
 265                 {
 266                 /* If the command didn't *have* to be supported, we fake
 267                  * success. This allows certain settings to be specified for
 268                  * multiple ENGINEs and only require a change of ENGINE id
 269                  * (without having to selectively apply settings). Eg. changing
 270                  * from a hardware device back to the regular software ENGINE
 271                  * without editing the config file, etc. */
 272                 if(cmd_optional)
 273                         {
 274                         ERR_clear_error();
 275                         return 1;
 276                         }
 277                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
 278                         ENGINE_R_INVALID_CMD_NAME);
 279                 return 0;
 280                 }
 281         /* Force the result of the control command to 0 or 1, for the reasons
 282          * mentioned before. */
 283         if (ENGINE_ctrl(e, num, i, p, f) > 0)
 284                 return 1;
 285         return 0;
 286         }
 287 
 288 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
 289                                 int cmd_optional)
 290         {
 291         int num, flags;
 292         long l;
 293         char *ptr;
 294         if((e == NULL) || (cmd_name == NULL))
 295                 {
 296                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 297                         ERR_R_PASSED_NULL_PARAMETER);
 298                 return 0;
 299                 }
 300         if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
 301                                         ENGINE_CTRL_GET_CMD_FROM_NAME,
 302                                         0, (void *)cmd_name, NULL)) <= 0))
 303                 {
 304                 /* If the command didn't *have* to be supported, we fake
 305                  * success. This allows certain settings to be specified for
 306                  * multiple ENGINEs and only require a change of ENGINE id
 307                  * (without having to selectively apply settings). Eg. changing
 308                  * from a hardware device back to the regular software ENGINE
 309                  * without editing the config file, etc. */
 310                 if(cmd_optional)
 311                         {
 312                         ERR_clear_error();
 313                         return 1;
 314                         }
 315                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 316                         ENGINE_R_INVALID_CMD_NAME);
 317                 return 0;
 318                 }
 319         if(!ENGINE_cmd_is_executable(e, num))
 320                 {
 321                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 322                         ENGINE_R_CMD_NOT_EXECUTABLE);
 323                 return 0;
 324                 }
 325         if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0)
 326                 {
 327                 /* Shouldn't happen, given that ENGINE_cmd_is_executable()
 328                  * returned success. */
 329                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 330                         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                 {
 337                 if(arg != NULL)
 338                         {
 339                         ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 340                                 ENGINE_R_COMMAND_TAKES_NO_INPUT);
 341                         return 0;
 342                         }
 343                 /* We deliberately force the result of ENGINE_ctrl() to 0 or 1
 344                  * rather than returning it as "return data". This is to ensure
 345                  * usage of these commands is consistent across applications and
 346                  * that certain applications don't understand it one way, and
 347                  * others another. */
 348                 if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
 349                         return 1;
 350                 return 0;
 351                 }
 352         /* So, we require input */
 353         if(arg == NULL)
 354                 {
 355                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 356                         ENGINE_R_COMMAND_TAKES_INPUT);
 357                 return 0;
 358                 }
 359         /* If it takes string input, that's easy */
 360         if(flags & ENGINE_CMD_FLAG_STRING)
 361                 {
 362                 /* Same explanation as above */
 363                 if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
 364                         return 1;
 365                 return 0;
 366                 }
 367         /* If it doesn't take numeric either, then it is unsupported for use in
 368          * a config-setting situation, which is what this function is for. This
 369          * should never happen though, because ENGINE_cmd_is_executable() was
 370          * used. */
 371         if(!(flags & ENGINE_CMD_FLAG_NUMERIC))
 372                 {
 373                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 374                         ENGINE_R_INTERNAL_LIST_ERROR);
 375                 return 0;
 376                 }
 377         l = strtol(arg, &ptr, 10);
 378         if((arg == ptr) || (*ptr != '\0'))
 379                 {
 380                 ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
 381                         ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
 382                 return 0;
 383                 }
 384         /* Force the result of the control command to 0 or 1, for the reasons
 385          * mentioned before. */
 386         if(ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
 387                 return 1;
 388         return 0;
 389         }