* check_size
Syntax: check_size [EMAIL PROTECTED] requested_size[K|M]
Check quota of user and of domain. If current disk usage plus
requested_size more than quota, answer is -ERR, else say +OK
* check_user
Syntax: check_user [EMAIL PROTECTED]
Check exist of [EMAIL PROTECTED] Answer is +OK, if [EMAIL PROTECTED] valid user,
alias, maillist. Else, answer is -ERR, if [EMAIL PROTECTED] not exist or user
set bounce_all_mail flag.
diff -ur vpopmail-5.4.16.orig/maildirquota.c vpopmail-5.4.16/maildirquota.c
--- vpopmail-5.4.16.orig/maildirquota.c 2006-01-17 22:08:34.000000000 +0300
+++ vpopmail-5.4.16/maildirquota.c 2006-06-15 17:06:33.000000000 +0400
@@ -47,8 +47,8 @@
static int docheckquota(const char *dir, int *maildirsize_fdptr,
const char *quota_type, long xtra_size, int xtra_cnt, int *percentage);
static int docount(const char *, time_t *, off_t *, unsigned *);
-static int maildir_checkquota(const char *dir, int *maildirsize_fdptr,
- const char *quota_type, long xtra_size, int xtra_cnt);
+//static int maildir_checkquota(const char *dir, int *maildirsize_fdptr,
+// const char *quota_type, long xtra_size, int xtra_cnt);
/* moved into maildirquota.h as non-static
static int maildir_addquota(const char *dir, int maildirsize_fd,
const char *quota_type, long maildirsize_size, int maildirsize_cnt);
@@ -404,7 +404,7 @@
}
-static int maildir_checkquota(const char *dir,
+int maildir_checkquota(const char *dir,
int *maildirsize_fdptr,
const char *quota_type,
long xtra_size,
@@ -477,8 +477,10 @@
}
close(maildirsize_fd);
- if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60)
+ if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60) {
+ free(checkfolder);
return (n);
+ }
}
/* rebuild the maildirsize file */
diff -ur vpopmail-5.4.16.orig/maildirquota.h vpopmail-5.4.16/maildirquota.h
--- vpopmail-5.4.16.orig/maildirquota.h 2005-03-20 20:01:43.000000000 +0300
+++ vpopmail-5.4.16/maildirquota.h 2006-06-15 15:27:41.000000000 +0400
@@ -17,6 +17,8 @@
int domain_over_maildirquota(const char *userdir);
int user_over_maildirquota(const char *dir, const char *quota);
int vmaildir_readquota(const char *dir, const char *quota);
+int maildir_checkquota(const char *dir, int *maildirsize_fdptr, const char
*quota_type, long xtra_size, int xtra_cnt);
+
int maildir_addquota(const char *, /* Pointer to the maildir */
int, /* Must be the int pointed to by 2nd arg to checkquota */
diff -ur vpopmail-5.4.16.orig/vpopmaild.c vpopmail-5.4.16/vpopmaild.c
--- vpopmail-5.4.16.orig/vpopmaild.c 2006-01-17 22:20:47.000000000 +0300
+++ vpopmail-5.4.16/vpopmaild.c 2006-06-15 17:45:53.000000000 +0400
@@ -27,6 +27,7 @@
#include "vpopmail.h"
#include "vauth.h"
#include "vlimits.h"
+#include "maildirquota.h"
/* two responses */
#define RET_OK "+OK \r\n"
@@ -66,6 +67,7 @@
char TmpDomain[AUTH_SIZE];
int compact_output = 0;
+int logged_in = 0;
int login();
int add_user();
@@ -101,6 +103,8 @@
int mod_list();
int quit();
int help();
+int check_user();
+int check_size();
/* utility functions */
void send_user_info(struct vqpasswd *tmpvpw);
@@ -118,47 +122,59 @@
char *command;
int (*func)();
char *help;
+ int access_level;
} func_t;
/*
-{"login", login, "[EMAIL PROTECTED] password<crlf>" },
+{"login", login, "[EMAIL PROTECTED] password<crlf>", access },
*/
+#define ACCESS_ANONYMOUS 1
+#define ACCESS_USER 2
+#define ACCESS_QA_ADMIN 4
+#define ACCESS_SA_ADMIN 8
+#define ACCESS_AUTHORIZED ACCESS_USER | ACCESS_QA_ADMIN | ACCESS_SA_ADMIN
+#define ACCESS_ANYONE ACCESS_ANONYMOUS | ACCESS_AUTHORIZED
+#define ACCESS_ADMINS ACCESS_QA_ADMIN | ACCESS_SA_ADMIN
+
func_t Functions[] = {
-{"add_user", add_user, "[EMAIL PROTECTED] password<crlf>" },
-{"del_user", del_user, "[EMAIL PROTECTED]<crlf>" },
-{"mod_user", mod_user, "[EMAIL PROTECTED] (option lines)<crlf>.<crlf>" },
-{"user_info", user_info, "user_domain<crlf>" },
-{"add_alias_domain", add_alias_domain, "domain alias<crlf>" },
-{"add_domain", add_domain, "domain [EMAIL PROTECTED]<crlf>" },
-{"del_domain", del_domain, "domain<crlf>" },
-{"dom_info", dom_info, "domain<crlf>" },
-{"mk_dir", mk_dir, "/full/path/to/dir<crlf>" },
-{"rm_dir", rm_dir, "/full/path/to/dir<crlf>" },
-{"list_dir", list_dir, "/full/path/to/dir<crlf>" },
-{"rm_file", rm_file, "/full/path/to/file<crlf>" },
-{"write_file", write_file, "/full/path (data lines)<crlf>.<crlf>" },
-{"read_file", read_file, "/full/path<crlf>" },
-{"list_domains", list_domains, "[page per_page]<crlf>" },
-{"find_domain", find_domain, "domain [per-page]<crlf>" },
-{"domain_count", domain_count, "<crlf>" },
-{"list_users", list_users, "domain<crlf>" },
-{"list_alias", list_alias, "domain<crlf>" },
-{"list_lists", list_lists, "domain<crlf>" },
-{"get_ip_map", get_ip_map, "domain<crlf>" },
-{"add_ip_map", add_ip_map, "domain ip<crlf>" },
-{"del_ip_map", del_ip_map, "domain<crlf>" },
-{"show_ip_map", show_ip_map, "domain<crlf>" },
-{"get_limits", get_limits, "domain<crlf>" },
-{"set_limits", set_limits, "domain (option lines)<crlf>.<crlf>"},
-{"del_limits", del_limits, "domain<crlf>" },
-{"get_lastauth", get_lastauth, "[EMAIL PROTECTED]<crlf>" },
-{"add_list", add_list, "domain listname (command line options)<crlf>" },
-{"del_list", del_list, "domain listname<crlf>"},
-{"mod_list", mod_list, "domain listname (command line options)<crlf>" },
-{"quit", quit, "quit" },
-{"help", help, "help" },
-{NULL, NULL } };
+{"add_user", add_user, "[EMAIL PROTECTED] password<crlf>", ACCESS_ADMINS },
+{"del_user", del_user, "[EMAIL PROTECTED]<crlf>", ACCESS_ADMINS },
+{"mod_user", mod_user, "[EMAIL PROTECTED] (option lines)<crlf>.<crlf>",
ACCESS_AUTHORIZED },
+{"user_info", user_info, "user_domain<crlf>", ACCESS_ADMINS },
+{"add_alias_domain", add_alias_domain, "domain alias<crlf>", ACCESS_SA_ADMIN },
+{"add_domain", add_domain, "domain [EMAIL PROTECTED]<crlf>", ACCESS_SA_ADMIN },
+{"del_domain", del_domain, "domain<crlf>", ACCESS_SA_ADMIN },
+{"dom_info", dom_info, "domain<crlf>", ACCESS_SA_ADMIN },
+{"mk_dir", mk_dir, "/full/path/to/dir<crlf>", ACCESS_AUTHORIZED },
+{"rm_dir", rm_dir, "/full/path/to/dir<crlf>", ACCESS_AUTHORIZED },
+{"list_dir", list_dir, "/full/path/to/dir<crlf>", ACCESS_AUTHORIZED },
+{"rm_file", rm_file, "/full/path/to/file<crlf>", ACCESS_AUTHORIZED },
+{"write_file", write_file, "/full/path (data lines)<crlf>.<crlf>",
ACCESS_AUTHORIZED },
+{"read_file", read_file, "/full/path<crlf>", ACCESS_AUTHORIZED },
+{"list_domains", list_domains, "[page per_page]<crlf>", ACCESS_SA_ADMIN },
+{"find_domain", find_domain, "domain [per-page]<crlf>", ACCESS_SA_ADMIN },
+{"domain_count", domain_count, "<crlf>", ACCESS_SA_ADMIN },
+{"list_users", list_users, "domain<crlf>", ACCESS_ADMINS },
+{"list_alias", list_alias, "domain<crlf>", ACCESS_ADMINS },
+{"list_lists", list_lists, "domain<crlf>", ACCESS_ADMINS },
+{"get_ip_map", get_ip_map, "domain<crlf>", ACCESS_ANYONE },
+{"add_ip_map", add_ip_map, "domain ip<crlf>", ACCESS_SA_ADMIN },
+{"del_ip_map", del_ip_map, "domain<crlf>", ACCESS_SA_ADMIN },
+{"show_ip_map", show_ip_map, "domain<crlf>", ACCESS_SA_ADMIN },
+{"get_limits", get_limits, "domain<crlf>", ACCESS_AUTHORIZED },
+{"set_limits", set_limits, "domain (option lines)<crlf>.<crlf>", ACCESS_ADMINS
},
+{"del_limits", del_limits, "domain<crlf>", ACCESS_SA_ADMIN },
+{"get_lastauth", get_lastauth, "[EMAIL PROTECTED]<crlf>", ACCESS_AUTHORIZED },
+{"add_list", add_list, "domain listname (command line options)<crlf>",
ACCESS_ADMINS },
+{"del_list", del_list, "domain listname<crlf>", ACCESS_ADMINS },
+{"mod_list", mod_list, "domain listname (command line options)<crlf>",
ACCESS_ADMINS },
+{"quit", quit, "", ACCESS_ANYONE },
+{"help", help, "", ACCESS_ANYONE },
+{"login", login, "[EMAIL PROTECTED] password [compact]", ACCESS_ANONYMOUS },
+{"check_user", check_user, "[EMAIL PROTECTED]<crlf>", ACCESS_ANYONE },
+{"check_size", check_size, "[EMAIL PROTECTED] message_size<crlf>",
ACCESS_ANYONE },
+{NULL, NULL, NULL, 0 } };
int wait_read()
@@ -207,7 +223,7 @@
int read_size;
char *command;
int i;
- int found;
+ int found,accpass;
if( vauth_open( 1 )) {
snprintf(WriteBuf,sizeof(WriteBuf),
@@ -219,23 +235,6 @@
snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
wait_write();
- read_size = wait_read();
- if ( read_size < 0 ) {
- snprintf(WriteBuf,sizeof(WriteBuf),
- RET_ERR "XXX read timeout" RET_CRLF);
- wait_write();
- exit(-1);
- }
-
- /* authenticate first or drop connection */
- if ( login() < 0 ) {
- wait_write();
- vclose();
- exit(-1);
- } else {
- wait_write();
- }
-
while(1) {
read_size = wait_read();
if ( read_size < 0 ) {
@@ -255,6 +254,22 @@
for(found=0,i=0;found==0&&Functions[i].command!=NULL;++i ) {
if ( strcasecmp(Functions[i].command, command) == 0 ) {
found = 1;
+ accpass = 0;
+ if (!logged_in && !(Functions[i].access_level & ACCESS_ANONYMOUS)) {
+ snprintf(WriteBuf, sizeof(WriteBuf),
+ RET_ERR "XXX authorization first" RET_CRLF);
+ continue;
+ }
+
+ if (Functions[i].access_level & ACCESS_ANONYMOUS) accpass = 1;
+ if (logged_in && Functions[i].access_level & ACCESS_USER) accpass = 1;
// users can access
+ if (logged_in && AuthVpw.pw_gid & QA_ADMIN &&
Functions[i].access_level & ACCESS_QA_ADMIN) accpass = 1;
+ if (logged_in && AuthVpw.pw_gid & SA_ADMIN &&
Functions[i].access_level & ACCESS_SA_ADMIN) accpass = 1;
+ if (!accpass) {
+ snprintf(WriteBuf, sizeof(WriteBuf),
+ RET_ERR "XXX Permission denied for use this command" RET_CRLF);
+ continue;
+ }
Functions[i].func();
}
}
@@ -269,26 +284,12 @@
int login()
{
- char *command;
char *email;
char *pass;
char *param;
uid_t uid;
gid_t gid;
-
- if ((command=strtok(ReadBuf,TOKENS))==NULL) {
- snprintf(WriteBuf, sizeof(WriteBuf),
- RET_ERR "XXX authorization first" RET_CRLF);
- return(-1);
- }
-
- if (strcasecmp(command, "login" ) != 0 ) {
- if (strcasecmp(command, "help") == 0 ) help();
- snprintf(WriteBuf, sizeof(WriteBuf),
- RET_ERR "XXX authorization first" RET_CRLF);
- return(-1);
- }
if ((email=strtok(NULL,TOKENS))==NULL) {
snprintf(WriteBuf, sizeof(WriteBuf),
RET_ERR "XXX email address required" RET_CRLF);
@@ -366,6 +367,7 @@
send_user_info(&AuthVpw);
snprintf(WriteBuf, sizeof(WriteBuf), "." RET_CRLF);
+ logged_in = 1;
return(0);
}
@@ -2236,15 +2238,24 @@
int help()
{
- int i;
+ int i,accpass;
snprintf(WriteBuf,sizeof(WriteBuf), RET_OK_MORE);
wait_write();
- snprintf(WriteBuf,sizeof(WriteBuf),"login [EMAIL PROTECTED] password"
RET_CRLF);
- wait_write();
+ //snprintf(WriteBuf,sizeof(WriteBuf),"login [EMAIL PROTECTED] password"
RET_CRLF);
+ //wait_write();
for(i=0;Functions[i].command!=NULL;++i ) {
+
+ accpass = 0;
+ if (!logged_in && !(Functions[i].access_level & ACCESS_ANONYMOUS))
continue;
+ if (Functions[i].access_level & ACCESS_ANONYMOUS) accpass = 1;
+ if (logged_in && Functions[i].access_level & ACCESS_USER) accpass = 1; //
users can access
+ if (logged_in && AuthVpw.pw_gid & QA_ADMIN && Functions[i].access_level &
ACCESS_QA_ADMIN) accpass = 1;
+ if (logged_in && AuthVpw.pw_gid & SA_ADMIN && Functions[i].access_level &
ACCESS_SA_ADMIN) accpass = 1;
+ if (!accpass) continue;
+
snprintf(WriteBuf, sizeof(WriteBuf), "%s %s" RET_CRLF,
Functions[i].command,
Functions[i].help );
@@ -2254,6 +2265,213 @@
return(0);
}
+int check_user()
+{
+ char *user;
+ char domain[MAX_PW_DOMAIN+1];
+ char *yp;
+ char user_dir[MAX_BUFF];
+ char path[MAX_BUFF];
+ char buf[1024];
+ int readed,offset;
+ FILE *fd;
+ struct vqpasswd *user_passwd = NULL;
+
+ if ((user=strtok(NULL,TOKENS))==NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf),
+ RET_ERR "XXX email required" RET_CRLF);
+ return(-1);
+ }
+
+ if (!(yp = strchr(user,'@'))) {
+ snprintf(WriteBuf,sizeof(WriteBuf),
+ RET_ERR "XXX email must be in [EMAIL PROTECTED] format" RET_CRLF);
+ return(-1);
+ }
+
+ *yp=0;
+ yp++;
+ strncpy(domain, yp, sizeof(domain));
+
+ // code based on chkuser patch by Antonio Nati
(http://www.interazioni.it/opensource)
+ // rewriten by Dmitriy MiksIr ([EMAIL PROTECTED])
+
+ if (vget_assign(domain, user_dir, sizeof(user_dir), NULL, NULL) == NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX domain not exist"
RET_CRLF);
+ return(-1);
+ }
+
+ snprintf(path, sizeof(path), "%s/.qmail-default", user_dir);
+ readed = 0;
+
+ fd = fopen(path, "r");
+ if (fd == NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX can not open
.qmail-default" RET_CRLF);
+ return(-1);
+ }
+
+ // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+ readed = fread(buf, 1, sizeof(buf) - 1, fd);
+ fclose (fd);
+
+ buf[readed] = 0;
+ if (strstr(buf, " " BOUNCE_ALL) == NULL
+ // uncomment line bottom if want always bounce mail even vpopmail
setted for delete mail
+ && strstr(buf, " " DELETE_ALL) == NULL
+ ) {
+ // if in .qmail-default not found bounce string
+ // as result all mail for domain must be recieved
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+ }
+
+ if (valias_select (user, domain) != NULL) {
+ // alias for [EMAIL PROTECTED] found,pass
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+ }
+
+ user_passwd = vauth_getpw(user, domain);
+
+ if (user_passwd == NULL) {
+ for (offset = 1; offset <= (readed - 1); offset++) {
+ if (*(user + offset) == '-') {
+ *(user + offset) = 0;
+ user_passwd = vauth_getpw(user, domain);
+ *(user + offset) = '-';
+ if (user_passwd != NULL) break;
+ }
+ }
+ }
+
+ if (user_passwd != NULL) {
+ if (user_passwd->pw_flags & BOUNCE_MAIL) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX exist, but user
set flag for bounce all mail" RET_CRLF);
+ return(-1);
+ }
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+ }
+
+ while ((yp = strchr(user,'.'))) *yp = ':';
+
+ snprintf(path, sizeof(path), "%s/.qmail-%s", user_dir, user);
+ fd = fopen(path, "r");
+ if (fd != NULL) {
+ // path/.qmail-user exists, pass
+ fclose(fd);
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+ }
+
+ readed = strlen(user);
+ for (offset = readed - 1; offset > 0; --offset) {
+ if (*(user + offset) == '-') {
+ *(user + offset) = 0;
+ snprintf(path, sizeof(path), "%s/.qmail-%s-default", user_dir,
user);
+ *(user + offset) = '-';
+ fd = fopen(path, "r");
+ if (fd != NULL) {
+ // path/.qmail-ext-default exists, pass
+ fclose(fd);
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+ }
+ }
+ }
+
+ while ((yp = strchr(user,':'))) *yp = '.';
+
+ // ezmlm must be already checked, because it create symlink .qmail-listname
and .qmail-listname-default
+ // mailman seems be ok too
+
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX User not found" RET_CRLF);
+ return(-1);
+
+}
+
+int check_size()
+{
+ char *user, *yp;
+ char domain[MAX_PW_DOMAIN+1];
+ char user_dir[MAX_BUFF];
+ char path[MAX_BUFF];
+ char *size;
+ unsigned long asksize,userq,limitq;
+ int userc,i,retv;
+ struct vqpasswd *user_passwd = NULL;
+ struct vlimits limits;
+
+ if ((user=strtok(NULL,TOKENS))==NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf),
+ RET_ERR "XXX email required" RET_CRLF);
+ return(-1);
+ }
+
+ if ((size=strtok(NULL,TOKENS))==NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf),
+ RET_ERR "XXX size required" RET_CRLF);
+ return(-1);
+ }
+
+ if (!(yp = strchr(user,'@'))) {
+ snprintf(WriteBuf,sizeof(WriteBuf),
+ RET_ERR "XXX email must be in [EMAIL PROTECTED] format" RET_CRLF);
+ return(-1);
+ }
+
+ *yp=0;
+ yp++;
+ strncpy(domain, yp, sizeof(domain));
+
+ if (vget_assign(domain, user_dir, sizeof(user_dir), NULL, NULL) == NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX domain not exist"
RET_CRLF);
+ return(-1);
+ }
+
+ user_passwd = vauth_getpw(user, domain);
+ if (user_passwd == NULL) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX user not found"
RET_CRLF);
+ return(-1);
+ }
+
+ asksize = atol(format_maildirquota(size));
+
+ if ((strcmp(user_passwd->pw_shell, "NOQUOTA"))) {
+ // quota for user is set
+ int fd = -1;
+ snprintf(path, sizeof(path), "%s/Maildir", user_passwd->pw_dir);
+ for (i=0;i<10;i++) {
+ retv = maildir_checkquota(path, &fd, user_passwd->pw_shell, asksize,
1);
+ if (fd >= 0) close(fd);
+ if (retv == 0) break;
+ // overquoted
+ if (errno != EAGAIN) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX mailbox is over
quota (Quota: %s)" RET_CRLF, user_passwd->pw_shell);
+ return(-1);
+ }
+ sleep(1);
+ }
+ }
+ if (!(vget_limits(domain, &limits)) && (limits.diskquota != 0 ||
limits.maxmsgcount != 0)) {
+ limitq = limits.diskquota * 1024 * 1024;
+ if (!(readdomainquota(user_dir, &userq, &userc))) {
+ if (limits.diskquota > 0 && (userq + asksize) > limitq) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX domain is over
quota (Quota: %luS)" RET_CRLF, limitq);
+ return(-1);
+ }
+ if (limits.maxmsgcount > 0 && userc >= limits.maxmsgcount) {
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_ERR "XXX domain is over
quota (Quota: %dC)" RET_CRLF, limits.maxmsgcount);
+ return(-1);
+ }
+ }
+ }
+
+ snprintf(WriteBuf,sizeof(WriteBuf), RET_OK);
+ return(0);
+}
+
+
int bkscandir(const char *dirname,
struct dirent ***namelist,
int (*select)(struct dirent *),