rgpgfs.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. // posix
  6. #include <dirent.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. // http://libfuse.github.io/doxygen/globals.html
  11. #define FUSE_USE_VERSION 31
  12. #include <fuse.h>
  13. // https://www.gnupg.org/documentation/manuals/gpgme/Function-and-Data-Index.html
  14. #include <gpgme.h>
  15. #define FUSE_PATH_BUF_LEN 256
  16. static char cache_dir[] = "/tmp/rgpgfs-cache-XXXXXX";
  17. static const size_t CACHE_PATH_BUF_LEN = sizeof(cache_dir) + FUSE_PATH_BUF_LEN;
  18. static gpgme_ctx_t gpgme_ctx;
  19. static const char gpgme_recip_fpr[] =
  20. "1234567890ABCDEF1234567890ABCDEF12345678";
  21. static gpgme_key_t gpgme_recip_key;
  22. static int rgpgfs_mkdirs(char *path) {
  23. char *delimiter = strrchr(path, '/');
  24. if (delimiter == NULL) {
  25. errno = ENOTSUP;
  26. return 1;
  27. }
  28. *delimiter = '\0';
  29. struct stat statbuf;
  30. if (lstat(path, &statbuf) && (rgpgfs_mkdirs(path) || mkdir(path, S_IRWXU))) {
  31. *delimiter = '/';
  32. return 1;
  33. }
  34. *delimiter = '/';
  35. return 0;
  36. }
  37. static int rgpgfs_encrypt(const char *source_path, char *cache_path) {
  38. // fprintf(stderr, "rgpgfs_encrypt('%s', %p)\n", source_path, cache_path);
  39. size_t source_path_len = strnlen(source_path, FUSE_PATH_BUF_LEN);
  40. if (source_path_len >= FUSE_PATH_BUF_LEN) {
  41. errno = ENAMETOOLONG;
  42. perror("rgpgfs_encrypt");
  43. return 1;
  44. }
  45. strcpy(cache_path, cache_dir);
  46. strcat(cache_path, source_path);
  47. struct stat source_stat;
  48. if (lstat(source_path, &source_stat)) {
  49. perror("rgpgfs_encrypt: failed to stat source file");
  50. return 1;
  51. }
  52. struct stat cache_stat;
  53. if (lstat(cache_path, &cache_stat) ||
  54. source_stat.st_mtim.tv_sec > cache_stat.st_mtim.tv_sec) {
  55. if (rgpgfs_mkdirs(cache_path)) {
  56. perror("rgpgfs_encrypt: failed to create dirs");
  57. return 1;
  58. }
  59. FILE *cache_file = fopen(cache_path, "w");
  60. if (cache_file == NULL) {
  61. perror("rgpgfs_encrypt: failed to open cache file");
  62. return 1;
  63. }
  64. fprintf(cache_file, "path: %s\n", source_path);
  65. fprintf(cache_file, "size: %lu bytes\n", source_stat.st_size);
  66. fprintf(cache_file, "mod time: %ld\n", source_stat.st_mtim.tv_sec);
  67. fclose(cache_file);
  68. printf("encrypted %s\n", source_path);
  69. }
  70. return 0;
  71. }
  72. static int rgpgfs_getattr(const char *source_path, struct stat *statbuf,
  73. struct fuse_file_info *fi) {
  74. if (lstat(source_path, statbuf))
  75. return -errno;
  76. if (!S_ISDIR(statbuf->st_mode)) {
  77. char cache_path[CACHE_PATH_BUF_LEN];
  78. if (rgpgfs_encrypt(source_path, cache_path))
  79. return -errno;
  80. if (lstat(cache_path, statbuf))
  81. return -errno;
  82. }
  83. return 0;
  84. }
  85. static int rgpgfs_access(const char *path, int mask) {
  86. int res = access(path, mask);
  87. // printf("rgpgfs_access(%s, %d) = %d\n", path, mask, res);
  88. if (res == -1)
  89. return -errno;
  90. return 0;
  91. }
  92. static int rgpgfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  93. off_t offset, struct fuse_file_info *fi,
  94. enum fuse_readdir_flags flags) {
  95. DIR *dirp = opendir(path);
  96. if (dirp == NULL)
  97. return -errno;
  98. struct dirent *entp;
  99. while ((entp = readdir(dirp)) != NULL) {
  100. struct stat statbf;
  101. memset(&statbf, 0, sizeof(statbf));
  102. statbf.st_ino = entp->d_ino;
  103. statbf.st_mode = entp->d_type << 12;
  104. if (filler(buf, entp->d_name, &statbf, 0, 0))
  105. break;
  106. }
  107. closedir(dirp);
  108. return 0;
  109. }
  110. static int rgpgfs_open(const char *source_path, struct fuse_file_info *fi) {
  111. // fprintf(stderr, "rgpgfs_open('%s', %p)", source_path, fi);
  112. char cache_path[CACHE_PATH_BUF_LEN];
  113. if (rgpgfs_encrypt(source_path, cache_path))
  114. return -errno;
  115. int res = open(cache_path, fi->flags);
  116. if (res == -1)
  117. return -errno;
  118. fi->fh = res;
  119. return 0;
  120. }
  121. static int rgpgfs_read(const char *path, char *buf, size_t count, off_t offset,
  122. struct fuse_file_info *fi) {
  123. if (fi == NULL) {
  124. return ENOTSUP;
  125. }
  126. ssize_t bytes_num = pread(fi->fh, buf, count, offset);
  127. if (bytes_num == -1)
  128. return -errno;
  129. return bytes_num;
  130. }
  131. static int rgpgfs_release(const char *path, struct fuse_file_info *fi) {
  132. close(fi->fh);
  133. return 0;
  134. }
  135. static struct fuse_operations rgpgfs_fuse_operations = {
  136. .getattr = rgpgfs_getattr,
  137. .open = rgpgfs_open,
  138. .read = rgpgfs_read,
  139. .release = rgpgfs_release,
  140. .readdir = rgpgfs_readdir,
  141. .access = rgpgfs_access,
  142. };
  143. int main(int argc, char *argv[]) {
  144. if (mkdtemp(cache_dir) == NULL) {
  145. return 1;
  146. }
  147. printf("cache: %s\n", cache_dir);
  148. printf("gpgme version: %s\n", gpgme_check_version(NULL));
  149. gpg_error_t gpgme_init_err = gpgme_new(&gpgme_ctx);
  150. if (gpgme_init_err != GPG_ERR_NO_ERROR) {
  151. fprintf(stderr, "Failed to initialize gpgme: %s (%d)\n",
  152. gpg_strerror(gpgme_init_err), gpgme_init_err);
  153. return 1;
  154. }
  155. gpg_error_t gpgme_get_key_err =
  156. gpgme_get_key(gpgme_ctx, gpgme_recip_fpr, &gpgme_recip_key, 0);
  157. switch (gpgme_get_key_err) {
  158. case GPG_ERR_NO_ERROR:
  159. break;
  160. case GPG_ERR_EOF:
  161. fprintf(stderr, "Could not find key %s\n", gpgme_recip_fpr);
  162. return 1;
  163. case GPG_ERR_AMBIGUOUS_NAME:
  164. fprintf(stderr, "Key name '%s' is ambiguous\n", gpgme_recip_fpr);
  165. return 1;
  166. case GPG_ERR_INV_VALUE:
  167. default:
  168. fprintf(stderr, "Failed to load key %s: %s (%d)\n", gpgme_recip_fpr,
  169. gpg_strerror(gpgme_init_err), gpgme_get_key_err);
  170. return 1;
  171. }
  172. if (!gpgme_recip_key->can_encrypt) {
  173. fprintf(stderr, "Selected key %s can not be used for encryption\n",
  174. gpgme_recip_key->fpr);
  175. return 1;
  176. }
  177. printf("recipient: %s\n", gpgme_recip_key->fpr);
  178. // TODO rm -r cache_dir (see man nftw)
  179. int fuse_main_err = fuse_main(argc, argv, &rgpgfs_fuse_operations, NULL);
  180. gpgme_release(gpgme_ctx);
  181. return fuse_main_err;
  182. }