keymgmt.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include "platform.h"
  2. #include <sys/stat.h>
  3. #include <inttypes.h>
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "crypto.h"
  9. #include "getopt.h"
  10. #include "humansize.h"
  11. #include "keyfile.h"
  12. #include "passphrase_entry.h"
  13. #include "readpass.h"
  14. #include "warnp.h"
  15. static void usage(void);
  16. static void
  17. usage(void)
  18. {
  19. fprintf(stderr, "usage: tarsnap-keymgmt %s %s %s %s %s key-file ...\n",
  20. "--outkeyfile new-key-file", "[--passphrased]",
  21. "[--passphrase-mem maxmem]", "[--passphrase-time maxtime]",
  22. "[-r] [-w] [-d] [--nuke]");
  23. fprintf(stderr, " tarsnap-keymgmt --print-key-id key-file\n");
  24. fprintf(stderr, " tarsnap-keymgmt --print-key-permissions "
  25. "key-file\n");
  26. fprintf(stderr, " tarsnap-keymgmt --version\n");
  27. exit(1);
  28. /* NOTREACHED */
  29. }
  30. static void
  31. print_id(const char *keyfilename)
  32. {
  33. uint64_t machinenum = (uint64_t)(-1);
  34. /* Read keyfile and machine name. */
  35. if (keyfile_read(keyfilename, &machinenum, ~0, 0,
  36. PASSPHRASE_TTY_STDIN, NULL)) {
  37. warnp("Cannot read key file: %s", keyfilename);
  38. exit(1);
  39. }
  40. /* Print key ID. */
  41. fprintf(stdout, "%" PRIu64 "\n", machinenum);
  42. exit(0);
  43. /* NOTREACHED */
  44. }
  45. static void
  46. print_permissions(const char *keyfilename)
  47. {
  48. uint64_t machinenum = (uint64_t)(-1);
  49. int has_read;
  50. int has_write;
  51. int has_delete;
  52. /* Read keyfile and machine name. */
  53. if (keyfile_read(keyfilename, &machinenum, ~0, 0,
  54. PASSPHRASE_TTY_STDIN, NULL)) {
  55. warnp("Cannot read key file: %s", keyfilename);
  56. exit(1);
  57. }
  58. /* Determine permissions. */
  59. has_read = (crypto_keys_missing(CRYPTO_KEYMASK_READ) == NULL);
  60. has_write = (crypto_keys_missing(CRYPTO_KEYMASK_WRITE) == NULL);
  61. has_delete = (crypto_keys_missing(CRYPTO_KEYMASK_AUTH_DELETE) == NULL);
  62. /* Print key permissions. */
  63. fprintf(stdout, "This key has permissions for: ");
  64. if (has_read && has_write && has_delete)
  65. fprintf(stdout, "reading, writing, and deleting.\n");
  66. if (has_read && has_write && !has_delete)
  67. fprintf(stdout, "reading and writing.\n");
  68. if (has_read && !has_write && has_delete)
  69. fprintf(stdout, "reading and deleting.\n");
  70. if (has_read && !has_write && !has_delete)
  71. fprintf(stdout, "reading.\n");
  72. if (!has_read && has_write && has_delete)
  73. fprintf(stdout, "writing and nuking.\n");
  74. if (!has_read && has_write && !has_delete)
  75. fprintf(stdout, "writing.\n");
  76. if (!has_read && !has_write && has_delete)
  77. fprintf(stdout, "nuking.\n");
  78. if (!has_read && !has_write && !has_delete)
  79. fprintf(stdout, "nothing.\n");
  80. exit(0);
  81. /* NOTREACHED */
  82. }
  83. int
  84. main(int argc, char **argv)
  85. {
  86. const char * newkeyfile = NULL;
  87. int keyswanted = 0;
  88. char * tok, * brkb = NULL, * eptr;
  89. long keynum;
  90. uint64_t machinenum = (uint64_t)(-1);
  91. uint64_t kfmachinenum;
  92. const char * missingkey;
  93. int passphrased = 0;
  94. uint64_t maxmem = 0;
  95. double maxtime = 1.0;
  96. char * passphrase;
  97. const char * print_key_id_file = NULL;
  98. const char * print_key_permissions_file = NULL;
  99. const char * ch;
  100. char * optarg_copy; /* for strtok_r. */
  101. WARNP_INIT;
  102. /* Initialize key cache. */
  103. if (crypto_keys_init()) {
  104. warnp("Key cache initialization failed");
  105. exit(1);
  106. }
  107. /* Parse arguments. */
  108. while ((ch = GETOPT(argc, argv)) != NULL) {
  109. GETOPT_SWITCH(ch) {
  110. GETOPT_OPTARG("--outkeyfile"):
  111. if (newkeyfile != NULL)
  112. usage();
  113. newkeyfile = optarg;
  114. break;
  115. GETOPT_OPT("-r"):
  116. keyswanted |= CRYPTO_KEYMASK_READ;
  117. break;
  118. GETOPT_OPT("-w"):
  119. keyswanted |= CRYPTO_KEYMASK_WRITE;
  120. break;
  121. GETOPT_OPT("-d"):
  122. /*
  123. * Deleting data requires both delete authorization
  124. * and being able to read archives -- we need to be
  125. * able to figure out which bits are part of the
  126. * archive.
  127. */
  128. keyswanted |= CRYPTO_KEYMASK_READ;
  129. keyswanted |= CRYPTO_KEYMASK_AUTH_DELETE;
  130. break;
  131. GETOPT_OPT("--nuke"):
  132. keyswanted |= CRYPTO_KEYMASK_AUTH_DELETE;
  133. break;
  134. GETOPT_OPTARG("--keylist"):
  135. /*
  136. * This is a deliberately undocumented option used
  137. * mostly for testing purposes; it allows a list of
  138. * keys to be specified according to their numbers in
  139. * crypto/crypto.h instead of using the predefined
  140. * sets of "read", "write" and "delete" keys.
  141. */
  142. if ((optarg_copy = strdup(optarg)) == NULL) {
  143. warn0("Out of memory");
  144. exit(0);
  145. }
  146. for (tok = strtok_r(optarg_copy, ",", &brkb);
  147. tok;
  148. tok = strtok_r(NULL, ",", &brkb)) {
  149. keynum = strtol(tok, &eptr, 0);
  150. if ((eptr == tok) ||
  151. (keynum < 0) || (keynum > 31)) {
  152. warn0("Not a valid key number: %s",
  153. tok);
  154. free(optarg_copy);
  155. exit(1);
  156. }
  157. keyswanted |= (uint32_t)(1) << keynum;
  158. }
  159. free(optarg_copy);
  160. break;
  161. GETOPT_OPTARG("--passphrase-mem"):
  162. if (maxmem != 0)
  163. usage();
  164. if (humansize_parse(optarg, &maxmem)) {
  165. warnp("Cannot parse --passphrase-mem"
  166. " argument: %s", optarg);
  167. exit(1);
  168. }
  169. if (maxmem > SIZE_MAX) {
  170. fprintf(stderr,
  171. "Passphrase memory size is too large\n");
  172. exit(1);
  173. }
  174. break;
  175. GETOPT_OPTARG("--passphrase-time"):
  176. if (maxtime != 1.0)
  177. usage();
  178. maxtime = strtod(optarg, NULL);
  179. if ((maxtime < 0.05) || (maxtime > 86400)) {
  180. warn0("Invalid --passphrase-time argument: %s",
  181. optarg);
  182. exit(1);
  183. }
  184. break;
  185. GETOPT_OPT("--passphrased"):
  186. if (passphrased != 0)
  187. usage();
  188. passphrased = 1;
  189. break;
  190. GETOPT_OPTARG("--print-key-id"):
  191. if (print_key_id_file != NULL)
  192. usage();
  193. print_key_id_file = optarg;
  194. break;
  195. GETOPT_OPTARG("--print-key-permissions"):
  196. if (print_key_permissions_file != NULL)
  197. usage();
  198. print_key_permissions_file = optarg;
  199. break;
  200. GETOPT_OPT("--version"):
  201. fprintf(stderr, "tarsnap-keymgmt %s\n",
  202. PACKAGE_VERSION);
  203. exit(0);
  204. GETOPT_MISSING_ARG:
  205. warn0("Missing argument to %s", ch);
  206. /* FALLTHROUGH */
  207. GETOPT_DEFAULT:
  208. usage();
  209. }
  210. }
  211. argc -= optind;
  212. argv += optind;
  213. /* We can't print ID and permissions at the same time. */
  214. if ((print_key_id_file != NULL) && (print_key_permissions_file != NULL))
  215. usage();
  216. if ((print_key_id_file != NULL) ||
  217. (print_key_permissions_file != NULL)) {
  218. /* We can't combine printing info with generating a new key. */
  219. if (newkeyfile != NULL)
  220. usage();
  221. /* We should have processed all arguments. */
  222. if (argc != 0)
  223. usage();
  224. /* Print info. */
  225. if (print_key_id_file != NULL)
  226. print_id(print_key_id_file);
  227. if (print_key_permissions_file != NULL)
  228. print_permissions(print_key_permissions_file);
  229. }
  230. /* We should have an output key file. */
  231. if (newkeyfile == NULL)
  232. usage();
  233. /*
  234. * It doesn't make sense to specify --passphrase-mem or
  235. * --passphrase-time if we're not using a passphrase.
  236. */
  237. if (((maxmem != 0) || (maxtime != 1.0)) && (passphrased == 0))
  238. usage();
  239. /* Warn the user if they're being silly. */
  240. if (keyswanted == 0) {
  241. warn0("None of {-r, -w, -d, --nuke} options are specified."
  242. " This will create a key file with no keys, which is"
  243. " probably not what you intended.");
  244. }
  245. /* Read the specified key files. */
  246. while (argc-- > 0) {
  247. /*
  248. * Suck in the key file. We could mask this to only load the
  249. * keys we want to copy, but there's no point really since we
  250. * export keys selectively.
  251. */
  252. if (keyfile_read(argv[0], &kfmachinenum, ~0, 0,
  253. PASSPHRASE_TTY_STDIN, NULL)) {
  254. warnp("Cannot read key file: %s", argv[0]);
  255. exit(1);
  256. }
  257. /*
  258. * Check that we're not using key files which belong to
  259. * different machines.
  260. */
  261. if (machinenum == (uint64_t)(-1)) {
  262. machinenum = kfmachinenum;
  263. } else if (machinenum != kfmachinenum) {
  264. warn0("Keys from %s do not belong to the "
  265. "same machine as earlier keys", argv[0]);
  266. exit(1);
  267. }
  268. /* Move on to the next file. */
  269. argv++;
  270. }
  271. /* Make sure that we have the necessary keys. */
  272. if ((missingkey = crypto_keys_missing(keyswanted)) != NULL) {
  273. warn0("The %s key is required but not in any input key files",
  274. missingkey);
  275. exit(1);
  276. }
  277. /* If the user wants to passphrase the keyfile, get the passphrase. */
  278. if (passphrased != 0) {
  279. if (readpass(&passphrase,
  280. "Please enter passphrase for keyfile encryption",
  281. "Please confirm passphrase for keyfile encryption", 1)) {
  282. warnp("Error reading password");
  283. exit(1);
  284. }
  285. } else {
  286. passphrase = NULL;
  287. }
  288. /* Write out new key file. */
  289. if (keyfile_write(newkeyfile, machinenum, keyswanted,
  290. passphrase, (size_t)maxmem, maxtime))
  291. exit(1);
  292. /* Success! */
  293. return (0);
  294. }