uxagentc.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * SSH agent client code.
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <assert.h>
  7. #include <unistd.h>
  8. #include <sys/socket.h>
  9. #include <sys/un.h>
  10. #include "putty.h"
  11. #include "misc.h"
  12. #include "tree234.h"
  13. #include "puttymem.h"
  14. #define GET_32BIT(cp) \
  15. (((unsigned long)(unsigned char)(cp)[0] << 24) | \
  16. ((unsigned long)(unsigned char)(cp)[1] << 16) | \
  17. ((unsigned long)(unsigned char)(cp)[2] << 8) | \
  18. ((unsigned long)(unsigned char)(cp)[3]))
  19. int agent_exists(void)
  20. {
  21. if (getenv("SSH_AUTH_SOCK") != NULL)
  22. return TRUE;
  23. return FALSE;
  24. }
  25. static tree234 *agent_connections;
  26. struct agent_connection {
  27. int fd;
  28. char *retbuf;
  29. char sizebuf[4];
  30. int retsize, retlen;
  31. void (*callback)(void *, void *, int);
  32. void *callback_ctx;
  33. };
  34. static int agent_conncmp(void *av, void *bv)
  35. {
  36. struct agent_connection *a = (struct agent_connection *) av;
  37. struct agent_connection *b = (struct agent_connection *) bv;
  38. if (a->fd < b->fd)
  39. return -1;
  40. if (a->fd > b->fd)
  41. return +1;
  42. return 0;
  43. }
  44. static int agent_connfind(void *av, void *bv)
  45. {
  46. int afd = *(int *) av;
  47. struct agent_connection *b = (struct agent_connection *) bv;
  48. if (afd < b->fd)
  49. return -1;
  50. if (afd > b->fd)
  51. return +1;
  52. return 0;
  53. }
  54. static int agent_select_result(int fd, int event)
  55. {
  56. int ret;
  57. struct agent_connection *conn;
  58. assert(event == 1); /* not selecting for anything but R */
  59. conn = find234(agent_connections, &fd, agent_connfind);
  60. if (!conn) {
  61. uxsel_del(fd);
  62. return 1;
  63. }
  64. ret = read(fd, conn->retbuf+conn->retlen, conn->retsize-conn->retlen);
  65. if (ret <= 0) {
  66. if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf);
  67. conn->retbuf = NULL;
  68. conn->retlen = 0;
  69. goto done;
  70. }
  71. conn->retlen += ret;
  72. if (conn->retsize == 4 && conn->retlen == 4) {
  73. conn->retsize = GET_32BIT(conn->retbuf);
  74. if (conn->retsize <= 0) {
  75. conn->retbuf = NULL;
  76. conn->retlen = 0;
  77. goto done;
  78. }
  79. conn->retsize += 4;
  80. assert(conn->retbuf == conn->sizebuf);
  81. conn->retbuf = snewn(conn->retsize, char);
  82. memcpy(conn->retbuf, conn->sizebuf, 4);
  83. }
  84. if (conn->retlen < conn->retsize)
  85. return 0; /* more data to come */
  86. done:
  87. /*
  88. * We have now completed the agent query. Do the callback, and
  89. * clean up. (Of course we don't free retbuf, since ownership
  90. * of that passes to the callback.)
  91. */
  92. conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen);
  93. uxsel_del(fd);
  94. close(fd);
  95. del234(agent_connections, conn);
  96. sfree(conn);
  97. return 0;
  98. }
  99. int agent_query(void *in, int inlen, void **out, int *outlen,
  100. void (*callback)(void *, void *, int), void *callback_ctx)
  101. {
  102. char *name;
  103. int sock;
  104. struct sockaddr_un addr;
  105. int done;
  106. struct agent_connection *conn;
  107. name = getenv("SSH_AUTH_SOCK");
  108. if (!name)
  109. goto failure;
  110. sock = socket(PF_UNIX, SOCK_STREAM, 0);
  111. if (sock < 0) {
  112. perror("socket(PF_UNIX)");
  113. exit(1);
  114. }
  115. addr.sun_family = AF_UNIX;
  116. strncpy(addr.sun_path, name, sizeof(addr.sun_path));
  117. if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  118. close(sock);
  119. goto failure;
  120. }
  121. for (done = 0; done < inlen ;) {
  122. int ret = write(sock, (char *)in + done, inlen - done);
  123. if (ret <= 0) {
  124. close(sock);
  125. goto failure;
  126. }
  127. done += ret;
  128. }
  129. if (!agent_connections)
  130. agent_connections = newtree234(agent_conncmp);
  131. conn = snew(struct agent_connection);
  132. conn->fd = sock;
  133. conn->retbuf = conn->sizebuf;
  134. conn->retsize = 4;
  135. conn->retlen = 0;
  136. conn->callback = callback;
  137. conn->callback_ctx = callback_ctx;
  138. add234(agent_connections, conn);
  139. uxsel_set(sock, 1, agent_select_result);
  140. return 0;
  141. failure:
  142. *out = NULL;
  143. *outlen = 0;
  144. return 1;
  145. }