/*  conn_to_pgpd.c

    Source file for conn_to_pgpd  (connect to PGPdaemon).

    Copyright (C) 1994  Richard Gooch

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
    The postal address is:
      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
*/

/*  This programme intercepts messages sent by user mail agents to the
    sendmail daemon and checks to see if messages can be encrypted using the
    recipient's PGP public keys.


    Written by      Richard Gooch   5-JUN-1994

    Updated by      Richard Gooch   5-JUN-1994

    Updated by      Richard Gooch   16-JUN-1994: Added tests for existence of
  S_ISSOCK  .

    Last updated by Richard Gooch   17-JUN-1994: Added tests for existence of
  S_IRWXG  S_IRWXO  AF_UNIX  and  SOCK_STREAM  .


*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "pgpsendmail.h"


int connect_to_pgpdaemon (pgppath)
/*  This routine will connect to the PGPdaemon.
    The value of the PGPPATH environment variable must be pointed to by
    pgppath  .
    The routine returns a descriptor which is a connection to the PGPdaemon on
    success, else it returns -1.
*/
char *pgppath;
{
    int sock;
    struct sockaddr_un un_addr;
    struct stat statbuf;
    char socket_filename[STRING_LENGTH];
    ERRNO_TYPE errno;
    extern char *sys_errlist[];

    /*  Check socket  */
    (void) sprintf (socket_filename, "%s/.pgpd.socket", pgppath);
    if (stat (socket_filename, &statbuf) != 0)
    {
	(void) fprintf (stderr, "Error stat'ing: \"%s\"\t%s\n",
			socket_filename, sys_errlist[errno]);
	return (-1);
    }
    /*  The following contortion is an attempt to work around brain-damaged
	platforms like NEXTSTEP which don't have the  S_ISSOCK  macro.
	At the time of writing, I don't know if the other macros are defined
	on NEXTSTEP. One can hope (probably in vain).  */
#ifndef S_ISSOCK
#  if defined(S_IFMT) && defined(S_IFSOCK)
#    define S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)
#  else
    (void) fprintf (stderr, "Don't know how to check for sockets\n");
    return (-1);
#  endif
#endif
#ifdef S_ISSOCK
    if ( !S_ISSOCK (statbuf.st_mode) )
    {
	(void) fprintf (stderr, "File: \"%s\" is not a socket\n",
			socket_filename);
	return (-1);
    }
    if (getuid () != statbuf.st_uid)
    {
	(void) fprintf (stderr, "File: \"%s\" is not owned by you\n",
			socket_filename);
	return (-1);
    }
    /*  Yet another contortion for NEXTSTEP.  */
#  ifndef S_IRWXG
#    if defined(S_IRGRP) && defined(S_IWGRP) && defined(S_IXGRP)
#      define S_IRWXG (S_IRGRP|S_IWGRP|S_IXGRP)
#    endif
#  endif
#  ifndef S_IRWXO
#    if defined(S_IROTH) && defined(S_IWOTH) && defined(S_IXOTH)
#      define S_IRWXO (S_IROTH|S_IWOTH|S_IXOTH)
#    endif
#  endif
#  if !defined(S_IRWXG) || !defined(S_IRWXO)
    (void) fprintf (stderr, "Cannot determine file protections\n");
    return (-1);
#  else
    if ( (statbuf.st_mode & (S_IRWXG | S_IRWXO) ) != 0 )
    {
	(void) fprintf (stderr, "File: \"%s\" is accessible by others\n",
			socket_filename);
	return (-1);
    }
    /*  Create socket  */
    /*  I added the following test pre-emptively (expecting more trouble)  */
#    if !defined(AF_UNIX) || !defined(SOCK_STREAM)
    (void) fprintf (stderr, "Platform does not have Unix sockets!\n");
    return (-1);
#    else
    if ( ( sock = socket (AF_UNIX, SOCK_STREAM, 0) ) < 0 )
    {
	(void) fprintf (stderr, "Error creating socket\t%s\n",
			sys_errlist[errno]);
	return (-1);
    }
    /*  Set up addressing info  */
    un_addr.sun_family = AF_UNIX;
    (void) sprintf (un_addr.sun_path, "%s", socket_filename);
    /*  Connect to other end (PGPdaemon)  */
    if (connect (sock, (struct sockaddr *) &un_addr, (int) sizeof un_addr)
	!= 0)
    {
	/*  No connection made  */
	if ( (errno != ECONNREFUSED) && (errno != ENOENT) )
	{
	    (void) fprintf (stderr,
			    "Error connecting to Unix socket\t%s\n",
			    sys_errlist[errno]);
	    (void) close (sock);
	    return (-1);
	}
	if (close (sock) != 0)
	{
	    (void) fprintf (stderr,
			    "Error closing unix socket: %d\t%s\n",
			    sock, sys_errlist[errno]);
	}
	return (-1);
    }
    /*  Return the connection descriptor  */
    return (sock);
#    endif  /*  !defined(AF_UNIX) || !defined(SOCK_STREAM)  */
#  endif  /*  !defined(S_IRWXG) || !defined(S_IRWXO)  */
#endif  /*  S_ISSOCK  */
}   /*  End Function connect_to_pgpdaemon  */
