/* * $Id: vlimits.c,v 1.17 2007/05/22 03:59:00 rwidmer Exp $ * handle domain limits in both file format * Brian Kolaci */ #include #include #include #include #include #include #include #include #include "config.h" #include "vpopmail.h" #include "vauth.h" #include "vlimits.h" #define TOKENS " :\t\n\r" void vdefault_limits (struct vlimits *limits) { /* initialize structure */ memset(limits, 0, sizeof(*limits)); limits->maxpopaccounts = -1; limits->maxaliases = -1; limits->maxforwards = -1; limits->maxautoresponders = -1; limits->maxmailinglists = -1; /* // if this fails, we have the very basic limits above vlimits_read_limits_file(VLIMITS_DEFAULT_FILE, limits);*/ } /* read in the limits file pointed contained in dir * parse the contents of the file and return result in a vlimits struct */ int vlimits_read_limits_file(const char *dir, struct vlimits * limits) { char buf[MAX_BUFF]; char * s1; char * s2; FILE * fs; /* open the nominated limits file */ if ((fs = fopen(dir, "r")) == NULL) return (-1); /* suck in each line of the file */ while (fgets(buf, sizeof(buf), fs) != NULL) { /* skip comments */ if (*buf == '#') continue; /* if the line contains no tokens, skip on to next line */ if ((s1 = strtok(buf, TOKENS)) == NULL) continue; if (!strcmp(s1, "maxpopaccounts")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxpopaccounts = atoi(s2); } if (!strcmp(s1, "maxaliases")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxaliases = atoi(s2); } if (!strcmp(s1, "maxforwards")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxforwards = atoi(s2); } if (!strcmp(s1, "maxautoresponders")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxautoresponders = atoi(s2); } if (!strcmp(s1, "maxmailinglists")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxmailinglists = atoi(s2); } if (!strcmp(s1, "quota")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->diskquota = atoi(s2); } if (!strcmp(s1, "maxmsgcount")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->maxmsgcount = atoi(s2); } if (!strcmp(s1, "default_quota")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->defaultquota = atoi(s2); } if (!strcmp(s1, "default_maxmsgcount")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->defaultmaxmsgcount = atoi(s2); } if (!strcmp(s1, "disable_pop")) { limits->disable_pop = 1; } if (!strcmp(s1, "disable_imap")) { limits->disable_imap = 1; } if (!strcmp(s1, "disable_dialup")) { limits->disable_dialup = 1; } if (!strcmp(s1, "disable_password_changing")) { limits->disable_passwordchanging = 1; } if (!strcmp(s1, "disable_external_relay")) { limits->disable_relay = 1; } if (!strcmp(s1, "disable_smtp")) { limits->disable_smtp = 1; } if (!strcmp(s1, "disable_webmail")) { limits->disable_webmail = 1; } if (!strcmp(s1, "disable_spamassassin")) { limits->disable_spamassassin = 1; } if (!strcmp(s1, "delete_spam")) { limits->delete_spam = 1; } if (!strcmp(s1, "disable_maildrop")) { limits->disable_maildrop = 1; } if (!strcmp(s1, "perm_account")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_account = atoi(s2) & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_alias")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_alias = atoi(s2) & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_forward")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_forward = atoi(s2) & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_autoresponder")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_autoresponder = atoi(s2) & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_maillist")) { unsigned long perm; if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; perm = atol(s2); limits->perm_maillist = perm & VLIMIT_DISABLE_ALL; perm >>= VLIMIT_DISABLE_BITS; limits->perm_maillist_users = perm & VLIMIT_DISABLE_ALL; perm >>= VLIMIT_DISABLE_BITS; limits->perm_maillist_moderators = perm & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_quota")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_quota = atoi(s2) & VLIMIT_DISABLE_ALL; } if (!strcmp(s1, "perm_defaultquota")) { if ((s2 = strtok(NULL, TOKENS)) == NULL) continue; limits->perm_defaultquota = atoi(s2) & VLIMIT_DISABLE_ALL; } } fclose(fs); return 0; } /* Take the limits struct, and write it out as a .qmailadmin-limits * in the nominated dir */ int vlimits_write_limits_file(const char *dir, const struct vlimits *limits) { FILE * fs; /* open the limits file (overwrite if it already exists) */ if ((fs = fopen(dir, "w+")) != NULL) { /* write out limits into the file */ fprintf(fs, "maxpopaccounts: %d\n", limits->maxpopaccounts); fprintf(fs, "maxaliases: %d\n", limits->maxaliases); fprintf(fs, "maxforwards: %d\n", limits->maxforwards); fprintf(fs, "maxautoresponders: %d\n", limits->maxautoresponders); fprintf(fs, "maxmailinglists: %d\n", limits->maxmailinglists); fprintf(fs, "quota: %d\n", limits->diskquota); fprintf(fs, "maxmsgcount: %d\n", limits->maxmsgcount); fprintf(fs, "default_quota: %d\n", limits->defaultquota); fprintf(fs, "default_maxmsgcount: %d\n", limits->defaultmaxmsgcount); if (limits->disable_pop) fprintf(fs, "disable_pop\n"); if (limits->disable_imap) fprintf(fs, "disable_imap\n"); if (limits->disable_dialup) fprintf(fs, "disable_dialup\n"); if (limits->disable_passwordchanging) fprintf(fs, "disable_password_changing\n"); if (limits->disable_webmail) fprintf(fs, "disable_webmail\n"); if (limits->disable_relay) fprintf(fs, "disable_external_relay\n"); if (limits->disable_smtp) fprintf(fs, "disable_smtp\n"); if (limits->disable_spamassassin) fprintf(fs, "disable_spamassassin\n"); if (limits->delete_spam) fprintf(fs, "delete_spam\n"); if (limits->disable_maildrop) fprintf(fs, "disable_maildrop\n"); fprintf(fs, "perm_account: %d\n", limits->perm_account); fprintf(fs, "perm_alias: %d\n", limits->perm_alias); fprintf(fs, "perm_forward: %d\n", limits->perm_forward); fprintf(fs, "perm_autoresponder: %d\n", limits->perm_autoresponder); fprintf(fs, "perm_maillist: %d\n", limits->perm_maillist); fprintf(fs, "perm_quota: %d\n", (limits->perm_quota)|(limits->perm_maillist_users<perm_maillist_moderators<<(VLIMIT_DISABLE_BITS*2))); fprintf(fs, "perm_defaultquota: %d\n", limits->perm_defaultquota); fclose(fs); } else { fprintf(stderr, "vlimits: failed to open limits file (%d): %s\n", errno, dir); return -1; } return 0; } int vlimits_get_flag_mask(struct vlimits *limits) { int mask = 0; if (limits->disable_pop != 0) { mask |= NO_POP; } if (limits->disable_smtp != 0) { mask |= NO_SMTP; } if (limits->disable_imap != 0) { mask |= NO_IMAP; } if (limits->disable_relay != 0) { mask |= NO_RELAY; } if (limits->disable_webmail != 0) { mask |= NO_WEBMAIL; } if (limits->disable_passwordchanging != 0) { mask |= NO_PASSWD_CHNG; } if (limits->disable_dialup != 0) { mask |= NO_DIALUP; } if (limits->disable_spamassassin != 0) { mask |= NO_SPAMASSASSIN; } if (limits->delete_spam != 0) { mask |= DELETE_SPAM; } if (limits->disable_maildrop != 0) { mask |= NO_MAILDROP; } return mask; /* this feature has been temporarily disabled until we can figure * out a solution to the problem where edited users will have domain * limits saved into their user limits. */ //return 0; } #ifndef ENABLE_MYSQL_LIMITS /* grab the limits for this domain * look first for a ~vpopmail/domains/domain/.qmailadmin-limits * if not found, try ~vpopmail/etc/vlimits.default * if neither found, return error */ int vget_limits(const char *domain, struct vlimits *limits) { char mydomain[MAX_BUFF]; char dir[MAX_BUFF]; uid_t uid; gid_t gid; /* initialise a limits struct. */ vdefault_limits(limits); /* use copy of name as vget_assign may change it on us */ snprintf(mydomain, sizeof(mydomain), "%s", domain); /* extract the dir, uid, gid of the domain */ if (vget_assign(mydomain, dir, sizeof(dir), &uid, &gid) == NULL) { fprintf (stderr, "Error. Domain %s was not found in the assign file\n", mydomain); return (-1); } /* work out the location of the .qmailadmin-limits file */ strncat (dir, "/.qmailadmin-limits", sizeof(dir)-strlen(dir)-1); /* try to read in the contents of the .qmailadmin-limits file. * and populate the limits struct with the result */ if (vlimits_read_limits_file (dir, limits) == 0) { /* Successfully read the file in */ chown(dir,uid,gid); chmod(dir, S_IRUSR|S_IWUSR); } else if (vlimits_read_limits_file (VLIMITS_DEFAULT_FILE, limits) == 0) { /* We couldn't find a .qmailadmin-limits in the domain's dir. * but we did find a global file at ~vpopmail/etc/vlimits.default file * so we have used that instead */ } else { /* No ~vpopmail/domains/domain/.qmailadmin-limits * and also no ~vpopmail/etc/vlimits.default * so return error */ return -1; } return 0; } /* Take the limits struct, and write it out as a .qmailadmin-limits * in the nominated domain's dir */ int vset_limits(const char *domain, const struct vlimits *limits) { char mydomain[MAX_BUFF]; char dir[MAX_BUFF]; uid_t uid; gid_t gid; /* use copy of name as vget_assign may change it on us */ snprintf(mydomain, sizeof(mydomain), "%s", domain); /* get the dir, uid and gid of the nominated domain */ if (vget_assign(mydomain, dir, sizeof(dir), &uid, &gid) == NULL) { fprintf (stderr, "Error. Domain %s was not found in the assign file\n",mydomain); return(-1); } strncat(dir, "/.qmailadmin-limits", sizeof(dir)-strlen(dir)-1); if (vlimits_write_limits_file (dir, limits) != 0) { return -1; } return 0; } /* delete the .qmailadmin-limits file for the nominated domain */ int vdel_limits(const char *domain) { char mydomain[MAX_BUFF]; char dir[MAX_BUFF]; uid_t uid; gid_t gid; /* use copy of name as vget_assign may change it on us */ snprintf(mydomain, sizeof(mydomain), "%s", domain); /* get filename */ if (vget_assign(mydomain, dir, sizeof(dir), &uid, &gid) == NULL) { printf ("Failed vget_assign for %s\n",mydomain); return (-1); } strncat(dir, "/.qmailadmin-limits", sizeof(dir)-strlen(dir)-1); return unlink(dir); } #endif void vlimits_setflags (struct vqpasswd *pw, char *domain) { struct vlimits limits; if ((! (pw->pw_gid & V_OVERRIDE)) && (vget_limits (domain, &limits) == 0)) { pw->pw_flags = pw->pw_gid | vlimits_get_flag_mask (&limits); } else pw->pw_flags = pw->pw_gid; }