/*
 * privlaunch.c 0.0.2
 *
 * Begränsade möjligheter att köra program som root för en viss användare.
 *
 * ALLOWUID skall sättas till det user id som får köra programmet (www-data).
 * Använd "id" för att ta reda på en användares uiser id (eller titta
 * i /etc/passwd).
 *
 * hitta userid:	id www-data
 * kompilera:		gcc -o privlaunch privlaunch.c
 * sätt ägare:		chown root:root privlaunch
 * sätt suid-bit:	chmod ug+s privlaunch
 *
 * Andreas Henriksson <andreas@fjortis.info>, 2004-09-16.
 */



/* --- edit here --- */
#define ALLOWUID 1001
/* --- edit here --- */


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

typedef struct cmdstruct {
	int options;	/* antal argument till kommandot */
	char *optdesc;	/* beskrivning (syntax) för argumenten) */
	char *cmdstr;	/* kommandosträng */
	char *cmddesc;	/* beskrivning av kommandot */
} cmd_t;


void print_commands(char *progname, cmd_t *cmdarr, int cmds) {
	int i;
	for (i=0; i < cmds; i++) {
		fprintf(stderr, "[%s]:\t\t %s %d %s\n", cmdarr[i].cmddesc,
				progname, i,
				cmdarr[i].optdesc != NULL ? cmdarr[i].optdesc : "");
	}
}

int main(int argc, char *argv[])
{
	int cmd;
	char buf[1024];

	cmd_t cmdarr[] = {
		{
			.options	= 0,
			.optdesc	= NULL,
			.cmdstr		= "ifdown eth0;ifup eth0",
			.cmddesc	= "restart network",
			
		},
		{
			.options	= 2,
			.optdesc	= "yyyy-mm-dd hh:mm:ss",
			.cmdstr		= "date --set='%s %s'",
			.cmddesc	= "set date",
		},
		{
			.options	= 0,
			.optdesc	= NULL,
			.cmdstr		= "hwclock --systohc",
			.cmddesc	= "save time to hardware",
		},
		/* --- edit here --- */
		/* add more command blocks here ... */
		/* --- edit here--- */
	};


	if ((getuid() != ALLOWUID) && (getuid() != 0)) {
		fprintf(stderr, "ERROR: you're user id (%d) doesn't match allowed id.\n", getuid());
		exit(1);
	}

	if (argc < 2) {
		fprintf(stderr, "Syntax: %s <command-id> [<options> ...]\n\n",
				argv[0]);
		print_commands(argv[0], cmdarr, sizeof(cmdarr)/sizeof(cmd_t));
		exit(2);
	}

	cmd=atoi(argv[1]);

	if ((cmd < 0) || (cmd > (sizeof(cmdarr)/sizeof(cmd_t)))) {
		fprintf(stderr, "ERROR: invalid command specified\n");
		exit(3);
	}

	/* fprintf(stderr, "DEBUG: command:%s\n", cmdarr[cmd].cmdstr); */

	if (setuid(0) || setgid(0) || seteuid(0) || setegid(0)) {
		fprintf(stderr, "ERROR: failed gaining root privilegies. Missing suid bit on binary?\n");
		exit(3);
	}

	if (argc < (2 + cmdarr[cmd].options)) {
		fprintf(stderr, "ERROR: missing argument(s).\n\n");
		print_commands(argv[0], cmdarr, sizeof(cmdarr)/sizeof(cmd_t));
		exit(4);
	}

	switch (cmdarr[cmd].options) {
		case 0:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr);
			break;
		case 1:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr,
					argv[2]);
			break;
		case 2:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr,
					argv[2], argv[3]);
			break;
		case 3:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr,
					argv[2], argv[3], argv[4]);
			break;
		case 4:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr,
					argv[2], argv[3], argv[4],
					argv[5]);
			break;
		case 5:
			snprintf(buf, sizeof(buf), cmdarr[cmd].cmdstr,
					argv[2], argv[3], argv[4],
					argv[5], argv[6]);
			break;
		default:
			fprintf(stderr, "ERROR: to many arguments....\n");
			exit(5);
	}

	system(buf);

	/* not reached unless system-call failed! */
	return -1;
}

