Advertisement
Guest User

Calibre's SUID Mount Helper

a guest
Nov 1st, 2011
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.18 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/wait.h>
  9. #include <fcntl.h>
  10.  
  11. #define MARKER ".created_by_calibre_mount_helper"
  12. #define False 0
  13. #define True 1
  14.  
  15. int exists(const char *path) {
  16.     struct stat file_info;
  17.     if (stat(path, &file_info) == 0) return True;
  18.     return False;
  19. }
  20.  
  21. int get_root() {
  22.     int res;
  23.     res = setreuid(0, 0);
  24.     if (res != 0) return False;
  25.     if (setregid(0, 0) != 0) return False;
  26.     return True;
  27. }
  28.  
  29. void ensure_root() {
  30.     if (!get_root()) {
  31.         fprintf(stderr, "Failed to get root.\n");
  32.         exit(EXIT_FAILURE);
  33.     }
  34. }
  35.  
  36. int do_mount(const char *dev, const char *mp) {
  37.     char options[1000], marker[2000];
  38. #ifdef __NetBSD__
  39.     char uids[100], gids[100];
  40. #endif
  41.     int errsv;
  42.  
  43.     if (!exists(dev)) {
  44.         fprintf(stderr, "Specified device node does not exist\n");
  45.         return EXIT_FAILURE;
  46.     }
  47.     if (!exists(mp)) {
  48.         if (mkdir(mp, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
  49.             errsv = errno;
  50.             fprintf(stderr, "Failed to create mount point with error: %s\n", strerror(errsv));
  51.         }
  52.     }
  53.     snprintf(marker, 2000, "%s/%s", mp, MARKER);
  54.     if (!exists(marker)) {
  55.         int fd = creat(marker, S_IRUSR|S_IWUSR);
  56.         if (fd == -1) {
  57.             int errsv = errno;
  58.             fprintf(stderr, "Failed to create marker with error: %s\n", strerror(errsv));
  59.             return EXIT_FAILURE;
  60.         }
  61.         close(fd);
  62.     }
  63. #ifdef __NetBSD__
  64.     snprintf(options, 1000, "rw,noexec,nosuid,sync,nodev");
  65.     snprintf(uids, 100, "%d", getuid());
  66.     snprintf(gids, 100, "%d", getgid());
  67. #else
  68. #ifdef __FreeBSD__
  69.     snprintf(options, 1000, "rw,noexec,nosuid,sync,-u=%d,-g=%d",getuid(),getgid());
  70. #else
  71.     snprintf(options, 1000, "rw,noexec,nosuid,sync,nodev,quiet,shortname=mixed,uid=%d,gid=%d,umask=077,fmask=0177,dmask=0077,utf8,iocharset=iso8859-1", getuid(), getgid());
  72. #endif
  73. #endif
  74.  
  75.     ensure_root();
  76.  
  77. #ifdef __NetBSD__
  78.     execlp("mount_msdos", "mount_msdos", "-u", uids, "-g", gids, "-o", options, dev, mp, NULL);
  79. #else
  80. #ifdef __FreeBSD__
  81.     execlp("mount", "mount", "-t", "msdosfs", "-o", options, dev, mp, NULL);
  82. #else
  83.     execlp("mount", "mount", "-t", "auto", "-o", options, dev, mp, NULL);
  84. #endif
  85. #endif
  86.     errsv = errno;
  87.     fprintf(stderr, "Failed to mount with error: %s\n", strerror(errsv));
  88.     return EXIT_FAILURE;
  89. }
  90.  
  91. int call_eject(const char *dev, const char *mp) {
  92.     int ret, pid, errsv, i, status = EXIT_FAILURE;
  93.  
  94.     pid = fork();
  95.     if (pid == -1) {
  96.         fprintf(stderr, "Failed to fork\n");
  97.         exit(EXIT_FAILURE);
  98.     }
  99.  
  100.     if (pid == 0) { /* Child process */
  101.         ensure_root();
  102. #ifdef __NetBSD__
  103.         execlp("eject", "eject", dev, NULL);
  104. #else
  105. #ifdef __FreeBSD__
  106.     execlp("umount", "umount", dev, NULL);
  107. #else
  108.         execlp("eject", "eject", "-s", dev, NULL);
  109. #endif
  110. #endif
  111.         /* execlp failed */
  112.         errsv = errno;
  113.         fprintf(stderr, "Failed to eject with error: %s\n", strerror(errsv));
  114.         exit(EXIT_FAILURE);
  115.     } else { /* Parent */
  116.         for (i = 0; i < 7; i++) {
  117.             sleep(1);
  118.             ret = waitpid(pid, &status, WNOHANG);
  119.             if (ret == -1) return False;
  120.             if (ret > 0) break;
  121.         }
  122.         return WIFEXITED(status) && WEXITSTATUS(status) == 0;
  123.     }
  124.     return False;
  125. }
  126.  
  127. int call_umount(const char *dev, const char *mp) {
  128.     int ret, pid, errsv, i, status = EXIT_FAILURE;
  129.  
  130.     pid = fork();
  131.     if (pid == -1) {
  132.         fprintf(stderr, "Failed to fork\n");
  133.         exit(EXIT_FAILURE);
  134.     }
  135.  
  136.     if (pid == 0) { /* Child process */
  137.         ensure_root();
  138. #ifdef __FreeBSD__
  139.         execlp("umount", "umount", mp, NULL);
  140. #else
  141.         execlp("umount", "umount", "-l", mp, NULL);
  142. #endif
  143.         /* execlp failed */
  144.         errsv = errno;
  145.         fprintf(stderr, "Failed to umount with error: %s\n", strerror(errsv));
  146.         exit(EXIT_FAILURE);
  147.     } else { /* Parent */
  148.         for (i = 0; i < 7; i++) {
  149.             sleep(1);
  150.             ret = waitpid(pid, &status, WNOHANG);
  151.             if (ret == -1) return False;
  152.             if (ret > 0) break;
  153.         }
  154.         return WIFEXITED(status) && WEXITSTATUS(status) == 0;
  155.     }
  156.     return False;
  157. }
  158.  
  159. int cleanup_mount_point(const char *mp) {
  160.     char marker[2000];
  161.     int urt, rmd, errsv;
  162.  
  163.     snprintf(marker, 2000, "%s/%s", mp, MARKER);
  164.     if (exists(marker)) {
  165.         urt = unlink(marker);
  166.         if (urt == -1) {
  167.             errsv = errno;
  168.             fprintf(stderr, "Failed to unlink marker: %s\n", strerror(errsv));
  169.             return EXIT_FAILURE;
  170.         }
  171.     }
  172.     rmd = rmdir(mp);
  173.     if (rmd == -1) {
  174.         errsv = errno;
  175.         fprintf(stderr, "Failed to remove mount point: %s\n", strerror(errsv));
  176.         return EXIT_FAILURE;
  177.     }
  178.     return EXIT_SUCCESS;
  179. }
  180.  
  181. int do_eject(const char *dev, const char *mp) {
  182.     int unmounted = False;
  183.  
  184.     ensure_root();
  185.  
  186.     unmounted = call_eject(dev, mp);
  187.     if (!unmounted) call_umount(dev, mp);
  188.     if (unmounted) return cleanup_mount_point(mp);
  189.     return EXIT_FAILURE;
  190. }
  191.  
  192. int cleanup(const char *dev, const char *mp) {
  193.     ensure_root();
  194.     call_umount(dev, mp);
  195.     return cleanup_mount_point(mp);
  196. }
  197.  
  198. int main(int argc, char** argv)
  199. {
  200.     char *action, *dev, *mp;
  201.     int status = EXIT_FAILURE;
  202.  
  203.     /*printf("Real UID\t= %d\n", getuid());
  204.     printf("Effective UID\t= %d\n", geteuid());
  205.     printf("Real GID\t= %d\n", getgid());
  206.     printf("Effective GID\t= %d\n", getegid());*/
  207.  
  208.     if (argc != 4) {
  209.         fprintf(stderr, "Needs 3 arguments: action, device node and mount point\n");
  210.         exit(EXIT_FAILURE);
  211.     }
  212.     action = argv[1]; dev = argv[2]; mp = argv[3];
  213.  
  214.     if (strncmp(action, "mount", 5) == 0) {
  215.         status = do_mount(dev, mp);
  216.     } else if (strncmp(action, "eject", 5) == 0) {
  217.         status = do_eject(dev, mp);
  218.     } else if (strncmp(action, "cleanup", 7) == 0) {
  219.         status = cleanup(dev, mp);
  220.     } else {
  221.         fprintf(stderr, "Unrecognized action: must be mount, eject or cleanup\n");
  222.     }
  223.  
  224.     return status;
  225. }
  226.  
  227.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement