Postfix version of smmapd
Benjamin Donnachie
benjamin at pythagoras.no-ip.org
Sat Jan 13 17:14:49 EST 2007
I couldn't find anything suitable through Google, so I modified smmapd
to work with postfix. Unfortunately, I haven't been able to test it
fully yet as the version of postfix with my distro doesn't support tcp
look ups (And I'm too lazy to recompile at the moment!).
However, tests over telnet were fine and this patch against cyrus-imapd
v2.3.7 might be useful to someone...
Ben
-------------- next part --------------
--- smmapd.c 2005-07-01 23:13:45.000000000 +0100
+++ postmapd.c 2007-01-13 21:30:23.000000000 +0000
@@ -37,42 +37,27 @@
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * smmapd.c -- sendmail socket map daemon
+ * postmapd.c -- postfix local recipient table lookup.
+ * Adapted by Ben Donnachie from smmapd.c -- sendmail socket map daemon
*
+ * Postfix table lookups can be directed to a TCP server.
*
- * From Sendmail Operations Guide:
+ * Request format:
+ * get SPACE key NEWLINE
+ * Lookup data under the specified key
+ * put SPACE key SPACE value NEWLINE
+ * Not currently implemented
+ *
+ * Reply format:
+ * 500 SPACE text NEWLINE
+ * Requested data does not exist. Text describes nature of problem.
+ * 400 SPACE text NEWLINE
+ * Temporary error condition. Text describes nature of problem.
+ * 200 SPACE text NEWLINE
+ * Request was successful. Text contains encoded version of data.
*
- * The socket map uses a simple request/reply protocol over TCP or
- * UNIX domain sockets to query an external server. Both requests and
- * replies are text based and encoded as netstrings, i.e., a string
- * "hello there" becomes:
+ * $Id: postmapd.c,v 1.1.1.1 2007/01/13 21:29:45 benjamin Exp $
*
- * 11:hello there,
- *
- * Note: neither requests nor replies end with CRLF.
- *
- * The request consists of the database map name and the lookup key
- * separated by a space character:
- *
- * <mapname> <key>
- *
- * The server responds with a status indicator and the result (if any):
- *
- * <status> <result>
- *
- * The status indicator is one of the following upper case words:
- *
- * OK the key was found, result contains the looked up value
- * NOTFOUND the key was not found, the result is empty
- * TEMP a temporary failure occured
- * TIMEOUT a timeout occured on the server side
- * PERM a permanent failure occured
- *
- * In case of errors (status TEMP, TIMEOUT or PERM) the result field
- * may contain an explanatory message.
- *
- *
- * $Id: smmapd.c,v 1.1.2.14 2005/07/01 22:13:45 ken3 Exp $
*/
#include <config.h>
@@ -334,6 +319,7 @@
}
sprintf(buf,"%d:cyrus %s,%c",strlen(key)+6,key,4);
+ // Does this get sent back to postfix?
sendto(soc,buf,strlen(buf),0,(struct sockaddr *)&sin,sizeof(sin));
x = sizeof(sfrom);
@@ -363,59 +349,41 @@
int begin_handling(void)
{
- int c;
- while ((c = prot_getc(map_in)) != EOF) {
- int r = 0, sawdigit = 0, len = 0, size = 0;
- struct auth_state *authstate = NULL;
- char request[MAXREQUEST+1];
- char *mapname = NULL, *key = NULL;
- const char *errstring = NULL;
-
- if (signals_poll() == SIGHUP) {
- /* caught a SIGHUP, return */
- return 0;
- }
+ while (SIGHUP != signals_poll()) {
- while (isdigit(c)) {
- sawdigit = 1;
- len = len*10 + c - '0';
- if (len > MAXREQUEST || len < 0) {
- /* we overflowed */
+ char request[MAXREQUEST+2];
+ char *key = NULL;
+ const char *errstring = NULL;
+ int r = 0, length = 0;
+ struct auth_state *authstate = NULL;
+
+ if (0 == (length = prot_read (map_in, (char *) &request, MAXREQUEST+1))) {
+ fatal("Error reading stream", EC_IOERR);
+ }
+
+ if (length > MAXREQUEST || length < 0) {
fatal("string too big", EC_IOERR);
- }
- c = prot_getc(map_in);
- }
- if (c == EOF) {
- errstring = prot_error(map_in);
- r = IMAP_IOERROR;
- }
- if (!sawdigit || c != ':') {
- errstring = "missing length";
- r = IMAP_PROTOCOL_ERROR;
- }
- if (!r && prot_read(map_in, request, len) != len) {
- errstring = "request size doesn't match length";
- r = IMAP_PROTOCOL_ERROR;
- }
- if (!r && (c = prot_getc(map_in)) != ',') {
- errstring = "missing terminator";
- r = IMAP_PROTOCOL_ERROR;
- }
+ }
- if (!r) {
- request[len] = '\0';
- mapname = request;
- if (!(key = strchr(request, ' '))) {
- errstring = "missing key";
+ if (strncmp("GET", request, 3) && strncmp("get", request, 3)) {
+ errstring = "unknown request";
r = IMAP_PROTOCOL_ERROR;
- }
}
- if (!r) {
- *key++ = '\0';
+ while (length > 1 && (request[length-1] == '\r' || request[length-1] == '\n'))
+ length--;
+
+ request[length] = '\0';
- r = verify_user(key, size, authstate);
+ if (!r && ((length < 5) || (request[3] != ' '))) {
+ errstring = "missing key";
+ r = IMAP_PROTOCOL_ERROR;
+ }
+
+ if (!r) {
+ key=&request[4];
+ r = verify_user(key, strlen(key), authstate);
}
switch (r) {
@@ -424,35 +392,32 @@
break;
case 0:
- prot_printf(map_out, "%d:OK %s,", 3+strlen(key), key);
+ prot_printf(map_out, "200 %s\r\n", key);
break;
case IMAP_MAILBOX_NONEXISTENT:
- prot_printf(map_out, "%d:NOTFOUND %s,",
- 9+strlen(error_message(r)), error_message(r));
+ prot_printf(map_out, "500 %s\r\n", error_message(r));
break;
case IMAP_QUOTA_EXCEEDED:
if (!config_getswitch(IMAPOPT_LMTP_OVER_QUOTA_PERM_FAILURE)) {
- prot_printf(map_out, "%d:TEMP %s,", strlen(error_message(r))+5,
- error_message(r));
+ prot_printf(map_out, "400 %s\r\n", error_message(r));
break;
}
/* fall through - permanent failure */
default:
if (errstring)
- prot_printf(map_out, "%d:PERM %s (%s),",
- 5+strlen(error_message(r))+3+strlen(errstring),
- error_message(r), errstring);
+ prot_printf(map_out, "500 %s (%s)\r\n", error_message(r), errstring);
else
- prot_printf(map_out, "%d:PERM %s,",
- 5+strlen(error_message(r)), error_message(r));
+ prot_printf(map_out, "500 %s\r\n", error_message(r));
break;
}
- }
- return 0;
+ }
+
+ return 0;
+
}
void printstring(const char *s __attribute__((unused)))
More information about the Info-cyrus
mailing list