qfile-unpacker.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #define _GNU_SOURCE
  2. #include <ioall.h>
  3. #include <grp.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <pwd.h>
  8. #include <sys/stat.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <sys/fsuid.h>
  12. #include <gui-fatal.h>
  13. #include <errno.h>
  14. #include "filecopy.h"
  15. #define INCOMING_DIR_ROOT "/home/user/incoming"
  16. int prepare_creds_return_uid(char *username)
  17. {
  18. struct passwd *pwd;
  19. pwd = getpwnam(username);
  20. if (!pwd) {
  21. perror("getpwnam");
  22. exit(1);
  23. }
  24. setenv("HOME", pwd->pw_dir, 1);
  25. setenv("USER", username, 1);
  26. setgid(pwd->pw_gid);
  27. initgroups(username, pwd->pw_gid);
  28. setfsuid(pwd->pw_uid);
  29. return pwd->pw_uid;
  30. }
  31. void wait_for_child(int statusfd)
  32. {
  33. int status;
  34. if (read(statusfd, &status, sizeof status)!=sizeof status)
  35. gui_fatal("File copy error: Internal error reading status from unpacker");
  36. errno = status;
  37. switch (status) {
  38. case LEGAL_EOF: break;
  39. case 0: gui_fatal("File copy: Connection terminated unexpectedly"); break;
  40. case EINVAL: gui_fatal("File copy: Corrupted data from packer"); break;
  41. case EEXIST: gui_fatal("File copy: not overwriting existing file. Clean ~/incoming, and retry copy"); break;
  42. default: gui_fatal("File copy");
  43. }
  44. }
  45. extern void do_unpack(int);
  46. int main(int argc, char ** argv)
  47. {
  48. char *incoming_dir;
  49. int pipefds[2];
  50. int uid;
  51. char *remote_domain;
  52. pipe(pipefds);
  53. uid = prepare_creds_return_uid("user");
  54. remote_domain = getenv("QREXEC_REMOTE_DOMAIN");
  55. if (!remote_domain) {
  56. gui_fatal("Cannot get remote domain name");
  57. exit(1);
  58. }
  59. mkdir(INCOMING_DIR_ROOT, 0700);
  60. asprintf(&incoming_dir, "%s/from-%s", INCOMING_DIR_ROOT, remote_domain);
  61. mkdir(incoming_dir, 0700);
  62. if (chdir(incoming_dir))
  63. gui_fatal("Error chdir to %s", incoming_dir);
  64. switch (fork()) {
  65. case -1:
  66. perror("fork");
  67. exit(1);
  68. case 0:
  69. if (chroot(incoming_dir)) //impossible
  70. gui_fatal("Error chroot to %s", incoming_dir);
  71. setuid(uid);
  72. close(pipefds[0]);
  73. do_unpack(pipefds[1]);
  74. exit(0);
  75. default:;
  76. }
  77. setuid(uid);
  78. close(pipefds[1]);
  79. wait_for_child(pipefds[0]);
  80. return 0;
  81. }