/* ** Copyright 2004-2011 Double Precision, Inc. See COPYING for ** distribution information. */ /* */ #include #include #include #include #include #include #include #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 "htmllibdir.h" #if HAVE_UNISTD_H #include #endif #if HAVE_DIRENT_H #include #define NAMLEN(dirent) strlen(dirent->d_name) #else #define dirent direct #define NAMLEN(dirent) ((dirent)->d_namlen) #if HAVE_SYS_NDIR_H #include #endif #if HAVE_SYS_DIR_H #include #endif #if HAVE_NDIR_H #include #endif #endif #include #include #if HAVE_UTIME_H #include #endif #include #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= unicode_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=unicode_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(""); p_ident_name(identifier); printf(""); showrights(maildir_aclt_ascstr(acl)); printf(" (%s) (%s)\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("
"); output_scriptptrpostinfo(); printf("\n" "\n"); printf("" "\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("\n", getarg("UPDATE")); printf("
%s%s

"); printf("\n"); printf("\n", getarg("UPDATEHDR")); printf("\n" "" "" "
%s
" "\n" ""); a=getarg("ACL_all"); while (*a) { char buf2[40]; sprintf(buf2, "ACL_%c", *a); printf("\n", *a, *a, strchr(editaccess, *a) ? "checked=\"checked\"":"", getarg(buf2)); ++a; } printf("
" "%s
 " "
\n"); }