linux/net/rxrpc/ar-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
  25/*
  26 * get an RxRPC security module
  27 */
  28static struct rxrpc_security *rxrpc_security_get(struct rxrpc_security *sec)
  29{
  30        return try_module_get(sec->owner) ? sec : NULL;
  31}
  32
  33/*
  34 * release an RxRPC security module
  35 */
  36static void rxrpc_security_put(struct rxrpc_security *sec)
  37{
  38        module_put(sec->owner);
  39}
  40
  41/*
  42 * look up an rxrpc security module
  43 */
  44static struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
  45{
  46        struct rxrpc_security *sec = NULL;
  47
  48        _enter("");
  49
  50        down_read(&rxrpc_security_sem);
  51
  52        list_for_each_entry(sec, &rxrpc_security_methods, link) {
  53                if (sec->security_index == security_index) {
  54                        if (unlikely(!rxrpc_security_get(sec)))
  55                                break;
  56                        goto out;
  57                }
  58        }
  59
  60        sec = NULL;
  61out:
  62        up_read(&rxrpc_security_sem);
  63        _leave(" = %p [%s]", sec, sec ? sec->name : "");
  64        return sec;
  65}
  66
  67/**
  68 * rxrpc_register_security - register an RxRPC security handler
  69 * @sec: security module
  70 *
  71 * register an RxRPC security handler for use by RxRPC
  72 */
  73int rxrpc_register_security(struct rxrpc_security *sec)
  74{
  75        struct rxrpc_security *psec;
  76        int ret;
  77
  78        _enter("");
  79        down_write(&rxrpc_security_sem);
  80
  81        ret = -EEXIST;
  82        list_for_each_entry(psec, &rxrpc_security_methods, link) {
  83                if (psec->security_index == sec->security_index)
  84                        goto out;
  85        }
  86
  87        list_add(&sec->link, &rxrpc_security_methods);
  88
  89        printk(KERN_NOTICE "RxRPC: Registered security type %d '%s'\n",
  90               sec->security_index, sec->name);
  91        ret = 0;
  92
  93out:
  94        up_write(&rxrpc_security_sem);
  95        _leave(" = %d", ret);
  96        return ret;
  97}
  98
  99EXPORT_SYMBOL_GPL(rxrpc_register_security);
 100
 101/**
 102 * rxrpc_unregister_security - unregister an RxRPC security handler
 103 * @sec: security module
 104 *
 105 * unregister an RxRPC security handler
 106 */
 107void rxrpc_unregister_security(struct rxrpc_security *sec)
 108{
 109
 110        _enter("");
 111        down_write(&rxrpc_security_sem);
 112        list_del_init(&sec->link);
 113        up_write(&rxrpc_security_sem);
 114
 115        printk(KERN_NOTICE "RxRPC: Unregistered security type %d '%s'\n",
 116               sec->security_index, sec->name);
 117}
 118
 119EXPORT_SYMBOL_GPL(rxrpc_unregister_security);
 120
 121/*
 122 * initialise the security on a client connection
 123 */
 124int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
 125{
 126        struct rxrpc_key_token *token;
 127        struct rxrpc_security *sec;
 128        struct key *key = conn->key;
 129        int ret;
 130
 131        _enter("{%d},{%x}", conn->debug_id, key_serial(key));
 132
 133        if (!key)
 134                return 0;
 135
 136        ret = key_validate(key);
 137        if (ret < 0)
 138                return ret;
 139
 140        if (!key->payload.data)
 141                return -EKEYREJECTED;
 142        token = key->payload.data;
 143
 144        sec = rxrpc_security_lookup(token->security_index);
 145        if (!sec)
 146                return -EKEYREJECTED;
 147        conn->security = sec;
 148
 149        ret = conn->security->init_connection_security(conn);
 150        if (ret < 0) {
 151                rxrpc_security_put(conn->security);
 152                conn->security = NULL;
 153                return ret;
 154        }
 155
 156        _leave(" = 0");
 157        return 0;
 158}
 159
 160/*
 161 * initialise the security on a server connection
 162 */
 163int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
 164{
 165        struct rxrpc_security *sec;
 166        struct rxrpc_local *local = conn->trans->local;
 167        struct rxrpc_sock *rx;
 168        struct key *key;
 169        key_ref_t kref;
 170        char kdesc[5+1+3+1];
 171
 172        _enter("");
 173
 174        sprintf(kdesc, "%u:%u", ntohs(conn->service_id), conn->security_ix);
 175
 176        sec = rxrpc_security_lookup(conn->security_ix);
 177        if (!sec) {
 178                _leave(" = -ENOKEY [lookup]");
 179                return -ENOKEY;
 180        }
 181
 182        /* find the service */
 183        read_lock_bh(&local->services_lock);
 184        list_for_each_entry(rx, &local->services, listen_link) {
 185                if (rx->service_id == conn->service_id)
 186                        goto found_service;
 187        }
 188
 189        /* the service appears to have died */
 190        read_unlock_bh(&local->services_lock);
 191        rxrpc_security_put(sec);
 192        _leave(" = -ENOENT");
 193        return -ENOENT;
 194
 195found_service:
 196        if (!rx->securities) {
 197                read_unlock_bh(&local->services_lock);
 198                rxrpc_security_put(sec);
 199                _leave(" = -ENOKEY");
 200                return -ENOKEY;
 201        }
 202
 203        /* look through the service's keyring */
 204        kref = keyring_search(make_key_ref(rx->securities, 1UL),
 205                              &key_type_rxrpc_s, kdesc);
 206        if (IS_ERR(kref)) {
 207                read_unlock_bh(&local->services_lock);
 208                rxrpc_security_put(sec);
 209                _leave(" = %ld [search]", PTR_ERR(kref));
 210                return PTR_ERR(kref);
 211        }
 212
 213        key = key_ref_to_ptr(kref);
 214        read_unlock_bh(&local->services_lock);
 215
 216        conn->server_key = key;
 217        conn->security = sec;
 218
 219        _leave(" = 0");
 220        return 0;
 221}
 222
 223/*
 224 * secure a packet prior to transmission
 225 */
 226int rxrpc_secure_packet(const struct rxrpc_call *call,
 227                        struct sk_buff *skb,
 228                        size_t data_size,
 229                        void *sechdr)
 230{
 231        if (call->conn->security)
 232                return call->conn->security->secure_packet(
 233                        call, skb, data_size, sechdr);
 234        return 0;
 235}
 236
 237/*
 238 * secure a packet prior to transmission
 239 */
 240int rxrpc_verify_packet(const struct rxrpc_call *call, struct sk_buff *skb,
 241                        u32 *_abort_code)
 242{
 243        if (call->conn->security)
 244                return call->conn->security->verify_packet(
 245                        call, skb, _abort_code);
 246        return 0;
 247}
 248
 249/*
 250 * clear connection security
 251 */
 252void rxrpc_clear_conn_security(struct rxrpc_connection *conn)
 253{
 254        _enter("{%d}", conn->debug_id);
 255
 256        if (conn->security) {
 257                conn->security->clear(conn);
 258                rxrpc_security_put(conn->security);
 259                conn->security = NULL;
 260        }
 261
 262        key_put(conn->key);
 263        key_put(conn->server_key);
 264}
 265