"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/utils_keyring.c" (13 Jan 2022, 5281 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils_keyring.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * kernel keyring utilities
    3  *
    4  * Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2016-2021 Ondrej Kozina
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include <errno.h>
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include <unistd.h>
   26 #include <sys/syscall.h>
   27 
   28 #include "libcryptsetup.h"
   29 #include "libcryptsetup_macros.h"
   30 #include "utils_keyring.h"
   31 
   32 #ifndef HAVE_KEY_SERIAL_T
   33 #define HAVE_KEY_SERIAL_T
   34 typedef int32_t key_serial_t;
   35 #endif
   36 
   37 #ifdef KERNEL_KEYRING
   38 
   39 static const struct {
   40     key_type_t type;
   41     const char *type_name;
   42 } key_types[] = {
   43     { LOGON_KEY,    "logon" },
   44     { USER_KEY, "user"  },
   45 };
   46 
   47 #include <linux/keyctl.h>
   48 
   49 /* request_key */
   50 static key_serial_t request_key(const char *type,
   51     const char *description,
   52     const char *callout_info,
   53     key_serial_t keyring)
   54 {
   55     return syscall(__NR_request_key, type, description, callout_info, keyring);
   56 }
   57 
   58 /* add_key */
   59 static key_serial_t add_key(const char *type,
   60     const char *description,
   61     const void *payload,
   62     size_t plen,
   63     key_serial_t keyring)
   64 {
   65     return syscall(__NR_add_key, type, description, payload, plen, keyring);
   66 }
   67 
   68 /* keyctl_read */
   69 static long keyctl_read(key_serial_t key, char *buffer, size_t buflen)
   70 {
   71     return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen);
   72 }
   73 
   74 /* keyctl_revoke */
   75 static long keyctl_revoke(key_serial_t key)
   76 {
   77     return syscall(__NR_keyctl, KEYCTL_REVOKE, key);
   78 }
   79 
   80 /* keyctl_unlink */
   81 static long keyctl_unlink(key_serial_t key, key_serial_t keyring)
   82 {
   83     return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
   84 }
   85 #endif
   86 
   87 int keyring_check(void)
   88 {
   89 #ifdef KERNEL_KEYRING
   90     /* logon type key descriptions must be in format "prefix:description" */
   91     return syscall(__NR_request_key, "logon", "dummy", NULL, 0) == -1l && errno != ENOSYS;
   92 #else
   93     return 0;
   94 #endif
   95 }
   96 
   97 int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
   98 {
   99 #ifdef KERNEL_KEYRING
  100     key_serial_t kid;
  101     const char *type_name = key_type_name(ktype);
  102 
  103     if (!type_name || !key_desc)
  104         return -EINVAL;
  105 
  106     kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
  107     if (kid < 0)
  108         return -errno;
  109 
  110     return 0;
  111 #else
  112     return -ENOTSUP;
  113 #endif
  114 }
  115 
  116 /* currently used in client utilities only */
  117 int keyring_add_key_in_user_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
  118 {
  119 #ifdef KERNEL_KEYRING
  120     const char *type_name = key_type_name(ktype);
  121     key_serial_t kid;
  122 
  123     if (!type_name || !key_desc)
  124         return -EINVAL;
  125 
  126     kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_USER_KEYRING);
  127     if (kid < 0)
  128         return -errno;
  129 
  130     return 0;
  131 #else
  132     return -ENOTSUP;
  133 #endif
  134 }
  135 
  136 /* alias for the same code */
  137 int keyring_get_key(const char *key_desc,
  138             char **key,
  139             size_t *key_size)
  140 {
  141     return keyring_get_passphrase(key_desc, key, key_size);
  142 }
  143 
  144 int keyring_get_passphrase(const char *key_desc,
  145               char **passphrase,
  146               size_t *passphrase_len)
  147 {
  148 #ifdef KERNEL_KEYRING
  149     int err;
  150     key_serial_t kid;
  151     long ret;
  152     char *buf = NULL;
  153     size_t len = 0;
  154 
  155     do
  156         kid = request_key(key_type_name(USER_KEY), key_desc, NULL, 0);
  157     while (kid < 0 && errno == EINTR);
  158 
  159     if (kid < 0)
  160         return -errno;
  161 
  162     /* just get payload size */
  163     ret = keyctl_read(kid, NULL, 0);
  164     if (ret > 0) {
  165         len = ret;
  166         buf = malloc(len);
  167         if (!buf)
  168             return -ENOMEM;
  169 
  170         /* retrieve actual payload data */
  171         ret = keyctl_read(kid, buf, len);
  172     }
  173 
  174     if (ret < 0) {
  175         err = errno;
  176         if (buf)
  177             crypt_safe_memzero(buf, len);
  178         free(buf);
  179         return -err;
  180     }
  181 
  182     *passphrase = buf;
  183     *passphrase_len = len;
  184 
  185     return 0;
  186 #else
  187     return -ENOTSUP;
  188 #endif
  189 }
  190 
  191 static int keyring_revoke_and_unlink_key_type(const char *type_name, const char *key_desc)
  192 {
  193 #ifdef KERNEL_KEYRING
  194     key_serial_t kid;
  195 
  196     if (!type_name || !key_desc)
  197         return -EINVAL;
  198 
  199     do
  200         kid = request_key(type_name, key_desc, NULL, 0);
  201     while (kid < 0 && errno == EINTR);
  202 
  203     if (kid < 0)
  204         return 0;
  205 
  206     if (keyctl_revoke(kid))
  207         return -errno;
  208 
  209     /*
  210      * best effort only. the key could have been linked
  211      * in some other keyring and its payload is now
  212      * revoked anyway.
  213      */
  214     keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING);
  215     keyctl_unlink(kid, KEY_SPEC_PROCESS_KEYRING);
  216     keyctl_unlink(kid, KEY_SPEC_USER_KEYRING);
  217 
  218     return 0;
  219 #else
  220     return -ENOTSUP;
  221 #endif
  222 }
  223 
  224 const char *key_type_name(key_type_t type)
  225 {
  226 #ifdef KERNEL_KEYRING
  227     unsigned int i;
  228 
  229     for (i = 0; i < ARRAY_SIZE(key_types); i++)
  230         if (type == key_types[i].type)
  231             return key_types[i].type_name;
  232 #endif
  233     return NULL;
  234 }
  235 
  236 int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc)
  237 {
  238     return keyring_revoke_and_unlink_key_type(key_type_name(ktype), key_desc);
  239 }