COPYRIGHT010064400001530000150000000016210655365420700127340ustar00millscserv00002540041553/* * Copyright University of Manitoba 1998. * Written by J. Gary mills * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. The author and the University of Manitoba are not responsible * for the consequences of use of this software, no matter how awful, * even if they arise from flaws in it. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Since few users ever read sources, * credits must appear in the documentation. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. Since few users * ever read sources, credits must appear in the documentation. * * 4. This notice may not be removed or altered. */ Changes010064400001530000150000000017000761035104700127210ustar00millscserv00002540041553 1.12: o Added support for DB 4.1.x o Included Makefile settings for AIX (David Barroso Berrueta) 1.11: o Added support for DB version 3.1.x. 1.10: o Added support for postfix (Jeff Johnson) and exim (Mark Clements) MTAs. o Included Makefile settings for FreeBSD 2.2.x (Forrest Aldrich). 1.9: o Fixed IP address byte order bug when RPC client and server ran on hosts with different byte orders (Konstantin Martynenko). 1.8: o Included Makefile settings for RedHat Linux (Andreas Fink). o Added a dracd-setup script for RedHat Linux (Andreas Fink). 1.7: o Added support for `rpcgen -C'. o Included Makefile settings for IRIX-6.2 (Ayamura Kikuchi). 1.6: o Added support for DB version 2.6. 1.5: o Source changes now recorded in a Changes file. o ps command fixed in dracd-setup (Brian J. Coan). o Reviewed IP address byte order issues (Brian J. Coan and Michael Tratz). o Added support for DB version 1.85 (Brian J. Coan). INSTALL010064400001530000150000000155370761035262200124740ustar00millscserv00002540041553These installation instructions are for specific operating systems and software levels, but should at least serve as examples. See the DRAC web page http://mail.cc.umanitoba.ca/drac/index.html for the most current instructions. DRAC is now incorporated into Debian Linux. You don't need to compile DRAC for this Linux version. For more information, see: http://packages.debian.org/drac http://ftp.debian.org/debian/pool/main/d/drac/ http://buildd.debian.org/build.php?arch=&pkg=drac http://bugs.debian.org/drac You _must_ compile DRAC with the same version of the Berkeley db package that was used to compile your copy of sendmail. This may not be the default version that is currently installed on your system. One way to determine this is `strings /usr/lib/sendmail | grep -i sleepy'. Versions 2.x, 3.x, or 4.x of the Berkeley db package (http://www.sleepycat.com/) is recommended, but version 1.85 will also work. The critical thing is to use the same version that was used to compile sendmail. 1) Edit Makefile to suit your system. For Solaris: INSTALL = /usr/ucb/install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DTI_RPC -DFCNTL_LOCK -DSYSINFO CC = RANLIB = : CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = -L/path/to/db/library -lnsl -ldb TSTLIBS = -L. -ldrac -lnsl MANLIB = 3 MANADM = 1m For SunOS 4.x: INSTALL = install EBIN = /usr/local/etc MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFLOCK_LOCK -DGETHOST CC = RANLIB = ranlib CFLAGS = -Dstrtoul=strtol $(DEFS) -g -I/path/to/db/include LDLIBS = -L/path/to/db/library -ldb TSTLIBS = -L. -ldrac RPCGENFLAGS = -I MANLIB = 3 MANADM = 8 For BSDI: INSTALL = install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFCNTL_LOCK -DGETHOST CC = RANLIB = ranlib CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = -L/path/to/db/library -ldb TSTLIBS = -L. -ldrac MANLIB = 3 MANADM = 8 For IRIX 6.2: INSTALL = /usr/bin/X11/bsdinst EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DTI_RPC -DFCNTL_LOCK -DSYSINFO -D_SVR4_TIRPC CC = RANLIB = : CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = -L/path/to/db/library -lnsl -ldb TSTLIBS = -L. -ldrac -lnsl MANLIB = 3 MANADM = 1m For NetBSD: INSTALL = install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFCNTL_LOCK -DGETHOST -DDASH_C CC = RANLIB = ranlib CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = TSTLIBS = -L. -ldrac RPCGENFLAGS = -C MANLIB = 3 MANADM = 8 For FreeBSD 2.2.x: INSTALL = install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFLOCK_LOCK -DGETHOST -DDASH_C CC = RANLIB = ranlib CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = TSTLIBS = -L. -ldrac RPCGENFLAGS = -I -C MANLIB = 3 MANADM = 8 For FreeBSD-4.1 with gdbm-1.8 INSTALL = install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFLOCK_LOCK -DGETHOST -DDASH_C CC = cc RANLIB = : CFLAGS = $(DEFS) -g -I/usr/local/include LDLIBS = TSTLIBS = -L. -ldrac RPCGENFLAGS = -C MANLIB = 3 MANADM = 1m For Linux: INSTALL = install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DSOCK_RPC -DFCNTL_LOCK -DGETHOST -DDASH_C CC = RANLIB = : CFLAGS = $(DEFS) -g LDLIBS = -ldb TSTLIBS = -L. -ldrac RPCGENFLAGS = -C -I MANLIB = 3 MANADM = 8 For AIX: INSTALL = /usr/ucb/install EBIN = /usr/local/sbin MAN = /usr/local/man/man DEFS = -DD_BSD -DBSD_INCLUDES -DSOCK_RPC -DFCNTL_LOCK -DGETHOST -DDEBUG CC = RANLIB = : CFLAGS = $(DEFS) -g -I/path/to/db/include LDLIBS = -L/path/to/db/library -ldb TSTLIBS = -L. -ldrac RPCGENFLAGS = MANLIB = 3 MANADM = 1m 2) Compile the package: $ make 3) Install the server: # make install 4) Install the man pages: # make install-man 5) Install the startup script: For Solaris, customize dracd-setup and install it in /etc/init.d , with a link S78dracd in /etc/rc2.d . 6) Start the daemon: For Solaris... # sh /etc/init.d/dracd-setup start 7) Modify POP/IMAP servers: The dracauth() client function is suitable for mail servers that run a separate instance for each mail user. It should be called just after the user has been authenticated successfully. Other mail servers will require a more complex interface. See testing.c and dracauth.c for details. The server hostname can be specified as "localhost" if it's running on the same machine, but it would be better as a run-time configuration parameter. Here's a sample patch that works for qpopper: --------8<-------- *** pop_pass.c-nodrac Sat Jun 27 10:56:00 1998 --- pop_pass.c Wed Jul 22 22:54:04 1998 *************** *** 19,24 **** --- 19,28 ---- #include #include "popper.h" + #ifdef DRAC_AUTH + #include + #include + #endif /* DRAC_AUTH */ /* This error message is vague on purpose to help reduce help improve *************** *** 502,507 **** --- 506,519 ---- /* Initialize the last-message-accessed number */ p->last_msg = 0; + + #ifdef DRAC_AUTH + { + char *err; + if (dracauth("localhost", inet_addr(p->ipaddr), &err) != 0) + pop_log(p,POP_PRIORITY,err); + } + #endif /* DRAC_AUTH */ /* Authorization completed successfully */ return (pop_msg (p,POP_SUCCESS, *** make.solaris2-nodrac Sat Feb 17 14:25:15 1996 --- make.solaris2 Wed Jul 22 23:06:47 1998 *************** *** 39,45 **** -DAUTH -DMAILOCK -DDEBUG -DBINMAIL_IS_SETGID \ -DNO_AT_HOST -DNFS_SPOOL -DPOP_ACCT -DPOP_LLOG \ -DNONAUTHFILE=\"/etc/popper.deny\" \ ! -DBULLDIR=\"/var/spool/bulls\" TARGET = popper.solaris2 --- 39,45 ---- -DAUTH -DMAILOCK -DDEBUG -DBINMAIL_IS_SETGID \ -DNO_AT_HOST -DNFS_SPOOL -DPOP_ACCT -DPOP_LLOG \ -DNONAUTHFILE=\"/etc/popper.deny\" \ ! -DBULLDIR=\"/var/spool/bulls\" -DDRAC_AUTH TARGET = popper.solaris2 *************** *** 56,62 **** ${TARGET}: ${OBJS} ! ${CC} ${OBJS} -o ${TARGET} -lsocket -lnsl -lresolv -lkrb -lmail tar: ${SRCS} ${DOCS} ${MAKEFILE} rm -f ${TAR} *.Z* --- 56,62 ---- ${TARGET}: ${OBJS} ! ${CC} ${OBJS} -o ${TARGET} -L/usr/local/src/drac -ldrac -lsocket -lnsl -lresolv -lkrb -lmail tar: ${SRCS} ${DOCS} ${MAKEFILE} rm -f ${TAR} *.Z* --------8<-------- 8) Install the modified mail server: For qpopper, it's `make' and `make install'. 9) Modify sendmail.cf: For sendmail 8.9.0, add the following to your .mc file under LOCAL_CONFIG... # dynamic relay authorization control map Kdrac btree /etc/mail/dracd and the following under LOCAL_RULESETS... SLocal_check_rcpt # allow recent POP/IMAP mail clients to relay R$* $: $&{client_addr} R$+ $: $(drac $1 $: ? $) R? $@ ? R$+ $@ $#OK and then re-make the .cf file 10) Restart sendmail: The SMTP and queue daemons will need to be restarted. see: http://packages.debian.org/drac http://ftp.debian.org/debian/pool/main/d/drac/ http://buildd.debian.org/build.php?arch=&pkg=drac http://bugs.debian.orPORTING010064400001530000150000000021610673455177200125120ustar00millscserv00002540041553This package has only been compiled and tested under a small number of Unix operating systems. See the INSTALL file for details. Other operating systems will require at least a review of the Makefile settings. rpc.dracd handles IP addresses internally as unsigned longs in network byte order. struct in_addr and the conversion functions inet_addr() and inet_ntoa() are compatible with this format. The IP address sent over the RPC connection must be converted to host byte order before being sent, and converted to network byte order after being received, so as to work correctly on both big-endian and little-endian machines. The following unportable code sections in rpc.dracd.c may need to be conditionally-compiled for other systems. Most of this is now handled in the Makefile... o Include files o RPC server interface: svc_getreqset(), svc_fdset o Obtaining the client IP address: svc_getrpccaller(), taddr2uaddr(), getnetconfigent(), freenetconfigent() o Memory clearing and copying: memset(), memcpy() o Convert string to unsigned long: strtoul() o File locking: fcntl() o Obtaining the local host name: sysinfo() README010064400001530000150000000030070671757131500123210ustar00millscserv00002540041553 Dynamic Relay Authorization Control Please see the web page http://mail.cc.umanitoba.ca/drac/index.html for up to date information on DRAC. Description: o Uses Berkeley db package to maintain a relay authorization map for sendmail, /etc/mail/dracd.db . o POP and IMAP mail servers make an RPC call to add an entry to the authorization cache after they have authenticated each user. o The daemon, rpc.dracd, adds or updates entries in the cache, and periodically expires old entries. o Only trusted mail servers are permitted to communicate with rpc.dracd, as controlled by /etc/mail/dracd.allow . o The daemon can optionally re-create the database on startup. o Expiry time and cache file name can be set by command-line options. Issues: o Default trusted mail hosts: all local IP addresses. o Locking: must be compatible with sendmail. Lock around put() and sync() calls. Need locking for expiry as well. o Need periodic timing for expiry, not an idle timeout. o RPC contents: client IP address. o Database key: dotted decimal IP address. o Database value: ASCII expiry time. o Keys and values should not be nul-terminated. o Daemon should catch SIGTERM and close database. o Client library needs a timeout in case server is down. Enhancements: o Use ioctl() to obtain IP addresses of all interfaces. o Drop procedure in client library. o Time-to-live sent along with IP address. o Stronger client-server security. o Lazy syncing of database. o Database in shared memory (shared with sendmail). version.h010064400001530000150000000000270761035071300132640ustar00millscserv00002540041553#define VERSION "1.12" dracauth.3010064400001530000150000000046560660571167500133340ustar00millscserv00002540041553.\" dracauth(server, userip, errmsg) .\" Copyright University of Manitoba 1998. .TH dracauth 3 "22 Jul 1998" .SH NAME dracauth \- Dynamic Relay Authorization Control client interface .SH SYNOPSIS .LP .B cc .RI "[ " "flag" " \|.\|.\|. ] " "file" " \|.\|.\|." .B \-ldrac .RI "[ " "library" " \|.\|.\|. ]" .SH MT-LEVEL .LP Unsafe .SH DESCRIPTION .IX "Dynamic Relay Authorization Control client interface" "dracauth" "" "\(em \fLdracauth\fP" .PP Dynamic Relay Authorization Control uses Berkeley db package to maintain a relay authorization map for sendmail. POP and IMAP mail servers make an RPC call to add an entry to the authorization cache after they have authenticated each user. .SS Routines .PP .BI "dracauth(char *" "server" , .BI "unsigned long " "userip" , .BI "char **" "errmsg" ); .PP .BI "dracconn(char *" "server" , .BI "char **" "errmsg" ); .PP .BI "dracsend(unsigned long " "userip" , .BI "char **" "errmsg" ); .PP .BI "dracdisc(char **" "errmsg" ); .IP .B dracauth(\|) sends a request to the server running on host \f2server\f1 to authorize SMTP relaying from IP address \f2userip\f1. It does the connect, send, and disconnect in one operation. \f2errmsg\f1 is the address of an uninitialized character pointer. If this parameter is non-NULL, .B dracauth(\|) will store a pointer to an error message at this location. .IP .B dracconn(\|) initiates an RPC connection to the server running on host \f2server\f1. \f2errmsg\f1 is the address of an uninitialized character pointer. If this parameter is non-NULL, .B dracconn(\|) will store a pointer to an error message at this location. .IP .B dracsend(\|) sends a request over the RPC connection to authorize SMTP relaying from IP address \f2userip\f1. \f2errmsg\f1 is the address of an uninitialized character pointer. If this parameter is non-NULL, .B dracsend(\|) will store a pointer to an error message at this location. .IP .B dracdisc(\|) terminates the RPC connection. \f2errmsg\f1 is the address of an uninitialized character pointer. If this parameter is non-NULL, .B dracdisc(\|) will store a pointer to an error message at this location. .SH RETURN VALUES .PP All integer functions return .B 0 if the requested operation is successful, or non-zero and an error message pointer if the operation failed. .SH FILES .PD 0 .TP 20 .B libdrac.a .PD .SH "SEE ALSO" .BR rpc.dracd (1m) .SH NOTES This interface is unsafe in multithreaded applications. Unsafe interfaces should be called only from the main thread. rpc.dracd.1m010064400001530000150000000037000655565146700135470ustar00millscserv00002540041553.\" rpc.dracd [-i] [-e expire] [dbfile] '\"macro stdmacro .\" Copyright University of Manitoba 1998. .nr X .TH rpc.dracd 1M "22 Jul 1998" .SH NAME rpc.dracd \- Dynamic Relay Authorization Control server .SH SYNOPSIS \f3rpc.dracd\f1 [\|\f3\-i\f1\| ] [ \f3\-e \f2expire\f1 ] [ \f2dbfile\f1 ] .SH AVAILABILITY .LP ftp.cc.umanitoba.ca:/src .SH DESCRIPTION .IX "rpc.dracd command" "" "\fLrpc.dracd\fP \(em Dynamic Relay Authorization Control server" .IX "servers" "Dynamic Relay Authorization Control server" "" "Dynamic Relay Authorization Control server \(em \fLrpc.dracd\fP" \f4rpc.dracd\f1 is the Dynamic Relay Authorization Control server. It uses the Berkeley db package to maintain a relay authorization map for sendmail, by default \f4/etc/mail/dracd.db\f1. POP and IMAP mail servers make an RPC call to add an entry to the authorization cache after they have authenticated each user. The daemon, rpc.dracd, adds or updates entries in the cache, and periodically expires old entries. Only trusted mail servers are permitted to communicate with rpc.dracd, as controlled by \f4/etc/mail/dracd.allow\f1. If this file does not exist, all local IP addresses are permitted. .SS Allow File Format The Allow File file consists of entries of the form: .LP .RS \f4netmask \f2netaddr\fP\f1 .br .RE .LP where both .I netmask and .I netaddr must be dotted quads. .PD .RE .SH OPTIONS .TP 15 .BI \-i Initialize the database on startup. .TP .BI \-e \0expire Set the expire time limit. .I expire is the number of minutes the entries will remain in the database. It defaults to 30 minutes. .TP .BI dbfile Use a different database file name. .br .ne 4 .LP .SH FILES .PD 0 .TP 30 .B /etc/mail/dracd.db default database file .TP .B /etc/mail/dracd.allow default allow file. .PD .SH SEE ALSO .BR dracauth (3) .SH NOTES The following signals have the specified effect when sent to the server process using the .BR kill (1) command. .TP 20 .SM SIGTERM closes the database and terminates the server. dracd.allow-sample010064400001530000150000000003430713046343400150250ustar00millscserv00002540041553# dracd.allow: clients trusted by rpc.dracd # # The format of this file is one of more lines of # # netmask netaddr # Both netmask and netaddr must be dotted quads. # 255.255.255.255 192.168.16.8 255.255.255.255 127.0.0.1 #### dracd-setup010075500001530000150000000012330701112466700135710ustar00millscserv00002540041553#!/bin/sh - # # dracd-setup PATH=/usr/local/bin:/priv/usr/sbin:/usr/local/sbin:/usr/bin:/usr/sbin export PATH DAEMON=rpc.dracd #DRACD_PID=`ps -axc | grep 'rpc.dracd$' | sed -e 's/^ *//' -e 's/ .*//'` DRACD_PID=`ps -e | grep 'rpc.drac$' | sed -e 's/^ *//' -e 's/ .*//'` dracd_running() { ps -p $DRACD_PID >/dev/null 2>&1 } case "$1" in start) if dracd_running; then echo "$DAEMON is already running" >&2 else echo "starting $DAEMON" >&2 $DAEMON fi ;; stop) if dracd_running; then echo "stopping $DAEMON" >&2 kill $DRACD_PID else echo "$DAEMON is not running" >&2 fi ;; *) echo "Usage: /etc/init.d/dracd-setup {start|stop}" >&2 ;; esac #!/end dracd-setup.linux010075500001530000150000000012300671760145700147350ustar00millscserv00002540041553#!/bin/sh - # Put this file into /etc/rc.d/init.d/dracd # and link it intot he run levels you want to use it # by doing "ln -s /etc/rc.d/init.d/dracd /etc/rc.d/rc./S99dracd" # # dracd-setup # Source function library. . /etc/rc.d/init.d/functions # See how we were called. case "$1" in start) echo -n "Starting rpc.dracd daemon: " daemon rpc.dracd& echo touch /var/lock/subsys/rpc.dracd ;; stop) echo -n "Stopping rpc.dracd daemon: " killproc rpc.dracd echo rm -f /var/lock/subsys/rpc.dracd ;; *) echo "Usage: dracd {start|stop}" exit 1 esac exit 0 Makefile010064400001530000150000000055700761035173000130760ustar00millscserv00002540041553 #### Makefile for drac ## Tuneables # Paths INSTALL = /usr/ucb/install EBIN = /usr/local/sbin MAN = /usr/local/man/man # OS-Dependant settings # Choose one of this pair... # -DTI_RPC # Transport-independant RPC # -DSOCK_RPC # Socket RPC # Choose one of this pair... # -DFCNTL_LOCK # fcntl() locking # -DFLOCK_LOCK # flock() locking # Choose one of this pair... # -DSYSINFO # hostname from sysinfo() # -DGETHOST # hostname from gethostname() # If rpcgen -C is specified below... # -DDASH_C # ANSI-C mode # Settings for postfix and exim # Do not set these for sendmail # -DREQ_HASH # requires hash format # -DCIDR_KEY # keys in CIDR format # -DTERM_KD # keys and data nul-terminated DEFS = -DTI_RPC -DFCNTL_LOCK -DSYSINFO # Compiler flags CC = cc RANLIB = : CFLAGS = $(DEFS) -g -I/usr/local/src/db/db-4.1.25/build_unix #CFLAGS = $(DEFS) -g -I/usr/local/src/db/db-3.1.17/build_unix #CFLAGS = $(DEFS) -g -I/usr/local/src/db/db-2.4.14/Unix #CFLAGS = $(DEFS) -g -I/usr/local/src/db/db.1.85/PORT/sunos.5.2/include LDLIBS = -L/usr/local/src/db/db-4.1.25/build_unix -lnsl -ldb-4.1 #LDLIBS = -L/usr/local/src/db/db-3.1.17/build_unix -lnsl -ldb #LDLIBS = -L/usr/local/src/db/db-2.4.14/Unix -lnsl -ldb #LDLIBS = -L/usr/local/src/db/db.1.85/PORT/sunos.5.2 -lnsl -ldb TSTLIBS = -L. -ldrac -lnsl RPCGENFLAGS = #RPCGENFLAGS = -C # Man sections MANLIB = 3 MANADM = 1m ## Nothing to change after this point # Package files DOCFILES = COPYRIGHT Changes INSTALL PORTING README version.h dracauth.3 \ rpc.dracd.1m dracd.allow-sample dracd-setup dracd-setup.linux MAKEFILE = Makefile RPC_SRC = drac.x LIB_SRC = dracauth.c SVC_SRC = rpc.dracd.c TST_SRC = testing.c PACKAGE = $(DOCFILES) $(MAKEFILE) $(RPC_SRC) $(LIB_SRC) $(SVC_SRC) $(TST_SRC) # Final targets CLIENT = testing SERVER = rpc.dracd LIBRAR = libdrac.a # rpcgen output RPC_H = drac.h RPC_XDR = drac_xdr.c RPC_SVC = drac_svc.c RPC_CLNT = drac_clnt.c RPC_ALL = $(RPC_H) $(RPC_XDR) $(RPC_SVC) $(RPC_CLNT) # Object files LIB_OBJ = dracauth.o SVC_OBJ = rpc.dracd.o TST_OBJ = testing.o H_OBJS = drac_xdr.o drac_svc.o drac_clnt.o $(SVC_OBJ) $(LIB_OBJ) L_OBJS = $(LIB_OBJ) drac_xdr.o drac_clnt.o S_OBJS = $(SVC_OBJ) drac_xdr.o drac_svc.o # Rules all: $(CLIENT) $(SERVER) $(RPC_ALL): $(RPC_SRC) rpcgen $(RPCGENFLAGS) $(RPC_SRC) $(H_OBJS): $(RPC_H) $(LIB_OBJ) $(SVC_OBJ): $(MAKEFILE) $(LIBRAR): $(L_OBJS) rm -f $@ ar cq $@ $(L_OBJS) $(RANLIB) $@ $(CLIENT): $(TST_OBJ) $(LIBRAR) $(CC) -o $(CLIENT) $(TST_OBJ) $(TSTLIBS) $(SERVER): $(S_OBJS) $(CC) -o $(SERVER) $(S_OBJS) $(LDLIBS) clean: rm -f core $(RPC_ALL) $(H_OBJS) $(TST_OBJ) $(CLIENT) \ $(SERVER) $(LIBRAR) tar: $(PACKAGE) tar cf drac.tar $(PACKAGE) install: $(SERVER) $(INSTALL) -c -o bin -g bin -m 0755 $(SERVER) $(EBIN) install-man: $(SERVER).1m dracauth.3 $(INSTALL) -c -m 0444 $(SERVER).1m $(MAN)$(MANADM)/$(SERVER).$(MANADM) $(INSTALL) -c -m 0444 dracauth.3 $(MAN)$(MANLIB)/dracauth.$(MANLIB) drac.x010064400001530000150000000010440656372275600125500ustar00millscserv00002540041553/* * Dynamic Relay Authorization Control */ #ifdef RPC_SVC %#define svc_run drac_run %#define main dracmain #endif #ifdef RPC_HDR %#ifndef CLIENT %#include %#endif #endif struct drac_add_parm { unsigned long ip_addr; /* In network order */ }; enum addstat { ADD_SUCCESS, /* Succeeded */ ADD_PERM, /* Permission denied */ ADD_SYSERR, /* System error */ ADD_UNKOWN /* Unknown */ }; program DRACPROG { version DRACVERS { /* * Update my passwd entry */ addstat DRACPROC_ADD(drac_add_parm) = 1; } = 1; } = 900101; ntrol */ #ifdef RPC_SVC %#define svc_run drac_run %#define main dracmain #endif #ifdef RPC_HDR %#ifndef CLIENT %#include %#endif #endif struct drac_add_parm { unsigned long ip_addr; /* In network order */ }; enum addstat { ADD_SUCCESS, /* Succeeded */ ADD_PERM, /* Permission denied */ ADD_SYSERR, /* System error */ ADD_UNKOWN /* Unknown */ }; program DRACPROG { version DRACVERS { /* * Update my passwd entry */ addstat DRACPROC_ADD(dracdracauth.c010064400001530000150000000061320673456306000133770ustar00millscserv00002540041553/* * DRAC client library functions: * * dracauth(server, userip, errmsg) * server = hostname of DRAC server * userip = IP address to authorize for relaying * errmsg = place to store pointer to error message * * dracconn(server, errmsg) * server = hostname of DRAC server * errmsg = place to store pointer to error message * dracsend(userip, errmsg) * userip = IP address to authorize for relaying * errmsg = place to store pointer to error message * dracdisc(errmsg) * errmsg = place to store pointer to error message */ #include #include #include "drac.h" int dracauth(server, userip, errmsg) char *server; unsigned long userip; char **errmsg; { CLIENT *clnt; addstat *result; drac_add_parm dracproc_add_1_arg; #ifdef TI_RPC clnt = clnt_create(server, DRACPROG, DRACVERS, "datagram_v"); #endif #ifdef SOCK_RPC clnt = clnt_create(server, DRACPROG, DRACVERS, "udp"); #endif if (clnt == (CLIENT *) NULL) { if ( errmsg ) *errmsg = clnt_spcreateerror(server); return (-1); } dracproc_add_1_arg.ip_addr = ntohl(userip); /* to host byte order */ result = dracproc_add_1(&dracproc_add_1_arg, clnt); if (result == (addstat *) NULL) { if ( errmsg ) *errmsg = clnt_sperror(clnt, "call failed"); clnt_destroy(clnt); return (-2); } clnt_destroy(clnt); if ( errmsg ) { switch (*result) { case ADD_SUCCESS: *errmsg = "Server reports add succeeded"; break; case ADD_PERM: *errmsg = "Server reports permission denied"; break; case ADD_SYSERR: *errmsg = "Server reports system error"; break; default: *errmsg = "Server reports unknown error"; } } return *result; } static CLIENT *clnt; int dracconn(server, errmsg) char *server; char **errmsg; { #ifdef TI_RPC clnt = clnt_create(server, DRACPROG, DRACVERS, "datagram_v"); #endif #ifdef SOCK_RPC clnt = clnt_create(server, DRACPROG, DRACVERS, "udp"); #endif if (clnt == (CLIENT *) NULL) { if ( errmsg ) *errmsg = clnt_spcreateerror(server); return (-1); } if ( errmsg ) *errmsg = "Connect succeeded"; return 0; } int dracsend(userip, errmsg) unsigned long userip; char **errmsg; { addstat *result; drac_add_parm dracproc_add_1_arg; if (clnt == (CLIENT *) NULL) { if ( errmsg ) *errmsg = "Not connected"; return (-1); } dracproc_add_1_arg.ip_addr = ntohl(userip); /* to host byte order */ result = dracproc_add_1(&dracproc_add_1_arg, clnt); if (result == (addstat *) NULL) { if ( errmsg ) *errmsg = clnt_sperror(clnt, "call failed"); return (-2); } if ( errmsg ) { switch (*result) { case ADD_SUCCESS: *errmsg = "Server reports add succeeded"; break; case ADD_PERM: *errmsg = "Server reports permission denied"; break; case ADD_SYSERR: *errmsg = "Server reports system error"; break; default: *errmsg = "Server reports unknown error"; } } return *result; } int dracdisc(errmsg) char **errmsg; { if (clnt == (CLIENT *) NULL) { if ( errmsg ) *errmsg = "Not connected"; return (-1); } clnt_destroy(clnt); clnt = (CLIENT *) NULL; if ( errmsg ) *errmsg = "Disconnect succeeded"; return 0; } /**/ rpc.dracd.c010064400001530000150000000275210761034717600134530ustar00millscserv00002540041553/* * rpc.dracd: Dynamic Relay Authorization Control daemon */ #include #include #include #include #include #ifdef TI_RPC #include #include #endif #include #include #include #include #include #include #include #include #include #include #ifdef FLOCK_LOCK #include #endif #ifdef SYSINFO #include #endif #ifdef GETHOST #include #include #endif #ifndef DB_VERSION_MAJOR #define DB_VERSION_MAJOR 1 #endif #include "drac.h" #define DBFILE "/etc/mail/dracd.db" #define ALFILE "/etc/mail/dracd.allow" struct net_def { struct net_def *nd_next; struct in_addr nd_mask; struct in_addr nd_addr; }; int initdb = 0; /* initialize database option */ int terminate = 0; /* terminate daemon flag */ long explimit = 30 * 60; /* expiry limit (seconds) */ char *dbfile = DBFILE; /* database file name */ char *alfile = ALFILE; /* allow file name */ struct net_def *net_tbl; /* trusted network table */ #if DB_VERSION_MAJOR < 2 #elif DB_VERSION_MAJOR == 2 DB_ENV *dbenv; /* db environment structure */ #else #endif DB *dbp; /* DB structure */ int dbfd; /* db file descriptor */ #ifdef DEBUG FILE *debugf; #endif /* On SIGTERM, must close db */ void catcher(n) int n; { terminate = 1; } /* Parse command-line options */ main(argc, argv) int argc; char **argv; { int c; extern char *optarg; extern int optind; while ((c = getopt(argc, argv, "ie:")) != EOF) { switch (c) { case 'i': initdb = 1; break; case 'e': explimit = atoi(optarg) * 60; break; case '?': fprintf(stderr, "Usage: %s [-i] [-e expire] [dbfile]\n", argv[0]); exit(2); } } if ( optind < argc ) dbfile = argv[optind]; dracmain(); /* the main function from rpcgen */ exit(1); } /* Called once after fork */ drac_run() { int sel; time_t nexte, now; fd_set readfs; struct timeval to; #if DB_VERSION_MAJOR < 2 #ifndef REQ_HASH BTREEINFO bti; #endif #elif DB_VERSION_MAJOR == 2 DB_ENV adbenv; DB_INFO dbinfo; #else #endif #ifdef DEBUG debugf = fopen("/var/tmp/drac.debug", "a+"); #endif iniclist(); /* Schedule the next expire */ nexte = time((time_t *)NULL) + explimit / 10; /* Catch SIGTERM */ signal(SIGTERM, catcher); /* Open the database and save the file descriptor */ #if DB_VERSION_MAJOR < 2 #ifdef REQ_HASH errno = 0; dbp = dbopen(dbfile, (initdb) ? O_CREAT|O_TRUNC|O_RDWR : O_CREAT|O_RDWR, 0644, DB_HASH, (void *)NULL); #else memset(&bti, 0, sizeof(bti)); bti.psize = 512; errno = 0; dbp = dbopen(dbfile, (initdb) ? O_CREAT|O_TRUNC|O_RDWR : O_CREAT|O_RDWR, 0644, DB_BTREE, &bti); #endif #elif DB_VERSION_MAJOR == 2 memset(&adbenv, 0, sizeof(adbenv)); dbenv = &adbenv; memset(&dbinfo, 0, sizeof(dbinfo)); dbinfo.db_pagesize = 512; #ifdef REQ_HASH errno = db_open(dbfile, DB_HASH, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644, dbenv, &dbinfo, &dbp); #else errno = db_open(dbfile, DB_BTREE, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644, dbenv, &dbinfo, &dbp); #endif #elif DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 errno = db_create(&dbp, NULL, 0); if ( errno != 0 ) { syslog(LOG_ERR, "drac_run db_create failed: %m"); exit(3); } dbp->set_pagesize(dbp, 512); #ifdef REQ_HASH errno = dbp->open(dbp, NULL, dbfile, NULL, DB_HASH, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644); #else errno = dbp->open(dbp, NULL, dbfile, NULL, DB_BTREE, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644); #endif #else errno = db_create(&dbp, NULL, 0); if ( errno != 0 ) { syslog(LOG_ERR, "drac_run db_create failed: %m"); exit(3); } dbp->set_pagesize(dbp, 512); #ifdef REQ_HASH errno = dbp->open(dbp, dbfile, NULL, DB_HASH, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644); #else errno = dbp->open(dbp, dbfile, NULL, DB_BTREE, (initdb) ? DB_TRUNCATE|DB_CREATE : DB_CREATE, 0644); #endif #endif if ( errno != 0 ) { syslog(LOG_ERR, "drac_run open failed: %m"); exit(3); } #if DB_VERSION_MAJOR < 2 errno = 0; dbfd = dbp->fd(dbp); #else errno = dbp->fd(dbp, &dbfd); #endif if ( errno != 0 ) { syslog(LOG_ERR, "drac_run fd failed: %m"); exit(3); } /* Repeat forever */ while (1) { #ifdef DEBUG fprintf(debugf, "Select bits: %x\n", svc_fdset.fds_bits[0]); fflush(debugf); #endif /* Wait for action */ memcpy(&readfs, &svc_fdset, sizeof(fd_set)); to.tv_sec = explimit / 10; to.tv_usec = 0L; sel = select(FD_SETSIZE, &readfs, (fd_set *)NULL, (fd_set *)NULL, &to); now = time((time_t *)NULL); switch ( sel ) { case 0: /* Timeout */ nexte = now + explimit / 10; expire(); break; case (-1): /* Error */ if ( errno != EINTR ) { syslog(LOG_ERR, "drac_run select failed: %m"); } else if ( terminate ) { #if DB_VERSION_MAJOR < 2 (void)dbp->close(dbp); #else (void)dbp->close(dbp, 0); #endif exit(0); } break; default: /* Ready */ if ( now >= nexte ) { nexte = now + explimit / 10; expire(); } svc_getreqset(&readfs); /* Service the request */ } } } /* Add an entry to the database */ addstat * #ifdef DASH_C dracproc_add_1_svc(argp, rqstp) #else dracproc_add_1(argp, rqstp) #endif drac_add_parm *argp; struct svc_req *rqstp; { static addstat result; #ifdef TI_RPC struct netbuf *nb; struct netconfig *nc; char *cad, *pt; #endif #ifdef SOCK_RPC struct sockaddr_in *si; #endif struct in_addr client_ip, requ_ip; DBT key, data; char akey[32], alimit[32]; struct net_def *nd; result = ADD_SUCCESS; /* Get the IP address of the client */ #ifdef TI_RPC if ( (nc = getnetconfigent(rqstp->rq_xprt->xp_netid)) == NULL || (nb = svc_getrpccaller(rqstp->rq_xprt)) == NULL || (cad = taddr2uaddr(nc, nb)) == NULL ) { if (nc) freenetconfigent(nc); result = ADD_SYSERR; return (&result); } if ( (pt = strrchr(cad, '.')) != NULL ) *pt = '\0'; if ( (pt = strrchr(cad, '.')) != NULL ) *pt = '\0'; client_ip.s_addr = inet_addr(cad); freenetconfigent(nc); free(cad); #endif #ifdef SOCK_RPC if ( (si = svc_getcaller(rqstp->rq_xprt)) == NULL ) { result = ADD_SYSERR; return (&result); } client_ip.s_addr = si->sin_addr.s_addr; #endif #ifdef DEBUG fprintf(debugf, "Client Address: %s\n", inet_ntoa(client_ip)); fflush(debugf); #endif /* Check agains the table of trusted clients */ for ( nd = net_tbl; nd != NULL; nd = nd->nd_next ) { if ( (client_ip.s_addr & nd->nd_mask.s_addr) == nd->nd_addr.s_addr ) break; } if ( nd == NULL ) { result = ADD_PERM; return (&result); } /* Set up for the add */ requ_ip.s_addr = htonl(argp->ip_addr); /* to network byte order */ #ifdef DEBUG fprintf(debugf, "Requested IP Address: %s\n", inet_ntoa(requ_ip)); fflush(debugf); #endif memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); strcpy(akey, inet_ntoa(requ_ip)); #ifdef CIDR_KEY strcat(akey, "/32"); #endif key.data = akey; #ifdef TERM_KD key.size = strlen(akey) + 1; #else key.size = strlen(akey); #endif sprintf(alimit, "%lu", time((time_t *)NULL) + explimit); data.data = alimit; #ifdef TERM_KD data.size = strlen(alimit) + 1; #else data.size = strlen(alimit); #endif /* Do the add and sync, with locking */ if ( lockdb() == (-1) ) { syslog(LOG_ERR, "dracproc_add_1 lockdb failed: %m"); } #if DB_VERSION_MAJOR < 2 errno = 0; dbp->put(dbp, &key, &data, 0); #else errno = dbp->put(dbp, NULL, &key, &data, 0); #endif if ( errno != 0 ) { syslog(LOG_ERR, "dracproc_add_1 put failed: %m"); result = ADD_SYSERR; } #if DB_VERSION_MAJOR < 2 errno = 0; dbp->sync(dbp, 0); #else errno = dbp->sync(dbp, 0); #endif if ( errno != 0 ) { syslog(LOG_ERR, "dracproc_add_1 sync failed: %m"); } (void)unlockdb(); /* Send result code back to client */ return (&result); } /* Expire old entries from the database */ expire() { #if DB_VERSION_MAJOR < 2 int seqerr, flags; #else DBC *dbcp; #endif DBT key, data; time_t old; char alimit[32]; /* Oldest possible entry is now */ old = time((time_t *)NULL); /* Lock the database */ if ( lockdb() == (-1) ) { syslog(LOG_ERR, "expire lockdb failed: %m"); } /* Obtain a cursor */ #if DB_VERSION_MAJOR < 2 flags = R_FIRST; #else # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6 errno = dbp->cursor(dbp, NULL, &dbcp, 0); #else errno = dbp->cursor(dbp, NULL, &dbcp); #endif if ( errno != 0 ) { syslog(LOG_ERR, "expire cursor failed: %m"); return 0; } #endif /* Scan the database, deleting old entries */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); #if DB_VERSION_MAJOR < 2 while ((seqerr = dbp->seq(dbp, &key, &data, flags)) == 0) { flags = R_NEXT; #else while ((errno = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { #endif memcpy(alimit, data.data, data.size); #ifndef TERM_KD alimit[data.size] = '\0'; #endif if ( strtoul(alimit, (char **)NULL, 10) < old ) { #if DB_VERSION_MAJOR < 2 errno = 0; dbp->del(dbp, &key, R_CURSOR); #else errno = dbcp->c_del(dbcp, 0); #endif if ( errno != 0 ) { syslog(LOG_ERR, "expire c_del failed: %m"); } } } #if DB_VERSION_MAJOR < 2 if (seqerr != 1) { #else if (errno != DB_NOTFOUND) { #endif syslog(LOG_ERR, "expire c_get failed: %m"); } /* Discard the cursor */ #if DB_VERSION_MAJOR < 2 errno = 0; dbp->sync(dbp, 0); #else (void)dbcp->c_close(dbcp); errno = dbp->sync(dbp, 0); #endif if ( errno != 0 ) { syslog(LOG_ERR, "expire sync failed: %m"); } /* Unlock the database */ (void) unlockdb(); } /* Lock the database */ lockdb() { #ifdef FCNTL_LOCK struct flock lfd; memset(&lfd, 0, sizeof(lfd)); lfd.l_type = F_WRLCK; return fcntl(dbfd, F_SETLKW, &lfd); #endif #ifdef FLOCK_LOCK return flock(dbfd, LOCK_EX); #endif } /* Unlock the database */ unlockdb() { #ifdef FCNTL_LOCK struct flock lfd; memset(&lfd, 0, sizeof(lfd)); lfd.l_type = F_UNLCK; return fcntl(dbfd, F_SETLK, &lfd); #endif #ifdef FLOCK_LOCK return flock(dbfd, LOCK_UN); #endif } /* Initialize the trusted client table */ /* All in network byte order */ iniclist() { FILE *alfp; char buf[128], mask[32], addr[32], hname[128]; struct net_def *nd; struct hostent *he; unsigned long **p; /* Check if the allow file exists */ if ( (alfp = fopen(alfile, "r")) != NULL ) { /* Read lines from the file */ while ( fgets(buf, sizeof(buf), alfp) != NULL ) { if ( buf[0] == '#' ) continue; if ( sscanf(buf, "%[0-9.] %[0-9.]", mask, addr) == 2 ) { /* Create table entry from the line */ nd = (struct net_def *)malloc(sizeof(struct net_def)); if ( nd != NULL ) { nd->nd_next = net_tbl; nd->nd_mask.s_addr = inet_addr(mask); nd->nd_addr.s_addr = inet_addr(addr); net_tbl = nd; } else { syslog(LOG_ERR, "iniclist malloc failed"); } } } } else { /* Default to loopback address */ nd = (struct net_def *)malloc(sizeof(struct net_def)); if ( nd != NULL ) { nd->nd_next = net_tbl; nd->nd_mask.s_addr = htonl(0xffffffff); nd->nd_addr.s_addr = htonl(0x7f000001); net_tbl = nd; } /* Add local IP addresses */ #ifdef SYSINFO (void)sysinfo(SI_HOSTNAME, hname, sizeof(hname)); #endif #ifdef GETHOST (void)gethostname(hname, sizeof(hname)); #endif if ( (he = gethostbyname(hname)) != NULL ) { for (p = (unsigned long **)he->h_addr_list; *p != NULL; p++) { nd = (struct net_def *)malloc(sizeof(struct net_def)); if ( nd != NULL ) { nd->nd_next = net_tbl; nd->nd_mask.s_addr = htonl(0xffffffff); nd->nd_addr.s_addr = **p; net_tbl = nd; } else { syslog(LOG_ERR, "iniclist malloc failed"); } } } } } /**/ testing.c010064400001530000150000000006770656372001600132650ustar00millscserv00002540041553/* * Test client for dracauth */ #include #include #include #include main(argc, argv) int argc; char *argv[]; { int rc; char *host; unsigned long ip; char *err; if (argc < 3) { printf("usage: %s server_host client_addr\n", argv[0]); exit(1); } host = argv[1]; ip = inet_addr(argv[2]); rc = dracauth(host, ip, &err); if (rc != 0) printf("%s: %s\n", argv[0], err); }