2 ** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
3 ** distribution information.
6 /* Based on code by Christian Loitsch <courier-imap@abc.fgecko.com> */
15 #include <sys/types.h>
16 /* used to avoid zombies */
20 #include <sys/select.h>
23 #include "authcustom.h"
24 #include "courierauthdebug.h"
26 #include "courierauthdebug.h"
28 #include "authpipelib.h"
29 #include "authpiperc.h"
31 static int lastIn
= -1;
32 static int lastOut
= -1;
33 static pid_t childPID
= -1;
35 static void eliminatePipe(pid_t child
);
37 static void execChild(int to
[], int from
[])
39 DPRINTF("executing %s", PIPE_PROGRAM
);
41 close(STDIN_FILENO
); dup2(to
[0], STDIN_FILENO
);
42 close(STDOUT_FILENO
); dup2(from
[1], STDOUT_FILENO
);
43 close(to
[0]); close(to
[1]); close(from
[0]); close(from
[1]);
45 execl(PIPE_PROGRAM
, PIPE_PROGRAM
, NULL
);
47 DPRINTF("pipe: failed to execute %s: %s",PIPE_PROGRAM
, strerror(errno
));
53 DPRINTF("closing pipe");
54 if (lastIn
>= 0) { close(lastIn
); lastIn
= -1; }
55 if (lastOut
>= 0) { close (lastOut
); lastOut
= -1; }
56 if (childPID
> 1) { eliminatePipe(childPID
); childPID
= -1; }
59 static int forkPipe(int *dataIn
, int *dataOut
, pid_t
*child
)
63 /* let's create 2 pipes */
65 DPRINTF("pipe: failed to create pipe: %s", strerror(errno
));
70 DPRINTF("pipe: failed to create pipe: %s", strerror(errno
));
71 close(to
[0]); close(to
[1]);
75 DPRINTF("attempting to fork");
78 DPRINTF("pipe: failed to fork: %s", strerror(errno
));
79 close(to
[0]); close(to
[1]); close(from
[0]); close(from
[1]);
84 if(*child
== 0) execChild(to
, from
);
87 DPRINTF("Pipe auth. started Pipe-program (pid %d)", *child
);
89 close(to
[0]); close(from
[1]);
90 *dataIn
= from
[0]; *dataOut
= to
[1];
94 /* kills and waits for child
95 * in a quite inefficient way, but this shouldn't happen very often */
96 static void eliminatePipe(pid_t child
)
100 /* let's first look, if child is already terminated */
101 DPRINTF("trying to wait for child (WNOHANG) (pid %d)", child
);
102 if (waitpid(child
, NULL
, WNOHANG
) > 0) return;
104 DPRINTF("sleep 2 seconds and try again to wait for pid %d", child
);
105 /* let's give the pipe-program a few seconds to terminate */
106 sleep(2); /* don't care if interrupted earlier */
107 if (waitpid(child
, NULL
, WNOHANG
) > 0) return;
110 DPRINTF("killing (SIGTERM) child pid %d", child
);
111 kill(child
, SIGTERM
);
113 /* give it a few seconds */
114 for (seconds
= 10; seconds
> 0; sleep(1), seconds
--)
115 if (waitpid(child
, NULL
, WNOHANG
) > 0) return;
117 /* ok, let's KILL it */
118 DPRINTF("killing (SIGKILL) child pid %d", child
);
119 if (kill(child
, SIGKILL
) == 0)
121 /* and wait, unless we have a kernel bug, it MUST terminate */
122 DPRINTF("waitpiding for child pid (blocking!) %d)", child
);
123 waitpid(child
, NULL
, 0);
128 DPRINTF("error when sending sigkill to %d", child
);
129 if (errno
!= ESRCH
) return;
130 /* strange, we can not kill our own child with SIGKILL*/
132 /* errno indicates process does not exist, maybe it's dead
133 * by now, let's try 1 final time, else, ignore it */
134 DPRINTF("maybe because already dead (pid: %d)", child
);
135 waitpid(child
, NULL
, WNOHANG
);
139 int getPipe(int *dataIn
, int *dataOut
)
145 /* Simple test if the child is still usable: do a read
146 ** poll on dataIn. If the child has closed the pipe,
147 ** or there is spurious data, the fd will be ready. */
151 FD_SET(lastIn
, &fdr
);
154 rv
= select(lastIn
+1, &fdr
, 0, 0, &tv
);
157 DPRINTF("reusing pipe, with in: %d out: %d", lastIn
, lastOut
);
163 perror("authpipe: getPipe: select");
166 DPRINTF("child died or sent spurious data (pid: %d)", childPID
);
170 /* ok pipe was not usable; either this is the first call, or
171 * the pipe broke the connection.
172 * We have to clean up and start a new one */
175 DPRINTF("forking new one");
176 rv
= forkPipe(&lastIn
, &lastOut
, &childPID
);
179 DPRINTF("couldn't fork new pipe");
186 DPRINTF("new pipe has in: %d, out: %d", lastIn
, lastOut
);