ipop3d.c   ipop3d.c 
/* ======================================================================== /* ========================================================================
* Copyright 1988-2007 University of Washington * Copyright 1988-2008 University of Washington
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* *
* ======================================================================== * ========================================================================
*/ */
/* /*
* Program: IPOP3D - IMAP to POP3 conversion server * Program: IPOP3D - IMAP to POP3 conversion server
* *
* Author: Mark Crispin * Author: Mark Crispin
* Networks and Distributed Computing * UW Technology
* Computing & Communications
* University of Washington * University of Washington
* Administration Building, AG-44
* Seattle, WA 98195 * Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU * Internet: MRC@Washington.EDU
* *
* Date: 1 November 1990 * Date: 1 November 1990
* Last Edited: 17 September 2007 * Last Edited: 19 February 2008
*/ */
/* Parameter files */ /* Parameter files */
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
extern int errno; /* just in case */ extern int errno; /* just in case */
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include "c-client.h" #include "c-client.h"
skipping to change at line 58 skipping to change at line 56
#define TRANSACTION 1 #define TRANSACTION 1
#define UPDATE 2 #define UPDATE 2
#define LOGOUT 3 #define LOGOUT 3
/* Eudora food */ /* Eudora food */
#define STATUS "Status: %s%s\015\012" #define STATUS "Status: %s%s\015\012"
#define SLEN (sizeof (STATUS)-3) #define SLEN (sizeof (STATUS)-3)
/* Global storage */ /* Global storage */
char *version = "101"; /* edit number of this server */ char *version = "104"; /* edit number of this server */
short state = AUTHORIZATION; /* server state */ short state = AUTHORIZATION; /* server state */
short critical = NIL; /* non-zero if in critical code */ short critical = NIL; /* non-zero if in critical code */
MAILSTREAM *stream = NIL; /* mailbox stream */ MAILSTREAM *stream = NIL; /* mailbox stream */
time_t idletime = 0; /* time we went idle */ time_t idletime = 0; /* time we went idle */
unsigned long nmsgs = 0; /* current number of messages */ unsigned long nmsgs = 0; /* current number of messages */
unsigned long ndele = 0; /* number of deletes */ unsigned long ndele = 0; /* number of deletes */
unsigned long nseen = 0; /* number of mark-seens */ unsigned long nseen = 0; /* number of mark-seens */
unsigned long last = 0; /* highest message accessed */ unsigned long last = 0; /* highest message accessed */
unsigned long il = 0; /* initial last message */ unsigned long il = 0; /* initial last message */
char challenge[128]; /* challenge */ char challenge[128]; /* challenge */
skipping to change at line 112 skipping to change at line 110
char *s,*t; char *s,*t;
char tmp[MAILTMPLEN]; char tmp[MAILTMPLEN];
time_t autologouttime; time_t autologouttime;
char *pgmname = (argc && argv[0]) ? char *pgmname = (argc && argv[0]) ?
(((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ? (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
s+1 : argv[0]) : "ipop3d"; s+1 : argv[0]) : "ipop3d";
/* set service name before linkage */ /* set service name before linkage */
mail_parameters (NIL,SET_SERVICENAME,(void *) "pop"); mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
#include "linkage.c" #include "linkage.c"
/* initialize server */ /* initialize server */
server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint); server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL);
mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT);
s = myusername_full (&i); /* get user name and flags */
mail_parameters (NIL,SET_BLOCKENVINIT,NIL);
if (i == MU_LOGGEDIN) { /* allow EXTERNAL if logged in already */
mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL");
mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s);
}
{ /* set up MD5 challenge */ { /* set up MD5 challenge */
AUTHENTICATOR *auth = mail_lookup_auth (1); AUTHENTICATOR *auth = mail_lookup_auth (1);
while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->ne xt; while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->ne xt;
/* build challenge -- less than 128 chars */ /* build challenge -- less than 128 chars */
if (auth && auth->server && !(auth->flags & AU_DISABLE)) if (auth && auth->server && !(auth->flags & AU_DISABLE))
sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (), sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
(unsigned long) time (0),tcp_serverhost ()); (unsigned long) time (0),tcp_serverhost ());
else challenge[0] = '\0'; /* no MD5 authentication */ else challenge[0] = '\0'; /* no MD5 authentication */
} }
/* There are reports of POP3 clients which get upset if anything appears /* There are reports of POP3 clients which get upset if anything appears
skipping to change at line 154 skipping to change at line 159
alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT); alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
clearerr (stdin); /* clear stdin errors */ clearerr (stdin); /* clear stdin errors */
/* read command line */ /* read command line */
while (!PSIN (tmp,MAILTMPLEN)) { while (!PSIN (tmp,MAILTMPLEN)) {
/* ignore if some interrupt */ /* ignore if some interrupt */
if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
else { else {
char *e = ferror (stdin) ? char *e = ferror (stdin) ?
strerror (errno) : "Unexpected client disconnect"; strerror (errno) : "Unexpected client disconnect";
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = tmp,"%.80s, while reading line",e); sprintf (logout = tmp,"%.80s, while reading line",e);
goodbye = NIL; goodbye = NIL;
rset (); /* try to gracefully close the stream */ rset (); /* try to gracefully close the stream */
if (state == TRANSACTION) mail_close (stream); if (state == TRANSACTION) mail_close (stream);
stream = NIL; stream = NIL;
state = LOGOUT; state = LOGOUT;
sayonara (1); sayonara (1);
} }
} }
alarm (0); /* make sure timeout disabled */ alarm (0); /* make sure timeout disabled */
skipping to change at line 206 skipping to change at line 211
} }
else switch (state) { /* else dispatch based on state */ else switch (state) { /* else dispatch based on state */
case AUTHORIZATION: /* waiting to get logged in */ case AUTHORIZATION: /* waiting to get logged in */
if (!strcmp (s,"AUTH")) { if (!strcmp (s,"AUTH")) {
if (t && *t) { /* mechanism given? */ if (t && *t) { /* mechanism given? */
if (host) fs_give ((void **) &host); if (host) fs_give ((void **) &host);
if (user) fs_give ((void **) &user); if (user) fs_give ((void **) &user);
if (pass) fs_give ((void **) &pass); if (pass) fs_give ((void **) &pass);
s = strtok (t," "); /* get mechanism name */ s = strtok (t," "); /* get mechanism name */
/* get initial response */ /* get initial response */
initial = strtok (NIL,"\015\012"); if (initial = strtok (NIL,"\015\012")) {
if ((*initial == '=') && !initial[1]) ++initial;
else if (!*initial) initial = NIL;
}
if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) { if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
PSOUT ("-ERR Bad authentication\015\012"); PSOUT ("-ERR Bad authentication\015\012");
syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s, syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
tcp_clienthost ()); tcp_clienthost ());
} }
else if ((state = mbxopen ("INBOX")) == TRANSACTION) else if ((state = mbxopen ("INBOX")) == TRANSACTION)
syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu", syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu",
user,tcp_clienthost (),nmsgs,stream->nmsgs); user,tcp_clienthost (),nmsgs,stream->nmsgs);
else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox", else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox",
user,tcp_clienthost ()); user,tcp_clienthost ());
skipping to change at line 540 skipping to change at line 548
/* do logout hook if needed */ /* do logout hook if needed */
if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL)); if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
_exit (status); /* all done */ _exit (status); /* all done */
} }
/* Clock interrupt /* Clock interrupt
*/ */
void clkint () void clkint ()
{ {
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "-ERR Autologout; idle for too long\015\012"; goodbye = "-ERR Autologout; idle for too long\015\012";
logout = "Autologout"; logout = "Autologout";
if (critical) state = LOGOUT; /* badly hosed if in critical code * / if (critical) state = LOGOUT; /* badly hosed if in critical code * /
else { /* try to gracefully close the stream */ else { /* try to gracefully close the stream */
if ((state == TRANSACTION) && !stream->lock) { if ((state == TRANSACTION) && !stream->lock) {
rset (); rset ();
mail_close (stream); mail_close (stream);
} }
state = LOGOUT; state = LOGOUT;
stream = NIL; stream = NIL;
skipping to change at line 563 skipping to change at line 571
} }
/* Kiss Of Death interrupt /* Kiss Of Death interrupt
*/ */
void kodint () void kodint ()
{ {
/* only if idle */ /* only if idle */
if (idletime && ((time (0) - idletime) > KODTIMEOUT)) { if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "-ERR Received Kiss of Death\015\012"; goodbye = "-ERR Received Kiss of Death\015\012";
logout = "Killed (lost mailbox lock)"; logout = "Killed (lost mailbox lock)";
if (critical) state =LOGOUT;/* must defer if in critical code */ if (critical) state =LOGOUT;/* must defer if in critical code */
else { /* try to gracefully close the stream */ else { /* try to gracefully close the stream */
if ((state == TRANSACTION) && !stream->lock) { if ((state == TRANSACTION) && !stream->lock) {
rset (); rset ();
mail_close (stream); mail_close (stream);
} }
state = LOGOUT; state = LOGOUT;
stream = NIL; stream = NIL;
skipping to change at line 585 skipping to change at line 593
} }
} }
} }
/* Hangup interrupt /* Hangup interrupt
*/ */
void hupint () void hupint ()
{ {
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = NIL; /* nobody left to talk to */ goodbye = NIL; /* nobody left to talk to */
logout = "Hangup"; logout = "Hangup";
if (critical) state = LOGOUT; /* must defer if in critical code */ if (critical) state = LOGOUT; /* must defer if in critical code */
else { /* try to gracefully close the stream */ else { /* try to gracefully close the stream */
if ((state == TRANSACTION) && !stream->lock) { if ((state == TRANSACTION) && !stream->lock) {
rset (); rset ();
mail_close (stream); mail_close (stream);
} }
state = LOGOUT; state = LOGOUT;
stream = NIL; stream = NIL;
sayonara (1); /* die die die */ sayonara (1); /* die die die */
} }
} }
/* Termination interrupt /* Termination interrupt
*/ */
void trmint () void trmint ()
{ {
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "-ERR Killed\015\012"; goodbye = "-ERR Killed\015\012";
logout = "Killed"; logout = "Killed";
if (critical) state = LOGOUT; /* must defer if in critical code */ if (critical) state = LOGOUT; /* must defer if in critical code */
/* Make no attempt at graceful closure since a shutdown may be in /* Make no attempt at graceful closure since a shutdown may be in
* progress, and we won't have any time to do mail_close() actions. * progress, and we won't have any time to do mail_close() actions.
*/ */
else sayonara (1); /* die die die */ else sayonara (1); /* die die die */
} }
/* Parse PASS command /* Parse PASS command
* Accepts: pointer to command argument * Accepts: pointer to command argument
skipping to change at line 697 skipping to change at line 705
alarm (LOGINTIMEOUT); /* get a response under timeout */ alarm (LOGINTIMEOUT); /* get a response under timeout */
clearerr (stdin); /* clear stdin errors */ clearerr (stdin); /* clear stdin errors */
/* read buffer */ /* read buffer */
while (!PSIN ((char *) resp,RESPBUFLEN)) { while (!PSIN ((char *) resp,RESPBUFLEN)) {
/* ignore if some interrupt */ /* ignore if some interrupt */
if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
else { else {
char *e = ferror (stdin) ? char *e = ferror (stdin) ?
strerror (errno) : "Command stream end of file"; strerror (errno) : "Command stream end of file";
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = tmp,"%.80s, while reading authentication",e); sprintf (logout = tmp,"%.80s, while reading authentication",e);
goodbye = NIL; goodbye = NIL;
state = LOGOUT; state = LOGOUT;
sayonara (1); sayonara (1);
} }
} }
if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) { if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) {
int c; int c;
while ((c = PBIN ()) != '\012') if (c == EOF) { while ((c = PBIN ()) != '\012') if (c == EOF) {
/* ignore if some interrupt */ /* ignore if some interrupt */
if (ferror (stdin) && (errno == EINTR)) clearerr (stdin); if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
else { else {
char *e = ferror (stdin) ? char *e = ferror (stdin) ?
strerror (errno) : "Command stream end of file"; strerror (errno) : "Command stream end of file";
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = tmp,"%.80s, while reading auth char",e); sprintf (logout = tmp,"%.80s, while reading auth char",e);
goodbye = NIL; goodbye = NIL;
state = LOGOUT; state = LOGOUT;
sayonara (1); sayonara (1);
} }
} }
return NIL; return NIL;
} }
alarm (0); /* make sure timeout disabled */ alarm (0); /* make sure timeout disabled */
if (t[-1] == '\015') --t; /* remove CR */ if (t[-1] == '\015') --t; /* remove CR */
skipping to change at line 938 skipping to change at line 946
case NIL: /* information message */ case NIL: /* information message */
case PARSE: /* parse glitch */ case PARSE: /* parse glitch */
break; /* too many of these to log */ break; /* too many of these to log */
case WARN: /* warning */ case WARN: /* warning */
syslog (LOG_DEBUG,"%s",string); syslog (LOG_DEBUG,"%s",string);
break; break;
case BYE: /* driver broke connection */ case BYE: /* driver broke connection */
if (state != UPDATE) { if (state != UPDATE) {
char tmp[MAILTMPLEN]; char tmp[MAILTMPLEN];
alarm (0); /* disable all interrupts */ alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN); server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = tmp,"Mailbox closed (%.80s)",string); sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
goodbye = NIL; goodbye = NIL;
state = LOGOUT; state = LOGOUT;
sayonara (1); sayonara (1);
} }
break; break;
case ERROR: /* error that broke command */ case ERROR: /* error that broke command */
default: /* default should never happen */ default: /* default should never happen */
syslog (LOG_NOTICE,"%s",string); syslog (LOG_NOTICE,"%s",string);
break; break;
 End of changes. 16 change blocks. 
17 lines changed or deleted 25 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/