/*
**  PipeQi -- Connect to the Qi server via a pipe connection
**
**      Parameters:
**              LocalQi - pathname to the qi program
**              To - pointer to stream descriptor
**              From - pointer to stream descriptor
**
**      Returns:
**               0 if successful
**              -1 if any error
**
**      Side Effects:
**              Initializes global QiFields by calling GetFields()
**              Reports error via syslog
**
**      History:
**              Code based on OpenQi.c and qtacacsd's main program.
**              Allan Tuchman <[email protected]>
*/

#include <qiapi.h>
#include <syslog.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>


/* vfork is available under AIX (and others?), but only with -lbsd */
#if (defined(_AIX)) && !defined(vfork)
# define        vfork           fork
#endif /* AIX && !vfork */

#define FILE_NULL       ((FILE *) NULL)
#define CPNULL          ((char *) NULL)


int
PipeQi (LocalQi, To, From)
char    *LocalQi;
FILE    **To, **From;
{
   int Pid;            /* value from fork() */
   int P1[2], P2[2];   /* Parent/child pipes for Qi */

   if (QiDebug)
       fprintf(stderr, "establishing pipe connection to %s\r\n", LocalQi);

   if (pipe (P1) == -1) {
       if (QiDebug)
           fprintf(stderr, "PipeQi: Pipe(1): %s\r\n", sys_errlist[errno]);
       syslog(LOG_ERR, "PipeQi: pipe(1): %m");
       return(-1);
       }
   if (pipe (P2) == -1) {
       if (QiDebug)
           fprintf(stderr, "PipeQi: Pipe(2): %s\r\n", sys_errlist[errno]);
       syslog(LOG_ERR, "PipeQi: pipe(2): %m");
       return(-1);
       }
   if ((Pid = vfork()) == -1) {
       if (QiDebug)
           fprintf(stderr, "PipeQi: vfork(): %s\r\n", sys_errlist[errno]);
       syslog(LOG_ERR, "PipeQi: vfork(): %m");
       return(-1);
       }

   if (Pid == 0) {     /* child */
       /* Close and dup, close and dup */
       if (close (0) == -1) {
           if (QiDebug)
               fprintf(stderr, "PipeQi: close(0): %s\r\n", sys_errlist[errno]);
           syslog(LOG_ERR, "PipeQi: close(0): %m");
           return(-1);
       }
       if (fcntl (P1[0], F_DUPFD, 0) == -1) {
           if (QiDebug)
               fprintf(stderr, "PipeQi: fcntl(0): %s\r\n", sys_errlist[errno]);
           syslog(LOG_ERR, "PipeQi: fcntl(0): %m");
           return(-1);
       }
       if (close (1) == -1) {
           if (QiDebug)
               fprintf(stderr, "PipeQi: close(1): %s\r\n", sys_errlist[errno]);
           syslog(LOG_ERR, "PipeQi: close(1): %m");
           return(-1);
       }
       if (fcntl (P2[1], F_DUPFD, 1) == -1) {
           if (QiDebug)
               fprintf(stderr, "PipeQi: fcntl(1): %s\r\n", sys_errlist[errno]);
           syslog(LOG_ERR, "PipeQi: fcntl(1): %m");
           return(-1);
       }

       /* Close all open file descriptors */
       (void) close (P1[0]);
       (void) close (P1[1]);
       (void) close (P2[0]);
       (void) close (P2[1]);

       /* Fire up Qi */
       execl (LocalQi, "qi", "-q", CPNULL);
       if (QiDebug)
           fprintf(stderr, "%s %s \r\nexecl failed: %s\r\n",
                                       LocalQi, "qi -q", sys_errlist[errno]);
       syslog(LOG_ERR, "%s execl: %s", LocalQi, sys_errlist[errno]);
       return(-1);
   }

   /* Assign stream descriptors to pipe components */
   if ((*To = fdopen (P1[1], "w")) == FILE_NULL) {
       if (QiDebug)
           fprintf(stderr, "PipeQi: fdopen(To): %s\r\n", sys_errlist[errno]);
       syslog(LOG_ERR, "PipeQi: fdopen(To): %m");
       return(-1);
       }
   if ((*From = fdopen (P2[0], "r")) == FILE_NULL) {
       if (QiDebug)
           fprintf(stderr, "PipeQi: fdopen(From): %s\r\n",
                                                       sys_errlist[errno]);
       syslog(LOG_ERR, "PipeQi: fdopen(From): %m");
       return(-1);
       }


   /* Initialize QiFields global */
   if (QiFields == QIF_NULL &&
                       (QiFields = GetFields(*To, *From)) == QIF_NULL)
       return(-1);


   /* Connection ok */
   return (0);
}