linux/net/rxrpc/security.c
<<
>>
Prefs
   1/* RxRPC security handling
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/net.h>
  14#include <linux/skbuff.h>
  15#include <linux/udp.h>
  16#include <linux/crypto.h>
  17#include <net/sock.h>
  18#include <net/af_rxrpc.h>
  19#include <keys/rxrpc-type.h>
  20#include "ar-internal.h"
  21
  22static LIST_HEAD(rxrpc_security_methods);
  23static DECLARE_RWSEM(rxrpc_security_sem);
  24
  25static const struct rxrpc_security *rxrpc_security_types[] = {
  26        [RXRPC_SECURITY_NONE]   = &rxrpc_no_security,
  27#ifdef CONFIG_RXKAD
  28        [RXRPC_SECURITY_RXKAD]  = &rxkad,
  29#endif
  30};
  31
  32int __init rxrpc_init_security(void)
  33{
  34        int i, ret;
  35
  36        for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
  37                if (rxrpc_security_types[i]) {
  38                        ret = rxrpc_security_types[i]->init();
  39                        if (ret < 0)
  40                                goto failed;
  41                }
  42        }
  43
  44        return 0;
  45
  46failed:
  47        for (i--; i >= 0; i--)
  48                if (rxrpc_security_types[i])
  49                        rxrpc_security_types[i]->exit();
  50        return ret;
  51}
  52
  53void rxrpc_exit_security(void)
  54{
  55        int i;
  56
  57        for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
  58                if (rxrpc_security_types[i])
  59                        rxrpc_security_types[i]->exit();
  60}
  61
  62/*
  63 * look up an rxrpc security module
  64 */
  65static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
  66{
  67        if (security_index >= ARRAY_SIZE(rxrpc_security_types))
  68                return NULL;
  69        return rxrpc_security_types[security_index];
  70}
  71
  72/*
  73 * initialise the security on a client connection
  74 */
  75int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
  76{
  77        const struct rxrpc_security *sec;
  78        struct rxrpc_key_token *token;
  79        struct key *key = conn->params.key;
  80        int ret;
  81
  82        _enter("{%d},{%x}", conn->debug_id, key_serial(key));
  83
  84        if (!key)
  85                return 0;
  86
  87        ret = key_validate(key);
  88        if (ret < 0)
  89                return ret;
  90
  91        token = key->payload.data[0];
  92        if (!token)
  93                return -EKEYREJECTED;
  94
  95        sec = rxrpc_security_lookup(token->security_index);
  96        if (!sec)
  97                return -EKEYREJECTED;
  98        conn->security = sec;
  99
 100        ret = conn->security->init_connection_security(conn);
 101        if (ret < 0) {
 102                conn->security = &rxrpc_no_security;
 103                return ret;
 104        }
 105
 106        _leave(" = 0");
 107        return 0;
 108}
 109
 110/*
 111 * initialise the security on a server connection
 112 */
 113int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
 114{
 115        const struct rxrpc_security *sec;
 116        struct rxrpc_local *local = conn->params.local;
 117        struct rxrpc_sock *rx;
 118        struct key *key;
 119        key_ref_t kref;
 120        char kdesc[5 + 1 + 3 + 1];
 121
 122        _enter("");
 123
 124        sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
 125
 126        sec = rxrpc_security_lookup(conn->security_ix);
 127        if (!sec) {
 128                _leave(" = -ENOKEY [lookup]");
 129                return -ENOKEY;
 130        }
 131
 132        /* find the service */
 133        read_lock(&local->services_lock);
 134        rx = rcu_dereference_protected(local->service,
 135                                       lockdep_is_held(&local->services_lock));
 136        if (rx && (rx->srx.srx_service == conn->service_id ||
 137                   rx->second_service == conn->service_id))
 138                goto found_service;
 139
 140        /* the service appears to have died */
 141        read_unlock(&local->services_lock);
 142        _leave(" = -ENOENT");
 143        return -ENOENT;
 144
 145found_service:
 146        if (!rx->securities) {
 147                read_unlock(&local->services_lock);
 148                _leave(" = -ENOKEY");
 149                return -ENOKEY;
 150        }
 151
 152        /* look through the service's keyring */
 153        kref = keyring_search(make_key_ref(rx->securities, 1UL),
 154                              &key_type_rxrpc_s, kdesc);
 155        if (IS_ERR(kref)) {
 156                read_unlock(&local->services_lock);
 157                _leave(" = %ld [search]", PTR_ERR(kref));
 158                return PTR_ERR(kref);
 159        }
 160
 161        key = key_ref_to_ptr(kref);
 162        read_unlock(&local->services_lock);
 163
 164        conn->server_key = key;
 165        conn->security = sec;
 166
 167        _leave(" = 0");
 168        return 0;
 169}
 170