agent: Avoid appending a '\0' byte to the response of READKEY
[gnupg.git] / common / t-exectool.c
1 /* t-exectool.c - Module test for exectool.c
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <unistd.h>
26
27 #include "util.h"
28 #include "exectool.h"
29
30 static int verbose;
31
32 #define fail(msg, err)                                           \
33   do { fprintf (stderr, "%s:%d: %s failed: %s\n",                \
34                 __FILE__,__LINE__, (msg), gpg_strerror (err));   \
35     exit (1);                                                    \
36   } while(0)
37
38 static void
39 test_executing_true (void)
40 {
41   gpg_error_t err;
42   const char *pgmname     = "/bin/true";
43   const char *alt_pgmname = "/usr/bin/true";
44   const char *argv[]     = { NULL, NULL };
45   char *result;
46   size_t len;
47
48   if (access (pgmname, X_OK))
49     {
50       if (access (alt_pgmname, X_OK))
51         {
52           fprintf (stderr, "skipping test: %s not executable: %s\n",
53                    pgmname, strerror (errno));
54           return;
55         }
56       pgmname = alt_pgmname;
57     }
58
59   if (verbose)
60     fprintf (stderr, "Executing %s...\n", pgmname);
61
62   err = gnupg_exec_tool (pgmname, argv, "", &result, &len);
63   if (err)
64     fail ("gnupg_exec_tool", err);
65
66   assert (result);
67   assert (len == 0);
68   free (result);
69 }
70
71 static void
72 test_executing_false (void)
73 {
74   gpg_error_t err;
75   const char *pgmname     = "/bin/false";
76   const char *alt_pgmname = "/usr/bin/false";
77   const char *argv[]     = { NULL, NULL };
78   char *result;
79   size_t len;
80
81   if (access (pgmname, X_OK))
82     {
83       if (access (alt_pgmname, X_OK))
84         {
85           fprintf (stderr, "skipping test: %s not executable: %s\n",
86                    pgmname, strerror (errno));
87           return;
88         }
89       pgmname = alt_pgmname;
90     }
91
92   if (verbose)
93     fprintf (stderr, "Executing %s...\n", pgmname);
94
95   err = gnupg_exec_tool (pgmname, argv, "", &result, &len);
96   assert (err == GPG_ERR_GENERAL);
97 }
98
99
100 static void
101 test_executing_cat (const char *vector)
102 {
103   gpg_error_t err;
104   const char *argv[] = { "/bin/cat", NULL };
105   char *result;
106   size_t len;
107
108   if (access (argv[0], X_OK))
109     {
110       fprintf (stderr, "skipping test: %s not executable: %s\n",
111                argv[0], strerror (errno));
112       return;
113     }
114
115   if (verbose)
116     fprintf (stderr, "Executing %s...\n", argv[0]);
117
118   err = gnupg_exec_tool (argv[0], &argv[1], vector, &result, &len);
119   if (err)
120     fail ("gnupg_exec_tool", err);
121
122   assert (result);
123
124   /* gnupg_exec_tool returns the correct length... */
125   assert (len == strlen (vector));
126   /* ... but 0-terminates data for ease of use.  */
127   assert (result[len] == 0);
128
129   assert (strcmp (result, vector) == 0);
130   free (result);
131 }
132
133
134 static void
135 test_catting_cat (void)
136 {
137   gpg_error_t err;
138   const char *argv[] = { "/bin/cat", "/bin/cat", NULL };
139   char *result;
140   size_t len;
141   estream_t in;
142   char *reference, *p;
143   size_t reference_len;
144
145   if (access (argv[0], X_OK))
146     {
147       fprintf (stderr, "skipping test: %s not executable: %s\n",
148                argv[0], strerror (errno));
149       return;
150     }
151
152   in = es_fopen (argv[1], "r");
153   if (in == NULL)
154     {
155       fprintf (stderr, "skipping test: could not open %s: %s\n",
156                argv[1], strerror (errno));
157       return;
158     }
159
160   err = es_fseek (in, 0L, SEEK_END);
161   if (err)
162     {
163       fprintf (stderr, "skipping test: could not seek in %s: %s\n",
164                argv[1], gpg_strerror (err));
165       return;
166     }
167
168   reference_len = es_ftell (in);
169   err = es_fseek (in, 0L, SEEK_SET);
170   assert (!err || !"rewinding failed");
171
172   reference = malloc (reference_len);
173   assert (reference || !"allocating reference buffer failed");
174
175   for (p = reference; p - reference < reference_len; )
176     {
177       size_t bytes_read, left;
178       left = reference_len - (p - reference);
179       if (left > 4096)
180         left = 4096;
181       err = es_read (in, p, left, &bytes_read);
182       if (err)
183         {
184           fprintf (stderr, "error reading %s: %s",
185                    argv[1], gpg_strerror (err));
186           exit (1);
187         }
188
189       p += bytes_read;
190     }
191   es_fclose (in);
192
193   if (verbose)
194     fprintf (stderr, "Executing %s %s...\n", argv[0], argv[1]);
195
196   err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
197   if (err)
198     fail ("gnupg_exec_tool", err);
199
200   assert (result);
201
202   /* gnupg_exec_tool returns the correct length... */
203   assert (len == reference_len);
204   assert (memcmp (result, reference, reference_len) == 0);
205   free (reference);
206   free (result);
207 }
208
209
210 int
211 main (int argc, char **argv)
212 {
213   int i;
214   char binjunk[256];
215
216   if (argc)
217     { argc--; argv++; }
218   if (argc && !strcmp (argv[0], "--verbose"))
219     {
220       verbose = 1;
221       argc--; argv++;
222     }
223
224   test_executing_true ();
225   test_executing_false ();
226   test_executing_cat ("Talking to myself here...");
227
228   for (i = 0; i < 255 /* one less */; i++)
229     binjunk[i] = i + 1; /* avoid 0 */
230   binjunk[255] = 0;
231
232   test_executing_cat (binjunk);
233   test_catting_cat ();
234
235   return 0;
236 }