/* This file is part of Kismet Kismet 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. Kismet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Kismet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * IPC remote * * Handles commands that can't/won't/shouldn't be handled by the main * Kismet process. The primary example of this is the root-level * control process used by the unprivileged Kismet to drive channel set * events. * * All commands and pointers MUST be set up BEFORE the IPC fork. * * An alternate child command can be specified. It MUST take as the first argument * an integer indicating the file descriptor number of the IPC pipe, and it MUST * understand the IPC protocol over this descriptor. * * The child binary must call SetChildExecMode(argc, argv) prior to filling in the * registered protocols, then call SpawnIPC() to kickstart processing. * * On some platforms (linux) a framework for passing file descriptors is available * as well via named unix sockets. Caller must send IPC to open early in the * initialization process and then try to open the socket locally. * */ #ifndef __IPC_REMOTE_H__ #define __IPC_REMOTE_H__ #include "config.h" #include #include #include #include #include #include #include #ifdef SYS_LINUX #include #include #include #include #include #include #include #endif #include #include #include "globalregistry.h" #include "pollable.h" #include "messagebus.h" #define IPC_CMD_PARMS GlobalRegistry *globalreg, const void *data, int len, \ const void *auxptr, int parent typedef int (*IPCmdCallback)(IPC_CMD_PARMS); // Builtin command IDs we force (added before assign, so start at 1) #define DIE_CMD_ID 1 #define MSG_CMD_ID 2 #define SYNC_CMD_ID 3 #define LAST_BUILTIN_CMD_ID 4 // Message client to redirect messages over the IPC link class IPC_MessageClient : public MessageClient { public: IPC_MessageClient(GlobalRegistry *in_globalreg, void *in_aux) : MessageClient(in_globalreg, in_aux) { }; virtual ~IPC_MessageClient() { } void ProcessMessage(string in_msg, int in_flags); }; // Message frame to go over IPC struct ipc_msgbus_pass { uint32_t msg_flags; uint32_t msg_len; // Redundant but simpler to read char msg[0]; }; // Super-generic IPC packet. This never sees outside of a unix dgram // frame, so we don't have to armor or protect it. Just a handy method for // tossing simple chunks of data. Commands are responsible for filling in // reasonable structs for *data struct ipc_packet { uint32_t sentinel; uint32_t ipc_cmdnum; uint32_t data_len; uint8_t ipc_ack; uint8_t data[0]; }; // Sync frame the link names and numbers with spawned ipc children struct ipc_sync { uint32_t ipc_cmdnum; uint8_t name[32]; }; // IPC sentinel const uint32_t IPCRemoteSentinel = 0xDECAFBAD; class IPCRemote : public Pollable { public: IPCRemote(); IPCRemote(GlobalRegistry *in_globalreg, string procname); virtual ~IPCRemote(); virtual void SetChildCmd(string in_cmd) { child_cmd = in_cmd; } // Start execution as the child and get the IPC descriptor from the // command line options passed from the IPC spawn virtual int SetChildExecMode(int argc, char *argv[]); virtual int SpawnIPC(); // Call after registering all services in a childexec, which don't have // to be registered before spawn virtual int SyncIPC(); // Get a shutdown virtual void CatchSigChild(int status) { exit_errno = WEXITSTATUS(status); ShutdownIPC(NULL); } // Shutdown takes an optional final packet to send before sending the // death packet virtual int ShutdownIPC(ipc_packet *pack); // IPC commands are integers, which means we get away without having to care // at all if they duplicate commands or whatever, so we don't even really // care about unique callbacks. Makes life easy for us. virtual int RegisterIPCCmd(IPCmdCallback in_callback, IPCmdCallback discard_ackback, void *in_aux, string name); virtual int SyncIPCCmd(ipc_sync *data); // Kick a command across (either direction) virtual int SendIPC(ipc_packet *pack); // Is the IPC ready for more commands? This would mean that the last // command was ack'd and that we don't have any queued up to still send. // Some uses might want to defer sending a command until the IPC is // settled. virtual int FetchReadyState(); pid_t FetchSpawnPid() { return ipc_pid; } int FetchErrno() { return exit_errno; } virtual int FetchIPCSynced() { return ipc_synced; } // Pollable system virtual int MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset); virtual int Poll(fd_set& in_rset, fd_set& in_wset); struct ipc_cmd_rec { void *auxptr; IPCmdCallback callback; string name; int id; }; protected: // Child process that never returns virtual void IPC_Child_Loop(); // Internal die functions virtual void IPCDie(); virtual int CheckPidVec(); GlobalRegistry *globalreg; // This isn't a ringbuf since it's dgram single-tx frames list cmd_buf; // Name of the process we'll use in the child string procname; int next_cmdid; // Pair used to talk to the Other Half int sockpair[2]; // PID of the child process pid_t ipc_pid; // Have we spawned a subproc? Blow up on setup commands if // we have. int ipc_spawned; map ipc_cmd_map; // Normally this would be a vec but it's a lot cheaper for ram and code size // to re-use the template map ipc_sync_map; // Cmd to run instead of a copy of ourself. string child_cmd; int child_exec_mode; friend class IPC_MessageClient; friend int ipc_die_callback(IPC_CMD_PARMS); friend int ipc_ack_callback(IPC_CMD_PARMS); // Reason we're exiting int exit_errno; // Have we been synced? (child) int ipc_synced; }; // Special IPCremote class for root control binary, used by IPC remote and // tuntap control, among others class RootIPCRemote : public IPCRemote { public: RootIPCRemote() { IPCRemote(); } RootIPCRemote(GlobalRegistry *in_globalreg, string procname); virtual ~RootIPCRemote() { IPCDie(); } virtual void CatchSigChild(int status) { if (!globalreg->spindown) { _MSG("Suid-root control binary failed: " + string(strerror(WEXITSTATUS(status))), MSGFLAG_FATAL); } // globalreg->fatal_condition = 1; IPCRemote::CatchSigChild(status); } virtual int OpenFDPassSock(); // Send a descriptor virtual int SendDescriptor(int in_fd); // Get a descriptor - there is no way to sync names or something to them, // so these should be called in pairs - send one, send a ipc command to // the other side to read it, and get it read. If commands are stacked in // order it should be fine. virtual int ReceiveDescriptor(); virtual int SyncIPC(); virtual int SyncRoot() { ipc_packet *pack = (ipc_packet *) malloc(sizeof(ipc_packet)); pack->data_len = 0; pack->ipc_cmdnum = rootipcsync_cmd; pack->ipc_ack = 0; return SendIPC(pack); } virtual int ShutdownIPC(ipc_packet *pack); virtual int FetchReadyState(); virtual void RootIPCSynced() { root_ipc_synced = 1; } virtual int FetchRootIPCSynced() { return root_ipc_synced; } protected: virtual void IPCDie(); virtual void ShutdownIPCPassFD(); #ifdef SYS_LINUX // Descriptor to the file descriptor passer (if one exists) int ipc_fd_fd; struct sockaddr_un unixsock; #endif int fdpass_cmd, rootipcsync_cmd; int root_ipc_synced; }; #endif