/* * A simple client interface to Identification Protocol servers * (was Authentication Service Protocol, RFC931 (obsolete)) * * See RFC1413 (supercedes RFC931) for a full understanding of the protocol. * Some quotes from section 6 on "Security Considerations": * * ``The information returned by this protocol is at most as trustworthy * as the host providing it OR the organization operating the host.'' * * ``The Identification Protocol is not intended as an authorization or * access control protocol. At best, it provides some additional * auditing information with respect to TCP connections.'' * * ``The use of the information returned by this protocol for other than * auditing is strongly discouraged.'' * * Note: this client is not fully conformant (robust) with the * specification, for example: it expects US-ASCII character set, and * does not process octet strings * * ident.c by Robocoder 95.03.15 - another tool for evil admin logging >=) */ #include <config.h> #define __tmi__ #ifdef __tmi__ /* assume TMI */ # include <mudlib.h> # include <uid.h> # include <net/socket.h> # include <logs.h> # include <driver/socket_err.h> # include <driver/runtime_config.h> # include <driver/origin.h> inherit DAEMON; #endif #ifdef __nightmare__ # include <std.h> # include <dirs.h> # include <daemons.h> # include <network.h> # include <security.h> inherit DAEMON; #define LOG_DIR DIR_LOGS "/" #endif #ifndef NET_IDENT_H #define NET_IDENT_H #ifndef IDENT_LOG #define IDENT_LOG "IDENT" #define IDENT_ERR_LOG "IDENT.err" #endif #define MAX_USER_ID_LEN 128 #define TIMEOUT_AUTH_INTERVAL (60) #define TIMEOUT_AUTH_CHECK (5 * 60) #endif /* NET_IDENT_H */ #define AUTH_PORT 113 #define IDENT_GAVE_UP 1 #define IDENT_TIMED_OUT 2 mapping noident; mapping sockinfo; #define LOCAL_ID(f) sockinfo[(f)][0] #define ID_OWNER(f) sockinfo[(f)][1] #define CALLBACK(f) sockinfo[(f)][2] #define TREQUEST(f) sockinfo[(f)][3] #define SOCKADDR(f) sockinfo[(f)][4] /* * some prototypes for local functions */ void write_cb(int fd, string str); void close_cb(int fd); /* * initialization */ void create() { #ifdef __tmi__ seteuid(ROOT_UID); #endif #ifdef __nightmare__ daemon::create(); set_no_clean(1); #endif sockinfo = ([ ]); noident = ([ ]); call_out("check_connections", TIMEOUT_AUTH_CHECK); } /* * initiate an Ident lookup with the remote server * * Inputs: * id - name of user, if ob_or_fd is the player object * - name of daemon requesting the service, if ob_or_fd is a socket * ob_or_fd - an object or a socket descriptor (see above) * myport - the local endpoint of the socket connection; * usually the mud login port * callback - an optional callback function of the form: * * void mycallback(mixed ob_or_fd, string user_id); * * - where ob_or_fd is a copy of what ident was given * and user_id is the response from a successful query * - note: the callback is _only_ called when an ident query * was successful */ void ident_user(string id, mixed ob_or_fd, int myport, mixed callback) { string addr; int myfd, ret, i; if (!id) return; if (!myport) myport = __PORT__; if (stringp(callback)) // Leto callback = (: previous_object(), $(callback) :); if (callback && !functionp(callback)) return; if ((addr = socket_address(ob_or_fd)) == "0.0.0.0 0") return; if ((myfd = socket_create(STREAM, "read_cb", "close_cb")) < 0) return; /* * socket_connect() usually always succeeds since inetd super server * handles initial connection before launching the ident server */ if (socket_connect(myfd, sprintf("%s%d", addr[0..i = strsrch(addr, ' ')], AUTH_PORT), "read_cb", "write_cb") != EESUCCESS) { socket_close(myfd); /* log error */ write_file(LOG_DIR IDENT_LOG, sprintf("[%s] %s@%s CONNECT REFUSED\n", ctime(time())[4..15], LOCAL_ID(myfd), SOCKADDR(myfd))); return; } sockinfo[myfd] = ({ id, ob_or_fd, callback, time(), addr[0..i-1] }); write_cb(myfd, sprintf("%s, %d\r\n", addr[i+1..<1], myport)); } /* * receive ident response * * format of response (string): * their_port, our_port : USERID : operating_system : user_id * their_port, our_port : USERID : OTHER : user_id_octet_string * their_port, our_port : ERROR : INVALID-PORT * their_port, our_port : ERROR : NO-USER * their_port, our_port : ERROR : HIDDEN-USER * their_port, our_port : ERROR : UNKNOWN-ERROR * * NB: we don't log errors... */ void read_cb(int fd, string str) { int i; string user_id; if (undefinedp(sockinfo[fd]) || origin() != ORIGIN_DRIVER) return; if ((i = strsrch(str, "USERID")) != -1) { /* get the user_id portion of the response */ i = strsrch(str, ':', i); user_id = str[i..<3]; /* skip trailing "\r\n" */ if (strlen(user_id) > MAX_USER_ID_LEN) user_id = user_id[0..MAX_USER_ID_LEN-1]; /* log ident */ write_file(LOG_DIR IDENT_LOG, sprintf("[%s] %s@s%s\n", ctime(time())[4..15], LOCAL_ID(fd), SOCKADDR(fd), user_id)); /* perform callback (if possible) */ if (CALLBACK(fd) && ID_OWNER(fd)) (*CALLBACK(fd))(ID_OWNER(fd), user_id); } else if ((i = strsrch(str, "ERROR")) != -1) { i = strsrch(str, ':', i); /* log error */ write_file(LOG_DIR IDENT_LOG, sprintf("[%s] %s@%s error%s\n", ctime(time())[4..15], LOCAL_ID(fd), SOCKADDR(fd), str[i..<3])); } close_cb(fd); } /* * send ident request to remote server */ void write_cb(int fd, string str) { int ret; if (undefinedp(sockinfo[fd]) || // !(origin() & (ORIGIN_DRIVER | ORIGIN_LOCAL))) ( (origin() != ORIGIN_DRIVER) && (origin()!=ORIGIN_LOCAL) ) ) return; if ((ret = socket_write(fd, str)) == EESUCCESS || ret == EECALLBACK) /* wait for the reply */ ; else if (ret == EEWOULDBLOCK || ret == EEALREADY) /* can't service request at this time...try again later */ call_out("write_cb", 15, str); else { /* * can't service request at all...just give up; * log it only if we haven't logged it before */ if (undefinedp(noident[SOCKADDR(fd)])) { write_file(LOG_DIR IDENT_ERR_LOG, sprintf("[%s] %s@%s: GAVE UP", ctime(time())[4..15], LOCAL_ID(fd), SOCKADDR(fd))); noident[SOCKADDR(fd)] = IDENT_GAVE_UP; } close_cb(fd); } } /* * close socket, and take care of internal accounting */ void close_cb(int fd) { if (undefinedp(sockinfo[fd]) || ( (origin()==ORIGIN_DRIVER)||(origin()==ORIGIN_LOCAL) ) ) return; map_delete(sockinfo, fd); socket_close(fd); } /* * periodically scan sockinfo for timed-out ident requests * (ie response not received) */ void check_connections() { int *fds, s; if (fds = keys(sockinfo)) { s = sizeof(fds); while (s--) /* timed-out...remove */ if ((TREQUEST(fds[s]) + TIMEOUT_AUTH_INTERVAL) > time()) { close_cb(fds[s]); /* log it only if we haven't logged it before */ if (undefinedp(noident[SOCKADDR(fds[s])])) { write_file(LOG_DIR IDENT_ERR_LOG, sprintf("[%s] %s@%s: TIMED OUT", ctime(time())[4..15], LOCAL_ID(fds[s]), SOCKADDR(fds[s]))); noident[SOCKADDR(fds[s])] = IDENT_TIMED_OUT; } } } call_out("check_connections", TIMEOUT_AUTH_CHECK); } /* eof */