PageRenderTime 61ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/pwmd.c

https://gitlab.com/bjk/fetchmail
C | 392 lines | 315 code | 59 blank | 18 comment | 73 complexity | a0daf99dd18f08427efe7a3422e663c4 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. /*
  2. Copyright (C) Ben Kibbey <bjk@luxsci.net>
  3. For license terms, see the file COPYING in this directory.
  4. */
  5. #ifdef HAVE_CONFIG_H
  6. #include <config.h>
  7. #endif
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <stdarg.h>
  12. #include <ctype.h>
  13. #include <libpwmd.h>
  14. #include "gettext.h"
  15. #include "pwmd.h"
  16. static void exit_with_pwmd_error(gpg_error_t rc)
  17. {
  18. report(stderr, GT_("pwmd: ERR %i: %s\n"), rc, gpg_strerror(rc));
  19. if (pwm) {
  20. pwmd_close(pwm);
  21. pwm = NULL;
  22. }
  23. /* Don't exit if daemonized. There may be other active accounts. */
  24. if (isatty(STDOUT_FILENO))
  25. exit(PS_SYNTAX);
  26. }
  27. static gpg_error_t status_cb(void *data, const char *line)
  28. {
  29. (void)data;
  30. if (!strncmp(line, "LOCKED", 6))
  31. report(stderr, "pwmd(%s): %s\n", pwmd_file, line);
  32. return 0;
  33. }
  34. #define MAX_PWMD_ARGS 8
  35. static gpg_error_t parse_socket_args (const char *str, char ***args)
  36. {
  37. gpg_error_t rc = 0;
  38. char buf[2048], *b;
  39. const char *p;
  40. int n = 0;
  41. static char *result[MAX_PWMD_ARGS] = {0};
  42. for (n = 0; n < MAX_PWMD_ARGS; n++)
  43. result[n] = NULL;
  44. n = 0;
  45. for (b = buf, p = str; *p; p++)
  46. {
  47. if (*p == ',')
  48. {
  49. *b = 0;
  50. result[n] = xstrdup (buf);
  51. if (!result[n])
  52. {
  53. rc = gpg_error (GPG_ERR_ENOMEM);
  54. break;
  55. }
  56. b = buf;
  57. *b = 0;
  58. n++;
  59. continue;
  60. }
  61. *b++ = *p;
  62. }
  63. if (!rc && buf[0])
  64. {
  65. *b = 0;
  66. result[n] = xstrdup (buf);
  67. if (!result[n])
  68. rc = gpg_error (GPG_ERR_ENOMEM);
  69. }
  70. if (rc)
  71. {
  72. for (n = 0; n < MAX_PWMD_ARGS; n++)
  73. {
  74. xfree(result[n]);
  75. result[n] = NULL;
  76. }
  77. }
  78. else
  79. *args = result;
  80. return rc;
  81. }
  82. int connect_to_pwmd(const char *socketname, const char *socket_args,
  83. const char *filename)
  84. {
  85. gpg_error_t rc;
  86. pwmd_init();
  87. /* Try to reuse an existing connection for another account on the same pwmd
  88. * server. If the socket name or any socket arguments have changed then
  89. * reopen the connection. */
  90. if (!pwm || (socketname && !pwmd_socket)
  91. || (!socketname && pwmd_socket) ||
  92. (socketname && pwmd_socket && strcmp(socketname, pwmd_socket))
  93. || (socket_args && !pwmd_socket_args)
  94. || (!socket_args && pwmd_socket_args)
  95. || (socket_args && pwmd_socket_args
  96. && strcmp (socket_args, pwmd_socket_args))) {
  97. pwmd_close(pwm);
  98. rc = pwmd_new("fetchmail", &pwm);
  99. if (rc) {
  100. exit_with_pwmd_error(rc);
  101. return 1;
  102. }
  103. rc = pwmd_setopt (pwm, PWMD_OPTION_SOCKET_TIMEOUT, 120);
  104. if (!rc)
  105. rc = pwmd_setopt(pwm, PWMD_OPTION_STATUS_CB, status_cb);
  106. if (rc) {
  107. exit_with_pwmd_error(rc);
  108. return 1;
  109. }
  110. if (socket_args) {
  111. char **args = NULL;
  112. int n;
  113. rc = parse_socket_args (socket_args, &args);
  114. if (!rc) {
  115. rc = pwmd_connect(pwm, socketname, args[0], args[1], args[2],
  116. args[3], args[4], args[5], args[6], args[7]);
  117. for (n = 0; n < MAX_PWMD_ARGS; n++)
  118. xfree(args[n]);
  119. }
  120. }
  121. else
  122. rc = pwmd_connect(pwm, socketname, NULL);
  123. if (rc) {
  124. exit_with_pwmd_error(rc);
  125. return 1;
  126. }
  127. pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_DESC, NULL);
  128. rc = pwmd_setopt (pwm, PWMD_OPTION_LOCK_TIMEOUT, 300);
  129. if (rc) {
  130. exit_with_pwmd_error(rc);
  131. return 1;
  132. }
  133. rc = pwmd_setopt(pwm, PWMD_OPTION_LOCK_ON_OPEN, 0);
  134. if (rc) {
  135. exit_with_pwmd_error(rc);
  136. return 1;
  137. }
  138. }
  139. if (run.pinentry_timeout > 0) {
  140. rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT,
  141. run.pinentry_timeout);
  142. if (rc) {
  143. exit_with_pwmd_error(rc);
  144. return 1;
  145. }
  146. }
  147. if (!pwmd_file || strcmp(filename, pwmd_file)) {
  148. /* Temporarily set so status_cb knows what file. */
  149. pwmd_file = filename;
  150. rc = pwmd_open(pwm, filename, NULL, NULL);
  151. pwmd_file = NULL;
  152. if (rc) {
  153. exit_with_pwmd_error(rc);
  154. return 1;
  155. }
  156. }
  157. /* May be null to use the default of ~/.pwmd/socket. */
  158. pwmd_socket = socketname;
  159. pwmd_socket_args = socket_args;
  160. pwmd_file = filename;
  161. return 0;
  162. }
  163. static int
  164. failure (const char *account, const char *id, gpg_error_t rc, int required)
  165. {
  166. if (!rc)
  167. return 0;
  168. if (gpg_err_code (rc) == GPG_ERR_ELEMENT_NOT_FOUND) {
  169. report(stderr, GT_("%spwmd(%s): %s(%s): %s\n"),
  170. required ? "" : GT_("WARNING: "), pwmd_file, account, id,
  171. gpg_strerror(rc));
  172. if (!required)
  173. return 0;
  174. }
  175. return 1;
  176. }
  177. static gpg_error_t
  178. alloc_result (const char *s, size_t len, char **result)
  179. {
  180. if (!len) {
  181. *result = NULL;
  182. return 0;
  183. }
  184. char *b = xmalloc (len+1);
  185. if (!b)
  186. return GPG_ERR_ENOMEM;
  187. memcpy (b, s, len);
  188. b[len] = 0;
  189. *result = b;
  190. return 0;
  191. }
  192. int get_pwmd_elements(const char *account, int protocol, struct query *ctl)
  193. {
  194. const char *prot1 = showproto(protocol);
  195. char *result, *prot;
  196. char *tmp = xstrdup(account);
  197. char *bulk = NULL;
  198. const char *bresult;
  199. size_t brlen, len;
  200. size_t offset = 0;
  201. char *str;
  202. gpg_error_t rcs[3] = { 0 };
  203. gpg_error_t rc, brc;
  204. int i;
  205. prot = xstrdup(prot1);
  206. for (i = 0; prot[i]; i++)
  207. prot[i] = tolower(prot[i]);
  208. for (i = 0; tmp[i]; i++) {
  209. if (i && tmp[i] == '^')
  210. tmp[i] = '\t';
  211. }
  212. rc = pwmd_bulk_append (&bulk, "NOP", 3, "NOP", NULL, 0, &offset);
  213. if (rc)
  214. goto done;
  215. rcs[0] = 0;
  216. rcs[1] = GPG_ERR_MISSING_ERRNO;
  217. str = pwmd_strdup_printf ("%s\t%s\thostname", tmp, prot);
  218. rc = pwmd_bulk_append_rc (&bulk, rcs, "HOST", 4, "GET", str, strlen (str),
  219. &offset);
  220. pwmd_free (str);
  221. if (rc)
  222. goto done;
  223. /*
  224. * Server port. Fetchmail tries standard ports for known services so it
  225. * should be alright if this element isn't found. ctl->server.protocol is
  226. * already set. This sets ctl->server.service.
  227. */
  228. rcs[0] = 0;
  229. rcs[1] = GPG_ERR_MISSING_ERRNO;
  230. offset--;
  231. str = pwmd_strdup_printf ("%s\t%s\tport", tmp, prot);
  232. rc = pwmd_bulk_append_rc (&bulk, rcs, "PORT", 4, "GET", str, strlen (str),
  233. &offset);
  234. pwmd_free (str);
  235. if (rc)
  236. goto done;
  237. rcs[0] = 0;
  238. rcs[1] = gpg_err_make (GPG_ERR_SOURCE_USER_1, GPG_ERR_ELEMENT_NOT_FOUND);
  239. rcs[2] = GPG_ERR_MISSING_ERRNO;
  240. offset--;
  241. str = pwmd_strdup_printf ("%s\tusername", tmp);
  242. rc = pwmd_bulk_append_rc (&bulk, rcs, "USER", 4, "GET", str, strlen (str),
  243. &offset);
  244. pwmd_free (str);
  245. if (rc)
  246. goto done;
  247. rcs[0] = 0;
  248. rcs[1] = GPG_ERR_MISSING_ERRNO;
  249. offset--;
  250. str = pwmd_strdup_printf ("%s\tpassword", tmp);
  251. rc = pwmd_bulk_append_rc (&bulk, rcs, "PASS", 4, "GET", str, strlen (str),
  252. &offset);
  253. pwmd_free (str);
  254. if (rc)
  255. goto done;
  256. #ifdef SSL_ENABLE
  257. /* It is up to the user to specify the sslmode via the command line or via
  258. * the rcfile rather than requiring an extra element. */
  259. rcs[0] = 0;
  260. rcs[1] = gpg_err_make (GPG_ERR_SOURCE_USER_1, GPG_ERR_ELEMENT_NOT_FOUND);
  261. rcs[2] = GPG_ERR_MISSING_ERRNO;
  262. offset--;
  263. str = pwmd_strdup_printf ("%s\t%s\tsslfingerprint", tmp, prot);
  264. rc = pwmd_bulk_append_rc (&bulk, rcs, "SSL", 3, "GET", str, strlen (str),
  265. &offset);
  266. pwmd_free (str);
  267. if (rc)
  268. goto done;
  269. #endif
  270. rc = pwmd_bulk_finalize (&bulk);
  271. if (!rc)
  272. rc = pwmd_bulk (pwm, &result, &len, NULL, NULL, bulk, strlen (bulk));
  273. if (rc)
  274. goto done;
  275. offset = 0;
  276. rc = pwmd_bulk_result (result, len, "HOST", 4, &offset, &bresult, &brlen,
  277. &brc);
  278. if (failure (account, "hostname", rc ? rc : brc, 1))
  279. goto done;
  280. if (ctl->server.pollname != ctl->server.via)
  281. xfree(ctl->server.via);
  282. alloc_result (bresult, brlen, &ctl->server.via);
  283. xfree(ctl->server.queryname);
  284. ctl->server.queryname = xstrdup(ctl->server.via);
  285. xfree(ctl->server.truename);
  286. ctl->server.truename = xstrdup(ctl->server.queryname);
  287. rc = pwmd_bulk_result (result, len, "PORT", 4, &offset, &bresult, &brlen,
  288. &brc);
  289. if (failure (account, "port", rc ? rc : brc, 0))
  290. goto done;
  291. xfree(ctl->server.service);
  292. ctl->server.service = NULL;
  293. if (brlen)
  294. alloc_result (bresult, brlen, &ctl->server.service);
  295. rc = pwmd_bulk_result (result, len, "USER", 4, &offset, &bresult, &brlen,
  296. &brc);
  297. if (failure (account, "username", rc ? rc : brc, 1))
  298. goto done;
  299. xfree(ctl->remotename);
  300. xfree(ctl->server.esmtp_name);
  301. ctl->remotename = ctl->server.esmtp_name = NULL;
  302. alloc_result (bresult, brlen, &ctl->remotename);
  303. alloc_result (bresult, brlen, &ctl->server.esmtp_name);
  304. rc = pwmd_bulk_result (result, len, "PASS", 4, &offset, &bresult, &brlen,
  305. &brc);
  306. if (failure (account, "password", rc ? rc : brc, !isatty (STDOUT_FILENO)))
  307. goto done;
  308. xfree(ctl->password);
  309. ctl->password = NULL;
  310. if (brlen)
  311. alloc_result (bresult, brlen, &ctl->password);
  312. brc = 0;
  313. #ifdef SSL_ENABLE
  314. rc = pwmd_bulk_result (result, len, "SSL", 3, &offset, &bresult, &brlen,
  315. &brc);
  316. if (failure (account, "sslfingerprint", rc ? rc : brc, 0))
  317. goto done;
  318. xfree(ctl->sslfingerprint);
  319. ctl->sslfingerprint = NULL;
  320. if (brlen)
  321. alloc_result (bresult, brlen, &ctl->sslfingerprint);
  322. brc = 0;
  323. #endif
  324. done:
  325. pwmd_free (result);
  326. pwmd_free (bulk);
  327. xfree(tmp);
  328. xfree(prot);
  329. if (rc || brc)
  330. exit_with_pwmd_error (rc ? rc : brc);
  331. return !!rc || !!brc;
  332. }