/*
 * pwdhd.c -- password hash daemon.
 *
 * Reads a pipe and when a request for data base rebuild comes in
 * this kicks off a rebuild operation.
 *
 * The following characters can be sent to the pipe to cause data
 * base rebuilds:
 *
 *  r  -- rebuild both data bases (exec mkpwdbm)
 *  p  -- rebuild passwd data base (mkpwdbm -p)
 *  s  -- rebuild shadow data base (mkpwdbm -s)
 *
 *
 * This will create a named pipe "/etc/pwdp" if it does not exist.
 */

#ident	"$Header: pwdhd.c 1.7 90/01/16 $"

/*
 * $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.
 */

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

int build_s;
int build_p;
int build_both;

main(argc, argv)
	int argc;
	char *argv[];
{
	int fd;
	int i, n, c, status;
	char *p;
	char buf[BUFSIZ];
	char *prog;
	struct stat sb1, sb2;
	int do_rebuild = 0;

	prog = argv[0];

	/* Can be run only by root. */

	if (getuid() != 0)
		exit(1);

	for (i=0; i < _NFILE; i++)	/* first three should do it */
		(void) close(i); 

	/* See if pipe exists.  Create if it does not. */

	if (stat(PWH_PIPE, &sb1) == -1) {
		umask(000);
		if (mknod(PWH_PIPE, 010622, 0) == -1)
			exit(2);
		umask(022);
	} else if ((sb1.st_mode & 0170000) != 010000)
		exit(3);

	if ((fd = open(PWH_PIPE, O_RDWR, 0)) == -1)
		exit(4);

	/*
	 * If the data base files don't exist, or if they sizes don't
	 * seem corect we will exec the mkpwdbm program with the "-f"
	 * flag to have a data base created.
	 */

	strcpy(buf, PASSWD_DBM);
	strcat(buf, ".pag");

	if (stat(buf, &sb1) == -1) {
		do_rebuild = 1;
	} else {
		if ((sb1.st_size % PBLKSIZ) != 0)
			do_rebuild = 1;
	}
	
	strcpy(buf, PASSWD_DBM);
	strcat(buf, ".dir");

	if (stat(buf, &sb1) == -1) {
		do_rebuild = 1;
	} else {
		if ((sb1.st_size % DBLKSIZ) != 0)
			do_rebuild = 1;
	}

	strcpy(buf, SHADOW_DBM);
	strcat(buf, ".pag");

	if (stat(buf, &sb1) == 0) {
		if ((sb1.st_size % PBLKSIZ) != 0)
			do_rebuild = 1;
	}
	
	strcpy(buf, SHADOW_DBM);
	strcat(buf, ".dir");

	if (stat(buf, &sb1) == 0) {
		if ((sb1.st_size % DBLKSIZ) != 0)
			do_rebuild = 1;
	}


	/*
	 * If all looks good check the times and insure that data base .pag
	 * files are as new as the data files.  This indicates they are
	 * valid.  If out of date then rebuild.
	 */
	
	if (do_rebuild == 0) {
		strcpy(buf, PASSWD_DBM);
		strcat(buf, ".pag");
		if (stat(PASSWD, &sb1) != 0)
			exit(5);
		if (stat(buf, &sb2) != 0)
			do_rebuild = 1;
		else if (sb1.st_mtime > sb2.st_mtime)
				do_rebuild = 1;
	}

	if (do_rebuild == 0) {
		strcpy(buf, SHADOW_DBM);
		strcat(buf, ".pag");
		if (stat(SHADOW, &sb1) == 0) {
			if (stat(buf, &sb2) != 0)
				do_rebuild = 1;
			else if (sb1.st_mtime > sb2.st_mtime)
					do_rebuild = 1;
		}
	}

	if (do_rebuild) {
		i = vfork();
		if (i == 0) {
			execl(PWH_BUILD, PWH_BUILD, "-f", (char *) 0);
			exit(6);
		}
		if (i == -1)
			exit(7);
		while ((c = wait(&status)) != i)
			;				/* wait for rebuild */
	}

	for (;;) {
		n = read(fd, buf, sizeof(buf));
		if (n <= 0)
			exit(8);
		build_s = build_p = build_both = 0;
		p = buf;
		for (i=0; i < n; i++) {
			if (*p == 'r')
				build_both = 1;
			else if (*p == 'p')
				build_p = 1;
			else if (*p == 's')
				build_s = 1;
			p++;
		}
		if (build_p && build_s)
			build_both = 1;
		if ((build_p == 0) && (build_s == 0) && (build_both == 0))
			continue;
		i = vfork();
		if (i == 0) {
			if (build_both)
				execl(PWH_BUILD, PWH_BUILD, (char *) 0);
			else if (build_p)
				execl(PWH_BUILD, PWH_BUILD, "-p", (char *) 0);
			else if (build_s)
				execl(PWH_BUILD, PWH_BUILD, "-s", (char *) 0);
			exit(9);
		}
		if (i == -1)
			exit(10);
		while ((c = wait(&status)) != i)
			;				/* wait for rebuild */
	}
}
