123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /* krxsecd.c: Rx security daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This daemon deals with:
- * - consulting the application as to whether inbound peers and calls should be authorised
- * - generating security challenges for inbound connections
- * - responding to security challenges on outbound connections
- */
- #include <linux/module.h>
- #include <linux/sched.h>
- #include <linux/completion.h>
- #include <linux/spinlock.h>
- #include <linux/init.h>
- #include <rxrpc/krxsecd.h>
- #include <rxrpc/transport.h>
- #include <rxrpc/connection.h>
- #include <rxrpc/message.h>
- #include <rxrpc/peer.h>
- #include <rxrpc/call.h>
- #include <linux/udp.h>
- #include <linux/ip.h>
- #include <net/sock.h>
- #include "internal.h"
- static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxsecd_sleepq);
- static DECLARE_COMPLETION(rxrpc_krxsecd_dead);
- static volatile int rxrpc_krxsecd_die;
- static atomic_t rxrpc_krxsecd_qcount;
- /* queue of unprocessed inbound messages with seqno #1 and
- * RXRPC_CLIENT_INITIATED flag set */
- static LIST_HEAD(rxrpc_krxsecd_initmsgq);
- static DEFINE_SPINLOCK(rxrpc_krxsecd_initmsgq_lock);
- static void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg);
- /*****************************************************************************/
- /*
- * Rx security daemon
- */
- static int rxrpc_krxsecd(void *arg)
- {
- DECLARE_WAITQUEUE(krxsecd, current);
- int die;
- printk("Started krxsecd %d\n", current->pid);
- daemonize("krxsecd");
- /* loop around waiting for work to do */
- do {
- /* wait for work or to be told to exit */
- _debug("### Begin Wait");
- if (!atomic_read(&rxrpc_krxsecd_qcount)) {
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (atomic_read(&rxrpc_krxsecd_qcount) ||
- rxrpc_krxsecd_die ||
- signal_pending(current))
- break;
- schedule();
- }
- remove_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd);
- set_current_state(TASK_RUNNING);
- }
- die = rxrpc_krxsecd_die;
- _debug("### End Wait");
- /* see if there're incoming calls in need of authenticating */
- _debug("### Begin Inbound Calls");
- if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
- struct rxrpc_message *msg = NULL;
- spin_lock(&rxrpc_krxsecd_initmsgq_lock);
- if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
- msg = list_entry(rxrpc_krxsecd_initmsgq.next,
- struct rxrpc_message, link);
- list_del_init(&msg->link);
- atomic_dec(&rxrpc_krxsecd_qcount);
- }
- spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
- if (msg) {
- rxrpc_krxsecd_process_incoming_call(msg);
- rxrpc_put_message(msg);
- }
- }
- _debug("### End Inbound Calls");
- try_to_freeze();
- /* discard pending signals */
- rxrpc_discard_my_signals();
- } while (!die);
- /* and that's all */
- complete_and_exit(&rxrpc_krxsecd_dead, 0);
- } /* end rxrpc_krxsecd() */
- /*****************************************************************************/
- /*
- * start up a krxsecd daemon
- */
- int __init rxrpc_krxsecd_init(void)
- {
- return kernel_thread(rxrpc_krxsecd, NULL, 0);
- } /* end rxrpc_krxsecd_init() */
- /*****************************************************************************/
- /*
- * kill the krxsecd daemon and wait for it to complete
- */
- void rxrpc_krxsecd_kill(void)
- {
- rxrpc_krxsecd_die = 1;
- wake_up_all(&rxrpc_krxsecd_sleepq);
- wait_for_completion(&rxrpc_krxsecd_dead);
- } /* end rxrpc_krxsecd_kill() */
- /*****************************************************************************/
- /*
- * clear all pending incoming calls for the specified transport
- */
- void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans)
- {
- LIST_HEAD(tmp);
- struct rxrpc_message *msg;
- struct list_head *_p, *_n;
- _enter("%p",trans);
- /* move all the messages for this transport onto a temp list */
- spin_lock(&rxrpc_krxsecd_initmsgq_lock);
- list_for_each_safe(_p, _n, &rxrpc_krxsecd_initmsgq) {
- msg = list_entry(_p, struct rxrpc_message, link);
- if (msg->trans == trans) {
- list_del(&msg->link);
- list_add_tail(&msg->link, &tmp);
- atomic_dec(&rxrpc_krxsecd_qcount);
- }
- }
- spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
- /* zap all messages on the temp list */
- while (!list_empty(&tmp)) {
- msg = list_entry(tmp.next, struct rxrpc_message, link);
- list_del_init(&msg->link);
- rxrpc_put_message(msg);
- }
- _leave("");
- } /* end rxrpc_krxsecd_clear_transport() */
- /*****************************************************************************/
- /*
- * queue a message on the incoming calls list
- */
- void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg)
- {
- _enter("%p", msg);
- /* queue for processing by krxsecd */
- spin_lock(&rxrpc_krxsecd_initmsgq_lock);
- if (!rxrpc_krxsecd_die) {
- rxrpc_get_message(msg);
- list_add_tail(&msg->link, &rxrpc_krxsecd_initmsgq);
- atomic_inc(&rxrpc_krxsecd_qcount);
- }
- spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
- wake_up(&rxrpc_krxsecd_sleepq);
- _leave("");
- } /* end rxrpc_krxsecd_queue_incoming_call() */
- /*****************************************************************************/
- /*
- * process the initial message of an incoming call
- */
- void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg)
- {
- struct rxrpc_transport *trans = msg->trans;
- struct rxrpc_service *srv;
- struct rxrpc_call *call;
- struct list_head *_p;
- unsigned short sid;
- int ret;
- _enter("%p{tr=%p}", msg, trans);
- ret = rxrpc_incoming_call(msg->conn, msg, &call);
- if (ret < 0)
- goto out;
- /* find the matching service on the transport */
- sid = ntohs(msg->hdr.serviceId);
- srv = NULL;
- spin_lock(&trans->lock);
- list_for_each(_p, &trans->services) {
- srv = list_entry(_p, struct rxrpc_service, link);
- if (srv->service_id == sid && try_module_get(srv->owner)) {
- /* found a match (made sure it won't vanish) */
- _debug("found service '%s'", srv->name);
- call->owner = srv->owner;
- break;
- }
- }
- spin_unlock(&trans->lock);
- /* report the new connection
- * - the func must inc the call's usage count to keep it
- */
- ret = -ENOENT;
- if (_p != &trans->services) {
- /* attempt to accept the call */
- call->conn->service = srv;
- call->app_attn_func = srv->attn_func;
- call->app_error_func = srv->error_func;
- call->app_aemap_func = srv->aemap_func;
- ret = srv->new_call(call);
- /* send an abort if an error occurred */
- if (ret < 0) {
- rxrpc_call_abort(call, ret);
- }
- else {
- /* formally receive and ACK the new packet */
- ret = rxrpc_conn_receive_call_packet(call->conn,
- call, msg);
- }
- }
- rxrpc_put_call(call);
- out:
- if (ret < 0)
- rxrpc_trans_immediate_abort(trans, msg, ret);
- _leave(" (%d)", ret);
- } /* end rxrpc_krxsecd_process_incoming_call() */
|