Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19 269 lines 7.0 kB view raw
1/* krxsecd.c: Rx security daemon 2 * 3 * Copyright (C) 2002 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 * This daemon deals with: 12 * - consulting the application as to whether inbound peers and calls should be authorised 13 * - generating security challenges for inbound connections 14 * - responding to security challenges on outbound connections 15 */ 16 17#include <linux/module.h> 18#include <linux/sched.h> 19#include <linux/completion.h> 20#include <linux/spinlock.h> 21#include <linux/init.h> 22#include <rxrpc/krxsecd.h> 23#include <rxrpc/transport.h> 24#include <rxrpc/connection.h> 25#include <rxrpc/message.h> 26#include <rxrpc/peer.h> 27#include <rxrpc/call.h> 28#include <linux/udp.h> 29#include <linux/ip.h> 30#include <net/sock.h> 31#include "internal.h" 32 33static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxsecd_sleepq); 34static DECLARE_COMPLETION(rxrpc_krxsecd_dead); 35static volatile int rxrpc_krxsecd_die; 36 37static atomic_t rxrpc_krxsecd_qcount; 38 39/* queue of unprocessed inbound messages with seqno #1 and 40 * RXRPC_CLIENT_INITIATED flag set */ 41static LIST_HEAD(rxrpc_krxsecd_initmsgq); 42static DEFINE_SPINLOCK(rxrpc_krxsecd_initmsgq_lock); 43 44static void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg); 45 46/*****************************************************************************/ 47/* 48 * Rx security daemon 49 */ 50static int rxrpc_krxsecd(void *arg) 51{ 52 DECLARE_WAITQUEUE(krxsecd, current); 53 54 int die; 55 56 printk("Started krxsecd %d\n", current->pid); 57 58 daemonize("krxsecd"); 59 60 /* loop around waiting for work to do */ 61 do { 62 /* wait for work or to be told to exit */ 63 _debug("### Begin Wait"); 64 if (!atomic_read(&rxrpc_krxsecd_qcount)) { 65 set_current_state(TASK_INTERRUPTIBLE); 66 67 add_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd); 68 69 for (;;) { 70 set_current_state(TASK_INTERRUPTIBLE); 71 if (atomic_read(&rxrpc_krxsecd_qcount) || 72 rxrpc_krxsecd_die || 73 signal_pending(current)) 74 break; 75 76 schedule(); 77 } 78 79 remove_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd); 80 set_current_state(TASK_RUNNING); 81 } 82 die = rxrpc_krxsecd_die; 83 _debug("### End Wait"); 84 85 /* see if there're incoming calls in need of authenticating */ 86 _debug("### Begin Inbound Calls"); 87 88 if (!list_empty(&rxrpc_krxsecd_initmsgq)) { 89 struct rxrpc_message *msg = NULL; 90 91 spin_lock(&rxrpc_krxsecd_initmsgq_lock); 92 93 if (!list_empty(&rxrpc_krxsecd_initmsgq)) { 94 msg = list_entry(rxrpc_krxsecd_initmsgq.next, 95 struct rxrpc_message, link); 96 list_del_init(&msg->link); 97 atomic_dec(&rxrpc_krxsecd_qcount); 98 } 99 100 spin_unlock(&rxrpc_krxsecd_initmsgq_lock); 101 102 if (msg) { 103 rxrpc_krxsecd_process_incoming_call(msg); 104 rxrpc_put_message(msg); 105 } 106 } 107 108 _debug("### End Inbound Calls"); 109 110 try_to_freeze(); 111 112 /* discard pending signals */ 113 rxrpc_discard_my_signals(); 114 115 } while (!die); 116 117 /* and that's all */ 118 complete_and_exit(&rxrpc_krxsecd_dead, 0); 119 120} /* end rxrpc_krxsecd() */ 121 122/*****************************************************************************/ 123/* 124 * start up a krxsecd daemon 125 */ 126int __init rxrpc_krxsecd_init(void) 127{ 128 return kernel_thread(rxrpc_krxsecd, NULL, 0); 129 130} /* end rxrpc_krxsecd_init() */ 131 132/*****************************************************************************/ 133/* 134 * kill the krxsecd daemon and wait for it to complete 135 */ 136void rxrpc_krxsecd_kill(void) 137{ 138 rxrpc_krxsecd_die = 1; 139 wake_up_all(&rxrpc_krxsecd_sleepq); 140 wait_for_completion(&rxrpc_krxsecd_dead); 141 142} /* end rxrpc_krxsecd_kill() */ 143 144/*****************************************************************************/ 145/* 146 * clear all pending incoming calls for the specified transport 147 */ 148void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans) 149{ 150 LIST_HEAD(tmp); 151 152 struct rxrpc_message *msg; 153 struct list_head *_p, *_n; 154 155 _enter("%p",trans); 156 157 /* move all the messages for this transport onto a temp list */ 158 spin_lock(&rxrpc_krxsecd_initmsgq_lock); 159 160 list_for_each_safe(_p, _n, &rxrpc_krxsecd_initmsgq) { 161 msg = list_entry(_p, struct rxrpc_message, link); 162 if (msg->trans == trans) { 163 list_move_tail(&msg->link, &tmp); 164 atomic_dec(&rxrpc_krxsecd_qcount); 165 } 166 } 167 168 spin_unlock(&rxrpc_krxsecd_initmsgq_lock); 169 170 /* zap all messages on the temp list */ 171 while (!list_empty(&tmp)) { 172 msg = list_entry(tmp.next, struct rxrpc_message, link); 173 list_del_init(&msg->link); 174 rxrpc_put_message(msg); 175 } 176 177 _leave(""); 178} /* end rxrpc_krxsecd_clear_transport() */ 179 180/*****************************************************************************/ 181/* 182 * queue a message on the incoming calls list 183 */ 184void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg) 185{ 186 _enter("%p", msg); 187 188 /* queue for processing by krxsecd */ 189 spin_lock(&rxrpc_krxsecd_initmsgq_lock); 190 191 if (!rxrpc_krxsecd_die) { 192 rxrpc_get_message(msg); 193 list_add_tail(&msg->link, &rxrpc_krxsecd_initmsgq); 194 atomic_inc(&rxrpc_krxsecd_qcount); 195 } 196 197 spin_unlock(&rxrpc_krxsecd_initmsgq_lock); 198 199 wake_up(&rxrpc_krxsecd_sleepq); 200 201 _leave(""); 202} /* end rxrpc_krxsecd_queue_incoming_call() */ 203 204/*****************************************************************************/ 205/* 206 * process the initial message of an incoming call 207 */ 208void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg) 209{ 210 struct rxrpc_transport *trans = msg->trans; 211 struct rxrpc_service *srv; 212 struct rxrpc_call *call; 213 struct list_head *_p; 214 unsigned short sid; 215 int ret; 216 217 _enter("%p{tr=%p}", msg, trans); 218 219 ret = rxrpc_incoming_call(msg->conn, msg, &call); 220 if (ret < 0) 221 goto out; 222 223 /* find the matching service on the transport */ 224 sid = ntohs(msg->hdr.serviceId); 225 srv = NULL; 226 227 spin_lock(&trans->lock); 228 list_for_each(_p, &trans->services) { 229 srv = list_entry(_p, struct rxrpc_service, link); 230 if (srv->service_id == sid && try_module_get(srv->owner)) { 231 /* found a match (made sure it won't vanish) */ 232 _debug("found service '%s'", srv->name); 233 call->owner = srv->owner; 234 break; 235 } 236 } 237 spin_unlock(&trans->lock); 238 239 /* report the new connection 240 * - the func must inc the call's usage count to keep it 241 */ 242 ret = -ENOENT; 243 if (_p != &trans->services) { 244 /* attempt to accept the call */ 245 call->conn->service = srv; 246 call->app_attn_func = srv->attn_func; 247 call->app_error_func = srv->error_func; 248 call->app_aemap_func = srv->aemap_func; 249 250 ret = srv->new_call(call); 251 252 /* send an abort if an error occurred */ 253 if (ret < 0) { 254 rxrpc_call_abort(call, ret); 255 } 256 else { 257 /* formally receive and ACK the new packet */ 258 ret = rxrpc_conn_receive_call_packet(call->conn, 259 call, msg); 260 } 261 } 262 263 rxrpc_put_call(call); 264 out: 265 if (ret < 0) 266 rxrpc_trans_immediate_abort(trans, msg, ret); 267 268 _leave(" (%d)", ret); 269} /* end rxrpc_krxsecd_process_incoming_call() */