readpass_file.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "insecure_memzero.h"
  4. #include "warnp.h"
  5. #include "readpass.h"
  6. /* Maximum file length. */
  7. #define MAXPASSLEN 2048
  8. /**
  9. * readpass_file(passwd, filename):
  10. * Read a passphrase from ${filename} and return it as a malloced
  11. * NUL-terminated string via ${passwd}. Print an error and fail if the file
  12. * is 2048 characters or more, or if it contains any newline \n or \r\n
  13. * characters other than at the end of the file. Do not include the \n or
  14. * \r\n characters in the passphrase.
  15. */
  16. int
  17. readpass_file(char ** passwd, const char * filename)
  18. {
  19. FILE * f;
  20. char passbuf[MAXPASSLEN];
  21. /* Open the file. */
  22. if ((f = fopen(filename, "r")) == NULL) {
  23. warnp("fopen(%s)", filename);
  24. goto err1;
  25. }
  26. /* Get a line from the file. */
  27. if ((fgets(passbuf, MAXPASSLEN, f)) == NULL) {
  28. if (ferror(f)) {
  29. warnp("fread(%s)", filename);
  30. goto err2;
  31. } else {
  32. /* We have a 0-byte password. */
  33. passbuf[0] = '\0';
  34. }
  35. }
  36. /* Bail if there's the line is too long, or if there's a second line. */
  37. if (fgetc(f) != EOF) {
  38. warn0("line too long, or more than 1 line in %s", filename);
  39. goto err2;
  40. }
  41. /* Close the file. */
  42. if (fclose(f)) {
  43. warnp("fclose(%s)", filename);
  44. goto err1;
  45. }
  46. /* Truncate at any newline character. */
  47. passbuf[strcspn(passbuf, "\r\n")] = '\0';
  48. /* Copy the password out. */
  49. if ((*passwd = strdup(passbuf)) == NULL) {
  50. warnp("Cannot allocate memory");
  51. goto err1;
  52. }
  53. /* Clean up. */
  54. insecure_memzero(passbuf, MAXPASSLEN);
  55. /* Success! */
  56. return (0);
  57. err2:
  58. if (fclose(f))
  59. warnp("fclose");
  60. err1:
  61. /* No harm in running this for all error paths. */
  62. insecure_memzero(passbuf, MAXPASSLEN);
  63. /* Failure! */
  64. return (-1);
  65. }