*BSD News Article 85450


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.carno.net.au!harbinger.cc.monash.edu.au!munnari.OZ.AU!spool.mu.edu!howland.erols.net!worldnet.att.net!news.dra.com!xara.net!emerald.xara.net!news.thenet.net!wlbr!moe.2bsd.com!sms
From: sms@moe.2bsd.com (Steven M. Schultz)
Subject: libident ported to 2.11BSD (#359)
Organization: 2BSD, Simi Valley CA USA
Message-ID: <E2wH45.HGo@moe.2bsd.com>
Date: Tue, 24 Dec 1996 04:14:29 GMT
Lines: 1893
Xref: euryale.cc.adfa.oz.au comp.bugs.2bsd:719

Subject: libident ported to 2.11BSD (#359)
Index:	usr.lib/libident 2.11BSD

Description:
	The IDENT client library has been ported to 2.11BSD.

	Libident is a collection of routines which applications use to
	communicate with and parse the responses from identd processes.

Repeat-By:
	Since this is a new library being added this section doesn't apply.

Fix:
	'libident-0.20' required only a couple minor reorderings of #include
	statements in order to compile under 2.11BSD.  A Makefile in the 2.11BSD
	style was created.  No other changes were required.

	Cut where indicated, saving to a file (/tmp/359) and then:

		cd /tmp
		sh 359
		patch -p0 < 359.patch
		cd /usr/src/usr.lib/libident
		make
		make install
		make clean

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.IIPO.GTEGSC.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.

------------------------cut here-------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	/tmp/359.patch
#	/usr/src/usr.lib/libident
# This archive created: Wed Dec 18 20:30:29 1996
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f '/tmp/359.patch'
then
	echo shar: "will not over-write existing file '/tmp/359.patch'"
else
cat << \SHAR_EOF > '/tmp/359.patch'
*** /usr/src/usr.lib/Makefile.old	Sat Oct 26 12:14:15 1996
--- /usr/src/usr.lib/Makefile	Fri Dec 13 20:09:03 1996
***************
*** 3,9 ****
  # All rights reserved.  The Berkeley software License Agreement
  # specifies the terms and conditions for redistribution.
  #
! #	@(#)Makefile	5.12.2 (2.11BSD GTE) 1996/10/24
  #
  DESTDIR=
  CFLAGS=	-O
--- 3,9 ----
  # All rights reserved.  The Berkeley software License Agreement
  # specifies the terms and conditions for redistribution.
  #
! #	@(#)Makefile	5.12.3 (2.11BSD GTE) 1996/12/13
  #
  DESTDIR=
  CFLAGS=	-O
***************
*** 12,18 ****
  
  # Subdirectories whose routines are included in the making of the
  # master tags file (/usr/lib/tags); the Fortran libraries should
! # be on this list, but we don't control them....
  #
  TAGSDIR=libcurses libdbm libln libm libmp libpc libtermlib libutil libvmf \
  	liberrlst
--- 12,18 ----
  
  # Subdirectories whose routines are included in the making of the
  # master tags file (/usr/lib/tags); the Fortran libraries should
! # be on this list.
  #
  TAGSDIR=libcurses libdbm libln libm libmp libpc libtermlib libutil libvmf \
  	liberrlst
***************
*** 24,30 ****
  #
  SUBDIR=	lib2648 libF77 libI77 libU77 libcurses libdbm libln \
  	libom libmp libplot libtermlib liby libutil libvmf \
! 	liberrlst libstubs
  
  # Shell scripts that need only be installed and are never removed.
  #
--- 24,30 ----
  #
  SUBDIR=	lib2648 libF77 libI77 libU77 libcurses libdbm libln \
  	libom libmp libplot libtermlib liby libutil libvmf \
! 	liberrlst libident libstubs
  
  # Shell scripts that need only be installed and are never removed.
  #
*** /VERSION.old	Wed Dec 18 19:49:44 1996
--- /VERSION	Wed Dec 18 20:29:17 1996
***************
*** 1,4 ****
! Current Patch Level: 358
  
  2.11 BSD
  ============
--- 1,4 ----
! Current Patch Level: 359
  
  2.11 BSD
  ============
SHAR_EOF
chmod 755 '/tmp/359.patch'
fi
if test ! -d '/usr/src/usr.lib/libident'
then
	mkdir '/usr/src/usr.lib/libident'
fi
cd '/usr/src/usr.lib/libident'
if test -f 'ident.h'
then
	echo shar: "will not over-write existing file 'ident.h'"
else
cat << \SHAR_EOF > 'ident.h'
/*
** ident.h
**
** Author: Peter Eriksson <pen@lysator.liu.se>
** Intruder: Pdr Emanuelsson <pell@lysator.liu.se>
*/

#ifndef __IDENT_H__
#define __IDENT_H__

#ifdef	__cplusplus
extern "C" {
#endif

/* Sigh */
#ifdef __STDC__
#  if __STDC__ == 1
#    define IS_STDC 1
#  endif
#endif

#ifdef __P
#  undef __P
#endif
    
#ifdef IS_STDC
#  define __P(AL)	                  AL

#ifdef IN_LIBIDENT_SRC
    
#  define __P1(t1,a1) \
    (t1 a1)
    
#  define __P2(t1,a1,t2,a2) \
    (t1 a1, t2 a2)
	
#  define __P3(t1,a1,t2,a2,t3,a3) \
    (t1 a1, t2 a2, t3 a3)
	    
#  define __P4(t1,a1,t2,a2,t3,a3,t4,a4) \
    (t1 a1, t2 a2, t3 a3, t4 a4)

#  define __P5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) \
    (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)

#  define __P7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) \
    (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7)
#endif
    
#else

#  define __P(AL)	                  ()

#ifdef IN_LIBIDENT_SRC
    
#  define __P1(t1,a1)                     (a1) \
    t1 a1;
#  define __P2(t1,a1,t2,a2)               (a1, a2) \
    t1 a1; \
    t2 a2;
#  define __P3(t1,a1,t2,a2,t3,a3)         (a1, a2, a3) \
    t1 a1; \
    t2 a2; \
    t3 a3;
#  define __P4(t1,a1,t2,a2,t3,a3,t4,a4)   (a1, a2, a3, a4) \
    t1 a1; \
    t2 a2; \
    t3 a3; \
    t4 a4;
#  define __P5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5)   (a1, a2, a3, a4, a5) \
    t1 a1; \
    t2 a2; \
    t3 a3; \
    t4 a4; \
    t5 a5;
#  define __P7(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5,t6,a6,t7,a7) \
    (a1, a2, a3, a4, a5, a6, a7) \
    t1 a1; \
    t2 a2; \
    t3 a3; \
    t4 a4; \
    t5 a5; \
    t6 a6; \
    t7 a7;
#endif
#endif

#ifdef IS_STDC
#  undef IS_STDC
#endif

#ifdef _AIX
#  include <sys/select.h>
#endif
#ifdef __sgi
#  include <bstring.h>
#endif
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/time.h>

#if defined(VMS) && !defined(FD_SETSIZE)
#  define FD_SETSIZE 64
#endif

/*
 * Sigh, GCC v2 complains when using undefined struct tags
 * in function prototypes...
 */
#if defined(__GNUC__) && !defined(INADDR_ANY)
#  define __STRUCT_IN_ADDR_P	void *
#else
#  define __STRUCT_IN_ADDR_P	struct in_addr *
#endif

#if defined(__GNUC__) && !defined(DST_NONE)
#  define __STRUCT_TIMEVAL_P	void *
#else
#  define __STRUCT_TIMEVAL_P	struct timeval *
#endif

#if defined(__sgi) && defined(_POSIX_SOURCE)
#  undef  __STRUCT_TIMEVAL_P
#  define __STRUCT_TIMEVAL_P	void *
#endif
	
#ifndef IDBUFSIZE
#  define IDBUFSIZE 2048
#endif

#ifndef IDPORT
#  define IDPORT	113
#endif

typedef struct
{
  int fd;
  char buf[IDBUFSIZE];
} ident_t;

typedef struct {
  int lport;                    /* Local port */
  int fport;                    /* Far (remote) port */
  char *identifier;             /* Normally user name */
  char *opsys;                  /* OS */
  char *charset;                /* Charset (what did you expect?) */
} IDENT;                        /* For higher-level routines */

/* Low-level calls and macros */
#define id_fileno(ID)	((ID)->fd)

extern ident_t * id_open __P((__STRUCT_IN_ADDR_P laddr,
			   __STRUCT_IN_ADDR_P faddr,
			   __STRUCT_TIMEVAL_P timeout));
  
extern int    id_close __P((ident_t *id));
  
extern int    id_query __P((ident_t *id,
			    int lport,
			    int fport,
			    __STRUCT_TIMEVAL_P timeout));
  
extern int    id_parse __P((ident_t *id,
			    __STRUCT_TIMEVAL_P timeout,
			    int *lport,
			    int *fport,
			    char **identifier,
			    char **opsys,
			    char **charset));
  
/* High-level calls */

extern IDENT *ident_lookup __P((int fd, int timeout));

extern char  *ident_id __P((int fd, int timeout));

extern IDENT *ident_query __P(( __STRUCT_IN_ADDR_P laddr, __STRUCT_IN_ADDR_P raddr, int lport, int rport, int timeout));

extern void   ident_free __P((IDENT *id));

extern char  id_version[];

#ifdef IN_LIBIDENT_SRC

extern char *id_strdup __P((char *str));
extern char *id_strtok __P((char *cp, char *cs, char *dc));

#endif

#ifdef	__cplusplus
}
#endif

#endif
SHAR_EOF
chmod 644 'ident.h'
fi
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
COPYRIGHT ISSUES:

	This version of 'libident' is hereby released into the
	Public Domain. It may be distributed for a fee or without
	a fee. We only ask you not to pretend you wrote it.

If you make any changes, please send sources or a diff of it to
us (pen@lysator.liu.se or pell@lysator.liu.se), so we can keep
_one_ unified version of libident available...

COMMENTS:

This is the second stab at a small library to interface to the Ident
protocol server. Maybe this will work correctly on some machines.. :-)
 
The ident-tester.c file is a small daemon (to be started from Inetd)
that does an ident lookup on you if you telnet into it. Can be used
to verify that your Ident server is working correctly.
 
I'm currently running this "ident-tester" on port 114 at lysator.liu.se
(130.236.254.1) if you wish to test your server.
 
/Peter Eriksson <pen@lysator.liu.se>, 1 Aug 1992


This library now contains some higher-level routines, as well as a
similar test program to test these (lookup-tester).

/Pdr Emanuelsson <pell@lysator.liu.se>, 4 April 1993


Support for NextStep 3.1 added.

/Michael Kuch <kuch@mailserv.zdv.uni-tuebingen.de>, 13 Aug 1993


Updated the ident.h header file to work with Linux, and reorganized the
Makefile for easier compilation...

/Peter Eriksson, 18 Oct 1994


Added the copyright notice at the top.

/Peter Eriksson, 29 Nov 1994


For release 0.18:

Added some bug fixes and improvements from Jean-Philippe Martin-Flatin
(syj@ecmwf.int).

/Peter Eriksson, 5 Oct 1995


For release 0.20:

Some cleanup of the distribution, and some bug fixes in the
ident-tester.c source. Perhaps it should be called 1.0? (Perhaps
it should use GNU Autoconf...)

/Peter Eriksson, 13 Nov 1996
SHAR_EOF
chmod 644 'README'
fi
if test -f 'id_parse.c'
then
	echo shar: "will not over-write existing file 'id_parse.c'"
else
cat << \SHAR_EOF > 'id_parse.c'
/*
** id_parse.c                    Receive and parse a reply from an IDENT server
**
** Author: Peter Eriksson <pen@lysator.liu.se>
** Fiddling: Pdr Emanuelsson <pell@lysator.liu.se>
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <string.h>
#  include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>

#ifdef _AIX
#  include <sys/select.h>
#endif

#ifdef _AIX
#  include <sys/select.h>
#endif
#ifdef VMS
#  include <sys/socket.h>     /* for fd_set */
#endif
#define IN_LIBIDENT_SRC
#include "ident.h"


int id_parse __P7(ident_t *, id,
		  struct timeval *, timeout,
		  int *, lport,
		  int *, fport,
		  char **, identifier,
		  char **, opsys,
		  char **, charset)
{
    char c, *cp, *tmp_charset;
    fd_set rs;
    int pos, res=0, lp, fp;
    
    errno = 0;
    
    tmp_charset = 0;
    
    if (!id)
	return -1;
    if (lport)
	*lport = 0;
    if (fport)
	*fport = 0;
    if (identifier)
	*identifier = 0;
    if (opsys)
	*opsys = 0;
    if (charset)
	*charset = 0;
    
    pos = strlen(id->buf);
    
    if (timeout)
    {
	FD_ZERO(&rs);
	FD_SET(id->fd, &rs);

#ifdef __hpux
	if ((res = select(FD_SETSIZE, (int *) &rs, (int *)0, (int *)0, timeout)) < 0)
#else
	if ((res = select(FD_SETSIZE, &rs, (fd_set *)0, (fd_set *)0, timeout)) < 0)
#endif
	    return -1;
	
	if (res == 0)
	{
	    errno = ETIMEDOUT;
	    return -1;
	}
    }
    
    /* Every octal value is allowed except 0, \n and \r */
    while (pos < sizeof(id->buf) &&
	   (res = read(id->fd, id->buf + pos, 1)) == 1 &&
	   id->buf[pos] != '\n' && id->buf[pos] != '\r')
	pos++;
    
    if (res < 0)
	return -1;
    
    if (res == 0)
    {
	errno = ENOTCONN;
	return -1;
    }
    
    if (id->buf[pos] != '\n' && id->buf[pos] != '\r')
	return 0;		/* Not properly terminated string */
    
    id->buf[pos++] = '\0';
    
    /*
    ** Get first field (<lport> , <fport>)
    */
    cp = id_strtok(id->buf, ":", &c);
    if (!cp)
	return -2;
    
    if (sscanf(cp, " %d , %d", &lp, &fp) != 2)
    {
	if (identifier)
	{
	    *identifier = id_strdup(cp);
	    if (*identifier == NULL)
	        return -4;
	}
	return -2;
    }
    
    if (lport)
	*lport = lp;
    if (fport)
	*fport = fp;
    
    /*
    ** Get second field (USERID or ERROR)
    */
    cp = id_strtok((char *)0, ":", &c);
    if (!cp)
	return -2;
    
    if (strcmp(cp, "ERROR") == 0)
    {
	cp = id_strtok((char *)0, "\n\r", &c);
	if (!cp)
	    return -2;
	
	if (identifier)
	{
	    *identifier = id_strdup(cp);
	    if (*identifier == NULL)
	        return -4;
	}
	
	return 2;
    }
    else if (strcmp(cp, "USERID") == 0)
    {
	/*
	** Get first subfield of third field <opsys>
	*/
	cp = id_strtok((char *) 0, ",:", &c);
	if (!cp)
	    return -2;
	
	if (opsys)
	{
	    *opsys = id_strdup(cp);
	    if (*opsys == NULL)
	        return -4;
	}
	
	/*
	** We have a second subfield (<charset>)
	*/
	if (c == ',')
	{
	    cp = id_strtok((char *)0, ":", &c);
	    if (!cp)
		return -2;
	    
	    tmp_charset = cp;
	    if (charset)
	    {
		*charset = id_strdup(cp);
		if (*charset == NULL)
		    return -4;
	    }
	    
	    /*
	    ** We have even more subfields - ignore them
	    */
	    if (c == ',')
		id_strtok((char *)0, ":", &c);
	}
	
	if (tmp_charset && strcmp(tmp_charset, "OCTET") == 0)
	    cp = id_strtok((char *)0, (char *)0, &c);
	else
	    cp = id_strtok((char *)0, "\n\r", &c);
	
	if (identifier)
	{
	    *identifier = id_strdup(cp);
	    if (*identifier == NULL)
	        return -4;
	}
	return 1;
    }
    else
    {
	if (identifier)
	{
	    *identifier = id_strdup(cp);
	    if (*identifier == NULL)
	        return -4;
	}
	return -3;
    }
}
SHAR_EOF
chmod 644 'id_parse.c'
fi
if test -f 'id_open.c'
then
	echo shar: "will not over-write existing file 'id_open.c'"
else
cat << \SHAR_EOF > 'id_open.c'
/*
** id_open.c                 Establish/initiate a connection to an IDENT server
**
** Author: Peter Eriksson <pen@lysator.liu.se>
** Fixes: Pdr Emanuelsson <pell@lysator.liu.se>
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <string.h>
#  include <unistd.h>
#  if !defined(__sgi) && !defined(VMS)
#    define bzero(p,l)     memset(p, 0, l)
#  endif
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/file.h>

#define IN_LIBIDENT_SRC
#include "ident.h"

#include <arpa/inet.h>

#ifdef _AIX
#  include <sys/select.h>
#endif

ident_t *id_open __P3(struct in_addr *, laddr,
		      struct in_addr *, faddr,
		      struct timeval *, timeout)
{
    ident_t *id;
    int res, tmperrno;
    struct sockaddr_in sin_laddr, sin_faddr;
    fd_set rs, ws, es;
#ifndef OLD_SETSOCKOPT
    int on = 1;
    struct linger linger;
#endif
    
    if ((id = (ident_t *) malloc(sizeof(*id))) == 0)
	return 0;
    
    if ((id->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
	free(id);
	return 0;
    }
    
    if (timeout)
    {
	if ((res = fcntl(id->fd, F_GETFL, 0)) < 0)
	    goto ERROR;

#ifndef VMS
	if (fcntl(id->fd, F_SETFL, res | FNDELAY) < 0)
	    goto ERROR;
#endif
    }

    /* We silently ignore errors if we can't change LINGER */
#ifdef OLD_SETSOCKOPT
    /* Old style setsockopt() */
    (void) setsockopt(id->fd, SOL_SOCKET, SO_DONTLINGER);
    (void) setsockopt(id->fd, SOL_SOCKET, SO_REUSEADDR);
#else
    /* New style setsockopt() */
    linger.l_onoff = 0;
    linger.l_linger = 0;
    
    (void) setsockopt(id->fd, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
    (void) setsockopt(id->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
#endif
    
    id->buf[0] = '\0';
    
    bzero((char *)&sin_laddr, sizeof(sin_laddr));
    sin_laddr.sin_family = AF_INET;
    sin_laddr.sin_addr = *laddr;
    sin_laddr.sin_port = 0;
    
    if (bind(id->fd, (struct sockaddr *) &sin_laddr, sizeof(sin_laddr)) < 0)
    {
#ifdef DEBUG
	perror("libident: bind");
#endif
	goto ERROR;
    }
    
    bzero((char *)&sin_faddr, sizeof(sin_faddr));
    sin_faddr.sin_family = AF_INET;
    sin_faddr.sin_addr = *faddr;
    sin_faddr.sin_port = htons(IDPORT);

    errno = 0;
    res = connect(id->fd, (struct sockaddr *) &sin_faddr, sizeof(sin_faddr));
    if (res < 0 && errno != EINPROGRESS)
    {
#ifdef DEBUG
	perror("libident: connect");
#endif
	goto ERROR;
    }

    if (timeout)
    {
	FD_ZERO(&rs);
	FD_ZERO(&ws);
	FD_ZERO(&es);
	
	FD_SET(id->fd, &rs);
	FD_SET(id->fd, &ws);
	FD_SET(id->fd, &es);

#ifdef __hpux
	if ((res = select(FD_SETSIZE, (int *) &rs, (int *) &ws, (int *) &es, timeout)) < 0)
#else
	if ((res = select(FD_SETSIZE, &rs, &ws, &es, timeout)) < 0)
#endif
	{
#ifdef DEBUG
	    perror("libident: select");
#endif
	    goto ERROR;
	}
	
	if (res == 0)
	{
	    errno = ETIMEDOUT;
	    goto ERROR;
	}
	
	if (FD_ISSET(id->fd, &es))
	    goto ERROR;
	
	if (!FD_ISSET(id->fd, &rs) && !FD_ISSET(id->fd, &ws))
	    goto ERROR;
    }
    
    return id;
    
  ERROR:
    tmperrno = errno;		/* Save, so close() won't erase it */
    close(id->fd);
    free(id);
    errno = tmperrno;
    return 0;
}
SHAR_EOF
chmod 644 'id_open.c'
fi
if test -f 'id_close.c'
then
	echo shar: "will not over-write existing file 'id_close.c'"
else
cat << \SHAR_EOF > 'id_close.c'
/*
** id_close.c                            Close a connection to an IDENT server
**
** Author: Peter Eriksson <pen@lysator.liu.se>
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <unistd.h>
#endif

#define IN_LIBIDENT_SRC
#include "ident.h"

int id_close __P1(ident_t *, id)
{
    int res;
  
    res = close(id->fd);
    free(id);
    
    return res;
}


SHAR_EOF
chmod 644 'id_close.c'
fi
if test -f 'id_query.c'
then
	echo shar: "will not over-write existing file 'id_query.c'"
else
cat << \SHAR_EOF > 'id_query.c'
/*
** id_query.c                             Transmit a query to an IDENT server
**
** Author: Peter Eriksson <pen@lysator.liu.se>
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <signal.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <string.h>
#  include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>

#ifdef _AIX
#  include <sys/select.h>
#endif

#ifdef _AIX
#  include <sys/select.h>
#endif
#ifdef VMS
#  include <sys/socket.h>     /* for fd_set */
#endif
#define IN_LIBIDENT_SRC
#include "ident.h"


int id_query __P4(ident_t *, id,
		  int, lport,
		  int, fport,
		  struct timeval *, timeout)
{
#ifdef SIGRETURNTYPE
    SIGRETURNTYPE (*old_sig)();
#else
    void (*old_sig) __P((int));
#endif
    int res;
    char buf[80];
    fd_set ws;
    
    sprintf(buf, "%d , %d\r\n", lport, fport);
    
    if (timeout)
    {
	FD_ZERO(&ws);
	FD_SET(id->fd, &ws);

#ifdef __hpux
	if ((res = select(FD_SETSIZE, (int *)0, (int *)&ws, (int *)0, timeout)) < 0)
#else
	if ((res = select(FD_SETSIZE, (fd_set *)0, &ws, (fd_set *)0, timeout)) < 0)
#endif
	    return -1;
	
	if (res == 0)
	{
	    errno = ETIMEDOUT;
	    return -1;
	}
    }

    old_sig = signal(SIGPIPE, SIG_IGN);
    
    res = write(id->fd, buf, strlen(buf));
    
    signal(SIGPIPE, old_sig);
    
    return res;
}
SHAR_EOF
chmod 644 'id_query.c'
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Place in the public domain 1996/12/13 - sms.
#
# @(#)Makefile 1.0 (2.11BSD) 1996/12/13
#

DESTDIR=
LIBDIR=$(DESTDIR)/usr/lib
INCDIR=$(DESTDIR)/usr/include
MANDIR=$(DESTDIR)/usr/man/cat3

CFLAGS=-O -DSIGRETURNTYPE=int -DHAVE_ANSIHEADERS

LFLAGS=-i
LIB= libident.a

SRCS = ident.c id_open.c id_close.c id_query.c id_parse.c support.c version.c
OBJS = ident.o id_open.o id_close.o id_query.o id_parse.o support.o version.o

.c.o:
	@${CC} -p ${CFLAGS} -c $*.c
	@-ld -X -o profiled/$*.o -r $*.o
	${CC} ${CFLAGS} -c $*.c
	@-ld -x -r $*.o
	@mv a.out $*.o

all: 	libident.a libident_p.a lookup-tester ident-tester ident.0

libident.a libident_p.a:	$(OBJS)
	@echo building normal libident
	@ar ru libident.a ${OBJS}
	ranlib libident.a
	@echo building profiled libident
	@cd profiled; ar ru ../libident_p.a ${OBJS}
	ranlib libident_p.a

ident-tester: libident.a ident-tester.o
	${CC} $(CFLAGS) ${LFLAGS} -o ident-tester ident-tester.o $(LIB)

lookup-tester: libident.a lookup-tester.o
	${CC} $(CFLAGS) ${LFLAGS} -o lookup-tester lookup-tester.o $(LIB)

ident.0: ident.3
	/usr/man/manroff ident.3 > ident.0

install: all
	install -c -m 644  libident.a $(LIBDIR)/libident.a
	install -c -m 644 libident_p.a $(LIBDIR)/libident_p.a
	ranlib $(LIBDIR)/libident.a $(LIBDIR)/libident_p.a
	install -c -m 444  ident.h $(INCDIR)/ident.h
	install -c -m 444 ident.0 $(MANDIR)/ident.0

clean:
	-rm -f libident.a libident_p.a ident-tester lookup-tester *.o ident.0
	-rm -f profiled/*.o

depend:
	mkdep ${CFLAGS} ${SRCS}
SHAR_EOF
chmod 644 'Makefile'
fi
if test -f 'ident-tester.c'
then
	echo shar: "will not over-write existing file 'ident-tester.c'"
else
cat << \SHAR_EOF > 'ident-tester.c'
/*
** ident-tester.c           A small daemon that can be used to test Ident
**                          servers
**
** Author: Peter Eriksson <pen@lysator.liu.se>, 10 Aug 1992
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <syslog.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/socket.h>

#define IN_LIBIDENT_SRC
#include "ident.h"

#include <arpa/inet.h>

/*
** Return the name of the connecting host, or the IP number as a string.
*/
char *gethost __P1(struct in_addr *, addr)
{
  struct hostent *hp;

  
  hp = gethostbyaddr((char *) addr, sizeof(struct in_addr), AF_INET);
  if (hp)
    return (char *) hp->h_name;
  else
    return inet_ntoa(*addr);
}

void
main __P2(int, argc,
	  char **, argv)
{
  struct sockaddr_in laddr, faddr;
  int len, res, lport, fport;
  ident_t *id;
  char *identifier, *opsys, *charset;
  

  puts("Welcome to the IDENT server tester, version 1.9\r\n");
  printf("(Linked with libident-%s)\r\n\n", id_version);
  
  fflush(stdout);
  
  len = sizeof(faddr);
  getpeername(0, (struct sockaddr *) &faddr, &len);

  len = sizeof(laddr);
  getsockname(0, (struct sockaddr *) &laddr, &len);

  printf("Connecting to Ident server at %s...\r\n", inet_ntoa(faddr.sin_addr));
  fflush(stdout);

#ifdef LOG_LOCAL3
  openlog("tidentd", 0, LOG_LOCAL3);
#else
  openlog("tidentd", 0);
#endif
  
  id = id_open(&laddr.sin_addr, &faddr.sin_addr, NULL);
  if (!id)
  {
      if (errno)
      {
	  int saved_errno = errno;
	  char *hs;
	  
	  perror("Connection denied");
	  fflush(stderr);

	  hs = gethost(&faddr.sin_addr);
	  errno = saved_errno;
	  syslog(LOG_DEBUG, "Error: id_open(): host=%s, error=%m", hs);
      }
      else
	  puts("Connection denied.");
      exit(0);
  }

  printf("Querying for lport %d, fport %d....\r\n",
	 (int) ntohs(faddr.sin_port),
	 (int) ntohs(laddr.sin_port));
  fflush(stdout);

  errno = 0;
  if (id_query(id, ntohs(faddr.sin_port), ntohs(laddr.sin_port), 0) < 0)
  {
      if (errno)
      {
	  int saved_errno = errno;
	  char *hs;
	  
	  perror("id_query()");
	  fflush(stderr);

	  hs = gethost(&faddr.sin_addr);
	  errno = saved_errno;
	  syslog(LOG_DEBUG, "Error: id_query(): host=%s, error=%m", hs);
		 
      }
      else
      {
	  puts("Query failed.\n");
      }
      
    exit(0);
  }

  printf("Reading response data...\r\n");
  fflush(stdout);

  res = id_parse(id, NULL,
		   &lport, &fport,
		   &identifier,
		   &opsys,
		   &charset);

  switch (res)
  {
    default:
      if (errno)
      {
	  int saved_errno = errno;
	  char *hs;
	  
	  perror("id_parse()");
	  hs = gethost(&faddr.sin_addr);
	  errno = saved_errno;
	  syslog(LOG_DEBUG, "Error: id_parse(): host=%s, error=%m", hs);
      }
      else
	  puts("Error: Invalid response (empty response?).\n");
      
      break;

    case -2:
	{
	    int saved_errno = errno;
	    char *hs = gethost(&faddr.sin_addr);

	    errno = saved_errno;
	    syslog(LOG_DEBUG, "Error: id_parse(): host=%s, Parse Error: %s",
		   hs,
		   identifier ? identifier : "<no information available>");
	    if (identifier)
		printf("Parse error on reply:\n  \"%s\"\n", identifier);
	    else
		printf("Unidentifiable parse error on reply.\n");
	}
        break;

    case -3:
	{
	    int saved_errno = errno;
	    char *hs = gethost(&faddr.sin_addr);

	    errno = saved_errno;
	    
	    syslog(LOG_DEBUG,
		   "Error: id_parse(): host=%s, Illegal reply type: %s",
		   hs,
		   identifier);

	    printf("Parse error in reply: Illegal reply type: %s\n",
		   identifier);
	}
        break;
	     
    case 0:
	{
	    int saved_errno = errno;
	    char *hs = gethost(&faddr.sin_addr);

	    errno = saved_errno;
	    
	    syslog(LOG_DEBUG, "Error: id_parse(): host=%s, NotReady",
		   hs);
	    puts("Not ready. This should not happen...\r");
	}
      break;

    case 2:
	{
	    int saved_errno = errno;
	    char *hs = gethost(&faddr.sin_addr);

	    errno = saved_errno;
	    
	    syslog(LOG_DEBUG, "Reply: Error: host=%s, error=%s",
		   hs, identifier);
	}
      
      printf("Error response is:\r\n");
      printf("   Lport........ %d\r\n", lport);
      printf("   Fport........ %d\r\n", fport);
      printf("   Error........ %s\r\n", identifier);
      break;

    case 1:
      if (charset)
	syslog(LOG_INFO,
	       "Reply: Userid: host=%s, opsys=%s, charset=%s, userid=%s",
	       gethost(&faddr.sin_addr), opsys, charset, identifier);
      else
	syslog(LOG_INFO, "Reply: Userid: host=%s, opsys=%s, userid=%s",
	       gethost(&faddr.sin_addr), opsys, identifier);
      
      printf("Userid response is:\r\n");
      printf("   Lport........ %d\r\n", lport);
      printf("   Fport........ %d\r\n", fport);
      printf("   Opsys........ %s\r\n", opsys);
      printf("   Charset...... %s\r\n", charset ? charset : "<not specified>");
      printf("   Identifier... %s\r\n", identifier);

      if (id_query(id, ntohs(faddr.sin_port), ntohs(laddr.sin_port), 0) >= 0)
      {
	if (id_parse(id, NULL,
		     &lport, &fport,
		     &identifier,
		     &opsys,
		     &charset) == 1)
	  printf("   Multiquery... Enabled\r\n");
      }
  }

  fflush(stdout);
  sleep(1);
  exit(0);
}

SHAR_EOF
chmod 644 'ident-tester.c'
fi
if test -f 'ident.c'
then
	echo shar: "will not over-write existing file 'ident.c'"
else
cat << \SHAR_EOF > 'ident.c'
/*
** ident.c	High-level calls to the ident lib
**
** Author: Pdr Emanuelsson <pell@lysator.liu.se>
** Hacked by: Peter Eriksson <pen@lysator.liu.se>
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <stdio.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <string.h>
#endif

#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>

#define IN_LIBIDENT_SRC
#include "ident.h"

#include <arpa/inet.h>


/* Do a complete ident query and return result */

IDENT *ident_lookup __P2(int, fd,
			 int, timeout)
{
    struct sockaddr_in localaddr, remoteaddr;
    int len;
    
    len = sizeof(remoteaddr);
    if (getpeername(fd, (struct sockaddr*) &remoteaddr, &len) < 0)
	return 0;
    
    len = sizeof(localaddr);
    if (getsockname(fd, (struct sockaddr *) &localaddr, &len) < 0)
	return 0;

    return ident_query( &localaddr.sin_addr, &remoteaddr.sin_addr,
		       ntohs(localaddr.sin_port), ntohs(remoteaddr.sin_port),
		       timeout);
}


IDENT *ident_query __P5(struct in_addr *, laddr,
			struct in_addr *, raddr,
			int, lport,
			int, rport,
			int, timeout)
{
    int res;
    ident_t *id;
    struct timeval timout;
    IDENT *ident=0;

    
    timout.tv_sec = timeout;
    timout.tv_usec = 0;
    
    if (timeout)
	id = id_open( laddr, raddr, &timout);
    else
	id = id_open( laddr, raddr, (struct timeval *)0);
    
    if (!id)
    {
	errno = EINVAL;
	return 0;
    }
  
    if (timeout)
	res = id_query(id, rport, lport, &timout);
    else
	res = id_query(id, rport, lport, (struct timeval *) 0);
    
    if (res < 0)
    {
	id_close(id);
	return 0;
    }
    
    ident = (IDENT *) malloc(sizeof(IDENT));
    if (!ident) {
	id_close(id);
	return 0;
    }
    
    if (timeout)
	res = id_parse(id, &timout,
		       &ident->lport,
		       &ident->fport,
		       &ident->identifier,
		       &ident->opsys,
		       &ident->charset);
    else
	res = id_parse(id, (struct timeval *) 0,
		       &ident->lport,
		       &ident->fport,
		       &ident->identifier,
		       &ident->opsys,
		       &ident->charset);
    
    if (res != 1)
    {
	free(ident);
	id_close(id);
	return 0;
    }
    
    id_close(id);
    return ident;			/* At last! */
}


char *ident_id __P2(int, fd,
		    int, timeout)
{
    IDENT *ident;
    char *id=0;
    
    ident = ident_lookup(fd, timeout);
    if (ident && ident->identifier && *ident->identifier)
    {
	id = id_strdup(ident->identifier);
	if (id == NULL)
	    return NULL;
    }

    ident_free(ident);
    return id;
}


void ident_free __P1(IDENT *, id)
{
    if (!id)
	return;
    if (id->identifier)
	free(id->identifier);
    if (id->opsys)
	free(id->opsys);
    if (id->charset)
	free(id->charset);
    free(id);
}
SHAR_EOF
chmod 644 'ident.c'
fi
if test -f 'ident.3'
then
	echo shar: "will not over-write existing file 'ident.3'"
else
cat << \SHAR_EOF > 'ident.3'
.\" Pdr Emanuelsson <pell@lysator.liu.se> 1993-03-28
.ds : \h'\w'u'u/5'\z"\h'-\w'e'u/5'
.TH IDENT 3 "4 April 1993" "Lysator ACS"
.SH NAME
ident_lookup, ident_id, ident_free, id_open, id_close, id_query, id_parse,
id_fileno \- query remote IDENT server
.SH SYNOPSIS
.nf
.B #include <ident.h>
.LP
.I High-level calls
.LP
.B IDENT *ident_lookup(int fd, int timeout)
.LP
.B char *ident_id(int fd, int timeout)
.LP
.B void ident_free(IDENT *id)
.LP
.I Low-level calls
.LP
.B id_t *id_open(laddr, faddr, timeout)
.B struct in_addr *laddr, *faddr;
.B struct timeval *timeout;
.LP
.B int id_close(id)
.B id_t *id;
.LP
.B id_query(id, lport, fport, timeout)
.B id_t *id;
.B int lport, fport;
.B struct timeval *timeout;
.LP
.B int id_parse(id, timeout, lport, fport, identifier,
.B		opsys, charset)
.B id_t *id;
.B struct timeval *timeout;
.B int *lport, *fport;
.B char **identifier, **opsys, **charset;
.LP
.B int id_fileno(id)
.B id_t *id;
.fi
.SH DESCRIPTION
.LP
.B ident_lookup
tries to connect to a remote
.B IDENT
server to establish the identity of the peer connected on
.I fd,
which should be a socket file descriptor.
.I timeout
is the longest permissible time to block waiting for an answer, and is
given in seconds. A value of 0 (zero) means wait indefinitely (which in the
most extreme case will normally be until the underlying network times out).
.B ident_lookup
returns a pointer to an
.I IDENT
struct, which has the following contents:
.RS
.LP
.nf
.ft B
typedef struct {
	int lport;		/* Local port */
	int fport;		/* Far (remote) port */
	char *identifier;	/* Normally user name */
	char *opsys;		/* OS */
	char *charset;		/* Charset (what did you expect?) */
} IDENT;
.ft R
.fi
.RE
.LP
For a full description of the different fields, refer to
.I RFC-1413.
.LP
All data returned by
.B ident_lookup
(including the
.SM IDENT
struct) points to malloc'd data, which can be freed with a call to
.B ident_free.
.B ident_lookup
returns 0 on error or timeout. Presently, this should normally be taken to
mean that the remote site is not running an
.SM IDENT
server, but it might naturally be caused by other network related problems
as well.
.B Note that
all fields of the
.SM IDENT
struct need not necessarily be set.
.LP
.B ident_id
takes the same parameters as
.B ident_lookup
but only returns a pointer to a malloc'd area containing the
.I identifier
string, which is probably the most wanted data from the
.SM IDENT
query.
.LP
.B ident_free
frees all data areas associated with the
.SM IDENT
struct pointed to by
.I id,
including the struct itself.
.LP
.ce
.I Low-level calls
.LP
The low-level calls can be used when greater flexibility is needed. For
example, if non-blocking I/O is needed, or multiple queries to the
same host are to be made.
.LP
.B id_open
opens a connection to the remote
.SM IDENT
server referred to by
.I faddr.
The timeout is specified by
.I timeout.
A null-pointer means wait indefinitely, while a pointer to a
zero-valued
.I timeval
struct sets non-blocking I/O, in the same way as for
.B select(2).
.B id_open
returns a pointer to an
.B id_t
datum, which is an opaque structure to be used as future reference
to the opened connection. When using non-blocking I/O it might however
be useful to access the underlying socket file descriptior, which
can be gotten at through the
.B id_fileno
macro described below.
.LP
.B id_close
closes the connection opened with
.B id_open
and frees all data associated with
.I id.
.LP
.B id_query
sends off a query to a remote
.SM IDENT
server.
.I lport
and
.I fport
are sent to the server to identify the connection for which
identification is needed.
.I timeout
is given as for
.B id_open.
If successful,
.B id_query
returns the number of bytes sent to the remote server. If not, -1 is
returned and
.B errno
is set.
.LP
.B id_parse
parses the reply to a query sent off by
.B id_query
and returns information to the locations pointed to by
.I lport, fport, identifier, opsys
and
.I charset.
For string data
.I (identifier, opsys
and
.I charset)
pointers to malloc'd space are returned.
.LP
.B id_parse
returns:
.RS
.TP
 1
If completely successful.
.TP
-3
Illegal reply type from remote server.
.I identifier
is set to the illegal reply.
.TP
-2
Cannot parse the reply from the server.
.I identifier
is normally set to the illegal reply.
.TP
-1
On general errors or timeout.
.TP
 0
When non-blocking mode is set and
.B id_parse
has not finished parsing the reply from the remote server.
.TP
 2
Indicates the query/reply were successful, but the remote server
experienced some error.
.I identifier
is set to the error message from the remote server.
.RE
.LP
For all errors,
.I errno
is set as appropriate.
.LP
.B id_fileno
is a macro that takes an
.B id_t
handle and returns the actual socket file descriptor used for
the connection to the remote server.
.SH ERRORS
.TP 15
ETIMEDOUT
The call timed out and non-blocking I/O was not set.
.SH EXAMPLES
.LP
Here's an example how to handle the reply from id_reply() in
the case that non-blocking I/O is set. Note that id_reply() will
return 0 as long as it's not finished parsing a reply.
.LP
.RS
.nf
.nj
int rcode;

 ...

idp = id_open(...)

 ...

while ((rcode = id_parse(idp, timeout,
			 &lport, &fport, &id, &op, &cs)) == 0)
	;

if (rcode < 0)
{
  if (errno == ETIMEDOUT)
    foo();	/* Lookup timed out */
  else
    bar();      /* Fatal error */
}
else if (rcode == 1)
{
  /* Valid USERID protocol reply */
}
else if (rcode == 2)
{
  /* Protocol ERROR reply */
}
.fi
.RE
.SH SEE ALSO
RFC-1413, socket(2), select(2)
.SH AUTHORS
Peter Eriksson
.I <pen@lysator.liu.se>
.br
P\*:ar Emanuelsson
.I <pell@lysator.liu.se>
.SH BUGS
For
.B ident_lookup
and
.B ident_id
the blocking time in extreme cases might be as much as three times
the value given in the
.I timeout
parameter.
SHAR_EOF
chmod 644 'ident.3'
fi
if test -f 'lookup-tester.c'
then
	echo shar: "will not over-write existing file 'lookup-tester.c'"
else
cat << \SHAR_EOF > 'lookup-tester.c'
/*
** lookup-tester.c	Tests the high-level ident calls.
**
** Author: Pdr Emanuelsson <pell@lysator.liu.se>, 28 March 1993
*/

#ifdef NeXT3
#  include <libc.h>
#endif

#include <errno.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <unistd.h>
#endif

#include <sys/types.h>

/* Need this to make fileno() visible when compiling with strict ANSI */
#ifndef _POSIX_C_SOURCE
#  define _POSIX_C_SOURCE
#endif
#include <stdio.h>

#define IN_LIBIDENT_SRC
#include "ident.h"

void
main __P2(int, argc,
	  char **, argv)
{
  IDENT *ident;
  char *user;

  chdir("/tmp");

  puts("Welcome to the other IDENT server tester, version 1.0\r\n\r");  

  puts("Testing ident_lookup...\r\n\r");
  fflush(stdout);

  ident = ident_lookup(fileno(stdin), 30);

  if (!ident)
    perror("ident");
  else {
    printf("IDENT response is:\r\n");
    printf("   Lport........ %d\r\n", ident->lport);
    printf("   Fport........ %d\r\n", ident->fport);
    printf("   Opsys........ %s\r\n", ident->opsys);
    printf("   Charset...... %s\r\n",
	   ident->charset ? ident->charset : "<not specified>");
    printf("   Identifier... %s\r\n", ident->identifier);
  }

  ident_free(ident);

  puts("\r\nTesting ident_id...\r\n\r");
  fflush(stdout);

  user = ident_id(fileno(stdin), 30);

  if (user)
    printf("IDENT response is identifier = %s\r\n", user);
  else
    puts("IDENT lookup failed!\r");

  fflush(stdout);
  sleep(1);
  exit(0);
}

SHAR_EOF
chmod 644 'lookup-tester.c'
fi
if test -f 'version.c'
then
	echo shar: "will not over-write existing file 'version.c'"
else
cat << \SHAR_EOF > 'version.c'
char id_version[] = "0.20";
SHAR_EOF
chmod 644 'version.c'
fi
if test -f 'INSTALL'
then
	echo shar: "will not over-write existing file 'INSTALL'"
else
cat << \SHAR_EOF > 'INSTALL'
To build the libident library for a supported target, just type:

	make <target>

where target can be one of:

	sunos5, sunos4, svr4, bsd, linux, nextstep3.0 or nextstep3.1

For other systems you'll need to hack the Makefile (please do send
me any patches you make so I can include them into the next version!)

			- Peter Eriksson <pen@lysator.liu.se>, 18 Oct 1994


SHAR_EOF
chmod 644 'INSTALL'
fi
if test -f 'support.c'
then
	echo shar: "will not over-write existing file 'support.c'"
else
cat << \SHAR_EOF > 'support.c'
/*
** support.c
**
** Author: Pr Emanuelsson <pell@lysator.liu.se>
** Hacked by: Peter Eriksson <pen@lysator.liu.se>
*/
#include <stdio.h>
#include <ctype.h>

#ifdef HAVE_ANSIHEADERS
#  include <stdlib.h>
#  include <string.h>
#else
#  define strchr(str, c) index(str, c)
#endif

#define IN_LIBIDENT_SRC
#include "ident.h"


char *id_strdup __P1(char *, str)
{
    char *cp;

    cp = (char *) malloc(strlen(str)+1);
    if (cp == NULL)
    {
#ifdef DEBUG
	perror("libident: malloc");
#endif
        return NULL;
    }

    strcpy(cp, str);

    return cp;
}


char *id_strtok __P3(char *, cp,
		      char *, cs,
		      char *, dc)
{
    static char *bp = 0;
    
    if (cp)
	bp = cp;
    
    /*
    ** No delimitor cs - return whole buffer and point at end
    */
    if (!cs)
    {
	while (*bp)
	    bp++;
	return cs;
    }
    
    /*
    ** Skip leading spaces
    */
    while (isspace(*bp))
	bp++;
    
    /*
    ** No token found?
    */
    if (!*bp)
	return 0;
    
    cp = bp;
    while (*bp && !strchr(cs, *bp))
	bp++;
    
    /*
    ** Remove trailing spaces
    */
    *dc = *bp;
    for (dc = bp-1; dc > cp && isspace(*dc); dc--)
	;
    *++dc = '\0';
    
    bp++;
    
    return cp;
}
SHAR_EOF
chmod 644 'support.c'
fi
if test ! -d 'profiled'
then
	mkdir 'profiled'
fi
cd 'profiled'
chmod 755 .
cd ..
chmod 755 .
cd ..
exit 0
#	End of shell archive