[mod.sources] chsh chfn for SV

sources-request@panda.UUCP (01/27/86)

Mod.sources:  Volume 3, Issue 98
Submitted by: decvax!cwruecmp!rexago1!rich (K. Richard Magill)

I got tired of editting passwd files so...

This is tested & running on a 3b2/300 SV.2.2.  It uses a lot of library
routines that probably don't exist outside SV.  (sorry).

----hack & slash here----
/*
 *	I AM NOT A SHELL ARCHIVE!
 *
 *	This file is chsh.c and contains a public domain version
 *	of chsh/chfn intended for SV.  Calling sequence is
 *
 *		chfn user new_name
 *	or	chsh user new_shell
 *	
 *	A null name means a null name. A null shell means /bin/sh.
 *	Your old passwd file is stored in /etc/passwd~.  Protections
 *	and passwd requests work like su.  To install use:
 *
 *		make chsh
 *		chmod 4555 chsh
 *		ln chsh /usr/lbin (or some such)
 *		ln chsh /usr/lbin/chfn
 *
 *	AAAAnyway, you get the idea.
 *
 *	K. Richard Magill, 26-jan-86.
 *	Last Mod 26-jan-86, rich.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>

#define WATCH(x)	if(x){perror(argv[0]);return(-1);}

char *PASSWD = "/etc/passwd";
char *BACKUP = "/etc/passwd~";
char *TEMP = "/tmp/chshXXXXXX";

void endpwent(), perror();
char *crypt(), *getpass(), *mktemp();
struct passwd *getpwent(), *getpwnam(), *fgetpwent();

main(argc, argv)
int argc;
char **argv;
{
	register int i;
	register struct passwd *p;
	FILE *fin, *fout;
	int target_id;
	struct stat stat_buf;

	if (argc < 2 || argc > 3) {
		(void) fprintf(stderr, "usage: %s login shell\n", argv[0]);
		return(-1);
	}	/* if usage error */

	/* is this person real? */

	if ((p = getpwnam(argv[1])) == NULL) {
		(void) fprintf(stderr, "%s: don't know %s\n",
			argv[0], argv[1]);
		return(-1);
	}	/* if person isn't real */

	/* do we have permission to do this? */
	target_id = p->pw_uid;

	if ((i = getuid()) != 0 && i != target_id) {
		char salt[3];

		salt[0] = p->pw_passwd[0];
		salt[1] = p->pw_passwd[1];
		salt[3] = '\0';

		if (*p->pw_passwd != '\0'
			&& strncmp(crypt(getpass("Password: "), salt),
			p->pw_passwd, 8)) {
			(void) fprintf(stderr, "Sorry.\n");
			return(-1);
		}	/* passwd didn't match */
	}	/* check for permission */

	/* set up files */

	endpwent();	/* close passwd file */

	WATCH((fin = fopen(PASSWD, "r")) == NULL);
	WATCH((fout = fopen(mktemp(TEMP), "w")) == NULL);

	while ((p = fgetpwent(fin)) != NULL) {
		if (p->pw_uid == target_id) {
			if (strcmp(argv[0], "chsh")) {
				p->pw_gecos = argv[2];
			} else {
				p->pw_shell = argv[2] == NULL ? "/bin/sh"
					: argv[2];
			}
		}	/* if this is entry to be changed */

		WATCH(putpwent(p, fout));
	}	/* while not eof (we couldn't recognize an error) */

	/* close files */
	WATCH(fclose(fin) || fclose(fout));

	/* remove old backup if it exists */
	WATCH(!stat(BACKUP, &stat_buf) && unlink(BACKUP));

	/* make current passwd file backup */
	WATCH(link(PASSWD, BACKUP) || unlink(PASSWD));

	/* make new file passwd */
	WATCH(link(TEMP, PASSWD) || unlink(TEMP));

	/* must have succeeded */
	return(0);
}	/* main */


/* EOF */