Пример #1
0
/*
 * pg_krb4_sendauth -- client routine to send authentication information to
 *					   the server
 *
 * This routine does not do mutual authentication, nor does it return enough
 * information to do encrypted connections.  But then, if we want to do
 * encrypted connections, we'll have to redesign the whole RPC mechanism
 * anyway.
 *
 * If the user is too lazy to feed us a hostname, we try to come up with
 * something other than "localhost" since the hostname is used as an
 * instance and instance names in v4 databases are usually actual hostnames
 * (canonicalized to omit all domain suffixes).
 */
static int
pg_krb4_sendauth(char *PQerrormsg, int sock,
				 struct sockaddr_in * laddr,
				 struct sockaddr_in * raddr,
				 const char *hostname)
{
	long		krbopts = 0;	/* one-way authentication */
	KTEXT_ST	clttkt;
	int			status;
	char		hostbuf[MAXHOSTNAMELEN];
	const char *realm = getenv("PGREALM");		/* NULL == current realm */

	if (!hostname || !(*hostname))
	{
		if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
			strcpy(hostbuf, "localhost");
		hostname = hostbuf;
	}

	pg_krb4_init();

	status = krb_sendauth(krbopts,
						  sock,
						  &clttkt,
						  PG_KRB_SRVNAM,
						  hostname,
						  realm,
						  (u_long) 0,
						  NULL,
						  NULL,
						  NULL,
						  laddr,
						  raddr,
						  PG_KRB4_VERSION);
	if (status != KSUCCESS)
	{
		snprintf(PQerrormsg, PQERRORMSG_LENGTH,
				 libpq_gettext("Kerberos 4 error: %s\n"),
				 krb_err_txt[status]);
		return STATUS_ERROR;
	}
	return STATUS_OK;
}
Пример #2
0
/*
 * Function: socket_connection
 *
 * Purpose: Opens the network connection with the mail host, without
 * 	doing any sort of I/O with it or anything.
 *
 * Arguments:
 * 	host	The host to which to connect.
 *	flags	Option flags.
 *
 * Return value: A file descriptor indicating the connection, or -1
 * 	indicating failure, in which case an error has been copied
 * 	into pop_error.
 */
static int
socket_connection (char *host, int flags)
{
  struct addrinfo *res, *it;
  struct addrinfo hints;
  int ret;
  struct servent *servent;
  struct sockaddr_in addr;
  char found_port = 0;
  const char *service;
  int sock;
  char *realhost;
#ifdef KERBEROS
#ifdef KERBEROS5
  krb5_error_code rem;
  krb5_context kcontext = 0;
  krb5_auth_context auth_context = 0;
  krb5_ccache ccdef;
  krb5_principal client, server;
  krb5_error *err_ret;
  register char *cp;
#else
  KTEXT ticket;
  MSG_DAT msg_data;
  CREDENTIALS cred;
  Key_schedule schedule;
  int rem;
#endif /* KERBEROS5 */
#endif /* KERBEROS */

  int try_count = 0;
  int connect_ok;

#ifdef WINDOWSNT
  {
    WSADATA winsockData;
    if (WSAStartup (0x101, &winsockData) == 0)
      have_winsock = 1;
  }
#endif

  memset (&addr, 0, sizeof (addr));
  addr.sin_family = AF_INET;

  /** "kpop" service is  never used: look for 20060515 to see why **/
#ifdef KERBEROS
  service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
#else
  service = POP_SERVICE;
#endif

#ifdef HESIOD
  if (! (flags & POP_NO_HESIOD))
    {
      servent = hes_getservbyname (service, "tcp");
      if (servent)
	{
	  addr.sin_port = servent->s_port;
	  found_port = 1;
	}
    }
#endif
  if (! found_port)
    {
      servent = getservbyname (service, "tcp");
      if (servent)
	{
	  addr.sin_port = servent->s_port;
	}
      else
	{
  /** "kpop" service is  never used: look for 20060515 to see why **/
#ifdef KERBEROS
	  addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
				POP_PORT : KPOP_PORT);
#else
	  addr.sin_port = htons (POP_PORT);
#endif
	}
    }

#define POP_SOCKET_ERROR "Could not create socket for POP connection: "

  sock = socket (PF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    {
      snprintf (pop_error, ERROR_MAX, "%s%s",
		POP_SOCKET_ERROR, strerror (errno));
      return (-1);

    }

  memset (&hints, 0, sizeof (hints));
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_CANONNAME;
  hints.ai_family = AF_INET;
  do
    {
      ret = getaddrinfo (host, service, &hints, &res);
      try_count++;
      if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
	{
	  strcpy (pop_error, "Could not determine POP server's address");
	  return (-1);
	}
    } while (ret != 0);

  for (it = res; it; it = it->ai_next)
    if (it->ai_addrlen == sizeof addr)
      {
	struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
	addr.sin_addr = in_a->sin_addr;
	if (! connect (sock, (struct sockaddr *) &addr, sizeof addr))
	  break;
      }
  connect_ok = it != NULL;
  if (connect_ok)
    {
      realhost = alloca (strlen (it->ai_canonname) + 1);
      strcpy (realhost, it->ai_canonname);
    }
  freeaddrinfo (res);

#define CONNECT_ERROR "Could not connect to POP server: "

  if (! connect_ok)
    {
      CLOSESOCKET (sock);
      snprintf (pop_error, ERROR_MAX, "%s%s", CONNECT_ERROR, strerror (errno));
      return (-1);

    }

#ifdef KERBEROS

#define KRB_ERROR "Kerberos error connecting to POP server: "
  if (! (flags & POP_NO_KERBEROS))
    {
#ifdef KERBEROS5
      rem = krb5_init_context (&kcontext);
      if (rem)
	{
	krb5error:
	  if (auth_context)
	    krb5_auth_con_free (kcontext, auth_context);
	  if (kcontext)
	    krb5_free_context (kcontext);
	  snprintf (pop_error, ERROR_MAX, "%s%s",
		    KRB_ERROR, error_message (rem));
	  CLOSESOCKET (sock);
	  return (-1);
	}

      rem = krb5_auth_con_init (kcontext, &auth_context);
      if (rem)
	goto krb5error;

      rem = krb5_cc_default (kcontext, &ccdef);
      if (rem)
	goto krb5error;

      rem = krb5_cc_get_principal (kcontext, ccdef, &client);
      if (rem)
	goto krb5error;

      for (cp = realhost; *cp; cp++)
	*cp = c_tolower (*cp);

      rem = krb5_sname_to_principal (kcontext, realhost,
				     POP_SERVICE, FALSE, &server);
      if (rem)
	goto krb5error;

      rem = krb5_sendauth (kcontext, &auth_context,
			   (krb5_pointer) &sock, (char *) "KPOPV1.0",
			   client, server,
			  AP_OPTS_MUTUAL_REQUIRED,
			  0,	/* no checksum */
			  0,	/* no creds, use ccache instead */
			  ccdef,
			  &err_ret,
			  0,	/* don't need subsession key */
			  0);	/* don't need reply */
      krb5_free_principal (kcontext, server);
      if (rem)
	{
	  int pop_error_len = snprintf (pop_error, ERROR_MAX, "%s%s",
					KRB_ERROR, error_message (rem));
#if defined HAVE_KRB5_ERROR_TEXT
	  if (err_ret && err_ret->text.length)
	    {
	      int errlen = err_ret->text.length;
	      snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
			" [server says '%.*s']", errlen, err_ret->text.data);
	    }
#elif defined HAVE_KRB5_ERROR_E_TEXT
	  if (err_ret && err_ret->e_text && **err_ret->e_text)
	    snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
		      " [server says '%s']", *err_ret->e_text);
#endif
	  if (err_ret)
	    krb5_free_error (kcontext, err_ret);
	  krb5_auth_con_free (kcontext, auth_context);
	  krb5_free_context (kcontext);

	  CLOSESOCKET (sock);
	  return (-1);
	}
#else  /* ! KERBEROS5 */
      ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
      rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
			  (char *) krb_realmofhost (realhost),
			  (unsigned long) 0, &msg_data, &cred, schedule,
			  (struct sockaddr_in *) 0,
			  (struct sockaddr_in *) 0,
			  "KPOPV0.1");
      free ((char *) ticket);
      if (rem != KSUCCESS)
	{
	  snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, krb_err_txt[rem]);
	  CLOSESOCKET (sock);
	  return (-1);
	}
#endif /* KERBEROS5 */
    }
#endif /* KERBEROS */

  return (sock);
} /* socket_connection */
Пример #3
0
/* This function has not been changed to deal with NO_SOCKET_TO_FD
   (i.e., systems on which sockets cannot be converted to file
   descriptors).  The first person to try building a kerberos client
   on such a system (OS/2, Windows 95, and maybe others) will have to
   take care of this.  */
void
start_kerberos4_server (cvsroot_t *root, struct buffer **to_server_p,
                        struct buffer **from_server_p)
{
    int s;
    int port;
    struct hostent *hp;
    struct sockaddr_in sin;
    char *hname;

    s = socket (AF_INET, SOCK_STREAM, 0);
    if (s < 0)
	error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));

    port = get_cvs_port_number (root);

    hp = init_sockaddr (&sin, root->hostname, port);

    hname = xstrdup (hp->h_name);
  
    TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d",
	   root->hostname,
	   inet_ntoa (sin.sin_addr),
	   port);

    if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
	error (1, 0, "connect to %s(%s):%d failed: %s",
	       root->hostname,
	       inet_ntoa (sin.sin_addr),
	       port, SOCK_STRERROR (SOCK_ERRNO));

    {
	const char *realm;
	struct sockaddr_in laddr;
	int laddrlen;
	KTEXT_ST ticket;
	MSG_DAT msg_data;
	CREDENTIALS cred;
	int status;

	realm = krb_realmofhost (hname);

	laddrlen = sizeof (laddr);
	if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0)
	    error (1, 0, "getsockname failed: %s", SOCK_STRERROR (SOCK_ERRNO));

	/* We don't care about the checksum, and pass it as zero.  */
	status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
			       hname, realm, (unsigned long) 0, &msg_data,
			       &cred, sched, &laddr, &sin, "KCVSV1.0");
	if (status != KSUCCESS)
	    error (1, 0, "kerberos authentication failed: %s",
		   krb_get_err_text (status));
	memcpy (kblock, cred.session, sizeof (C_Block));
    }

    close_on_exec (s);

    free (hname);

    /* Give caller the values it wants. */
    make_bufs_from_fds (s, s, 0, root, to_server_p, from_server_p, 1);
}
Пример #4
0
/*
 * The rcmd call itself.
 *      ahost (IN)      remote hostname
 *	addr (IN)	IP address
 *      locuser (IN)    local username
 *      remuser (IN)    remote username
 *      cmd (IN)        command to execute
 *       rank (IN)	MPI rank
 *      fd2p (IN/OUT)   if non-NULL, open stderr backchannel on this fd
 *      s (RETURN)      socket for stdout/sdin or -1 on failure
 */
static int
k4cmd(char *ahost, char *addr, char *locuser, char *remuser, char *cmd,
      int rank, int *fd2p, void **arg)
{
    KTEXT_ST ticket;            /* kerberos IV context */
    CREDENTIALS cred;
    Key_schedule schedule;
    MSG_DAT msg_data;
    struct sockaddr_in faddr;
    struct sockaddr_in laddr;

    int s, pid;
    sigset_t oldset, blockme;
    struct sockaddr_in sin, from;
    char c;
    int lport = IPPORT_RESERVED - 1;
    unsigned long krb_options = 0L;
    static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
    int status;
    int rc, rv;
    struct xpollfd xpfds[2];

    pid = getpid();

    sigemptyset(&blockme);
    sigaddset(&blockme, SIGURG);
    pthread_sigmask(SIG_BLOCK, &blockme, &oldset);
    for (;;) {
        s = privsep_rresvport(&lport);
        if (s < 0) {
            if (errno == EAGAIN)
                err("%p: %S: socket: All ports in use\n", ahost);
            else
                err("%p: %S: k4cmd: socket: %m\n", ahost);
            pthread_sigmask(SIG_SETMASK, &oldset, NULL);
            return (-1);
        }
        fcntl(s, F_SETOWN, pid);
        sin.sin_family = AF_INET;
        memcpy((caddr_t) & sin.sin_addr, addr, IP_ADDR_LEN);
        sin.sin_port = htons(KCMD_PORT);

        rv = connect(s, (struct sockaddr *) &sin, sizeof(sin));

        if (rv >= 0)
            break;
        (void) close(s);
        if (errno == EADDRINUSE) {
            lport--;
            continue;
        }
        if (errno == EINTR)
            err("%p: %S: connect timed out\n", ahost);
        else
            err("%p: %S: %m\n", ahost);
        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
        return (-1);
    }
    if (fd2p == 0) {
        write(s, "", 1);
        lport = 0;
    } else {
        char num[8];
        int s2, s3;
        socklen_t len = sizeof(from);

        s2 = privsep_rresvport(&lport);
        if (s2 < 0) {
            goto bad;
        }
        listen(s2, 1);
        (void) snprintf(num, sizeof(num), "%d", lport);
        if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
            err("%p: %S: write: setting up stderr: %m\n", ahost);
            (void) close(s2);
            goto bad;
        }
        errno = 0;
        xpfds[0].fd = s;
        xpfds[1].fd = s2;
        xpfds[0].events = xpfds[1].events = XPOLLREAD;
        if (((rv = xpoll(xpfds, 2, -1)) < 0) || rv != 1 || (xpfds[0].revents > 0)) {
          if (errno != 0)
            err("%p: %S: k4cmd: xpoll (setting up stderr): %m\n", ahost);
          else
            err("%p: %S: k4cmd: xpoll: protocol failure in circuit setup\n", ahost);
          (void) close(s2);
          goto bad;
        }
        s3 = accept(s2, (struct sockaddr *) &from, &len);
        (void) close(s2);
        if (s3 < 0) {
            err("%p: %S: accept: %m\n", ahost);
            lport = 0;
            goto bad;
        }
        *fd2p = s3;
        from.sin_port = ntohs((u_short) from.sin_port);
    }

    /*
     * Kerberos-authenticated service.  Don't have to send locuser, since
     * its already in the ticket, and we'll extract it on the other side. 
     */
    /*krb_options |= KOPT_DONT_CANON; */
    pthread_mutex_lock(&mylock);
    status = krb_sendauth(krb_options, s, &ticket, "rcmd", ahost,
                          NULL, (unsigned long) pid, &msg_data,
                          &cred, schedule, &laddr, &faddr, "KCMDV0.1");

    if (status != KSUCCESS) {
        /*
         * this part involves some very intimate knowledge of a
         * particular sendauth implementation to pry out the old
         * bits. This only catches the case of total failure -- but
         * that's the one where we get useful data from the remote
         * end. If we even get an authenticator back, then the
         * problem gets diagnosed locally anyhow. 
         */
        extern KRB_INT32 __krb_sendauth_hidden_tkt_len;
        char *old_data = (char *) &__krb_sendauth_hidden_tkt_len;
        char tmpbuf[LINEBUFSIZE];
        char *p = tmpbuf;

        if ((status == KFAILURE) && (*old_data == 1)) {
            strncpy(tmpbuf, old_data + 1, 3);
            tmpbuf[3] = '\0';
            err("%p: %S: %s", ahost, tmpbuf);
            *old_data = (-1);
        }
        if ((status == KFAILURE) && (*old_data == (char) -1)) {
            while (read(s, &c, 1) == 1) {
                /*(void) write(2, &c, 1); */
                *p++ = c;
                if (c == '\n')
                    break;
            }
            *p++ = '\0';
            err("%p: %S: %s", ahost, tmpbuf);
            status = -1;
        }
        switch (status) {
        case KDC_PR_UNKNOWN:
            err("%p: %S: not registered for kerberos\n", ahost);
            break;
        case NO_TKT_FIL:
            err("%p: %S: no tickets file found\n", ahost);
            break;
        default:
            err("%p: %S: k4cmd failed: %s\n", ahost,
                (status == -1) ? "k4cmd protocol failure" :
                krb_get_err_text(status));
        }
        pthread_mutex_unlock(&mylock);
        goto bad2;
    }
    pthread_mutex_unlock(&mylock);
    (void) write(s, remuser, strlen(remuser) + 1);
    (void) write(s, cmd, strlen(cmd) + 1);

    if ((rc = read(s, &c, 1)) != 1) {
        if (rc == -1) {
            err("%p: %S: read: %m\n", ahost);
        } else {
            err("%p: %S: k4cmd: bad connection with remote host\n", ahost);
        }
        goto bad2;
    }
    if (c != 0) {
        /* retrieve error string from remote server */
        char tmpbuf[LINEBUFSIZE];
        char *p = tmpbuf;

        while (read(s, &c, 1) == 1) {
            *p++ = c;
            if (c == '\n')
                break;
        }
        if (c != '\n')
            *p++ = '\n';
        *p++ = '\0';
        err("%S: %s", ahost, tmpbuf);
        goto bad2;
    }
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (s);
  bad2:
    if (lport)
        (void) close(*fd2p);
  bad:
    (void) close(s);
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    return (-1);
}