diff options
Diffstat (limited to 'sqwebmail/acl.c')
| -rw-r--r-- | sqwebmail/acl.c | 657 | 
1 files changed, 657 insertions, 0 deletions
| diff --git a/sqwebmail/acl.c b/sqwebmail/acl.c new file mode 100644 index 0000000..46bc9ec --- /dev/null +++ b/sqwebmail/acl.c @@ -0,0 +1,657 @@ +/* +** Copyright 2004-2011 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +/* +*/ +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> +#include	<fcntl.h> +#include	<errno.h> +#include	<courierauth.h> +#include	"config.h" +#include	"sqwebmail.h" +#include	"maildir.h" +#include	"cgi/cgi.h" +#include	"pref.h" +#include	"sqconfig.h" +#include	"auth.h" +#include	"acl.h" +#include	"maildir/maildirquota.h" +#include	"maildir/maildirrequota.h" +#include	"maildir/maildirgetquota.h" +#include	"maildir/maildirmisc.h" +#include	"maildir/maildircreate.h" +#include	"maildir/maildirwatch.h" +#include	"unicode/unicode.h" +#include	"htmllibdir.h" + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#if	HAVE_DIRENT_H +#include	<dirent.h> +#define	NAMLEN(dirent)	strlen(dirent->d_name) +#else +#define	dirent	direct +#define	NAMLEN(dirent)	((dirent)->d_namlen) +#if	HAVE_SYS_NDIR_H +#include	<sys/ndir.h> +#endif +#if	HAVE_SYS_DIR_H +#include	<sys/dir.h> +#endif +#if	HAVE_NDIR_H +#include	<ndir.h> +#endif +#endif + +#include	<sys/types.h> +#include	<sys/stat.h> +#if	HAVE_UTIME_H +#include	<utime.h> +#endif + +#include	"unicode/unicode.h" + +#include	"strftime.h" + + +/* ACL support stuff */ + +extern const char *sqwebmail_folder; +extern void output_urlencoded(const char *p); +extern void output_attrencoded(const char *p); +extern void output_scriptptrget(); +extern void output_scriptptr(); +extern void output_scriptptrpostinfo(); + +extern dev_t sqwebmail_homedir_dev; +extern ino_t sqwebmail_homedir_ino; + +extern const char *sqwebmail_content_charset; +int verify_shared_index_file=0; + +int maildir_info_suppress(const char *maildir) +{ +	struct stat stat_buf; + +	if (stat(maildir, &stat_buf) < 0 || + +	    (stat_buf.st_dev == sqwebmail_homedir_dev && +	     stat_buf.st_ino == sqwebmail_homedir_ino)) +		return 1; +	return 0; +} + +const char *maildir_shared_index_file() +{ +	static char *filenamep=NULL; + +	if (filenamep == NULL) +	{ +		const char *p=getenv("SQWEBMAIL_SHAREDINDEXFILE"); + +		if (!p || !*p) +			p=SHAREDINDEXFILE; + +		if (p && *p) +		{ +			const char *q=auth_getoptionenv("sharedgroup"); + +			if (!q) q=""; + +			filenamep=malloc(strlen(p)+strlen(q)+1); + +			if (!filenamep) +				enomem(); + +			strcat(strcpy(filenamep, p), q); +		} +	} + +	if (filenamep && verify_shared_index_file) +	{ +		struct stat stat_buf; + +		if (stat(filenamep, &stat_buf)) +		{ +			fprintf(stderr, "ERR: "); +			perror(filenamep); +		} +	} + +	return filenamep; +} + +int acl_read(maildir_aclt_list *l, const char *folder, +	     char **owner) +{ +	struct maildir_info minfo; +	int rc; + +	if (maildir_info_imap_find(&minfo, folder, +				   login_returnaddr())<0) +	{ +		return -1; +	} + +	rc=acl_read2(l, &minfo, owner); +	maildir_info_destroy(&minfo); +	return rc; +} + +int acl_read2(maildir_aclt_list *l, +	      struct maildir_info *minfo, +	      char **owner) +{ +	int rc; +	char *p; + +	if (minfo->mailbox_type == MAILBOXTYPE_OLDSHARED) +	{ +		/* Legacy shared., punt. */ + +		maildir_aclt_list_init(l); +		if (maildir_aclt_list_add(l, "anyone", +					  ACL_LOOKUP ACL_READ +					  ACL_SEEN ACL_WRITE +					  ACL_INSERT +					  ACL_DELETEMSGS ACL_EXPUNGE, NULL) < 0 +		    || (*owner=strdup("vendor=courier.internal")) == NULL) +		{ +			maildir_aclt_list_destroy(l); +			return -1; +		} +		return 0; +	} + +	if (minfo->homedir == NULL || minfo->maildir == NULL) +		return -1; + +	p=maildir_name2dir(".", minfo->maildir); + +	if (!p) +		return -1; + +	rc=maildir_acl_read(l, minfo->homedir, +			    strncmp(p, "./", 2) == 0 ? p+2:p); +	free(p); +	if (owner && rc == 0) +	{ +		*owner=minfo->owner; +		minfo->owner=NULL; +	} +	return rc; +} + +void acl_computeRightsOnFolder(const char *folder, char *rights) +{ +	maildir_aclt_list l; +	char *owner; + +	if (acl_read(&l, folder, &owner) < 0) +	{ +		*rights=0; +		return; +	} +	acl_computeRights(&l, rights, owner); +	if (owner) +		free(owner); +	maildir_aclt_list_destroy(&l); +} + +void acl_computeRights(maildir_aclt_list *l, char *rights, +		       const char *owner) +{ +	char *p, *q; + +	maildir_aclt a; + +	if (maildir_acl_computerights(&a, l, login_returnaddr(), owner) < 0) +	{ +		*rights=0; +		return; +	} + +	for (p=q=rights; *p; p++) +	{ +		if (strchr(maildir_aclt_ascstr(&a), *p)) +			*q++ = *p; +	} +	*q=0; +	maildir_aclt_destroy(&a); +} + +static void showrights(const char *buf) +{ +	size_t i; +	char buf2[40]; + +	for (i=0; buf[i]; i++) +	{ +		const char *p; + +		if (i) +			printf(", "); + +		sprintf(buf2, "ACL_%c", buf[i]); + +		p=getarg(buf2); +		if (p && *p) +			printf("%s", p); +		else +		{ +			buf2[0]=buf[i]; +			buf2[1]=0; + +			printf(getarg("ACL_unknown"), buf2); +		} +	} +} + +static void doupdate(); + +void listrights() +{ +	maildir_aclt_list l; +	char buf[40]; +	char *owner; + +	if (*cgi("do.update") || *cgi("delentity")) +	{ +		struct maildir_info minfo; + +		if (maildir_info_imap_find(&minfo, sqwebmail_folder, +					   login_returnaddr()) == 0) +		{ +			if (minfo.homedir) +			{ +				struct maildirwatch *w; +				char *lock; +				int tryanyway; + +				w=maildirwatch_alloc(minfo.homedir); + +				if (!w) +				{ +					maildir_info_destroy(&minfo); +					enomem(); +					return; +				} + +				lock=maildir_lock(minfo.homedir, w, +						  &tryanyway); + +				maildir_info_destroy(&minfo); + +				if (lock == NULL) +				{ +					if (!tryanyway) +					{ +						printf("%s", +						       getarg("ACL_noaccess")); +						return; +					} +				} +				doupdate(); +				if (lock) +				{ +					unlink(lock); +					free(lock); +				} +				maildirwatch_free(w); +			} +		} +	} + +	if (acl_read(&l, sqwebmail_folder, &owner) < 0) +	{ +		printf("%s", getarg("ACL_cantread")); +		return; +	} +	buf[0]=0; +	strncat(buf, getarg("ACL_all"), sizeof(buf)-2); +	acl_computeRights(&l, buf, owner); +	maildir_aclt_list_destroy(&l); +	if (owner) +		free(owner); + +	if (!maildir_acl_canlistrights(buf)) +	{ +		printf("%s", getarg("ACL_cantread")); +		return; +	} + +	showrights(buf); +} + +static void doupdate() +{ +	maildir_aclt_list l; +	char *owner; +	char buf[2]; +	char *p; +	struct maildir_info minfo; + +	if (maildir_info_imap_find(&minfo, sqwebmail_folder, +				   login_returnaddr()) < 0) +		return; + +	if (acl_read2(&l, &minfo, &owner) < 0) +	{ +		maildir_info_destroy(&minfo); +		return; +	} + +	strcpy(buf, ACL_ADMINISTER); +	acl_computeRights(&l, buf, owner); +	if (!*buf) +	{ +		if (owner) +			free(owner); +		maildir_aclt_list_destroy(&l); +		maildir_info_destroy(&minfo); +		return; +	} + +	if (*cgi("delentity")) +	{ +		if (maildir_aclt_list_del(&l, cgi("delentity"))) +			printf("%s", getarg("ACL_failed")); +	} + +	if (*cgi("do.update")) +	{ +		char *entity=NULL; +		const char *p; +		char new_acl[40]; + +		p=cgi("entitytype"); + +		if (strcmp(p, "anonymous") == 0 || +		    strcmp(p, "owner") == 0) +			entity=strdup(p); +		else if (strcmp(p, "user") == 0) +		{ +			p=cgi("entity"); + +			if (*p) +			{ +				entity=malloc(sizeof("user=")+strlen(p)); +				if (entity) +					strcat(strcpy(entity, "user="), p); +			} +		} +		else if (strcmp(p, "group") == 0) +		{ +			p=cgi("entity"); + +			if (*p) +			{ +				entity=malloc(sizeof("group=")+strlen(p)); +				if (entity) +					strcat(strcpy(entity, "group="), p); +			} +		} +		else +		{ +			entity=strdup(cgi("entity")); +		} + +		if (*cgi("negate") == '-' && entity) +		{ +			char *p=malloc(strlen(entity)+2); + +			if (p) +				strcat(strcpy(p, "-"), entity); +			free(entity); +			entity=p; +		} + +		if (entity) +		{ +			char *val= +				libmail_u_convert_toutf8(entity, +							 sqwebmail_content_charset, +							 NULL); + + +			if (val) +			{ +				free(entity); +				entity=val; +			} +		} +		p=getarg("ACL_all"); + +		new_acl[0]=0; + +		while (*p && strlen(new_acl) < sizeof(new_acl)-2) +		{ +			char b[40]; + +			sprintf(b, "acl_%c", *p); + +			if (*cgi(b)) +			{ +				b[0]=*p; +				b[1]=0; +				strcat(new_acl, b); +			} +			++p; +		} + +		if (!entity || !*entity || +		    maildir_aclt_list_add(&l, entity, new_acl, NULL) < 0) +			printf("%s", getarg("ACL_failed")); + +		if (entity) +			free(entity); +	} + +	p=maildir_name2dir(".", minfo.maildir); + +	if (p) +	{ +		const char *err_ident; + +		if (maildir_acl_write(&l, minfo.homedir, +				      strncmp(p, "./", 2) == 0 ? p+2:p, +				      owner, &err_ident)) +			printf("%s", getarg("ACL_failed")); +		free(p); +	} + +	if (owner) +		free(owner); +	maildir_aclt_list_destroy(&l); +	maildir_info_destroy(&minfo); +} + +static void p_ident_name(const char *identifier) +{ +	char *val=libmail_u_convert_fromutf8(identifier, +					     sqwebmail_content_charset, +					     NULL); + +	if (val) +	{ +		output_attrencoded(val); +		free(val); +		return; +	} + +	output_attrencoded(identifier); +} + +static int getacl_cb(const char *identifier, const maildir_aclt *acl, +		     void *dummy) +{ +	printf("<tr><td>"); +	p_ident_name(identifier); +	printf("</td><td>"); +	showrights(maildir_aclt_ascstr(acl)); + + + +	printf("<span class=\"folder-acl-list-action\"> (<a href=\""); +	output_scriptptrget(); +	printf("&form=acl&editentity="); +	output_urlencoded(identifier); +	printf("&editaccess="); +	output_urlencoded(maildir_aclt_ascstr(acl)); +	printf("\">%s</a>) (<a href=\"", getarg("EDIT")); +	output_scriptptrget(); +	printf("&form=acl&delentity="); +	output_urlencoded(identifier); +	printf("\">%s</a>)</td></tr>\n", getarg("DELETE")); +	return 0; +} + +void getacl() +{ +	maildir_aclt_list l; +	char buf[2]; +	char *owner; +	const char *a; +	const char *editentity=cgi("editentity"); +	const char *editaccess=cgi("editaccess"); + +	const char *entitytype=""; +	const char *entityval=""; +	int negate=0; + +	if (acl_read(&l, sqwebmail_folder, &owner) < 0) +	{ +		printf("%s", getarg("ACL_noaccess")); +		return; +	} +	strcpy(buf, ACL_ADMINISTER); +	acl_computeRights(&l, buf, owner); +	if (owner) +		free(owner); + +	if (buf[0] == 0) +	{ +		maildir_aclt_list_destroy(&l); +		return; +	} + +	printf("<form method=\"post\" name=\"form1\" action=\""); +	output_scriptptr(); +	printf("\">"); +	output_scriptptrpostinfo(); +	printf("<input type=\"hidden\" name=\"update\" value=\"1\" />\n" +	       "<input type=\"hidden\" name=\"form\" value=\"acl\" />\n"); +	printf("<table class=\"folder-acl-list\"><tbody>" +	       "<tr><th align=\"left\">%s</th><th align=\"left\">%s</th></tr>\n", +	       getarg("ENTITY"), +	       getarg("ACCESSRIGHTS")); + +	maildir_aclt_list_enum(&l, getacl_cb, NULL); + +	if (*editentity == '-') +	{ +		++editentity; +		negate=1; +	} + +	if (*editentity) +	{ +		if (strncmp(editentity, "user=", 5) == 0) +		{ +			entitytype="user"; +			entityval=editentity+5; +		} +		else if (strncmp(editentity, "group=", 6) == 0) +		{ +			entitytype="group"; +			entityval=editentity+6; +		} +		else if (strcmp(editentity, "owner") == 0 || +			 strcmp(editentity, "anonymous") == 0) +		{ +			entitytype=editentity; +		} +		else +		{ +			entitytype="other"; +			entityval=editentity; +		} +	} + +	printf("<tr><td colspan=\"2\"><hr width=\"90%%\" />"); +	printf("<table><tbody>\n"); +	printf("<tr><th colspan=\"2\" align=\"left\">%s</th></tr>\n", +	       getarg("UPDATEHDR")); +	printf("<tr align=\"top\"><td>" +	       "<select name=\"negate\" id=\"negate\">\n" +	       "<option value=\"\" > </option>\n" +	       "<option value=\"-\" %s>-</option>\n" +	       "</select>\n" +	       "<select name=\"entitytype\" id=\"entitytype\" " +	       "onchange=\"javascript:updent()\" >\n" +	       "<option value=\"user\" %s >%s</option>\n" +	       "<option value=\"group\" %s >%s</option>\n" +	       "<option value=\"owner\" %s >%s</option>\n" +	       "<option value=\"anonymous\" %s >%s</option>\n" +	       "<option value=\"administrators\" %s >%s</option>\n" +	       "<option value=\"other\" %s >%s</option>\n" +	       "</select><input type=\"text\" name=\"entity\" " +	       " id=\"entity\" value=\"", +	       negate ? "selected=\"selected\"":"", +	       strcmp(entitytype, "user") == 0 ? "selected=\"selected\"":"", +	       getarg("USER"), + +	       strcmp(entitytype, "group") == 0 ? "selected=\"selected\"":"", +	       getarg("GROUP"), + +	       strcmp(entitytype, "owner") == 0 ? "selected=\"selected\"":"", +	       getarg("OWNER"), + +	       strcmp(entitytype, "anonymous") == 0 ? "selected=\"selected\"":"", +	       getarg("ANONYMOUS"), + +	       strcmp(entitytype, "administrators") == 0 ? "selected=\"selected\"":"", +	       getarg("ADMINISTRATORS"), + +	       strcmp(entitytype, "other") == 0 ? "selected=\"selected\"":"", +	       getarg("OTHER")); + +	p_ident_name(entityval); + +	printf("\"/></td><td><table><tbody>"); + +	a=getarg("ACL_all"); + +	while (*a) +	{ +		char buf2[40]; + +		sprintf(buf2, "ACL_%c", *a); + +		printf("<tr><td><input type=\"checkbox\" name=\"acl_%c\" " +		       "id=\"acl_%c\" %s />" +		       "</td><td>%s</td></tr>\n", +		       *a, *a, +		       strchr(editaccess, *a) ? "checked=\"checked\"":"", +		       getarg(buf2)); +		++a; +	} + +	printf("</tbody></table></td></tr>\n" +	       "<tr><td> </td>" +	       "<td><input type=\"submit\" name=\"do.update\" value=\"%s\" />" +	       "</td>" +	       "</table></tbody></td></tr>\n", +	       getarg("UPDATE")); + +	printf("</tbody></table></form>\n"); +} + | 
