cert-gpgsm.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /* cert-gpgsm.c - Scute certificate searching.
  2. Copyright (C) 2006, 2007 g10 Code GmbH
  3. This file is part of Scute.
  4. Scute is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. Scute is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Scute; if not, write to the Free Software Foundation,
  14. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  15. In addition, as a special exception, g10 Code GmbH gives permission
  16. to link this library: with the Mozilla Foundation's code for
  17. Mozilla (or with modified versions of it that use the same license
  18. as the "Mozilla" code), and distribute the linked executables. You
  19. must obey the GNU General Public License in all respects for all of
  20. the code used other than "Mozilla". If you modify this file, you
  21. may extend this exception to your version of the file, but you are
  22. not obligated to do so. If you do not wish to do so, delete this
  23. exception statement from your version. */
  24. #if HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27. #include <time.h>
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <stdbool.h>
  32. #include <gpg-error.h>
  33. #include <assuan.h>
  34. #include "cert.h"
  35. #include "support.h"
  36. #include "debug.h"
  37. #ifndef HAVE_W32_SYSTEM
  38. #define COMPAT_FALLBACK
  39. #endif
  40. /* The maximum length of a key listing line. We take the double of
  41. the allowed Assuan line length to avoid a memmove after a part of a
  42. line has been processed. FIXME: There is actually no limit on the
  43. length of the line. */
  44. #define MAX_LINE_LEN (1024*2)
  45. struct search_ctx
  46. {
  47. /* The pending line in an active key listing. */
  48. char pending[MAX_LINE_LEN + 1];
  49. unsigned int pending_len;
  50. /* The caller's search callback, invoked for each certificate. */
  51. cert_search_cb_t search_cb;
  52. void *search_cb_hook;
  53. /* The current certificate. */
  54. struct cert cert;
  55. };
  56. /* Release allocated storage for the certificate CERT and reset the
  57. certificate. */
  58. static void
  59. cert_reset (struct cert *cert)
  60. {
  61. if (cert->issuer_serial)
  62. free (cert->issuer_serial);
  63. if (cert->issuer_name)
  64. free (cert->issuer_name);
  65. if (cert->uid)
  66. free (cert->uid);
  67. if (cert->cert_der)
  68. free (cert->cert_der);
  69. memset (cert, '\0', sizeof (struct cert));
  70. }
  71. /* Support routines for key list processing. */
  72. #define atoi_1(p) (*(p) - '0' )
  73. #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
  74. #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
  75. /* Parse the string TIMESTAMP into a time_t. The string may either be
  76. seconds since Epoch or in the ISO 8601 format like
  77. "20390815T143012". Returns 0 for an empty string or seconds since
  78. Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
  79. point to the next non-parsed character in TIMESTRING. */
  80. static time_t
  81. parse_timestamp (const char *timestamp, char **endp)
  82. {
  83. /* Need to skip leading spaces, because that is what strtoul does
  84. but not our ISO 8601 checking code. */
  85. while (*timestamp && *timestamp== ' ')
  86. timestamp++;
  87. if (!*timestamp)
  88. return 0;
  89. if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
  90. {
  91. struct tm buf;
  92. int year;
  93. year = atoi_4 (timestamp);
  94. if (year < 1900)
  95. return (time_t)(-1);
  96. /* Fixme: We would better use a configure test to see whether
  97. mktime can handle dates beyond 2038. */
  98. if (sizeof (time_t) <= 4 && year >= 2038)
  99. return (time_t)2145914603; /* 2037-12-31 23:23:23 */
  100. memset (&buf, 0, sizeof buf);
  101. buf.tm_year = year - 1900;
  102. buf.tm_mon = atoi_2 (timestamp+4) - 1;
  103. buf.tm_mday = atoi_2 (timestamp+6);
  104. buf.tm_hour = atoi_2 (timestamp+9);
  105. buf.tm_min = atoi_2 (timestamp+11);
  106. buf.tm_sec = atoi_2 (timestamp+13);
  107. if (endp)
  108. *endp = (char*)(timestamp + 15);
  109. #ifdef HAVE_TIMEGM
  110. return timegm (&buf);
  111. #else
  112. /* FIXME: Need to set TZ to UTC, but that is not
  113. thread-safe. */
  114. return mktime (&buf);
  115. #endif
  116. }
  117. else
  118. return (time_t)strtoul (timestamp, endp, 10);
  119. }
  120. /* Decode the C formatted string SRC and store the result in the
  121. buffer *DESTP which is LEN bytes long. If LEN is zero, then a
  122. large enough buffer is allocated with malloc and *DESTP is set to
  123. the result. Currently, LEN is only used to specify if allocation
  124. is desired or not, the caller is expected to make sure that *DESTP
  125. is large enough if LEN is not zero. */
  126. static gpg_error_t
  127. decode_c_string (const char *src, char **destp, size_t len)
  128. {
  129. char *dest;
  130. /* Set up the destination buffer. */
  131. if (len)
  132. {
  133. if (len < strlen (src) + 1)
  134. return gpg_error (GPG_ERR_INTERNAL);
  135. dest = *destp;
  136. }
  137. else
  138. {
  139. /* The converted string will never be larger than the original
  140. string. */
  141. dest = malloc (strlen (src) + 1);
  142. if (!dest)
  143. return gpg_error_from_syserror ();
  144. *destp = dest;
  145. }
  146. /* Convert the string. */
  147. while (*src)
  148. {
  149. if (*src != '\\')
  150. {
  151. *(dest++) = *(src++);
  152. continue;
  153. }
  154. switch (src[1])
  155. {
  156. #define DECODE_ONE(match,result) \
  157. case match: \
  158. src += 2; \
  159. *(dest++) = result; \
  160. break;
  161. DECODE_ONE ('\'', '\'');
  162. DECODE_ONE ('\"', '\"');
  163. DECODE_ONE ('\?', '\?');
  164. DECODE_ONE ('\\', '\\');
  165. DECODE_ONE ('a', '\a');
  166. DECODE_ONE ('b', '\b');
  167. DECODE_ONE ('f', '\f');
  168. DECODE_ONE ('n', '\n');
  169. DECODE_ONE ('r', '\r');
  170. DECODE_ONE ('t', '\t');
  171. DECODE_ONE ('v', '\v');
  172. case 'x':
  173. {
  174. int val = xtoi_2 (&src[2]);
  175. if (val == -1)
  176. {
  177. /* Should not happen. */
  178. *(dest++) = *(src++);
  179. *(dest++) = *(src++);
  180. if (*src)
  181. *(dest++) = *(src++);
  182. if (*src)
  183. *(dest++) = *(src++);
  184. }
  185. else
  186. {
  187. if (!val)
  188. {
  189. /* A binary zero is not representable in a C
  190. string. */
  191. *(dest++) = '\\';
  192. *(dest++) = '0';
  193. }
  194. else
  195. *((unsigned char *) dest++) = val;
  196. src += 4;
  197. }
  198. }
  199. break;
  200. default:
  201. {
  202. /* Should not happen. */
  203. *(dest++) = *(src++);
  204. *(dest++) = *(src++);
  205. }
  206. }
  207. }
  208. *(dest++) = 0;
  209. return 0;
  210. }
  211. /* The cert handler for certificate searches. This is invoked for
  212. each complete certificate found by search_certs_line, and the last
  213. pending certificate when EOF is encountered by search_certs. */
  214. static gpg_error_t
  215. search_certs_cert (struct search_ctx *ctx)
  216. {
  217. return (*ctx->search_cb) (ctx->search_cb_hook, &ctx->cert);
  218. }
  219. /* The line handler for certificate searches. This is invoked for
  220. each complete line found by search_certs. */
  221. static gpg_error_t
  222. search_certs_line (struct search_ctx *ctx)
  223. {
  224. char *line;
  225. enum { RT_NONE, RT_CRT, RT_CRS, RT_FPR, RT_GRP, RT_UID } rectype = RT_NONE;
  226. #define NR_FIELDS 16
  227. char *field[NR_FIELDS];
  228. int fields = 0;
  229. struct cert *cert;
  230. /* Strip a trailing carriage return. */
  231. if (ctx->pending_len > 0
  232. && ctx->pending[ctx->pending_len - 1] == '\r')
  233. ctx->pending_len--;
  234. ctx->pending[ctx->pending_len - 1] = '\0';
  235. ctx->pending_len = 0;
  236. cert = &ctx->cert;
  237. line = ctx->pending;
  238. while (line && fields < NR_FIELDS)
  239. {
  240. field[fields++] = line;
  241. line = strchr (line, ':');
  242. if (line)
  243. *(line++) = '\0';
  244. }
  245. if (!strcmp (field[0], "crt"))
  246. rectype = RT_CRT;
  247. else if (!strcmp (field[0], "crs"))
  248. rectype = RT_CRS;
  249. else if (!strcmp (field[0], "fpr"))
  250. rectype = RT_FPR;
  251. else if (!strcmp (field[0], "grp"))
  252. rectype = RT_GRP;
  253. else if (!strcmp (field[0], "uid"))
  254. rectype = RT_UID;
  255. else
  256. rectype = RT_NONE;
  257. switch (rectype)
  258. {
  259. case RT_CRT:
  260. case RT_CRS:
  261. /* Reinitialize CERT. */
  262. if (cert->valid)
  263. {
  264. gpg_error_t err;
  265. err = search_certs_cert (ctx);
  266. if (err)
  267. return err;
  268. cert_reset (cert);
  269. }
  270. cert->valid = true;
  271. #if 0
  272. /* Field 2 has the trust info. */
  273. if (fields >= 2)
  274. set_mainkey_trust_info (key, field[1]);
  275. #endif
  276. /* Field 3 has the key length. */
  277. if (fields >= 3)
  278. {
  279. int i = atoi (field[2]);
  280. /* Ignore invalid values. */
  281. if (i > 1)
  282. cert->length = i;
  283. }
  284. /* Field 4 has the public key algorithm. */
  285. if (fields >= 4)
  286. {
  287. int i = atoi (field[3]);
  288. if (i >= 1 && i < 128)
  289. cert->pubkey_algo = i;
  290. }
  291. /* Field 5 has the long keyid. Allow short key IDs for the
  292. output of an external keyserver listing. */
  293. if (fields >= 5 && strlen (field[4]) <= sizeof (cert->keyid) - 1)
  294. strcpy (cert->keyid, field[4]);
  295. /* Field 6 has the timestamp (seconds). */
  296. if (fields >= 6)
  297. cert->timestamp = parse_timestamp (field[5], NULL);
  298. /* Field 7 has the expiration time (seconds). */
  299. if (fields >= 7)
  300. cert->expires = parse_timestamp (field[6], NULL);
  301. /* Field 8 has the X.509 serial number. */
  302. if (fields >= 8)
  303. {
  304. cert->issuer_serial = strdup (field[7]);
  305. if (!cert->issuer_serial)
  306. return gpg_error_from_syserror ();
  307. }
  308. #if 0
  309. /* Field 9 has the ownertrust. */
  310. if (fields >= 9)
  311. set_ownertrust (key, field[8]);
  312. #endif
  313. /* Field 10 is the issuer name. */
  314. if (fields >= 10)
  315. if (decode_c_string (field[9], &cert->issuer_name, 0))
  316. return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
  317. /* Field 11 has the signature class. */
  318. #if 0
  319. /* Field 12 has the capabilities. */
  320. if (fields >= 12)
  321. set_mainkey_capability (key, field[11]);
  322. #endif
  323. break;
  324. case RT_UID:
  325. if (cert->valid)
  326. {
  327. /* Field 2 has the trust info, and field 10 has the user ID.
  328. Note that more than one UID field can appear. We only
  329. remember the last one. It's not used anyway. */
  330. if (fields >= 10 && !cert->uid)
  331. {
  332. if (decode_c_string (field[9], &cert->uid, 0))
  333. return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
  334. }
  335. }
  336. break;
  337. case RT_FPR:
  338. if (cert->valid)
  339. {
  340. /* Field 10 has the fingerprint (take only the first one). */
  341. if (fields >= 10 && strlen (field[9]) <= sizeof (cert->fpr) - 1)
  342. strcpy (cert->fpr, field[9]);
  343. /* Field 13 has the gpgsm chain ID (take only the first one). */
  344. if (fields >= 13 && strlen (field[12])
  345. <= sizeof (cert->chain_id) - 1)
  346. strcpy (cert->chain_id, field[12]);
  347. }
  348. break;
  349. case RT_GRP:
  350. if (cert->valid)
  351. {
  352. /* Field 10 has the key grip. */
  353. if (fields >= 10 && strlen (field[9]) <= sizeof (cert->grip) - 1)
  354. strcpy (cert->grip, field[9]);
  355. }
  356. break;
  357. case RT_NONE:
  358. /* Unknown record. */
  359. break;
  360. }
  361. return 0;
  362. }
  363. /* This is the data line callback handler provided to assuan_transact
  364. in scute_gpgsm_search_certs. It buffers incomplete lines, and also
  365. handles the EOF signal provided directly by
  366. scute_gpgsm_search_certs. */
  367. static gpg_error_t
  368. search_certs (void *hook, char *line, size_t line_len)
  369. {
  370. struct search_ctx *ctx = hook;
  371. gpg_error_t err;
  372. if (!line)
  373. {
  374. /* This indicates an EOF. */
  375. /* Check for a pending line, in case GPGSM didn't close with a
  376. newline. */
  377. if (ctx->pending_len)
  378. {
  379. err = search_certs_line (ctx);
  380. if (err)
  381. return err;
  382. }
  383. /* Check for a pending certificate. */
  384. if (ctx->cert.valid)
  385. return search_certs_cert (ctx);
  386. return 0;
  387. }
  388. while (line_len)
  389. {
  390. if (*line == '\n')
  391. {
  392. err = search_certs_line (ctx);
  393. if (err)
  394. return err;
  395. }
  396. else
  397. {
  398. if (ctx->pending_len >= MAX_LINE_LEN)
  399. return gpg_error (GPG_ERR_LINE_TOO_LONG);
  400. ctx->pending[ctx->pending_len++] = *line;
  401. }
  402. line++;
  403. line_len--;
  404. }
  405. return 0;
  406. }
  407. /* Invoke SEARCH_CB for each certificate found using assuan connection
  408. CTX to GPGSM. */
  409. static gpg_error_t
  410. scute_gpgsm_search_certs (assuan_context_t ctx, cert_search_cb_t search_cb,
  411. void *search_cb_hook)
  412. {
  413. gpg_error_t err;
  414. struct search_ctx search;
  415. err = assuan_transact (ctx, "OPTION with-key-data", NULL, NULL,
  416. NULL, NULL, NULL, NULL);
  417. if (err)
  418. return err;
  419. search.pending_len = 0;
  420. search.search_cb = search_cb;
  421. search.search_cb_hook = search_cb_hook;
  422. memset (&search.cert, '\0', sizeof (search.cert));
  423. err = assuan_transact (ctx, "DUMPKEYS", &search_certs, &search, NULL,
  424. NULL, NULL, NULL);
  425. if (err)
  426. goto out;
  427. /* Signal the EOF. This is not done by Assuan for us. */
  428. err = search_certs (&search, NULL, 0);
  429. if (err)
  430. goto out;
  431. out:
  432. cert_reset (&search.cert);
  433. return err;
  434. }
  435. struct search_ctx_by_field
  436. {
  437. /* What we are searching for. */
  438. enum { SEARCH_BY_GRIP, SEARCH_BY_FPR } field;
  439. /* The pattern we are looking for. */
  440. const char *pattern;
  441. cert_search_cb_t search_cb;
  442. void *search_cb_hook;
  443. };
  444. #ifdef COMPAT_FALLBACK
  445. /* This is a compatibility function for GPGSM 2.0.0, which does not
  446. support the --data option with the EXPORT command. */
  447. static gpg_error_t
  448. export_cert_compat (char *fpr, struct cert *cert)
  449. {
  450. gpg_error_t err;
  451. assuan_context_t ctx;
  452. const char *argv[] = { "gpgsm", "--server", NULL };
  453. int got;
  454. #define COMMANDLINELEN 80
  455. char cmd[COMMANDLINELEN];
  456. int output_fds[2];
  457. int child_fds[2];
  458. #define MAX_CERT_SIZE 4096
  459. cert->cert_der = malloc (MAX_CERT_SIZE);
  460. if (!cert->cert_der)
  461. return gpg_error_from_syserror ();
  462. if(pipe (output_fds) < 0)
  463. return gpg_error_from_syserror ();
  464. child_fds[0] = output_fds[1];
  465. child_fds[1] = -1;
  466. err = assuan_pipe_connect_ext (&ctx, get_gpgsm_path (), argv, child_fds,
  467. NULL, NULL, 128);
  468. close (output_fds[1]);
  469. if (err)
  470. {
  471. close (output_fds[0]);
  472. DEBUG ("failed to spawn %s\n", get_gpgsm_path ());
  473. return err;
  474. }
  475. snprintf (cmd, sizeof (cmd), "OUTPUT FD=%i", output_fds[1]);
  476. err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  477. if (err)
  478. goto export_out;
  479. /* FIXME: This will only work if the certificate is small and fits
  480. into the pipe buffer completely!!! */
  481. snprintf (cmd, sizeof (cmd), "EXPORT %s\n", cert->fpr);
  482. err = assuan_transact (ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  483. if (err)
  484. goto export_out;
  485. do
  486. {
  487. got = read (output_fds[0], cert->cert_der + cert->cert_der_len,
  488. MAX_CERT_SIZE - cert->cert_der_len);
  489. if (got > 0)
  490. cert->cert_der_len += got;
  491. }
  492. while (!err && got > 0 && cert->cert_der_len < MAX_CERT_SIZE);
  493. if (got < 0 || cert->cert_der_len == MAX_CERT_SIZE)
  494. err = gpg_error (GPG_ERR_GENERAL);
  495. export_out:
  496. assuan_disconnect (ctx);
  497. close (output_fds[0]);
  498. return err;
  499. }
  500. #endif
  501. struct export_hook
  502. {
  503. /* The exported data. */
  504. char *buffer;
  505. /* The length of the exported data buffer. */
  506. unsigned int buffer_len;
  507. /* The size of the allocated exported data buffer. */
  508. unsigned int buffer_size;
  509. };
  510. #define EXP_DATA_START 4096
  511. static gpg_error_t
  512. export_cert_cb (void *hook, char *line, size_t line_len)
  513. {
  514. struct export_hook *exp = hook;
  515. if (exp->buffer_size - exp->buffer_len < line_len)
  516. {
  517. unsigned int new_buffer_size = exp->buffer_size ?
  518. (exp->buffer_size * 2) : EXP_DATA_START;
  519. char *new_buffer = realloc (exp->buffer, new_buffer_size);
  520. if (!new_buffer)
  521. return gpg_error_from_syserror ();
  522. exp->buffer = new_buffer;
  523. exp->buffer_size = new_buffer_size;
  524. }
  525. memcpy (exp->buffer + exp->buffer_len, line, line_len);
  526. exp->buffer_len += line_len;
  527. return 0;
  528. }
  529. static gpg_error_t
  530. export_cert (char *fpr, struct cert *cert)
  531. {
  532. gpg_error_t err;
  533. assuan_context_t ctx;
  534. const char *argv[] = { "gpgsm", "--server", NULL };
  535. #define COMMANDLINELEN 80
  536. char cmd[COMMANDLINELEN];
  537. struct export_hook exp;
  538. err = assuan_pipe_connect_ext (&ctx, get_gpgsm_path (), argv, NULL,
  539. NULL, NULL, 128);
  540. if (err)
  541. {
  542. DEBUG ("spawning %s\n", get_gpgsm_path ());
  543. return err;
  544. }
  545. exp.buffer = NULL;
  546. exp.buffer_len = 0;
  547. exp.buffer_size = 0;
  548. snprintf (cmd, sizeof (cmd), "EXPORT --data -- %s\n", cert->fpr);
  549. err = assuan_transact (ctx, cmd, export_cert_cb, &exp,
  550. NULL, NULL, NULL, NULL);
  551. assuan_disconnect (ctx);
  552. if (!err)
  553. {
  554. cert->cert_der = exp.buffer;
  555. cert->cert_der_len = exp.buffer_len;
  556. }
  557. #ifdef COMPAT_FALLBACK
  558. else if (gpg_err_code (err) == GPG_ERR_ASS_NO_OUTPUT)
  559. {
  560. /* For compatibility with GPGSM 2.0.0, we fall back to a work
  561. around in that case. */
  562. if (cert->cert_der)
  563. {
  564. free (cert->cert_der);
  565. cert->cert_der = NULL;
  566. }
  567. err = export_cert_compat (fpr, cert);
  568. }
  569. #endif
  570. if (!err)
  571. err = scute_agent_is_trusted (fpr, &cert->is_trusted);
  572. return err;
  573. }
  574. static gpg_error_t
  575. search_certs_by_field (void *hook, struct cert *cert)
  576. {
  577. struct search_ctx_by_field *ctx = hook;
  578. gpg_error_t err = 0;
  579. if ((ctx->field == SEARCH_BY_GRIP && !strcmp (ctx->pattern, cert->grip))
  580. || (ctx->field == SEARCH_BY_FPR && !strcmp (ctx->pattern, cert->fpr)))
  581. {
  582. if (strlen (cert->fpr) != 40)
  583. return gpg_error (GPG_ERR_GENERAL);
  584. err = export_cert (cert->fpr, cert);
  585. if (err)
  586. return err;
  587. err = (*ctx->search_cb) (ctx->search_cb_hook, cert);
  588. }
  589. return err;
  590. }
  591. /* Invoke SEARCH_CB for each certificate found using assuan connection
  592. CTX to GPGSM. */
  593. gpg_error_t
  594. scute_gpgsm_search_certs_by_grip (const char *grip,
  595. cert_search_cb_t search_cb,
  596. void *search_cb_hook)
  597. {
  598. gpg_error_t err;
  599. assuan_context_t ctx;
  600. const char *argv[] = { "gpgsm", "--server", NULL };
  601. struct search_ctx_by_field search;
  602. err = assuan_pipe_connect_ext (&ctx, get_gpgsm_path (), argv, NULL,
  603. NULL, NULL, 128);
  604. if (err)
  605. {
  606. DEBUG ("spawning %s\n", get_gpgsm_path ());
  607. return err;
  608. }
  609. search.field = SEARCH_BY_GRIP;
  610. search.pattern = grip;
  611. search.search_cb = search_cb;
  612. search.search_cb_hook = search_cb_hook;
  613. err = scute_gpgsm_search_certs (ctx, &search_certs_by_field, &search);
  614. assuan_disconnect (ctx);
  615. return err;
  616. }
  617. /* Invoke SEARCH_CB for each certificate found using assuan connection
  618. CTX to GPGSM. */
  619. gpg_error_t
  620. scute_gpgsm_search_certs_by_fpr (const char *fpr,
  621. cert_search_cb_t search_cb,
  622. void *search_cb_hook)
  623. {
  624. gpg_error_t err;
  625. assuan_context_t ctx;
  626. const char *argv[] = { "gpgsm", "--server", NULL };
  627. struct search_ctx_by_field search;
  628. err = assuan_pipe_connect_ext (&ctx, get_gpgsm_path (), argv, NULL,
  629. NULL, NULL, 128);
  630. if (err)
  631. {
  632. DEBUG ("failed to spawn %s\n", get_gpgsm_path ());
  633. return err;
  634. }
  635. search.field = SEARCH_BY_FPR;
  636. search.pattern = fpr;
  637. search.search_cb = search_cb;
  638. search.search_cb_hook = search_cb_hook;
  639. err = scute_gpgsm_search_certs (ctx, &search_certs_by_field, &search);
  640. assuan_disconnect (ctx);
  641. return err;
  642. }