Index: src/sc-crontab.h
===================================================================
--- src/sc-crontab.h	(revision 98)
+++ src/sc-crontab.h	(working copy)
@@ -33,10 +33,12 @@
 typedef struct {
 	char uname[32];
 	char euname[32];
-	uid_t uid;
-	uid_t euid;
+	uid_t uid;    /* current user id */
+	uid_t euid;   /* user id of crontab user */
+	gid_t egid;   /* group id of crontab user */
 	char path[2][1024];
 	int remove;
+	int list;
 } in_user;
 
 void parse_input(int argc, char **argv, in_user *uvals);
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 98)
+++ src/Makefile.am	(working copy)
@@ -17,12 +17,18 @@
 sc_crontab_SOURCES=$(CRONTAB_SOURCECODE)
 
 install: install-am
-	chmod u+s "$(DESTDIR)/$(bindir)/sc-crontab"
+	chgrp @defgroup@ "$(DESTDIR)/$(bindir)/sc-crontab"
+	chmod o-x,o-r,u+s "$(DESTDIR)/$(bindir)/sc-crontab"
 	if ! test -d "$(DESTDIR)/$(localstatedir)" ; then \
 	mkdir -p "$(DESTDIR)/$(localstatedir)" ; \
 	mkdir "$(DESTDIR)/$(localstatedir)/tmp" ; \
 	mkdir "$(DESTDIR)/$(localstatedir)/crontabs" ; fi
 	if ! test -d "$(DESTDIR)/$(localstatedir)/crontabs" ; then mkdir -p "$(DESTDIR)/$(localstatedir)/crontabs" ; fi
 	if ! test -d "$(DESTDIR)/$(localstatedir)/tmp" ; then mkdir -p "$(DESTDIR)/$(localstatedir)/tmp" ; fi
-	chmod 700 "$(DESTDIR)/$(localstatedir)/crontabs"
-	chmod 700 "$(DESTDIR)/$(localstatedir)/tmp"
+	chgrp @defgroup@ "$(DESTDIR)/$(localstatedir)/crontabs" && chmod 750 "$(DESTDIR)/$(localstatedir)/crontabs"
+	chgrp @defgroup@ "$(DESTDIR)/$(localstatedir)/tmp" && chmod 750 "$(DESTDIR)/$(localstatedir)/tmp"
+# let only members of @group@ execute sc-crontab
+# the group should exists before make install is executed
+# by default the group is cron (since this project is only an example
+# and almost each Unix has a cron server installed with at least
+# a cron group
Index: src/sc-crontab.c
===================================================================
--- src/sc-crontab.c	(revision 98)
+++ src/sc-crontab.c	(working copy)
@@ -11,7 +11,8 @@
 	int i, j=0;
 	struct passwd *uinfo;
 	uvals->uid = uvals->euid = getuid();
-	uvals->remove = 0;
+	uvals->egid = getgid();
+	uvals->remove = uvals->list = 0;
 
 	uinfo = getpwuid(uvals->uid);
 	if(!uinfo)
@@ -29,6 +30,8 @@
 		{
 			if(!strcmp(argv[i], "-r"))
 				uvals->remove = 1;
+			else if(!strcmp(argv[i], "-l"))
+				uvals->list = 1;
 			else if(!strcmp(argv[i], "--help"))
 				help(argv[0], NULL, 0);
 			else
@@ -52,6 +55,7 @@
 
 				strcpy(uvals->euname, uinfo->pw_name);
 				uvals->euid = uinfo->pw_uid;
+				uvals->egid = uinfo->pw_gid;
 			}
 		}
 	}
@@ -62,7 +66,7 @@
 
 void help(const char *prog, const char* error, int status)
 {
-	char fmt[] = "usage: %s [-r] [username] [--help]\n";
+	char fmt[] = "usage: %s [-r | -l] [username] [--help]\n";
 	
 	if(status)
 		fprintf(stderr, "%s\n", error);
@@ -150,21 +154,52 @@
 
 	parse_input(argc, argv, &uinfo);
 
+	if(uinfo.remove && uinfo.list)
+		help(argv[0], "Option -l and -r cannot be passed together", 1);
+
 	/* set default editor to vi */
 	strcpy(editor, "vi");
 
-	tmp = getenv("EDITOR");
+	tmp = getenv("EDITOR"); /* it would be better to aks for an absolute path */
 
 	if(tmp)
 		strcpy(editor, tmp);
 
-	/* become root */
-	if(setuid(0))
+	if(uinfo.list)
 	{
-		perror("setuid");
-		return EXIT_FAILURE;
+		fd = open(uinfo.path[0], O_RDONLY);
+
+		if(fd == -1)
+                {
+                        if(errno == ENOENT)
+                        {
+                                fprintf(stderr, "You don't have any cron jobs to show\n");
+                                return EXIT_FAILURE;
+                        } else {
+                                fprintf(stderr, "Unexpected error while reading file: %s\n", strerror(errno));
+				close(fd);
+				return EXIT_FAILURE;
+			}
+                } else
+                        close(fd);
+
+		if((child = fork()) == -1)
+		{
+			perror("fork");
+			return EXIT_FAILURE;
+		}
+
+		if(child)
+		{
+			wait(NULL);
+			exit(EXIT_SUCCESS);
+		} else {
+			/* do not run as root !!! */
+			exit(execlp("cat", "cat", uinfo.path[0], NULL));
+		}
 	}
-
+	
+	
 	openlog("sc-crontab", LOG_PID, LOG_CRON);
 
 	if(uinfo.remove)
@@ -210,6 +245,15 @@
 
 	/* are there already cron jobs for current user? */
 
+	/* become root */
+
+	if(setuid(0))
+	{
+		perror("setuid");
+		closelog();
+		exit(EXIT_FAILURE);
+	}
+
 	fd = open(uinfo.path[0], O_RDONLY);
 
 	if(fd == -1)
@@ -230,11 +274,15 @@
 		}
 
 		write(fd, message, strlen(message));
+		
+		if(fchown(fd, uinfo.euid, uinfo.egid)==-1)
+			fprintf(stderr, "cannot change owner/group privileges on temporal file");
 
 		close(fd);
+
 	} else {
 		close(fd);
-		if(!copy(uinfo.path[0], uinfo.path[1], 0, 0, S_IRUSR | S_IWUSR))
+		if(!copy(uinfo.path[0], uinfo.path[1], uinfo.euid, uinfo.egid, S_IRUSR | S_IWUSR))
 		{
 			fprintf(stderr, "a safe copy of %s cannot be generated. Aborting...\n", uinfo.path[0]);
 			return EXIT_FAILURE;
@@ -260,10 +308,14 @@
 			{
 				fprintf(stderr, 
 					"The editor terminated with following error: %s\nThe cronjobs may not be saved\n", strerror(WEXITSTATUS(fd)));
+
+				if(unlink(uinfo.path[1]))
+					fprintf(stderr, "temporal file %s could not be removed\n", uinfo.path[1]);
+
 				return EXIT_FAILURE;
 			}
 
-			if(!copy(uinfo.path[1], uinfo.path[0], uinfo.euid, 0, S_IRUSR | S_IWUSR))
+			if(!copy(uinfo.path[1], uinfo.path[0], uinfo.euid, uinfo.egid, S_IRUSR | S_IWUSR))
 			{
 				fprintf(stderr, "The cron jobs could not be saved properly. The cronjobs may not be saved\n");
 				return EXIT_FAILURE;
@@ -299,9 +351,22 @@
 		
 	} else {
 		/* child proc */
-		execlp(editor, editor, uinfo.path[1], NULL);
+		/* this must NOT be executed as root !!! */
 
-		exit(errno);
+
+		if(uinfo.uid) { /* if root executes the program then you 
+				   don't need to change the uid of the process
+				   because the user has already a shell as root */
+			/* become user again */
+			if(setuid(uinfo.euid))
+			{
+				perror("setuid");
+				exit(EXIT_FAILURE);
+			} 
+		}
+		
+		/* running as user */
+		exit(execlp(editor, editor, uinfo.path[1], NULL));
 	}
 
 	closelog();
Index: configure.ac
===================================================================
--- configure.ac	(revision 98)
+++ configure.ac	(working copy)
@@ -19,10 +19,17 @@
 AC_ARG_WITH([shell-path], AC_HELP_STRING([--with-shell-path=DIR], [shell path, e.g. /bin/sh. overrides the path that configure found]), shellpath=$withval,
 shellpath=no)
 
+AC_ARG_WITH([default-group], AC_HELP_STRING([--with-default-group=DIR], [default group, (default: cron)]), defgroup=$withval,
+defgroup=no)
+
 if test "${shellpath}" == "yes" ; then
         shellpath=no
 fi
 
+if test "${defgroup}" == "yes" ; then
+	defgroup=no
+fi
+
 AC_MSG_CHECKING([which is the path of sh/bash])
 
 
@@ -64,6 +71,21 @@
 
 AC_SUBST(shellpath)
 
+if test "${defgroup}" == "no" ; then
+	defgroup=cron
+fi
+
+AC_MSG_CHECKING([whether ${defgroup} exists])
+
+if test -z "`grep ${defgroup} /etc/group`" ; then
+	AC_MSG_RESULT([no])
+	AC_MSG_ERROR([${defgroup} does not exists. Try with the option --with-default-group])
+else
+	AC_MSG_RESULT([yes])
+fi
+
+AC_SUBST(defgroup)
+
 dnl Setting C as the language
 AC_GNU_SOURCE
 
