Ignore GPG_ERR_EOF when killing scdaemon.
[libpwmd.git] / src / agent.c
blob9afdfd5b9b43a3201b233278ea881244e6c17dc2
1 /*
2 Copyright (C) 2016
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <pwd.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <sys/wait.h>
30 #include <fcntl.h>
31 #include <dirent.h>
33 #ifdef HAVE_LIMITS_H
34 #include <limits.h>
35 #endif
37 #include "pwmd-error.h"
38 #include "util-misc.h"
39 #include "mem.h"
40 #include "common.h"
41 #include "agent.h"
42 #include "util-string.h"
43 #include "mutex.h"
44 #include "rcfile.h"
45 #include "cache.h"
47 static gpg_error_t
48 mem_realloc_cb (void *data, const void *buffer, size_t len)
50 membuf_t *mem = (membuf_t *) data;
51 void *p;
53 if (!buffer)
54 return 0;
56 if ((p = xrealloc (mem->buf, mem->len + len)) == NULL)
57 return 1;
59 mem->buf = p;
60 memcpy ((char *) mem->buf + mem->len, buffer, len);
61 mem->len += len;
62 return 0;
65 static gpg_error_t
66 status_cb (void *data, const char *line)
68 struct agent_s *agent = data;
70 agent->inquire_maxlen = 0;
72 if (!strncmp (line, "INQUIRE_MAXLEN ", 15))
73 agent->inquire_maxlen = atoi (line + 15);
75 return 0;
78 static gpg_error_t
79 inquire_cb (void *user, const char *keyword)
81 struct agent_s *agent = user;
83 return assuan_send_data (agent->ctx, agent->inquire->line,
84 agent->inquire->len);
87 static gpg_error_t
88 assuan_command (struct agent_s *a, char **result,
89 size_t * len, const char *cmd)
91 gpg_error_t rc;
93 a->data.len = 0;
94 a->data.buf = NULL;
95 if (result)
96 *result = NULL;
97 if (len)
98 *len = 0;
100 rc = assuan_transact (a->ctx, cmd, mem_realloc_cb, &a->data,
101 inquire_cb, a, status_cb, a);
102 if (rc)
103 xfree (a->data.buf);
104 else
106 if (a->data.buf)
108 mem_realloc_cb (&a->data, "", 1);
109 if (result)
110 *result = (char *) a->data.buf;
111 else
112 xfree (a->data.buf);
114 if (len)
115 *len = a->data.len;
119 return rc;
122 gpg_error_t
123 agent_connect (struct agent_s *agent)
125 gpg_error_t rc;
126 assuan_context_t ctx = NULL;
127 static struct assuan_malloc_hooks mhooks = { xmalloc, xrealloc, xfree };
129 agent->did_restart = 0;
130 rc = assuan_new_ext (&ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, assuan_log_cb,
131 NULL);
132 if (rc)
133 return rc;
135 rc = assuan_socket_connect (ctx, agent->socket, ASSUAN_INVALID_PID, 0);
136 if (!rc)
138 if (agent->ctx)
139 assuan_release (agent->ctx);
141 agent->ctx = ctx;
143 else
145 if (ctx)
146 assuan_release (ctx);
149 return rc;
152 static gpg_error_t
153 send_to_agent (struct agent_s *agent, char **result, size_t *len,
154 const char *cmd)
156 gpg_error_t rc = 0;
158 if (!agent->ctx)
160 rc = agent_connect (agent);
161 if (rc)
162 return rc;
165 rc = assuan_command (agent, result, len, cmd);
166 if (!agent->restart && gpg_err_source (rc) == GPG_ERR_SOURCE_DEFAULT
167 && (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED
168 || gpg_err_code (rc) == GPG_ERR_EPIPE))
170 log_write (_ ("gpg-agent connection died (rc=%u), reconnecting"), rc);
171 agent->restart = 1;
172 rc = agent_connect (agent);
173 if (!rc)
175 agent->did_restart = 1;
176 rc = assuan_command (agent, result, len, cmd);
180 agent->restart = 0;
181 return rc;
184 gpg_error_t
185 agent_command (struct agent_s *agent, char **result, size_t * len,
186 const char *fmt, ...)
188 va_list ap;
189 char *cmd = NULL;
190 gpg_error_t rc;
192 va_start (ap, fmt);
194 if (str_vasprintf (&cmd, fmt, ap) > 0)
195 rc = send_to_agent (agent, result, len, cmd);
196 else
197 rc = GPG_ERR_ENOMEM;
199 xfree (cmd);
200 va_end (ap);
201 return rc;
204 void
205 agent_disconnect (struct agent_s *agent)
207 if (!agent)
208 return;
210 if (agent->ctx)
211 assuan_release (agent->ctx);
213 agent->ctx = NULL;
216 void
217 agent_free (struct agent_s *agent)
219 if (!agent)
220 return;
222 agent_disconnect (agent);
223 xfree (agent->socket);
224 xfree (agent);
227 gpg_error_t
228 agent_init (struct agent_s **agent)
230 struct agent_s *new;
231 FILE *fp;
232 char *buf;
233 char line[PATH_MAX], *p;
234 gpg_error_t rc = 0;
235 int ret;
236 char *gpghome = config_get_string ("global", "gpg_homedir");
238 if (gpghome)
239 buf = str_asprintf ("gpgconf --homedir %s --list-dirs", gpghome);
240 else
241 buf = str_asprintf ("gpgconf --homedir %s/.gnupg --list-dirs", homedir);
243 xfree (gpghome);
244 fp = popen (buf, "r");
245 if (!fp)
247 rc = gpg_error_from_syserror ();
248 xfree (buf);
249 return rc;
252 xfree (buf);
254 while ((p = fgets (line, sizeof(line), fp)))
256 if (line[strlen(line)-1] == '\n')
257 line[strlen(line)-1] = 0;
259 if (!strncmp (line, "agent-socket:", 13))
261 buf = str_dup (line+13);
262 break;
266 ret = pclose (fp);
267 if (ret)
269 xfree (buf);
270 return GPG_ERR_ASS_GENERAL;
273 new = xcalloc (1, sizeof (struct agent_s));
274 if (!new)
276 xfree (buf);
277 return GPG_ERR_ENOMEM;
280 new->socket = buf;
281 *agent = new;
282 return 0;
285 gpg_error_t
286 agent_set_option (struct agent_s * agent, const char *name, const char *value)
288 return agent_command (agent, NULL, NULL, "OPTION %s=%s", name, value);
291 gpg_error_t
292 agent_kill_scd (struct agent_s *agent)
294 gpg_error_t rc = 0;
296 if (config_get_boolean (NULL, "kill_scd"))
298 rc = agent_command (agent, NULL, NULL, "SCD KILLSCD");
299 if (rc && gpg_err_code (rc) != GPG_ERR_NO_SCDAEMON
300 && gpg_err_code (rc) != GPG_ERR_EPIPE
301 && gpg_err_code (rc) != GPG_ERR_EOF)
302 log_write ("%s: ERR %u: %s", __FUNCTION__, rc, pwmd_strerror (rc));
305 return rc;