/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: getpwnam.c 1.12 89/07/18 $@(#)libc-port:gen/getpwnam.c	1.10"
/*	3.0 SID #	1.2	*/

/*
 * This code modified to receive advice from a password data base.
 * This is optional.  If it exists it allows direct seeks into
 * the password file.
 */

/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*LINTLIBRARY*/
#include <stdio.h>
#include <pwd.h>
#include <shadow.h>
#include <ndbm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>

extern struct passwd *getpwent();
extern struct passwd *fgetpwent();
extern void setpwent(), endpwent();
extern int strncmp();

struct passwd *
getpwnam(name)
char	*name;
{
	register struct passwd *p;

#ifndef CCS
	DBM *db;
	datum d, k;
	int fd, c;
	FILE *fp;
	union {
		char s_c[4];
		int  s_s;
	}s;
	struct stat sb1, sb2;
	char buf[BUFSIZ];

	/* Try and open the data base for the password file. */

	db = dbm_open(PASSWD_DBM, O_RDONLY, 0444);
	if (db == (DBM *) 0)
		goto nohash;

	/*
	 * Password data base exists.  Look up the desired name.
	 * If not found retrieve the password status from the data base
	 * and compare with status now.  The present password size
	 * must match that recorded in the data base, and the data
	 * base file must have later or equal modification time.
	 */

	strcpy(buf, "n_");
	strcat(buf, name);

	k.dptr = buf;
	k.dsize = strlen(buf);
	d = dbm_fetch(db, k);
	if (d.dptr == (char *) 0) {		/* not found */
		if (dbm_error(db)) {
			(void) dbm_close(db);
			goto rebuild;
		}
		if (strcmp(name, "root") == 0) {
			(void) dbm_close(db);
			goto nohash;
		}
		k.dptr = "pw_stat_struct";
		k.dsize = strlen("pw_stat_struct");
		d = dbm_fetch(db, k);
		if (d.dptr == (char *) 0) {	/* should not happen */
			(void) dbm_close(db);
			goto nohash;
		}
		(void) memcpy(&sb1, d.dptr, sizeof(sb1));
		(void) dbm_close(db);
		if (stat(PASSWD, &sb2) != 0)	/* should not happen */
			goto nohash;
		if (sb1.st_size == sb2.st_size) {
			strcpy(buf, PASSWD_DBM);
			strcat(buf, ".pag");
			if (stat(buf, &sb1) != 0)
				goto nohash;
			if (sb1.st_mtime < sb2.st_mtime)
				goto rebuild;
			return((struct passwd *) NULL);
		} else
			goto rebuild;
	} else {				/* found */
		s.s_c[0] = d.dptr[0];
		s.s_c[1] = d.dptr[1];
		s.s_c[2] = d.dptr[2];
		s.s_c[3] = d.dptr[3];
		(void) dbm_close(db);
		if (s.s_s <= 0)
			goto nohash;
		if ((fp = fopen(PASSWD, "r")) == NULL)
			goto nohash;
		s.s_s -= 1;		/* back up past newline */
		if (fseek(fp, s.s_s, 0) < 0) {
			fclose(fp);
			goto rebuild;
		}
		c = getc(fp);
		if (c == -1) {
			fclose(fp);
			goto nohash;
		}
		if (c != '\n') {
			fclose(fp);
			goto rebuild;
		}
		p = fgetpwent(fp);
		(void) fclose(fp);
		if (p == (struct passwd *) NULL)
			goto rebuild;
		if (strcmp(p->pw_name, name) == 0)
			return(p);
		/* going to fall into rebuild */
	}
	
rebuild:
	if ((fd = open(PWH_PIPE, O_WRONLY|O_NDELAY, 0)) != -1) {
		(void) write(fd, "p", 1);
		(void) close(fd);
	}

nohash:

#endif	/* not CCS */

	setpwent();
	while ((p = getpwent()) && strcmp(name, p->pw_name))
		;
	endpwent();
	return (p);
}
