changeset 291:7da5c55b9330

0.8.3 commit
author mmj
date Thu, 12 Aug 2004 08:29:38 +1000
parents 1180bcbc90d9
children 958a3ecff04c
files ChangeLog README TODO TUNABLES UPGRADE VERSION listtexts/notifysub listtexts/notifyunsub src/Makefile.am src/chomp.c src/ctrlvalue.c src/listcontrol.c src/mlmmj-make-ml.sh src/mlmmj-process.c src/mlmmj-send.c src/mlmmj-sub.c src/mlmmj-unsub.c
diffstat 17 files changed, 250 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Jul 10 06:28:16 2004 +1000
+++ b/ChangeLog	Thu Aug 12 08:29:38 2004 +1000
@@ -1,3 +1,14 @@
+0.8.3
+ o Have mlmmj-make-ml.sh remind people about using cron if they want
+ o Replying to the confirmation address is enough to sub/unsub, no matter what
+   address is used the second time
+ o Fix possible DoS wrt. unsubscribing. Thank you Erik Toubro Nielsen
+ o Add 'notifysub' functionality to have owner know when people sub/unsub.
+   Thank you Kenneth Vestergaard Schmidt
+ o Use Return-Path: for envelope From. Thanks Anders Johansson
+ o Specification of which relayhost to use can now be done in control/relayhost
+ o Add configure check to link against libnsl if needed.
+ o Implement our own daemon() function since we don't have daemon() on Solaris
 0.8.2
  o Make sure we don't cut of the first char of an emailaddress
  o Fix header value copying (thanks Anders Johansson)
--- a/README	Sat Jul 10 06:28:16 2004 +1000
+++ b/README	Thu Aug 12 08:29:38 2004 +1000
@@ -1,4 +1,4 @@
-README mlmmj-0.8.2					Jul 3rd 2004
+README mlmmj-0.8.3					Aug 11th 2004
 
 This is an attempt at implementing a mailing list manager with the same
 functionality as the brilliant ezmlm, but with a decent license and mail server
--- a/TODO	Sat Jul 10 06:28:16 2004 +1000
+++ b/TODO	Thu Aug 12 08:29:38 2004 +1000
@@ -1,11 +1,9 @@
 Code cleanup:
- o Convert opening of write files to openrandexclrw
  o Add some more logging to mlmmj-maintd--actually we have to rethink logging a
    bit. Do we want to use our own /var/log/mlmmj
 
 Functionality items:
  o listname+get functionality
- o web interface
 
 Nice to do:
  o Convert mlmmj-sub, mlmmj-unsub and mlmmj-process (moderation) to use
--- a/TUNABLES	Sat Jul 10 06:28:16 2004 +1000
+++ b/TUNABLES	Thu Aug 12 08:29:38 2004 +1000
@@ -67,3 +67,13 @@
    When this file is present, a To: header including the recipients
    emailaddress will be added to outgoing mail. Recommended usage is to remove
    existing To: headers with delheaders (see above) first.
+
+ · relayhost			(normal)
+
+   The host specified (IP address og domainname, both works) in this file will
+   be used for relaying the mail sent to the list. Defaults to 127.0.0.1.
+
+ · notifysub			(boolean)
+
+   If this file is present, the owner(s) will get a mail with the address of
+   someone sub/unsubscribing to a mailinglist.
--- a/UPGRADE	Sat Jul 10 06:28:16 2004 +1000
+++ b/UPGRADE	Thu Aug 12 08:29:38 2004 +1000
@@ -1,4 +1,4 @@
-This applies to everyone using mlmmj > 0.7.3:
+This applies to everyone using mlmmj < 0.8.3:
 ---------------------------------------------
 
  Don't forget to upgrade the listtexts!
--- a/VERSION	Sat Jul 10 06:28:16 2004 +1000
+++ b/VERSION	Thu Aug 12 08:29:38 2004 +1000
@@ -1,1 +1,1 @@
-0.8.2
+0.8.3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/listtexts/notifysub	Thu Aug 12 08:29:38 2004 +1000
@@ -0,0 +1,9 @@
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+The following address has just subscribed to the mailinglist:
+
+*SUBADDR*
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/listtexts/notifyunsub	Thu Aug 12 08:29:38 2004 +1000
@@ -0,0 +1,9 @@
+Hi, this is the mlmmj program managing the mailinglist
+
+*LSTADDR*
+
+
+The following address has just unsubscribed from the mailinglist:
+
+*SUBADDR*
+
--- a/src/Makefile.am	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/Makefile.am	Thu Aug 12 08:29:38 2004 +1000
@@ -32,12 +32,13 @@
 mlmmj_sub_SOURCES = mlmmj-sub.c writen.c mylocking.c \
 			getlistaddr.c chomp.c random-int.c strgen.c \
 			subscriberfuncs.c print-version.c \
-			log_error.c mygetline.c prepstdreply.c memory.c
+			log_error.c mygetline.c prepstdreply.c memory.c \
+			statctrl.c
 
 mlmmj_unsub_SOURCES = mlmmj-unsub.c writen.c mylocking.c \
 			getlistaddr.c chomp.c subscriberfuncs.c random-int.c \
 			strgen.c print-version.c log_error.c mygetline.c \
-			prepstdreply.c memory.c
+			prepstdreply.c memory.c statctrl.c
 			
 mlmmj_bounce_SOURCES = mlmmj-bounce.c print-version.c log_error.c \
 		       subscriberfuncs.c strgen.c random-int.c writen.c \
--- a/src/chomp.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/chomp.c	Thu Aug 12 08:29:38 2004 +1000
@@ -26,7 +26,12 @@
 
 char *chomp(char *str)
 {
-	int i = strlen(str) - 1;
+	size_t i;
+
+	if(str == NULL)
+		return NULL;
+
+	i = strlen(str) - 1;
 
 	while(str[i] == '\n') {
 		str[i] = 0;
--- a/src/ctrlvalue.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/ctrlvalue.c	Thu Aug 12 08:29:38 2004 +1000
@@ -35,10 +35,13 @@
 
 char *ctrlvalue(const char *listdir, const char *ctrlstr)
 {
-	char *value = NULL;
-	char *filename = concatstr(3, listdir, "/control/", ctrlstr);
+	char *filename, *value = NULL;
 	int ctrlfd;
 
+	if(listdir == NULL)
+		return NULL;
+
+	filename = concatstr(3, listdir, "/control/", ctrlstr);
 	ctrlfd = open(filename, O_RDONLY);
 	myfree(filename);
 
--- a/src/listcontrol.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/listcontrol.c	Thu Aug 12 08:29:38 2004 +1000
@@ -156,11 +156,10 @@
 		if (closedlist) exit(EXIT_SUCCESS);
 		conffilename = concatstr(3, listdir, "/subconf/", param);
 		myfree(param);
-		if((tmpfd = open(conffilename, O_RDONLY)) > 0) {
+		if((tmpfd = open(conffilename, O_RDONLY)) >= 0) {
 			tmpstr = mygetline(tmpfd);
 			chomp(tmpstr);
 			close(tmpfd);
-			if(strcasecmp(tmpstr, fromemails->emaillist[0]) == 0) {
 				unlink(conffilename);
 				execlp(mlmmjsub, mlmmjsub,
 						"-L", listdir,
@@ -169,11 +168,6 @@
 				log_error(LOG_ARGS, "execlp() of '%s' failed",
 						mlmmjsub);
 				exit(EXIT_FAILURE);
-			} else {
-				/* Not proper confirm */
-				myfree(tmpstr);
-				exit(EXIT_SUCCESS);
-			}
 		} else /* Not a confirm so silently ignore */
 			exit(EXIT_SUCCESS);
 		break;
@@ -198,11 +192,10 @@
 		if (closedlist) exit(EXIT_SUCCESS);
 		conffilename = concatstr(3, listdir, "/unsubconf/", param);
 		myfree(param);
-		if((tmpfd = open(conffilename, O_RDONLY))) {
+		if((tmpfd = open(conffilename, O_RDONLY)) >= 0) {
 			tmpstr = mygetline(tmpfd);
 			close(tmpfd);
 			chomp(tmpstr);
-			if(strcasecmp(tmpstr, fromemails->emaillist[0]) == 0) {
 				unlink(conffilename);
 				execlp(mlmmjunsub, mlmmjunsub,
 						"-L", listdir,
@@ -211,10 +204,6 @@
 				log_error(LOG_ARGS, "execlp() of '%s' failed",
 						    mlmmjunsub);
 				exit(EXIT_FAILURE);
-			} else {
-				myfree(tmpstr);
-				exit(EXIT_SUCCESS);
-			}
 		} else /* Not a confirm so silently ignore */
 			exit(EXIT_SUCCESS);
 		break;
--- a/src/mlmmj-make-ml.sh	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/mlmmj-make-ml.sh	Thu Aug 12 08:29:38 2004 +1000
@@ -100,7 +100,13 @@
 	MLMMJRECIEVE="/path/to/mlmmj-recieve"
 fi
 
+MLMMJMAINTD=`which mlmmj-maintd 2>/dev/null`
+if [ -z "$MLMMJRECIEVE" ]; then
+	MLMMJMAINTD="/path/to/mlmmj-maintd"
+fi
+
 ALIAS="$LISTNAME:  \"|$MLMMJRECIEVE -L $SPOOLDIR/$LISTNAME/\""
+CRONENTRY="0 */2 * * * \"$MLMMJMAINTD -L $SPOOLDIR/$LISTNAME/\""
 
 if [ -n "$A_CREATE" ]; then
 	echo "I want to add the following to your /etc/aliases file:"
@@ -123,9 +129,13 @@
 	echo "Don't forget to add this to /etc/aliases:"
 	echo "$ALIAS"
 fi
+echo
+echo "If you're not starting mlmmj-maintd in daemon mode,"
+echo "don't forget to add this to your crontab:"
+echo $CRONENTRY
 
 echo
 echo " ** FINAL NOTES **
 1) The mailinglist directory have to be owned by the user running the 
 mailserver (i.e. starting the binaries to work the list)
-2) To run newaliases"
+2) Run newaliases"
--- a/src/mlmmj-process.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/mlmmj-process.c	Thu Aug 12 08:29:38 2004 +1000
@@ -495,7 +495,7 @@
 		recipdelim = NULL;
 
 	if(recipdelim) {
-		owner = concatstr(2, listdir, "control/owner");
+		owner = concatstr(2, listdir, "/control/owner");
 		if(owner && strncmp(recipdelim, "+owner@", 7) == 0) {
 			unlink(donemailname);
 			execlp(mlmmjsend, mlmmjsend,
--- a/src/mlmmj-send.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/mlmmj-send.c	Thu Aug 12 08:29:38 2004 +1000
@@ -37,6 +37,10 @@
 #include <stdarg.h>
 #include <sys/mman.h>
 #include <limits.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "mlmmj-send.h"
 #include "mlmmj.h"
@@ -461,10 +465,12 @@
 	char *listctrl = NULL, *subddirname = NULL, *listdir = NULL;
 	char *mlmmjbounce = NULL, *bindir, *mailmap, *probefile, *a;
 	char *body = NULL, *hdrs = NULL, *memmailsizestr = NULL;
+	char relay[16];
 	ssize_t memmailsize = 0;
 	DIR *subddir;
 	struct dirent *dp;
 	struct stat st;
+	struct hostent *relayent;
 
 	CHECKFULLPATH(argv[0]);
 	
@@ -642,12 +648,27 @@
 			 mindex);
 	}
 
+	if(!relayhost) {
+		relayhost = ctrlvalue(listdir, "relayhost");
+		chomp(relayhost);
+	}
 	if(!relayhost)
-		relayhost = mystrdup(RELAYHOST);
+		strncpy(relay, RELAYHOST, sizeof(relay));
+	else {
+		relayent = gethostbyname(relayhost);
+		if(relayent == NULL) {
+			strncpy(relay, RELAYHOST, sizeof(relay));
+		} else {
+			if(inet_ntop(relayent->h_addrtype,
+				     relayent->h_addr_list[0],
+				     relay, sizeof(relay)) == NULL)
+				strncpy(relay, RELAYHOST, sizeof(relay));
+		}
+	}
 
 	switch(listctrl[0]) {
 	case '1': /* A single mail is to be sent */
-		initsmtp(&sockfd, relayhost);
+		initsmtp(&sockfd, relay);
 		sendres = send_mail(sockfd, bounceaddr, to_addr, replyto,
 				mailmap, st.st_size, listdir, NULL,
 				hdrs, hdrslen, body, bodylen);
@@ -690,7 +711,7 @@
 		}
 		break;
 	case '2': /* Moderators */
-		initsmtp(&sockfd, relayhost);
+		initsmtp(&sockfd, relay);
 		if(send_mail_many(sockfd, bounceaddr, NULL, mailmap,
 				  st.st_size, subfd, NULL, NULL, listdir,
 				  NULL, hdrs, hdrslen, body, bodylen))
@@ -699,7 +720,7 @@
 			endsmtp(&sockfd);
 		break;
 	case '3': /* resending earlier failed mails */
-		initsmtp(&sockfd, relayhost);
+		initsmtp(&sockfd, relay);
 		if(send_mail_many(sockfd, NULL, NULL, mailmap, st.st_size,
 				subfd, listaddr, mailfilename, listdir,
 				mlmmjbounce, hdrs, hdrslen, body, bodylen))
@@ -709,7 +730,7 @@
 		unlink(subfilename);
 		break;
 	case '4': /* send mails to owner */
-		initsmtp(&sockfd, relayhost);
+		initsmtp(&sockfd, relay);
 		if(send_mail_many(sockfd, bounceaddr, NULL, mailmap, st.st_size,
 				subfd, listaddr, mailfilename, listdir,
 				mlmmjbounce, hdrs, hdrslen, body, bodylen))
@@ -718,7 +739,7 @@
 			endsmtp(&sockfd);
 		break;
 	case '5': /* bounceprobe - handle relayhost local users bouncing*/
-		initsmtp(&sockfd, relayhost);
+		initsmtp(&sockfd, relay);
 		sendres = send_mail(sockfd, bounceaddr, to_addr, replyto,
 				mailmap, st.st_size, listdir, NULL,
 				hdrs, hdrslen, body, bodylen);
@@ -762,7 +783,7 @@
 			}
 			myfree(subfilename);
 
-			initsmtp(&sockfd, relayhost);
+			initsmtp(&sockfd, relay);
 			sendres = send_mail_many(sockfd, NULL, NULL, mailmap,
 					st.st_size, subfd, listaddr,
 					archivefilename, listdir, mlmmjbounce,
--- a/src/mlmmj-sub.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/mlmmj-sub.c	Thu Aug 12 08:29:38 2004 +1000
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <sys/wait.h>
 
 #include "mlmmj.h"
 #include "mlmmj-sub.h"
@@ -41,6 +42,8 @@
 #include "subscriberfuncs.h"
 #include "log_error.h"
 #include "mygetline.h"
+#include "statctrl.h"
+#include "prepstdreply.h"
 #include "memory.h"
 
 void confirm_sub(const char *listdir, const char *listaddr,
@@ -120,6 +123,40 @@
 	exit(EXIT_FAILURE);
 }
 
+void notify_sub(const char *listdir, const char *listaddr,
+		const char *subaddr, const char *mlmmjsend)
+{
+	char *maildata[4] = { "*LSTADDR*", NULL, "*SUBADDR*", NULL };
+	char *listfqdn, *listname, *fromaddr, *fromstr, *subject;
+	char *queuefilename = NULL;
+
+	listname = genlistname(listaddr);
+	listfqdn = genlistfqdn(listaddr);
+	maildata[1] = mystrdup(listaddr);
+	maildata[3] = mystrdup(subaddr);
+	fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
+	fromstr = concatstr(3, listname, "+owner@", listfqdn);
+	subject = concatstr(2, "New subscription to ", listaddr);
+	queuefilename = prepstdreply(listdir, "notifysub", fromstr,
+				     fromstr, NULL, subject, 2, maildata);
+	MY_ASSERT(queuefilename)
+	myfree(listname);
+	myfree(listfqdn);
+	myfree(subject);
+	myfree(maildata[1]);
+	myfree(maildata[3]);
+	execlp(mlmmjsend, mlmmjsend,
+			"-l", "1",
+			"-T", fromstr,
+			"-F", fromaddr,
+			"-m", queuefilename, 0);
+
+	myfree(fromstr);
+
+	log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
+	exit(EXIT_FAILURE);
+}
+
 void generate_subconfirm(const char *listdir, const char *listaddr,
 			 const char *subaddr, const char *mlmmjsend)
 {
@@ -270,11 +307,12 @@
 {
 	char *listaddr, *listdir = NULL, *address = NULL, *subfilename = NULL;
 	char *mlmmjsend, *bindir, chstr[2];
-	int subconfirm = 0, confirmsub = 0, opt, subfilefd, lock;
-	int changeuid = 1;
+	int subconfirm = 0, confirmsub = 0, opt, subfilefd, lock, notifysub;
+	int changeuid = 1, status;
 	size_t len;
 	off_t suboff;
 	struct stat st;
+	pid_t pid, childpid;
 
 	CHECKFULLPATH(argv[0]);
 
@@ -376,8 +414,30 @@
 		return EXIT_SUCCESS;
 	}
 
-	if(confirmsub)
+	if(confirmsub) {
+		childpid = fork();
+
+		if(childpid < 0) {
+			log_error(LOG_ARGS, "Could not fork");
 		confirm_sub(listdir, listaddr, address, mlmmjsend);
+		}
+		
+		if(childpid > 0) {
+			do /* Parent waits for the child */
+				pid = waitpid(childpid, &status, 0);
+			while(pid == -1 && errno == EINTR);
+		}
+
+		/* child confirms subscription */
+		if(childpid == 0)
+			confirm_sub(listdir, listaddr, address, mlmmjsend);
+	}
+
+	notifysub = statctrl(listdir, "notifysub");
+
+	/* Notify list owner about subscription */
+	if (notifysub)
+		notify_sub(listdir, listaddr, address, mlmmjsend);
 
 	myfree(listaddr);
 
--- a/src/mlmmj-unsub.c	Sat Jul 10 06:28:16 2004 +1000
+++ b/src/mlmmj-unsub.c	Thu Aug 12 08:29:38 2004 +1000
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <libgen.h>
 #include <dirent.h>
+#include <sys/wait.h>
 
 #include "mlmmj.h"
 #include "mlmmj-unsub.h"
@@ -42,6 +43,8 @@
 #include "strgen.h"
 #include "log_error.h"
 #include "memory.h"
+#include "statctrl.h"
+#include "prepstdreply.h"
 
 void confirm_unsub(const char *listdir, const char *listaddr,
 		   const char *subaddr, const char *mlmmjsend)
@@ -122,6 +125,41 @@
 	exit(EXIT_FAILURE);
 }
 
+void notify_unsub(const char *listdir, const char *listaddr,
+		  const char *subaddr, const char *mlmmjsend)
+{
+        char *maildata[4] = { "*LSTADDR*", NULL, "*SUBADDR*", NULL };
+        char *listfqdn, *listname, *fromaddr, *fromstr, *subject;
+        char *queuefilename = NULL;
+
+        listname = genlistname(listaddr);
+        listfqdn = genlistfqdn(listaddr);
+        maildata[1] = mystrdup(listaddr);
+        maildata[3] = mystrdup(subaddr);
+        fromaddr = concatstr(3, listname, "+bounces-help@", listfqdn);
+        fromstr = concatstr(3, listname, "+owner@", listfqdn);
+        subject = concatstr(2, "Unsubscription from ", listaddr);
+        queuefilename = prepstdreply(listdir, "notifyunsub", fromstr,
+                                     fromstr, NULL, subject, 2, maildata);
+        MY_ASSERT(queuefilename)
+        myfree(listname);
+        myfree(listfqdn);
+        myfree(subject);
+        myfree(maildata[1]);
+        myfree(maildata[3]);
+        execlp(mlmmjsend, mlmmjsend,
+                        "-l", "1",
+                        "-T", fromstr,
+                        "-F", fromaddr,
+                        "-m", queuefilename, 0);
+
+        myfree(fromstr);
+
+        log_error(LOG_ARGS, "execlp() of '%s' failed", mlmmjsend);
+        exit(EXIT_FAILURE);
+}
+
+
 void generate_unsubconfirm(const char *listdir, const char *listaddr,
 			   const char *subaddr, const char *mlmmjsend)
 {
@@ -303,14 +341,15 @@
 
 int main(int argc, char **argv)
 {
-	int subread, subwrite, rlock, wlock, opt, unsubres;
-	int confirmunsub = 0, unsubconfirm = 0;
+	int subread, subwrite, rlock, wlock, opt, unsubres, status;
+	int confirmunsub = 0, unsubconfirm = 0, notifysub = 0;
 	char *listaddr, *listdir = NULL, *address = NULL, *subreadname = NULL;
 	char *subwritename, *mlmmjsend, *bindir;
 	char *subddirname;
 	off_t suboff;
 	DIR *subddir;
 	struct dirent *dp;
+	pid_t pid, childpid;
 
 	CHECKFULLPATH(argv[0]);
 	
@@ -462,10 +501,37 @@
 		myfree(subreadname);
 		myfree(subwritename);
 
-		if(confirmunsub)
-			confirm_unsub(listdir, listaddr, address, mlmmjsend);
+		closedir(subddir);
+
+		if(confirmunsub) {
+			childpid = fork();
+
+			if(childpid < 0) {
+				log_error(LOG_ARGS, "Could not fork");
+				confirm_unsub(listdir, listaddr, address,
+						mlmmjsend);
+			}
+
+			if(childpid > 0) {
+				do /* Parent waits for the child */
+					pid = waitpid(childpid, &status, 0);
+				while(pid == -1 && errno == EINTR);
 	}
-	closedir(subddir);
+
+			/* child confirms subscription */
+			if(childpid == 0)
+				confirm_unsub(listdir, listaddr, address,
+						mlmmjsend);
+		}
+        }
+
+
+        notifysub = statctrl(listdir, "notifysub");
+
+        /* Notify list owner about subscription */
+        if (notifysub)
+                notify_unsub(listdir, listaddr, address, mlmmjsend);
+
 	myfree(listaddr);
 
 	return EXIT_SUCCESS;