
See

	http://www.math.ubc.ca/~tam/Software/Qpopper.M2W/

for a full explanation of what this patch does.


Joseph Tam <tam at math dot ubc dot ca>
Network Administrator
Department of Mathematics
University of British Columbia
Canada V6T 1Z2

Phone:	604-822-6621
Fax:	604-822-6074	

================================================================================

*** popper.c-	Mon Jan 30 17:25:25 2006
--- popper.c	Mon Jan 30 17:23:27 2006
***************
*** 290,293 ****
--- 290,298 ----
      p.pcInEnd = p.pcInStart = p.pcInBuf;
  
+     // Trap Mail2Web sessions
+     if (strncmp(p.ipaddr,"168.144.",8)==0) {
+ 	void Mail2WebSession(POP *);
+ 	Mail2WebSession(&p);
+     } 
  
  /*
***************
*** 913,914 ****
--- 918,1085 ----
  }
  
+ 
+ //
+ // Create a fake Mail2Web POP3 session:  accept any username/password combination,
+ // then simulate the POP3 commands they use.  A successful authentication will
+ // stop them from passing this authentication information to other remote mail
+ // servers.  All mail retrieval commands will serve up a special Email message.
+ // The user will not be able to delete this message.
+ //
+ // Also, a timeout will be enforced so that connection cannot linger.
+ //
+ //				-- Joseph Tam, tam at math dot ubc dot ca, Jan 2006
+ //
+ #define SAFE_UID	555			// Qpopper will use this UID during fake session.
+ #define SAFE_GID	555			// Qpopper will use this GID during fake session.
+ #define SAFE_ROOT	"/var/qpopper/chroot"	// Chroot jail directory
+ #define	MAILBOX		"m2w.mbox"		// Name of mail box served up to client (relative to SAFE_ROOT)
+ #define	MAXMESS		100			// Maximum number of lines in fake mail message
+ #define MAXCMDS		20			// Maximum number of POP commands this session will do.
+ #define OUR_TIMEOUT	5			// Maximum number of seconds to wait for POP command.
+ // Extra message appended to fake Email
+ #define	EXTRA_FMT	"What you typed in: {username,password} = {%s,%s}"
+ 
+ 
+ //
+ // Send line to POP client: append \r\n.
+ //
+ void SendLine (POP *p, const char *s) {
+ 	char	s2[MAXLINELEN+2];
+ 
+ 	strncpy(s2,s,sizeof(s2));
+ 	strncat(s2,"\r\n",sizeof(s2));
+ 	pop_write(p,s2,strlen(s2));
+ 	pop_write_flush(p);
+ }
+ 
+ 
+ //
+ // Read Email message to serve up to client.
+ //
+ int ReadFakeMbox (POP *p, char **mess, int *nlines, int *size) {
+ 	FILE		*mbox=fopen(MAILBOX,"r");
+ 	char		buf[MAXLINELEN];
+ 	int		len;
+ 
+ 	*nlines = 0;
+ 	*size = 0;
+ 
+ 	if (mbox==NULL) return 0;
+ 
+ 	while (fgets(buf,sizeof(buf),mbox) && (*nlines<MAXMESS)) {
+ 		len = strlen(buf);
+ 		if (buf[len-1]=='\n') {
+ 			len--;
+ 			buf[len] = '\0';
+ 		}
+ 		mess[*nlines] = malloc(len+1);
+ 		strcpy(mess[*nlines],buf);
+ 		(*nlines)++;
+ 		*size += len+2;
+ 	}
+ 
+ 	if (*nlines>=MAXMESS)
+ 		pop_log(p,POP_NOTICE,"",0,"Mail2Web: mailbox limit reached.  Message may be truncated.");
+ 
+ 	fclose(mbox);
+ 	return 1;
+ }
+ 
+ 
+ void Mail2WebSession (POP *p) {
+ 	char		*FakeEmail[MAXMESS],
+ 			message[MAXLINELEN],
+ 			command[MAXLINELEN],
+ 			user[MAXLINELEN]="undefined",
+ 			pw[MAXLINELEN]="undefined",
+ 			extra[MAXLINELEN]="",
+ 			arg[MAXLINELEN];
+ 	int		ncmds, nlines, size, goodexit=0, extrasize=strlen(extra)+2;
+ 	register int	i;
+ 
+ 	// Start Mail2Web session: drop all privileges to protect against exploitation.
+ 	chdir(SAFE_ROOT);
+ 	chroot(SAFE_ROOT);
+ 	setuid(SAFE_UID);
+ 	setgid(SAFE_GID);
+ 
+ 	// Log this session
+ 	pop_log(p,POP_NOTICE,"",0,"Mail2Web: start ip=%s",p->ipaddr);
+ 
+ 	// Load in our fake mailbox message
+ 	if (!ReadFakeMbox(p,FakeEmail,&nlines,&size)) {
+ 		pop_log(p,POP_NOTICE,"",0,"Mail2Web: error reading mailbox.");
+ 		SendLine(p,"-ERR Oops.  Internal error.");
+ 		exit(1);
+ 	}
+ 
+ 	for (ncmds=0; (ncmds<MAXCMDS) && tgetline(message,MAXLINELEN,p,OUR_TIMEOUT); ncmds++) {
+ 
+ 		sscanf(message,"%s %s",command,arg);
+ 		pop_lower(command);
+ 
+ 		// Fascist logging
+ 		//pop_log(p,POP_NOTICE,"",0,"Mail2Web: command=%s",message);
+ 		pop_log(p,POP_NOTICE,"",0,"Mail2Web: command=%s",command);
+ 
+ 		if (strcmp(command,"user")==0) {
+ 			strncpy(user,arg,sizeof(user));
+ 			snprintf(extra,sizeof(extra),EXTRA_FMT,user,pw);
+ 			extrasize = strlen(extra)+2;
+ 			SendLine(p,"+OK Send password");
+ 		} else if (strcmp(command,"pass")==0) {
+ 			strncpy(pw,arg,sizeof(pw));
+ 			snprintf(extra,sizeof(extra),EXTRA_FMT,user,pw);
+ 			extrasize = strlen(extra)+2;
+ 			SendLine(p,"+OK Authenticated");
+ 		} else if (strcmp(command,"list")==0) {
+ 			SendLine(p,"+OK");
+ 			snprintf(message,sizeof(message),"1 %d",size+extrasize);
+ 			SendLine(p,message);
+ 			SendLine(p,".");
+ 		} else if (strcmp(command,"stat")==0) {
+ 			snprintf(message,sizeof(message),"+OK 1 %d",size+extrasize);
+ 			SendLine(p,message);
+ 		} else if (strcmp(command,"retr")==0) {
+ 			SendLine(p,"+OK Here it comes.");
+ 			for (i=0; i<nlines; i++)
+ 				SendLine(p,FakeEmail[i]);
+ 			SendLine(p,extra);
+ 			SendLine(p,".");
+ 		} else if (strcmp(command,"top")==0) {
+ 			// There's an argument supplied, but we'll assume it's "1".
+ 			SendLine(p,"+OK Here it comes.");
+ 
+ 			// Print header
+ 			for (i=0; (i<nlines) && FakeEmail[i][0]; i++)
+ 				SendLine(p,FakeEmail[i]);
+ 
+ 			// Print one line of body
+ 			if ((i+1)<nlines) {
+ 				SendLine(p,"");
+ 				SendLine(p,FakeEmail[i+1]);
+ 			}
+ 			SendLine(p,".");
+ 		} else if ((strcmp(command,"rset")==0) ||
+ 			(strcmp(command,"noop")==0) ||
+ 			(strcmp(command,"dele")==0) ) {
+ 			// Yeah, sure, whatever ...
+ 			SendLine(p,"+OK");
+ 		} else if (strcmp(command,"quit")==0) {
+ 			goodexit = 1;
+ 			ncmds = MAXCMDS+1;
+ 		} else
+ 			SendLine(p,"-ERR Unknown command");
+ 	};
+ 
+ 	if (goodexit) {
+ 		SendLine(p,"+OK Mail2Web: stop spreading user auth. info around.");
+ 		pop_log(p,POP_NOTICE,"",0,"Mail2Web: end ip=%s",p->ipaddr);
+ 	} else {
+ 		SendLine(p,"-ERR Mail2Web: stop spreading user auth. info around.");
+ 		pop_log(p,POP_NOTICE,"",0,"Mail2Web: timeout ip=%s (ncmds=%d)",p->ipaddr,ncmds);
+ 	}
+ 
+ 	// Let system close and clean everything up.
+ 	exit(0);
+ }
