Line data Source code
1 : /* fdpassing - Check the file descriptor passing.
2 : Copyright (C) 2006, 2009 Free Software Foundation, Inc.
3 :
4 : This file is part of Assuan.
5 :
6 : Assuan is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU Lesser General Public License as
8 : published by the Free Software Foundation; either version 3 of
9 : the License, or (at your option) any later version.
10 :
11 : Assuan is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public
17 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <stdio.h>
21 : #include <stdlib.h>
22 : #include <string.h>
23 : #include <assert.h>
24 : #include <sys/stat.h>
25 : #include <sys/socket.h>
26 : #include <unistd.h>
27 : #include <errno.h>
28 : #include <sys/wait.h> /* Used by main driver. */
29 :
30 : #include "../src/assuan.h"
31 : #include "common.h"
32 :
33 :
34 : /*
35 :
36 : S E R V E R
37 :
38 : */
39 :
40 : static gpg_error_t
41 6 : cmd_echo (assuan_context_t ctx, char *line)
42 : {
43 : int fd;
44 : int c;
45 : FILE *fp;
46 : int nbytes;
47 :
48 6 : log_info ("got ECHO command (%s)\n", line);
49 :
50 6 : fd = assuan_get_input_fd (ctx);
51 6 : if (fd == -1)
52 0 : return gpg_error (GPG_ERR_ASS_NO_INPUT);
53 6 : fp = fdopen (fd, "r");
54 6 : if (!fp)
55 : {
56 0 : log_error ("fdopen failed on input fd: %s\n", strerror (errno));
57 0 : return gpg_error (GPG_ERR_ASS_GENERAL);
58 : }
59 6 : nbytes = 0;
60 2700 : while ( (c=getc (fp)) != -1)
61 : {
62 2688 : putc (c, stdout);
63 2688 : nbytes++;
64 : }
65 6 : fflush (stdout);
66 6 : log_info ("done printing %d bytes to stdout\n", nbytes);
67 :
68 6 : fclose (fp);
69 6 : return 0;
70 : }
71 :
72 : static gpg_error_t
73 1 : register_commands (assuan_context_t ctx)
74 : {
75 : static struct
76 : {
77 : const char *name;
78 : gpg_error_t (*handler) (assuan_context_t, char *line);
79 : } table[] =
80 : {
81 : { "ECHO", cmd_echo },
82 : { "INPUT", NULL },
83 : { "OUTPUT", NULL },
84 : { NULL, NULL }
85 : };
86 : int i;
87 : gpg_error_t rc;
88 :
89 4 : for (i=0; table[i].name; i++)
90 : {
91 3 : rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
92 3 : if (rc)
93 0 : return rc;
94 : }
95 1 : return 0;
96 : }
97 :
98 :
99 : static void
100 1 : server (void)
101 : {
102 : int rc;
103 : assuan_context_t ctx;
104 :
105 1 : log_info ("server started\n");
106 :
107 1 : rc = assuan_new (&ctx);
108 1 : if (rc)
109 0 : log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));
110 :
111 1 : rc = assuan_init_pipe_server (ctx, NULL);
112 1 : if (rc)
113 0 : log_fatal ("assuan_init_pipe_server failed: %s\n", gpg_strerror (rc));
114 :
115 1 : rc = register_commands (ctx);
116 1 : if (rc)
117 0 : log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));
118 :
119 1 : assuan_set_log_stream (ctx, stderr);
120 :
121 : for (;;)
122 : {
123 3 : rc = assuan_accept (ctx);
124 2 : if (rc)
125 : {
126 1 : if (rc != -1)
127 0 : log_error ("assuan_accept failed: %s\n", gpg_strerror (rc));
128 1 : break;
129 : }
130 :
131 1 : log_info ("client connected. Client's pid is %ld\n",
132 1 : (long)assuan_get_pid (ctx));
133 :
134 1 : rc = assuan_process (ctx);
135 1 : if (rc)
136 0 : log_error ("assuan_process failed: %s\n", gpg_strerror (rc));
137 : }
138 :
139 1 : assuan_release (ctx);
140 1 : }
141 :
142 :
143 :
144 :
145 : /*
146 :
147 : C L I E N T
148 :
149 : */
150 :
151 :
152 : /* Client main. If true is returned, a disconnect has not been done. */
153 : static int
154 1 : client (assuan_context_t ctx, const char *fname)
155 : {
156 : int rc;
157 : FILE *fp;
158 : int i;
159 :
160 1 : log_info ("client started. Servers's pid is %ld\n",
161 1 : (long)assuan_get_pid (ctx));
162 :
163 7 : for (i=0; i < 6; i++)
164 : {
165 6 : fp = fopen (fname, "r");
166 6 : if (!fp)
167 : {
168 0 : log_error ("failed to open `%s': %s\n", fname,
169 0 : strerror (errno));
170 0 : return -1;
171 : }
172 :
173 6 : rc = assuan_sendfd (ctx, fileno (fp));
174 6 : if (rc)
175 : {
176 0 : log_error ("assuan_sendfd failed: %s\n", gpg_strerror (rc));
177 0 : return -1;
178 : }
179 6 : fclose (fp);
180 :
181 6 : rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL,
182 : NULL, NULL);
183 6 : if (rc)
184 : {
185 0 : log_error ("sending INPUT FD failed: %s\n", gpg_strerror (rc));
186 0 : return -1;
187 : }
188 :
189 6 : rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
190 6 : if (rc)
191 : {
192 0 : log_error ("sending ECHO failed: %s\n", gpg_strerror (rc));
193 0 : return -1;
194 : }
195 : }
196 :
197 : /* Give us some time to check with lsof that all descriptors are closed. */
198 : /* sleep (10); */
199 :
200 1 : assuan_release (ctx);
201 1 : return 0;
202 : }
203 :
204 :
205 :
206 :
207 : /*
208 :
209 : M A I N
210 :
211 : */
212 : int
213 2 : main (int argc, char **argv)
214 : {
215 2 : int last_argc = -1;
216 : assuan_context_t ctx;
217 : gpg_error_t err;
218 : int no_close_fds[2];
219 : const char *arglist[10];
220 2 : int is_server = 0;
221 2 : int with_exec = 0;
222 2 : char *fname = prepend_srcdir ("motd");
223 :
224 2 : if (argc)
225 : {
226 2 : log_set_prefix (*argv);
227 2 : argc--; argv++;
228 : }
229 4 : while (argc && last_argc != argc )
230 : {
231 0 : last_argc = argc;
232 0 : if (!strcmp (*argv, "--help"))
233 : {
234 0 : puts (
235 : "usage: ./fdpassing [options]\n"
236 : "\n"
237 : "Options:\n"
238 : " --verbose Show what is going on\n"
239 : " --with-exec Exec the child. Default is just a fork\n"
240 : );
241 0 : exit (0);
242 : }
243 0 : if (!strcmp (*argv, "--verbose"))
244 : {
245 0 : verbose = 1;
246 0 : argc--; argv++;
247 : }
248 0 : else if (!strcmp (*argv, "--debug"))
249 : {
250 0 : verbose = debug = 1;
251 0 : argc--; argv++;
252 : }
253 0 : else if (!strcmp (*argv, "--server"))
254 : {
255 0 : is_server = 1;
256 0 : argc--; argv++;
257 : }
258 0 : else if (!strcmp (*argv, "--with-exec"))
259 : {
260 0 : with_exec = 1;
261 0 : argc--; argv++;
262 : }
263 : }
264 :
265 :
266 2 : assuan_set_assuan_log_prefix (log_prefix);
267 :
268 2 : if (is_server)
269 : {
270 0 : server ();
271 0 : log_info ("server finished\n");
272 : }
273 : else
274 : {
275 : const char *loc;
276 :
277 2 : no_close_fds[0] = 2;
278 2 : no_close_fds[1] = -1;
279 2 : if (with_exec)
280 : {
281 0 : arglist[0] = "fdpassing";
282 0 : arglist[1] = "--server";
283 0 : arglist[2] = verbose? "--verbose":NULL;
284 0 : arglist[3] = NULL;
285 : }
286 :
287 2 : err = assuan_new (&ctx);
288 2 : if (err)
289 0 : log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
290 :
291 2 : err = assuan_pipe_connect (ctx, with_exec? "./fdpassing":NULL,
292 : with_exec ? arglist : &loc,
293 : no_close_fds, NULL, NULL, 1);
294 2 : if (err)
295 : {
296 0 : log_error ("assuan_pipe_connect failed: %s\n", gpg_strerror (err));
297 0 : assuan_release (ctx);
298 0 : errorcount++;
299 : }
300 2 : else if (!with_exec && loc[0] == 's')
301 : {
302 1 : server ();
303 1 : assuan_release (ctx);
304 1 : log_info ("server finished\n");
305 : }
306 : else
307 : {
308 1 : if (client (ctx, fname))
309 : {
310 0 : log_info ("waiting for server to terminate...\n");
311 0 : assuan_release (ctx);
312 : }
313 1 : log_info ("client finished\n");
314 : }
315 : }
316 :
317 2 : xfree (fname);
318 2 : return errorcount ? 1 : 0;
319 : }
320 :
|