/*
 * Suid wrapper for ikisite. Can run subcommands that allow themselves to
 * be run via a wrapper.
 *
 * To ensure only site owners can change their sites,
 * this wrapper expects the environment variable IKISITE_NONCE to be
 * set to contain a previously created nonce for the site.
 *
 * An exception is the create, branch, list, checksite, sitelookup,
 * enabledns, and updatecustomersite subcommands, which do not need a
 * nonce to be set.
 * 
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

extern char **environ;

int main (int argc, char **argv) {
	int i;
	char *args[argc+2];

	char *nonce=getenv("IKISITE_NONCE");
	if (!nonce) {
		if (! argv[1] ||
		    strcmp(argv[1], "create") == 0 ||
		    strcmp(argv[1], "branch") == 0 ||
		    strcmp(argv[1], "list") == 0 ||
		    strcmp(argv[1], "sitelookup") == 0 ||
		    strcmp(argv[1], "getsetup") == 0 ||
		    strcmp(argv[1], "updatecustomersite") == 0 ||
		    strcmp(argv[1], "checksite") == 0 ||
		    strcmp(argv[1], "enabledns") == 0 ||
		    strcmp(argv[1], "enable") == 0) {
			/* use a dummy value so ikisite still can tell
			 * it is being run from the wrapper */
			nonce="dummy";
		}
		else {
			fprintf(stderr, "IKISITE_NONCE not set\n");
			exit(1);
		}
	}

	/* suid safety */
#ifdef __TINYC__
	/* old tcc versions do not support modifying environ directly */
	if (clearenv() != 0) {
		perror("clearenv");
		exit(1);
	}
#else
	/* this is more portable on freebsd/osx, which lack clearenv */
	*environ = NULL;
#endif
	if (setenv("PATH", "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin", 1) != 0) {
		perror("setenv");
		exit(1);
	}
	if (setenv("IKISITE_NONCE", nonce, 1) != 0) {
		perror("setenv");
		exit(1);
	}

	if (setregid(0, 0) != 0) {
		perror("setregid");
		exit(1);
	}
	if (setreuid(0, 0) != 0) {
		perror("setreuid");
		exit(1);
	}

	/* Pass argv to ikisite. */
	args[0]="/usr/bin/ikisite";
	for (i=1; i<argc; i++) {
		args[i]=argv[i];
	}
	args[i]=NULL;

	execv(args[0], args);
	perror(args[0]);
	exit(1);
}
