1 /* pinentry.c
2 *
3 * Copyright 2011 Hans Alves <alves.h88@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21 /* for fdopen() */
22 #define _POSIX_SOURCE 1
23 #define _POSIX_C_SOURCE 1
24
25 #include "geanypg.h"
26
geanypg_getname(const char * uid_hint)27 static const char * geanypg_getname(const char * uid_hint)
28 {
29 int space = 0;
30 if (!uid_hint)
31 return NULL;
32 while (*uid_hint && !(space && *uid_hint != ' '))
33 {
34 if (*uid_hint == ' ')
35 space = 1;
36 ++uid_hint;
37 }
38 return uid_hint;
39 }
40
41 #ifdef __unix__
42
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46
geanypg_read_till(int fd,char delim)47 static void geanypg_read_till(int fd, char delim)
48 {
49 while (1)
50 {
51 char val;
52 ssize_t rv = read(fd, &val, 1);
53 if (rv <= 0 || val == delim)
54 break;
55 }
56 }
57
geanypg_read(int fd,char delim,int max,char * buffer)58 static int geanypg_read(int fd, char delim, int max, char * buffer)
59 {
60 int idx;
61 ssize_t rv = 1;
62 char ch = 0;
63 for (idx = 0; (idx < max - 1) && rv > 0 && ch != delim; ++idx)
64 {
65 rv = read(fd, &ch, 1);
66 buffer[idx] = ch;
67 }
68 buffer[idx ? idx - 1 : 0] = 0;
69 return idx ? idx - 1 : 0;
70 }
geanypg_passphrase_cb(void * hook,const char * uid_hint,const char * passphrase_info,int prev_was_bad,int fd)71 gpgme_error_t geanypg_passphrase_cb(void * hook,
72 const char * uid_hint,
73 const char * passphrase_info,
74 int prev_was_bad ,
75 int fd)
76 {
77 int outpipe[2];
78 int inpipe[2];
79 int childpid;
80 int status;
81 char readbuffer[2080] = {0}; /* pinentry should at least support passphrases of up to 2048 characters */
82 FILE * childin;
83
84 if (pipe(outpipe))
85 {
86 g_warning("%s", strerror(errno));
87 return gpgme_error_from_errno(errno);
88 }
89 if (pipe(inpipe))
90 {
91 g_warning("%s", strerror(errno));
92 return gpgme_error_from_errno(errno);
93 }
94
95 childpid = fork();
96 if (!childpid)
97 { /* pinentry */
98 char arg1[] = "pinentry";
99 char * argv[] = {NULL, NULL};
100
101 argv[0] = arg1;
102
103 close(outpipe[READ]);
104 dup2(outpipe[WRITE], STDOUT_FILENO);
105
106 close(inpipe[WRITE]);
107 dup2(inpipe[READ], STDIN_FILENO);
108
109 execvp(*argv, argv);
110 /* shouldn't get here */
111 g_warning("%s: %s", _("Could not use pinentry."), strerror(errno));
112 exit(1); /* kill the child */
113 }
114 /* GeanpyPG */
115 close(outpipe[WRITE]);
116 close(inpipe[READ]);
117 childin = fdopen(inpipe[WRITE], "w");
118
119 /* To understand what's happening here, read the pinentry documentation */
120 geanypg_read(outpipe[READ], ' ', 2049, readbuffer);
121 if (strncmp(readbuffer, "OK", 3))
122 {
123 g_warning(_("Unexpected output from pinentry."));
124 fclose(childin);
125 waitpid(childpid, &status, 0);
126 close(outpipe[READ]);
127 close(fd);
128 return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY, GPG_ERR_GENERAL);
129 }
130 geanypg_read_till(outpipe[READ], '\n'); /* read the rest of the first line after OK */
131 fprintf(childin, "SETTITLE GeanyPG %s\n", _("Passphrase entry"));
132 fflush(childin);
133 geanypg_read_till(outpipe[READ], '\n');
134
135 fprintf(childin, "SETPROMPT %s:\n", (uid_hint && *uid_hint ? "" : _("Passphrase")));
136 fflush(childin);
137 geanypg_read_till(outpipe[READ], '\n');
138
139 fprintf(childin, "SETDESC %s: %s\n",
140 (uid_hint && *uid_hint ? _("Enter passphrase for") : ""),
141 (uid_hint && *uid_hint ? geanypg_getname(uid_hint) : ""));
142 fflush(childin);
143 geanypg_read_till(outpipe[READ], '\n');
144
145 fprintf(childin, "GETPIN\n");
146 fflush(childin);
147
148 geanypg_read(outpipe[READ], ' ', 2049, readbuffer);
149 if (!strncmp(readbuffer, "D", 2))
150 {
151 while (1)
152 {
153 char val;
154 register ssize_t rv = read(outpipe[READ], &val, 1);
155 if (rv <= 0 || val == '\n')
156 {
157 while (!write(fd, "\n", 1));
158 break;
159 }
160 while (!write(fd, &val, 1));
161 }
162 }
163 else
164 {
165 unsigned long errval;
166 if (!strncmp(readbuffer, "ERR", 4))
167 {
168 geanypg_read(outpipe[READ], ' ', 2049, readbuffer);
169 sscanf(readbuffer, "%lu", &errval);
170 geanypg_read(outpipe[READ], '\n', 2049, readbuffer);
171 g_warning("%s %lu %s", _("pinentry gave error"), errval, readbuffer);
172 }
173 else
174 g_warning(_("Unexpected error from pinentry."));
175 fclose(childin);
176 waitpid(childpid, &status, 0);
177 close(outpipe[READ]);
178 close(fd);
179 return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY,
180 (!strncmp(readbuffer, "canceled", 9) ? GPG_ERR_CANCELED : GPG_ERR_GENERAL));
181 }
182
183
184 fclose(childin);
185 waitpid(childpid, &status, 0);
186 close(outpipe[READ]);
187 close(fd);
188 return GPG_ERR_NO_ERROR;
189 }
190
191 #else
192
geanypg_passphrase_cb(void * hook,const char * uid_hint,const char * passphrase_info,int prev_was_bad,int fd)193 gpgme_error_t geanypg_passphrase_cb(void *hook,
194 const char *uid_hint,
195 const char *passphrase_info,
196 int prev_was_bad ,
197 int fd)
198 {
199 dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Error, Passphrase input without using gpg-agent is not supported on Windows yet."));
200 return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY, GPG_ERR_CANCELED);
201 }
202 #endif
203
204