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