Download | Plain Text | No Line Numbers


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <errno.h>
  6. #include <pwd.h>
  7. #include <mntent.h>
  8. #include <time.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/quota.h>
  12.  
  13. #include <sys/sysmacros.h>
  14. #define CMP_DEV_T(a, b) (major(a) == major(b) && minor(a) == minor(b))
  15.  
  16. #define LOGPREFIX "QUOTA: "
  17.  
  18. int check_parent(const char *username)
  19. {
  20. pid_t parent;
  21. int num;
  22. char buf[256], buf2[256];
  23. const char *smtpbin = "/var/qmail/bin/qmail-smtpd";
  24.  
  25. // check parent
  26. parent = getppid();
  27. num = snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
  28. if (num < 0 || num > sizeof(buf))
  29. {
  30. fprintf(stderr, LOGPREFIX "Unable to copy string to buffer for user \"%s\".\n", username);
  31. return 0;
  32. }
  33.  
  34. num = readlink(buf, buf2, sizeof(buf2));
  35. if (num < 0)
  36. {
  37. fprintf(stderr, LOGPREFIX "Unable to read parent from proc-fs for user \"%s\": %s\n", username, strerror(errno));
  38. return 0;
  39. }
  40. buf2[num] = '\0';
  41.  
  42. if (strcmp(smtpbin, buf2) != 0)
  43. {
  44. fprintf(stderr, LOGPREFIX "Error: Parent \"%s\" doesn't match qmail-smtp for user \"%s\".\n", buf2, username);
  45. return 0;
  46. }
  47.  
  48. return 1;
  49. }
  50.  
  51. int main()
  52. {
  53. const char *username = NULL, *device_path = NULL;
  54. struct passwd *pw;
  55. struct stat st, st2;
  56. FILE *fp;
  57. struct mntent *ent;
  58. struct dqblk dq;
  59. time_t now;
  60. pid_t parent;
  61.  
  62. parent = getppid();
  63. username = getenv("DTUSER");
  64. if (!username)
  65. return 0;
  66.  
  67. // lookup user in passwd
  68. pw = getpwnam(username);
  69. if (pw == NULL)
  70. {
  71. fprintf(stderr, LOGPREFIX "Unable to get user \"%s\" from passwd!: %s\n", username, strerror(errno));
  72. return 0;
  73. }
  74.  
  75. // seteuid
  76. if (seteuid(pw->pw_uid))
  77. {
  78. fprintf(stderr, LOGPREFIX "Unable to call seteuid for user \"%s\": %s\n", username, strerror(errno));
  79. return 0;
  80. }
  81.  
  82. // check parent
  83. if (!check_parent(username))
  84. return 0;
  85.  
  86. if (pw->pw_dir == NULL)
  87. {
  88. fprintf(stderr, LOGPREFIX "User \"%s\" has no homedir?\n", username);
  89. return 0;
  90. }
  91.  
  92. // stat homedir to fetch blockdevice id
  93. if (stat(pw->pw_dir, &st) < 0)
  94. {
  95. fprintf(stderr, LOGPREFIX "Stat of \"%s\" of user \"%s\" failed: %s\n", pw->pw_dir, username, strerror(errno));
  96. return 0;
  97. }
  98.  
  99. // iterate over mounted devices and check blockdevice id
  100. fp = setmntent(_PATH_MOUNTED, "r");
  101. if (fp == NULL)
  102. {
  103. fprintf(stderr, LOGPREFIX "Unable to open %s!\n", _PATH_MOUNTED);
  104. return 0;
  105. }
  106. while ((ent = getmntent(fp)) != NULL)
  107. {
  108. if (strcmp(ent->mnt_type, MNTTYPE_SWAP) == 0 ||
  109. strcmp(ent->mnt_type, MNTTYPE_IGNORE) == 0)
  110. continue;
  111.  
  112. if (stat(ent->mnt_dir, &st2) == 0 &&
  113. CMP_DEV_T(st.st_dev, st2.st_dev))
  114. {
  115. device_path = ent->mnt_fsname;
  116. break;
  117. }
  118. }
  119. endmntent(fp);
  120.  
  121. // nothing found...
  122. if (device_path == NULL)
  123. {
  124. fprintf(stderr, LOGPREFIX "Unable to get mountpoint of user \"%s\".\n", username);
  125. return 0;
  126. }
  127.  
  128. // fetch quota
  129. if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device_path, pw->pw_uid, (caddr_t) &dq))
  130. {
  131. fprintf(stderr, LOGPREFIX "Unable to get quota of user \"%s\": %s.\n", username, strerror(errno));
  132. return 0;
  133. }
  134.  
  135. now = time(NULL);
  136. if ((dq.dqb_bhardlimit && btodb(dq.dqb_curspace) >= dq.dqb_bhardlimit)
  137. || (dq.dqb_ihardlimit && dq.dqb_curinodes >= dq.dqb_ihardlimit)
  138. || (dq.dqb_bsoftlimit && btodb(dq.dqb_curspace) >= dq.dqb_bsoftlimit && now >= dq.dqb_btime)
  139. || (dq.dqb_isoftlimit && dq.dqb_curinodes >= dq.dqb_isoftlimit && now >= dq.dqb_itime))
  140. {
  141. fprintf(stderr, LOGPREFIX "User \"%s\" is over quota.\n", username);
  142. printf("E553 User over quota. (#5.1.1)\r\n");
  143. }
  144.  
  145. return 0;
  146. }
  147.