uxmisc.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. * PuTTY miscellaneous Unix stuff
  3. */
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <assert.h>
  8. #include <errno.h>
  9. #include <unistd.h>
  10. #include <time.h>
  11. #include <sys/time.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <pwd.h>
  15. #include "putty.h"
  16. unsigned long getticks(void)
  17. {
  18. /*
  19. * We want to use milliseconds rather than the microseconds or
  20. * nanoseconds given by the underlying clock functions, because we
  21. * need a decent number of them to fit into a 32-bit word so it
  22. * can be used for keepalives.
  23. */
  24. #if defined HAVE_CLOCK_GETTIME && defined HAVE_DECL_CLOCK_MONOTONIC
  25. {
  26. /* Use CLOCK_MONOTONIC if available, so as to be unconfused if
  27. * the system clock changes. */
  28. struct timespec ts;
  29. if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
  30. return ts.tv_sec * TICKSPERSEC +
  31. ts.tv_nsec / (1000000000 / TICKSPERSEC);
  32. }
  33. #endif
  34. {
  35. struct timeval tv;
  36. gettimeofday(&tv, NULL);
  37. return tv.tv_sec * TICKSPERSEC + tv.tv_usec / (1000000 / TICKSPERSEC);
  38. }
  39. }
  40. Filename *filename_from_str(const char *str)
  41. {
  42. Filename *ret = snew(Filename);
  43. ret->path = dupstr(str);
  44. return ret;
  45. }
  46. Filename *filename_copy(const Filename *fn)
  47. {
  48. return filename_from_str(fn->path);
  49. }
  50. const char *filename_to_str(const Filename *fn)
  51. {
  52. return fn->path;
  53. }
  54. int filename_equal(const Filename *f1, const Filename *f2)
  55. {
  56. return !strcmp(f1->path, f2->path);
  57. }
  58. int filename_is_null(const Filename *fn)
  59. {
  60. return !fn->path[0];
  61. }
  62. void filename_free(Filename *fn)
  63. {
  64. sfree(fn->path);
  65. sfree(fn);
  66. }
  67. int filename_serialise(const Filename *f, void *vdata)
  68. {
  69. char *data = (char *)vdata;
  70. int len = strlen(f->path) + 1; /* include trailing NUL */
  71. if (data) {
  72. strcpy(data, f->path);
  73. }
  74. return len;
  75. }
  76. Filename *filename_deserialise(void *vdata, int maxsize, int *used)
  77. {
  78. char *data = (char *)vdata;
  79. char *end;
  80. end = memchr(data, '\0', maxsize);
  81. if (!end)
  82. return NULL;
  83. end++;
  84. *used = end - data;
  85. return filename_from_str(data);
  86. }
  87. char filename_char_sanitise(char c)
  88. {
  89. if (c == '/')
  90. return '.';
  91. return c;
  92. }
  93. #ifdef DEBUG
  94. static FILE *debug_fp = NULL;
  95. void dputs(const char *buf)
  96. {
  97. if (!debug_fp) {
  98. debug_fp = fopen("debug.log", "w");
  99. }
  100. if (write(1, buf, strlen(buf)) < 0) {} /* 'error check' to placate gcc */
  101. fputs(buf, debug_fp);
  102. fflush(debug_fp);
  103. }
  104. #endif
  105. char *get_username(void)
  106. {
  107. struct passwd *p;
  108. uid_t uid = getuid();
  109. char *user, *ret = NULL;
  110. /*
  111. * First, find who we think we are using getlogin. If this
  112. * agrees with our uid, we'll go along with it. This should
  113. * allow sharing of uids between several login names whilst
  114. * coping correctly with people who have su'ed.
  115. */
  116. user = getlogin();
  117. setpwent();
  118. if (user)
  119. p = getpwnam(user);
  120. else
  121. p = NULL;
  122. if (p && p->pw_uid == uid) {
  123. /*
  124. * The result of getlogin() really does correspond to
  125. * our uid. Fine.
  126. */
  127. ret = user;
  128. } else {
  129. /*
  130. * If that didn't work, for whatever reason, we'll do
  131. * the simpler version: look up our uid in the password
  132. * file and map it straight to a name.
  133. */
  134. p = getpwuid(uid);
  135. if (!p)
  136. return NULL;
  137. ret = p->pw_name;
  138. }
  139. endpwent();
  140. return dupstr(ret);
  141. }
  142. /*
  143. * Display the fingerprints of the PGP Master Keys to the user.
  144. * (This is here rather than in uxcons because it's appropriate even for
  145. * Unix GUI apps.)
  146. */
  147. void pgp_fingerprints(void)
  148. {
  149. fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
  150. "be used to establish a trust path from this executable to another\n"
  151. "one. See the manual for more information.\n"
  152. "(Note: these fingerprints have nothing to do with SSH!)\n"
  153. "\n"
  154. "PuTTY Master Key as of 2015 (RSA, 4096-bit):\n"
  155. " " PGP_MASTER_KEY_FP "\n\n"
  156. "Original PuTTY Master Key (RSA, 1024-bit):\n"
  157. " " PGP_RSA_MASTER_KEY_FP "\n"
  158. "Original PuTTY Master Key (DSA, 1024-bit):\n"
  159. " " PGP_DSA_MASTER_KEY_FP "\n", stdout);
  160. }
  161. /*
  162. * Set and clear fcntl options on a file descriptor. We don't
  163. * realistically expect any of these operations to fail (the most
  164. * plausible error condition is EBADF, but we always believe ourselves
  165. * to be passing a valid fd so even that's an assertion-fail sort of
  166. * response), so we don't make any effort to return sensible error
  167. * codes to the caller - we just log to standard error and die
  168. * unceremoniously. However, nonblock and no_nonblock do return the
  169. * previous state of O_NONBLOCK.
  170. */
  171. void cloexec(int fd) {
  172. int fdflags;
  173. fdflags = fcntl(fd, F_GETFD);
  174. if (fdflags < 0) {
  175. fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno));
  176. exit(1);
  177. }
  178. if (fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC) < 0) {
  179. fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno));
  180. exit(1);
  181. }
  182. }
  183. void noncloexec(int fd) {
  184. int fdflags;
  185. fdflags = fcntl(fd, F_GETFD);
  186. if (fdflags < 0) {
  187. fprintf(stderr, "%d: fcntl(F_GETFD): %s\n", fd, strerror(errno));
  188. exit(1);
  189. }
  190. if (fcntl(fd, F_SETFD, fdflags & ~FD_CLOEXEC) < 0) {
  191. fprintf(stderr, "%d: fcntl(F_SETFD): %s\n", fd, strerror(errno));
  192. exit(1);
  193. }
  194. }
  195. int nonblock(int fd) {
  196. int fdflags;
  197. fdflags = fcntl(fd, F_GETFL);
  198. if (fdflags < 0) {
  199. fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno));
  200. exit(1);
  201. }
  202. if (fcntl(fd, F_SETFL, fdflags | O_NONBLOCK) < 0) {
  203. fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno));
  204. exit(1);
  205. }
  206. return fdflags & O_NONBLOCK;
  207. }
  208. int no_nonblock(int fd) {
  209. int fdflags;
  210. fdflags = fcntl(fd, F_GETFL);
  211. if (fdflags < 0) {
  212. fprintf(stderr, "%d: fcntl(F_GETFL): %s\n", fd, strerror(errno));
  213. exit(1);
  214. }
  215. if (fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) {
  216. fprintf(stderr, "%d: fcntl(F_SETFL): %s\n", fd, strerror(errno));
  217. exit(1);
  218. }
  219. return fdflags & O_NONBLOCK;
  220. }
  221. FILE *f_open(const Filename *filename, char const *mode, int is_private)
  222. {
  223. if (!is_private) {
  224. return fopen(filename->path, mode);
  225. } else {
  226. int fd;
  227. assert(mode[0] == 'w'); /* is_private is meaningless for read,
  228. and tricky for append */
  229. fd = open(filename->path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
  230. if (fd < 0)
  231. return NULL;
  232. return fdopen(fd, mode);
  233. }
  234. }
  235. FontSpec *fontspec_new(const char *name)
  236. {
  237. FontSpec *f = snew(FontSpec);
  238. f->name = dupstr(name);
  239. return f;
  240. }
  241. FontSpec *fontspec_copy(const FontSpec *f)
  242. {
  243. return fontspec_new(f->name);
  244. }
  245. void fontspec_free(FontSpec *f)
  246. {
  247. sfree(f->name);
  248. sfree(f);
  249. }
  250. int fontspec_serialise(FontSpec *f, void *data)
  251. {
  252. int len = strlen(f->name);
  253. if (data)
  254. strcpy(data, f->name);
  255. return len + 1; /* include trailing NUL */
  256. }
  257. FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
  258. {
  259. char *data = (char *)vdata;
  260. char *end = memchr(data, '\0', maxsize);
  261. if (!end)
  262. return NULL;
  263. *used = end - data + 1;
  264. return fontspec_new(data);
  265. }
  266. char *make_dir_and_check_ours(const char *dirname)
  267. {
  268. struct stat st;
  269. /*
  270. * Create the directory. We might have created it before, so
  271. * EEXIST is an OK error; but anything else is doom.
  272. */
  273. if (mkdir(dirname, 0700) < 0 && errno != EEXIST)
  274. return dupprintf("%s: mkdir: %s", dirname, strerror(errno));
  275. /*
  276. * Now check that that directory is _owned by us_ and not writable
  277. * by anybody else. This protects us against somebody else
  278. * previously having created the directory in a way that's
  279. * writable to us, and thus manipulating us into creating the
  280. * actual socket in a directory they can see so that they can
  281. * connect to it and use our authenticated SSH sessions.
  282. */
  283. if (stat(dirname, &st) < 0)
  284. return dupprintf("%s: stat: %s", dirname, strerror(errno));
  285. if (st.st_uid != getuid())
  286. return dupprintf("%s: directory owned by uid %d, not by us",
  287. dirname, st.st_uid);
  288. if ((st.st_mode & 077) != 0)
  289. return dupprintf("%s: directory has overgenerous permissions %03o"
  290. " (expected 700)", dirname, st.st_mode & 0777);
  291. return NULL;
  292. }