make_dir_and_check_ours.c 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /*
  2. * Create a directory accessible only to us, and then check afterwards
  3. * that we really did end up with a directory with the right ownership
  4. * and permissions.
  5. *
  6. * The idea is that this is a directory in which we're about to create
  7. * something sensitive, like a listening Unix-domain socket for SSH
  8. * connection sharing or an SSH agent. We want to be protected against
  9. * somebody else previously having created the directory in a way
  10. * that's writable to us, and thus manipulating us into creating the
  11. * actual socket in a directory they can see so that they can connect
  12. * to it and (say) use our authenticated SSH sessions.
  13. *
  14. * NOTE: The strategy used in this function is not safe if the enemy
  15. * has unrestricted write access to the containing directory. In that
  16. * case, they could move our directory out of the way and make a new
  17. * one, after this function returns and before we create our socket
  18. * (or whatever) inside it.
  19. *
  20. * But this should be OK for temp directories (which modify the
  21. * default world-write behaviour by also setting the 't' bit,
  22. * preventing people from renaming or deleting things in there that
  23. * they don't own). And of course it's also safe if the directory is
  24. * writable only by our _own_ uid.
  25. */
  26. #include <errno.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include "putty.h"
  32. char *make_dir_and_check_ours(const char *dirname)
  33. {
  34. struct stat st;
  35. /*
  36. * Create the directory. We might have created it before, so
  37. * EEXIST is an OK error; but anything else is doom.
  38. */
  39. if (mkdir(dirname, 0700) < 0 && errno != EEXIST)
  40. return dupprintf("%s: mkdir: %s", dirname, strerror(errno));
  41. /*
  42. * Stat the directory and check its ownership and permissions.
  43. */
  44. if (stat(dirname, &st) < 0)
  45. return dupprintf("%s: stat: %s", dirname, strerror(errno));
  46. if (st.st_uid != getuid())
  47. return dupprintf("%s: directory owned by uid %d, not by us",
  48. dirname, st.st_uid);
  49. if ((st.st_mode & 077) != 0)
  50. return dupprintf("%s: directory has overgenerous permissions %03o"
  51. " (expected 700)", dirname, st.st_mode & 0777);
  52. return NULL;
  53. }