Index: src/util/Makefile.in --- src/util/Makefile.in.orig 2005-04-29 23:12:46 +0200 +++ src/util/Makefile.in 2005-07-09 11:40:08 +0200 @@ -3,7 +3,7 @@ attr_scan0.c attr_scan64.c base64_code.c basename.c binhash.c \ chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \ dict.c dict_alloc.c dict_db.c dict_cdb.c dict_dbm.c dict_debug.c dict_env.c \ - dict_cidr.c dict_ht.c dict_ni.c dict_nis.c \ + dict_cidr.c dict_ht.c dict_ni.c dict_nis.c dict_whoson.c \ dict_nisplus.c dict_open.c dict_pcre.c dict_regexp.c \ dict_static.c dict_tcp.c dict_unix.c dir_forest.c doze.c \ duplex_pipe.c environ.c events.c exec_command.c fifo_listen.c \ @@ -35,7 +35,7 @@ attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \ chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \ dict.o dict_alloc.o dict_db.o dict_cdb.o dict_dbm.o dict_debug.o dict_env.o \ - dict_cidr.o dict_ht.o dict_ni.o dict_nis.o \ + dict_cidr.o dict_ht.o dict_ni.o dict_nis.o dict_whoson.o \ dict_nisplus.o dict_open.o dict_pcre.o dict_regexp.o \ dict_static.o dict_tcp.o dict_unix.o dir_forest.o doze.o \ duplex_pipe.o environ.o events.o exec_command.o fifo_listen.o \ @@ -65,7 +65,7 @@ myaddrinfo.o sock_addr.o inet_proto.o cidr_match.o mask_addr.o HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ connect.h ctable.h dict.h dict_db.h dict_cdb.h dict_dbm.h dict_env.h \ - dict_cidr.h dict_ht.h dict_ni.h dict_nis.h \ + dict_cidr.h dict_ht.h dict_ni.h dict_nis.h dict_whoson.h \ dict_nisplus.h dict_pcre.h dict_regexp.h \ dict_static.h dict_tcp.h dict_unix.h dir_forest.h events.h \ exec_command.h find_inet.h fsspace.h fullname.h get_domainname.h \ Index: src/util/dict_open.c --- src/util/dict_open.c.orig 2005-03-17 17:33:02 +0100 +++ src/util/dict_open.c 2005-07-09 11:38:47 +0200 @@ -192,6 +192,7 @@ #include #include #include +#include /* * lookup table for available map types. @@ -237,6 +238,7 @@ #endif DICT_TYPE_STATIC, dict_static_open, DICT_TYPE_CIDR, dict_cidr_open, + DICT_TYPE_WHOSON, dict_whoson_open, 0, }; Index: src/util/dict_whoson.c --- /dev/null 2005-07-09 11:40:21 +0200 +++ src/util/dict_whoson.c 2005-07-09 11:38:47 +0200 @@ -0,0 +1,269 @@ +/*++ +/* NAME +/* dict_whoson 3 +/* SUMMARY +/* dictionary manager interface to whoson lookup tables +/* SYNOPSIS +/* #include +/* +/* DICT *dict_whoson_open(map, dummy, dict_flags) +/* const char *map; +/* int dummy; +/* int dict_flags; +/* DESCRIPTION +/* dict_whoson_open() make a WHOSON server accessible +/* via the generic dictionary operations described in +/* dict_open(3). +/* The \fIdummy\fR argument is not used. The only implemented +/* operation is dictionary lookup. +/* +/* Map names have the form host:port in case of a TCP +/* whoson server or /path/to/socket in case of a Unix domain +/* server. +/* +/* WHOSON protocol is designed to allow mail relay to +/* a given IP adress on a smtpd server without requiring +/* an SMTP authentication. Authentication has to be trusted +/* from another source (for example, a POP server) +/* +/* Keys have to be full IP addresses. If a value is found +/* for a key, lookup reply will be the constant string "OK", +/* the IP address key and the whoson server answer are logged. +/* +/* SEE ALSO +/* dict(3) generic dictionary manager +/* DIAGNOSTICS +/* Fatal errors: out of memory, unknown host or service name, +/* attempt to update or iterate over map. +/* Warnings: unable to connect to whoson server, connection +/* close, whoson server error. +/* BUGS +/* Only the lookup method is currently implemented. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include "sys_defs.h" +#include +#include + +#include "msg.h" +#include "mymalloc.h" +#include "vstring.h" +#include "vstream.h" +#include "vstring_vstream.h" +#include "valid_hostname.h" +#include "connect.h" +#include "stringops.h" +#include "dict_whoson.h" +#include "dict.h" + + +typedef struct { + DICT dict; /* generic members */ + VSTRING *input; /* raw I/O buffer */ + VSTRING *dummy; /* raw I/O buffer to skip empty lines */ + VSTREAM *fp; /* I/O stream */ +} DICT_WHOSON; + +#define DICT_WHOSON_TMOUT 100 + +/* + * Does the server stop when the whoson server fails ? + * + * According the nature of the map, it should be a bad thing + * exepted on a dedicaced SMTP after POP server. + */ + +#undef DICT_WHOSON_INSISTS + +#ifdef DICT_WHOSON_INSISTS +# define DICT_WHOSON_MAXTRY 10 +# define DICT_WHOSON_ERROR DICT_ERR_RETRY +#else +# define DICT_WHOSON_MAXTRY 10 +# define DICT_WHOSON_ERROR DICT_ERR_NONE +#endif + + +#define STR(x) vstring_str(x) + +/* dict_whoson_connect - connect to whoson server */ + +static int dict_whoson_connect(DICT_WHOSON *dict_whoson) +{ + int fd; + if (dict_whoson->dict.name[0] == '/') { /* unix domain socket */ + fd = unix_connect(dict_whoson->dict.name, BLOCKING, 0); + } else { + fd = inet_connect(dict_whoson->dict.name, BLOCKING, 0); + } + if (fd < 0) { + msg_warn("connect to WHOSON map %s: %m", dict_whoson->dict.name); + return -1; + } + + dict_whoson->fp = vstream_fdopen(fd, O_RDWR); + + vstream_control(dict_whoson->fp, + VSTREAM_CTL_TIMEOUT, DICT_WHOSON_TMOUT, + VSTREAM_CTL_END); + + dict_whoson->fp = vstream_fdopen(fd, O_RDWR); + + if (dict_whoson->input == 0) { + dict_whoson->input = vstring_alloc(10); + dict_whoson->dummy = vstring_alloc(10); + } + return 0; + +} + +/* dict_whoson_disconnect - disconnect from whoson server */ + +static void dict_whoson_disconnect(DICT_WHOSON *dict_whoson) +{ + (void) vstream_fclose(dict_whoson->fp); + dict_whoson->fp = 0; +} + +/* dict_whoson_lookup - request whoson server */ + + +static const char *dict_whoson_lookup(DICT *dict, const char *key) +{ + DICT_WHOSON *dict_whoson = (DICT_WHOSON *) dict; + char *myname = "dict_whoson_lookup"; + char *reply; + char *end_of_reply; + char *dummy; + int tries; + +#define RETURN(errval, result) { dict_errno = errval; return (result); } + + if (msg_verbose) + msg_info("%s: key %s", myname, key); + + if (valid_hostaddr(key, 0) == 0) { + if (msg_verbose) + msg_info("%s: %s is not a host address, dont send it to whoson server", + myname, key); + RETURN(DICT_ERR_NONE, 0); + } + + for (tries = 0; /* see below */ ; /* see below */ ) { + + /* + * Connect to the server, or use an existing connection. + */ + if (dict_whoson->fp != 0 || dict_whoson_connect(dict_whoson) == 0) { + + vstream_fprintf(dict_whoson->fp, "QUERY %s\r\n\r\n", key); + if (vstring_get_nonl(dict_whoson->input, dict_whoson->fp) > 0) { + + reply = STR(dict_whoson->input); + + /* + * wait for an empty line + */ + while(vstring_get_nonl(dict_whoson->dummy, dict_whoson->fp)>0) { + dummy = STR(dict_whoson->dummy); + if (dummy[0] == '\r') dummy ++; + if (dummy[0] == '\0') break; + } + + end_of_reply=reply + strlen(reply); + if (reply != end_of_reply && end_of_reply[-1] == '\r') + end_of_reply[-1]='\0'; + + /* + * Parse the answer + */ + + if (reply[0] == '+') { + /* + * send the anwser in log file + */ + msg_info("%s: user found '%.100s' for [%s] from %s", myname, + reply+1, key, dict_whoson->dict.name); + + RETURN(DICT_ERR_NONE, "OK"); + + } else if (reply[0] == '-') { + if (msg_verbose) { + msg_info("%s: user not found for [%s] from %s", myname, + key, dict_whoson->dict.name); + } + RETURN(DICT_ERR_NONE, 0); + + } else if (reply[0] == '*') { + msg_warn("%s: read whoson map reply from %s: %.100s", myname, + dict_whoson->dict.name, printable(reply, '?')); + RETURN(DICT_WHOSON_ERROR, 0); + } else { + msg_warn("%s: read whoson map reply from %s: bad sequence", + myname, dict_whoson->dict.name); + dict_whoson_disconnect(dict_whoson); + RETURN(DICT_WHOSON_ERROR, 0); + } + } else { + msg_warn("%s: read whoson map reply from %s: unexpected EOF (%m)", + myname, dict_whoson->dict.name); + dict_whoson_disconnect(dict_whoson); + } + + } + + /* + * Try to connect a limited number of times before giving up. + */ + if (++tries >= DICT_WHOSON_MAXTRY) + RETURN(DICT_WHOSON_ERROR, 0); + + /* + * Sleep between attempts, instead of hammering the server. + */ + sleep(1); + + } + +} + +/* dict_whoson_close - close whoson MAP */ + +static void dict_whoson_close(DICT *dict) { + DICT_WHOSON *dict_whoson = (DICT_WHOSON *) dict; + + if (dict_whoson->fp) + (void) vstream_fclose(dict_whoson->fp); + if (dict_whoson->input) + vstring_free(dict_whoson->input); + if (dict_whoson->dummy) + vstring_free(dict_whoson->dummy); + dict_free(dict); +} + +/* dict_whoson_open - open whoson MAP */ + +DICT *dict_whoson_open(const char *map, int unused_flags, int dict_flags) +{ + DICT_WHOSON *dict_whoson; + dict_errno = 0; + dict_whoson = (DICT_WHOSON *) dict_alloc(DICT_TYPE_WHOSON, map, + sizeof(*dict_whoson)); + dict_whoson->dict.lookup = dict_whoson_lookup; + dict_whoson->input = dict_whoson->dummy = 0; + dict_whoson->dict.flags = dict_flags & ~DICT_FLAG_FIXED; + dict_whoson->dict.close = dict_whoson_close; + dict_whoson->fp = 0; + return (DICT_DEBUG(&dict_whoson->dict)); +} Index: src/util/dict_whoson.h --- /dev/null 2005-07-09 11:40:21 +0200 +++ src/util/dict_whoson.h 2005-07-09 11:38:47 +0200 @@ -0,0 +1,37 @@ +#ifndef _DICT_WHOSON_H_INCLUDED_ +#define _DICT_WHOSON_H_INCLUDED_ + +/*++ +/* NAME +/* dict_whoson 3h +/* SUMMARY +/* dictionary manager interface to whoson-based lookup tables +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +#define DICT_TYPE_WHOSON "whoson" + +extern DICT *dict_whoson_open(const char *, int, int); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif