Line data Source code
1 : /* system.c - System support functions.
2 : Copyright (C) 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 2.1 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 :
21 : #ifdef HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <stdlib.h>
26 : #include <errno.h>
27 : #ifdef HAVE_SYS_TYPES_H
28 : /* Solaris 8 needs sys/types.h before time.h. */
29 : # include <sys/types.h>
30 : #endif
31 : #include <time.h>
32 : #ifdef HAVE_FCNTL_H
33 : #include <fcntl.h>
34 : #endif
35 :
36 : #include "assuan-defs.h"
37 : #include "debug.h"
38 :
39 : #ifdef _POSIX_OPEN_MAX
40 : #define MAX_OPEN_FDS _POSIX_OPEN_MAX
41 : #else
42 : #define MAX_OPEN_FDS 20
43 : #endif
44 :
45 : #define DEBUG_SYSIO 0
46 :
47 :
48 :
49 :
50 : /* Manage memory specific to a context. */
51 :
52 : void *
53 7 : _assuan_malloc (assuan_context_t ctx, size_t cnt)
54 : {
55 7 : return ctx->malloc_hooks.malloc (cnt);
56 : }
57 :
58 : void *
59 0 : _assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt)
60 : {
61 0 : return ctx->malloc_hooks.realloc (ptr, cnt);
62 : }
63 :
64 : void *
65 2 : _assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize)
66 : {
67 : void *ptr;
68 : size_t nbytes;
69 :
70 2 : nbytes = cnt * elsize;
71 :
72 : /* Check for overflow. */
73 2 : if (elsize && nbytes / elsize != cnt)
74 : {
75 0 : gpg_err_set_errno (ENOMEM);
76 0 : return NULL;
77 : }
78 :
79 2 : ptr = ctx->malloc_hooks.malloc (nbytes);
80 2 : if (ptr)
81 2 : memset (ptr, 0, nbytes);
82 2 : return ptr;
83 : }
84 :
85 : void
86 11 : _assuan_free (assuan_context_t ctx, void *ptr)
87 : {
88 11 : if (ptr)
89 7 : ctx->malloc_hooks.free (ptr);
90 11 : }
91 :
92 :
93 : /* Release the memory at PTR using the allocation handler of the
94 : context CTX. This is a convenience function. */
95 : void
96 0 : assuan_free (assuan_context_t ctx, void *ptr)
97 : {
98 0 : _assuan_free (ctx, ptr);
99 0 : }
100 :
101 :
102 :
103 : /* Copy the system hooks struct, paying attention to version
104 : differences. SRC is usually from the user, DST MUST be from the
105 : library. */
106 : void
107 0 : _assuan_system_hooks_copy (assuan_system_hooks_t dst,
108 : assuan_system_hooks_t src)
109 :
110 : {
111 : /* Reset the defaults. */
112 0 : if (dst != &_assuan_system_hooks)
113 0 : memcpy (dst, &_assuan_system_hooks, sizeof (*dst));
114 :
115 0 : dst->version = ASSUAN_SYSTEM_HOOKS_VERSION;
116 0 : if (src->version >= 1)
117 : {
118 0 : dst->usleep = src->usleep;
119 0 : dst->pipe = src->pipe;
120 0 : dst->close = src->close;
121 0 : dst->read = src->read;
122 0 : dst->write = src->write;
123 0 : dst->sendmsg = src->sendmsg;
124 0 : dst->recvmsg = src->recvmsg;
125 0 : dst->spawn = src->spawn;
126 0 : dst->waitpid = src->waitpid;
127 0 : dst->socketpair = src->socketpair;
128 : }
129 0 : if (src->version >= 2)
130 : {
131 0 : dst->socket = src->socket;
132 0 : dst->connect = src->connect;
133 : }
134 0 : if (src->version > 2)
135 : /* FIXME. Application uses newer version of the library. What to
136 : do? */
137 : ;
138 0 : }
139 :
140 :
141 :
142 : /* Sleep for the given number of microseconds. */
143 : void
144 0 : _assuan_usleep (assuan_context_t ctx, unsigned int usec)
145 : {
146 0 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx,
147 : "usec=%u", usec);
148 :
149 0 : (ctx->system.usleep) (ctx, usec);
150 0 : }
151 :
152 :
153 :
154 : /* Create a pipe with one inheritable end. */
155 : int
156 2 : _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
157 : {
158 : int err;
159 2 : TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "_assuan_pipe", ctx,
160 : "inherit_idx=%i (Assuan uses it for %s)",
161 : inherit_idx, inherit_idx ? "reading" : "writing");
162 :
163 2 : err = (ctx->system.pipe) (ctx, fd, inherit_idx);
164 2 : if (err)
165 0 : return TRACE_SYSRES (err);
166 :
167 2 : return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]);
168 : }
169 :
170 :
171 :
172 : /* Close the given file descriptor, created with _assuan_pipe or one
173 : of the socket functions. */
174 : int
175 9 : _assuan_close (assuan_context_t ctx, assuan_fd_t fd)
176 : {
177 9 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
178 : "fd=0x%x", fd);
179 :
180 9 : return (ctx->system.close) (ctx, fd);
181 : }
182 :
183 :
184 : /* Same as assuan_close but used for the inheritable end of a
185 : pipe. */
186 : int
187 2 : _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd)
188 : {
189 2 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx,
190 : "fd=0x%x", fd);
191 :
192 : #ifdef HAVE_W32CE_SYSTEM
193 : return 0; /* Nothing to do because it is a rendezvous id. */
194 : #else
195 2 : return (ctx->system.close) (ctx, fd);
196 : #endif
197 : }
198 :
199 :
200 :
201 : ssize_t
202 5 : _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
203 : {
204 : #if DEBUG_SYSIO
205 : ssize_t res;
206 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_read", ctx,
207 : "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
208 : res = (ctx->system.read) (ctx, fd, buffer, size);
209 : return TRACE_SYSRES (res);
210 : #else
211 5 : return (ctx->system.read) (ctx, fd, buffer, size);
212 : #endif
213 : }
214 :
215 :
216 :
217 : ssize_t
218 12 : _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
219 : size_t size)
220 : {
221 : #if DEBUG_SYSIO
222 : ssize_t res;
223 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_write", ctx,
224 : "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
225 : res = (ctx->system.write) (ctx, fd, buffer, size);
226 : return TRACE_SYSRES (res);
227 : #else
228 12 : return (ctx->system.write) (ctx, fd, buffer, size);
229 : #endif
230 : }
231 :
232 :
233 :
234 : int
235 32 : _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
236 : int flags)
237 : {
238 : #if DEBUG_SYSIO
239 : ssize_t res;
240 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx,
241 : "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
242 : res = (ctx->system.recvmsg) (ctx, fd, msg, flags);
243 : if (res > 0)
244 : {
245 : struct cmsghdr *cmptr;
246 :
247 : TRACE_LOG2 ("msg->msg_iov[0] = { iov_base=%p, iov_len=%i }",
248 : msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
249 : TRACE_LOGBUF (msg->msg_iov[0].iov_base, res);
250 :
251 : cmptr = CMSG_FIRSTHDR (msg);
252 : if (cmptr)
253 : {
254 : void *data = CMSG_DATA (cmptr);
255 : TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
256 : "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
257 : cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
258 : cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
259 : }
260 : }
261 : return TRACE_SYSRES (res);
262 : #else
263 32 : return (ctx->system.recvmsg) (ctx, fd, msg, flags);
264 : #endif
265 : }
266 :
267 :
268 :
269 : int
270 59 : _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
271 : int flags)
272 : {
273 : #if DEBUG_SYSIO
274 : ssize_t res;
275 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_sendmsg", ctx,
276 : "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
277 : {
278 : struct cmsghdr *cmptr;
279 :
280 : TRACE_LOG2 ("msg->iov[0] = { iov_base=%p, iov_len=%i }",
281 : msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
282 : TRACE_LOGBUF (msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
283 :
284 : cmptr = CMSG_FIRSTHDR (msg);
285 : if (cmptr)
286 : {
287 : void *data = CMSG_DATA (cmptr);
288 : TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
289 : "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
290 : cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
291 : cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
292 : }
293 : }
294 : res = (ctx->system.sendmsg) (ctx, fd, msg, flags);
295 : return TRACE_SYSRES (res);
296 : #else
297 59 : return (ctx->system.sendmsg) (ctx, fd, msg, flags);
298 : #endif
299 : }
300 :
301 :
302 :
303 : /* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT
304 : as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated
305 : FD_CHILD_LIST as given (no remapping), which must be inheritable.
306 : On Unix, call ATFORK with ATFORKVALUE after fork and before exec. */
307 : int
308 2 : _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
309 : const char **argv,
310 : assuan_fd_t fd_in, assuan_fd_t fd_out,
311 : assuan_fd_t *fd_child_list,
312 : void (*atfork) (void *opaque, int reserved),
313 : void *atforkvalue, unsigned int flags)
314 : {
315 : int res;
316 : int i;
317 2 : TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx,
318 : "name=%s,fd_in=0x%x,fd_out=0x%x,"
319 : "atfork=%p,atforkvalue=%p,flags=%i",
320 : name ? name : "(null)", fd_in, fd_out,
321 : atfork, atforkvalue, flags);
322 :
323 2 : if (name)
324 : {
325 1 : i = 0;
326 4 : while (argv[i])
327 : {
328 2 : TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
329 2 : i++;
330 : }
331 : }
332 2 : i = 0;
333 2 : if (fd_child_list)
334 : {
335 7 : while (fd_child_list[i] != ASSUAN_INVALID_FD)
336 : {
337 3 : TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]);
338 3 : i++;
339 : }
340 : }
341 :
342 2 : res = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out,
343 : fd_child_list, atfork, atforkvalue, flags);
344 :
345 3 : if (name)
346 : {
347 1 : TRACE_LOG1 ("pid = 0x%x", *r_pid);
348 : }
349 : else
350 : {
351 2 : TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
352 : }
353 :
354 3 : return TRACE_SYSERR (res);
355 : }
356 :
357 :
358 :
359 : /* FIXME: Add some sort of waitpid function that covers GPGME and
360 : gpg-agent's use of assuan. */
361 : pid_t
362 3 : _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
363 : int *status, int options)
364 : {
365 : #if DEBUG_SYSIO
366 : ssize_t res;
367 : TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx,
368 : "pid=%i, action=%i, status=%p, options=%i",
369 : pid, action, status, options);
370 : res = (ctx->system.waitpid) (ctx, pid, action, status, options);
371 : return TRACE_SYSRES (res);
372 : #else
373 3 : return (ctx->system.waitpid) (ctx, pid, action, status, options);
374 : #endif
375 : }
376 :
377 :
378 :
379 : int
380 1 : _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
381 : int protocol, assuan_fd_t filedes[2])
382 : {
383 : int res;
384 1 : TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx,
385 : "namespace=%i,style=%i,protocol=%i,filedes=%p",
386 : namespace, style, protocol, filedes);
387 :
388 1 : res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes);
389 1 : if (res == 0)
390 1 : TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
391 :
392 1 : return TRACE_SYSERR (res);
393 : }
394 :
395 :
396 :
397 : int
398 0 : _assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
399 : {
400 : int res;
401 0 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx,
402 : "namespace=%i,style=%i,protocol=%i",
403 : namespace, style, protocol);
404 :
405 0 : res = (ctx->system.socket) (ctx, namespace, style, protocol);
406 0 : return TRACE_SYSRES (res);
407 : }
408 :
409 :
410 : int
411 0 : _assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr, socklen_t length)
412 : {
413 : int res;
414 0 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_connect", ctx,
415 : "socket=%i,addr=%p,length=%i", sock, addr, length);
416 :
417 0 : res = (ctx->system.connect) (ctx, sock, addr, length);
418 0 : return TRACE_SYSRES (res);
419 : }
420 :
|