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.  
  61. username = getenv("DTUSER");
  62. if (!username)
  63. return 0;
  64.  
  65. // lookup user in passwd
  66. pw = getpwnam(username);
  67. if (pw == NULL)
  68. {
  69. fprintf(stderr, LOGPREFIX "Unable to get user \"%s\" from passwd!: %s\n", username, strerror(errno));
  70. return 0;
  71. }
  72.  
  73. // check parent
  74. if (!check_parent(username))
  75. return 0;
  76.  
  77. // seteuid
  78. if (seteuid(pw->pw_uid))
  79. {
  80. fprintf(stderr, LOGPREFIX "Unable to call seteuid for user \"%s\": %s\n", username, strerror(errno));
  81. return 0;
  82. }
  83.  
  84. if (pw->pw_dir == NULL)
  85. {
  86. fprintf(stderr, LOGPREFIX "User \"%s\" has no homedir?\n", username);
  87. return 0;
  88. }
  89.  
  90. // stat homedir to fetch blockdevice id
  91. if (stat(pw->pw_dir, &st) < 0)
  92. {
  93. fprintf(stderr, LOGPREFIX "Stat of \"%s\" of user \"%s\" failed: %s\n", pw->pw_dir, username, strerror(errno));
  94. return 0;
  95. }
  96.  
  97. // iterate over mounted devices and check blockdevice id
  98. fp = setmntent(_PATH_MOUNTED, "r");
  99. if (fp == NULL)
  100. {
  101. fprintf(stderr, LOGPREFIX "Unable to open %s!\n", _PATH_MOUNTED);
  102. return 0;
  103. }
  104. while ((ent = getmntent(fp)) != NULL)
  105. {
  106. if (strcmp(ent->mnt_type, MNTTYPE_SWAP) == 0 ||
  107. strcmp(ent->mnt_type, MNTTYPE_IGNORE) == 0)
  108. continue;
  109.  
  110. if (stat(ent->mnt_dir, &st2) == 0 &&
  111. CMP_DEV_T(st.st_dev, st2.st_dev))
  112. {
  113. device_path = ent->mnt_fsname;
  114. break;
  115. }
  116. }
  117. endmntent(fp);
  118.  
  119. // nothing found...
  120. if (device_path == NULL)
  121. {
  122. fprintf(stderr, LOGPREFIX "Unable to get mountpoint of user \"%s\".\n", username);
  123. return 0;
  124. }
  125.  
  126. // fetch quota
  127. if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device_path, pw->pw_uid, (caddr_t) &dq))
  128. {
  129. fprintf(stderr, LOGPREFIX "Unable to get quota of user \"%s\": %s.\n", username, strerror(errno));
  130. return 0;
  131. }
  132.  
  133. //TODO +space?
  134. now = time(NULL);
  135. if ((dq.dqb_bhardlimit && btodb(dq.dqb_curspace) >= dq.dqb_bhardlimit)
  136. || (dq.dqb_ihardlimit && dq.dqb_curinodes >= dq.dqb_ihardlimit)
  137. || (dq.dqb_bsoftlimit && btodb(dq.dqb_curspace) >= dq.dqb_bsoftlimit && dq.dqb_btime && now >= dq.dqb_btime)
  138. || (dq.dqb_isoftlimit && dq.dqb_curinodes >= dq.dqb_isoftlimit && dq.dqb_itime && now >= dq.dqb_itime))
  139. {
  140. fprintf(stderr, LOGPREFIX "User \"%s\" is over quota.\n", username);
  141. printf("E553 User over quota. (#5.1.1)\n");
  142. }
  143.  
  144. return 0;
  145. }
  146.