#include #include #include #include #include #include #include #include #include #include #include #include #define CMP_DEV_T(a, b) (major(a) == major(b) && minor(a) == minor(b)) #define LOGPREFIX "QUOTA: " int check_parent(const char *username) { pid_t parent; int num; char buf[256], buf2[256]; const char *smtpbin = "/var/qmail/bin/qmail-smtpd"; // check parent parent = getppid(); num = snprintf(buf, sizeof(buf), "/proc/%d/exe", parent); if (num < 0 || num > sizeof(buf)) { fprintf(stderr, LOGPREFIX "Unable to copy string to buffer for user \"%s\".\n", username); return 0; } num = readlink(buf, buf2, sizeof(buf2)); if (num < 0) { fprintf(stderr, LOGPREFIX "Unable to read parent from proc-fs for user \"%s\": %s\n", username, strerror(errno)); return 0; } buf2[num] = '\0'; if (strcmp(smtpbin, buf2) != 0) { fprintf(stderr, LOGPREFIX "Error: Parent \"%s\" doesn't match qmail-smtp for user \"%s\".\n", buf2, username); return 0; } return 1; } int main() { const char *username = NULL, *device_path = NULL; struct passwd *pw; struct stat st, st2; FILE *fp; struct mntent *ent; struct dqblk dq; time_t now; pid_t parent; parent = getppid(); username = getenv("DTUSER"); if (!username) return 0; // lookup user in passwd pw = getpwnam(username); if (pw == NULL) { fprintf(stderr, LOGPREFIX "Unable to get user \"%s\" from passwd!: %s\n", username, strerror(errno)); return 0; } // seteuid if (seteuid(pw->pw_uid)) { fprintf(stderr, LOGPREFIX "Unable to call seteuid for user \"%s\": %s\n", username, strerror(errno)); return 0; } // check parent if (!check_parent(username)) return 0; if (pw->pw_dir == NULL) { fprintf(stderr, LOGPREFIX "User \"%s\" has no homedir?\n", username); return 0; } // stat homedir to fetch blockdevice id if (stat(pw->pw_dir, &st) < 0) { fprintf(stderr, LOGPREFIX "Stat of \"%s\" of user \"%s\" failed: %s\n", pw->pw_dir, username, strerror(errno)); return 0; } // iterate over mounted devices and check blockdevice id fp = setmntent(_PATH_MOUNTED, "r"); if (fp == NULL) { fprintf(stderr, LOGPREFIX "Unable to open %s!\n", _PATH_MOUNTED); return 0; } while ((ent = getmntent(fp)) != NULL) { if (strcmp(ent->mnt_type, MNTTYPE_SWAP) == 0 || strcmp(ent->mnt_type, MNTTYPE_IGNORE) == 0) continue; if (stat(ent->mnt_dir, &st2) == 0 && CMP_DEV_T(st.st_dev, st2.st_dev)) { device_path = ent->mnt_fsname; break; } } endmntent(fp); // nothing found... if (device_path == NULL) { fprintf(stderr, LOGPREFIX "Unable to get mountpoint of user \"%s\".\n", username); return 0; } // fetch quota if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device_path, pw->pw_uid, (caddr_t) &dq)) { fprintf(stderr, LOGPREFIX "Unable to get quota of user \"%s\": %s.\n", username, strerror(errno)); return 0; } now = time(NULL); if ((dq.dqb_bhardlimit && btodb(dq.dqb_curspace) >= dq.dqb_bhardlimit) || (dq.dqb_ihardlimit && dq.dqb_curinodes >= dq.dqb_ihardlimit) || (dq.dqb_bsoftlimit && btodb(dq.dqb_curspace) >= dq.dqb_bsoftlimit && now >= dq.dqb_btime) || (dq.dqb_isoftlimit && dq.dqb_curinodes >= dq.dqb_isoftlimit && now >= dq.dqb_itime)) { fprintf(stderr, LOGPREFIX "User \"%s\" is over quota.\n", username); printf("E553 User over quota. (#5.1.1)\r\n"); } return 0; }