/*
 passwd-shell.c - /etc/passwd shell-based backend for standalone ldap server

 Copyright (c) 1995 Regents of the University of Michigan.
 All rights reserved.

 Redistribution and use in source and binary forms are permitted
 provided that this notice is preserved and that due credit is given
 to the University of Michigan at Ann Arbor. The name of the University
 may not be used to endorse or promote products derived from this
 software without specific prior written permission. This software
 is provided ``as is'' without express or implied warranty.
*/


#include "portable.h"

#include <stdio.h>
#include <stdlib.h>

#include <ac/string.h>
#include <ac/unistd.h>

#include <pwd.h>

#include <lber.h>
#include <ldap.h>

#include "shellutil.h"
#include "passwd-shell.h"


static void pwdfile_search LDAP_P(( struct ldop *op, FILE *ofp ));
static struct ldentry *pw2entry LDAP_P(( struct ldop *op, struct passwd *pw ));

static char	tmpbuf[ MAXLINELEN * 2 ];


int
main( int argc, char **argv )
{
    int			c, errflg;
    struct ldop		op;

    if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
	progname = estrdup( argv[ 0 ] );
    } else {
	progname = estrdup( progname + 1 );
    }

    errflg = debugflg = 0;

    while (( c = getopt( argc, argv, "d" )) != EOF ) {
	switch( c ) {
	case 'd':
#ifdef LDAP_DEBUG
	    ++debugflg;
#else /* LDAP_DEBUG */
	    fprintf( stderr, "%s: compile with -DLDAP_DEBUG for debugging\n",
		    progname );
#endif /* LDAP_DEBUG */
	    break;
	default:
	    ++errflg;
	}
    }

    if ( errflg || optind < argc ) {
	fprintf( stderr, "usage: %s [-d]\n", progname );
	exit( 1 );
    }

    debug_printf( "started\n" );

    (void) memset( (char *)&op, '\0', sizeof( op ));

    if ( parse_input( stdin, stdout, &op ) < 0 ) {
	exit( 0 );
    }

    if ( op.ldop_op != LDOP_SEARCH ) {
	write_result( stdout, LDAP_UNWILLING_TO_PERFORM, NULL,
		"Command Not Implemented" );
	exit( 0 );
    }

#ifdef LDAP_DEBUG
    dump_ldop( &op );
#endif /* LDAP_DEBUG */

    pwdfile_search( &op, stdout );

    exit( 0 );
}


static void
pwdfile_search( struct ldop *op, FILE *ofp )
{
    struct passwd	*pw;
    struct ldentry	*entry;
    int			oneentry;

    oneentry = ( strchr( op->ldop_dn, '@' ) != NULL );

    for ( pw = getpwent(); pw != NULL; pw = getpwent()) {
	if (( entry = pw2entry( op, pw )) != NULL ) {
	    if ( oneentry ) {
		if ( strcasecmp( op->ldop_dn, entry->lde_dn ) == 0 ) {
		    write_entry( op, entry, ofp );
		    break;
		}
	    } else if ( test_filter( op, entry )) {
		write_entry( op, entry, ofp );
	    }
	    free_entry( entry );
	}
    }
    endpwent();

    write_result( ofp, LDAP_SUCCESS, NULL, NULL );
}


static struct ldentry *
pw2entry( struct ldop *op, struct passwd *pw )
{
    struct ldentry	*entry;
    struct ldattr	*attr;
    int			i;

    entry = (struct ldentry *) ecalloc( 1, sizeof( struct ldentry ));

    /* 
     * construct the DN from pw_name
     */
    if ( strchr( op->ldop_suffixes[ 0 ], '=' ) != NULL ) {
	/*
	 * X.500 style DN
	 */
	sprintf( tmpbuf, "cn=%s, %s", pw->pw_name, op->ldop_suffixes[ 0 ] );
    } else {
	/*
	 * RFC-822 style DN
	 */
	sprintf( tmpbuf, "%s@%s", pw->pw_name, op->ldop_suffixes[ 0 ] );
    }
    entry->lde_dn = estrdup( tmpbuf );

    /*
     * for now, we simply derive the LDAP attribute values as follows:
     *  objectClass = person
     *  uid = pw_name
     *  sn = pw_name
     *  cn = pw_name
     *  cn = pw_gecos	(second common name)
     */
    entry->lde_attrs = (struct ldattr **)ecalloc( 5, sizeof( struct ldattr * ));
    i = 0;
    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
    attr->lda_name = estrdup( "objectClass" );
    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
    attr->lda_values[ 0 ] = estrdup( "person" );
    entry->lde_attrs[ i++ ] = attr;

    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
    attr->lda_name = estrdup( "uid" );
    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
    entry->lde_attrs[ i++ ] = attr;

    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
    attr->lda_name = estrdup( "sn" );
    attr->lda_values = (char **)ecalloc( 2, sizeof( char * ));
    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
    entry->lde_attrs[ i++ ] = attr;

    attr = (struct ldattr *)ecalloc( 1, sizeof( struct ldattr ));
    attr->lda_name = estrdup( "cn" );
    attr->lda_values = (char **)ecalloc( 3, sizeof( char * ));
    attr->lda_values[ 0 ] = estrdup( pw->pw_name );
    if ( pw->pw_gecos != NULL && *pw->pw_gecos != '\0' ) {
	attr->lda_values[ 1 ] = estrdup( pw->pw_gecos );
    }
    entry->lde_attrs[ i++ ] = attr;

    return( entry );
}
