/* xs.c by me@, then jhs@ */
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
	
extern int errno;

	int
main (argc, argv, envp)
	int argc;
	char *argv [];
	char *envp [];
	{
	char 		*shell, *name, *getenv();
	struct passwd	*ent;
	char 		ps1[128];
	char 		**av = argv;
	int 		ac = argc;
	int 		uid ;
	int		rslt = 0 ;
	
	uid = getuid();
#ifdef DEBUG
	printf("Your UID is %d\n",uid);
#endif
/* Makefile usually reads ~/.xs_uid then passes in eg -DROOT_UID=200 */
#ifndef ROOT_UID
#define	ROOT_UID	0
/* FreeBSD default first user:
 *	 5.0-RC1 1001:1001 
 *	10.0-ALPHA4 adduser 
 *		uid=1003 
 *		(cos I had used 1000 & 1002 but not 1001)
 *		gid=1017 
 *		(cos I had occupied a few sparseley between 1000 & 1016)  
 */
#endif
	if ((uid != ROOT_UID ) && ( uid != 0 )) 
		{
		/* Perhaps dont tell user permission is refused 
		   as it tempts him */
	  	/* fprintf(stderr, "Try /usr/local/bin/sx (for Zmodem)\n"); */
	  	fprintf(stderr, "UID err.\n");
	  	exit(1);
		}
	if ( uid == 0 )
		/* Complain about waste of shell process space */
		fprintf(stderr, "Un-necessary: You were previously root.\n"); 

	if ((argc > 1) && (argv[1][0] == '-')) 
		{
	  	name = av[1] + 1;
	  	sprintf(ps1, "PS1=(%s) ", name);
	  	av++;
	  	ac--;
		}
	else 	{
	  	name = "root";
	  	strcpy(ps1, "PS1=(#) ");
		}
	if ((ent = getpwnam(name)) == (struct passwd   *)NULL)
		{
	  	fprintf(stderr, "Can't find password entry for \"%s\"\n", name);
	  	exit(1);
		}

	if (!(setgid(ent->pw_gid) || setuid(ent->pw_uid))) 
		{
#ifndef scs	/* { BSD 4.2 */
	  	putenv(ps1);
#endif		/* } */
	  	if (ac == 1)
		   	if ((shell = getenv("SHELL")) != (char *)NULL )
				rslt = execl(shell, shell, (char *)0L);
		   	else
				rslt = execl("/bin/sh", "sh", (char *)(0L));
		 else
		 	{
			rslt = execvp(av[1], av + 1);
		    	}
		fprintf(stderr, "Error in %s: ", argv[0]);
		perror("");
	  	}
	else	{ 
		fprintf(stderr, "%s setuid failed - ", argv[0]);
		perror("");
	  	}
	/* man execl:
		If any of the exec() functions returns, an error
		will have occurred.  The return value is -1, and
		the global variable errno will be set to indicate
		the error.
	 */
	exit(rslt) ;
	}
