home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume20
/
opcom
/
opcom.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-22
|
9KB
|
426 lines
/*++
/* NAME
/* opcom 8
/* SUMMARY
/* execute an operator command.
/* SYNOPSIS
/* .fi
/* .B opcom
/* command [ arguments ]
/* DESCRIPTION
/* .I Opcom
/* enables users belonging to a special group (as defined in /etc/group)
/* to execute a limited set of commands with another userid (e.g. root)
/* or groupid. The file
/* .I XCOMMANDS
/* describes which commands are allowed for which groups and which
/* userid (groupid) must be used.
/* .br
/* .I Command
/* is a valid operator command, if it matches an entry in
/* .I XCOMMANDS.
/* Those entries have the following form:
/*
/* path-name : operator-group : [ new-userid ] [ : [ new-groupid ]]
/*
/* .I Command
/* matches an entry, if it is the basename of
/* .I path-name
/* and if the user executing
/* .I opcom
/* is a member of the group
/* .I operator-group
/* (as defined in /etc/group).
/* If
/* .I command
/* matches more than one entry, the first matching entry is selected.
/* This allows multiple levels of privilege.
/* .br
/* If no match is found,
/* .I opcom
/* aborts with the message "access denied.".
/*
/* .I Command
/* is executed with the given
/* .I arguments.
/* The environment is the current environment with the following
/* exceptions:
/* .br
/* If
/* .I user-id (group-id)
/* is not empty, the effective and real userid (groupid) are set to
/* .I user-id (group-id).
/* .br
/* If
/* .I user-id (group-id)
/* is empty, the effective and real userid (groupid)
/* are set to the real userid (groupid).
/*
/* The following environment variables are set:
/* .IP \- 2.4
/* COMMAND to
/* .I command.
/* .IP \-
/* GROUP to
/* .I operator-group.
/* .IP \-
/* IFS to blank, tab and new line.
/* .IP \-
/* ORGUSER to the login name of the real userid of the invoker of
/* .I opcom.
/* .IP \-
/* PATH to /
/* .IP \-
/* USER and LOGNAME to the login name of the real userid executing
/* .I command.
/* .RE
/*
/* If the script
/* .I XPROFILE
/* exists, this script will be executed
/* within the shell, that executes
/* .I command.
/* So changes to the environment (e.g. PATH) can be put there.
/* FILES
/* XCOMMANDS
/* XPROFILE
/* /etc/group
/* CAVEAT
/* Beware of Trojan horses: don't allow commands with shell escapes.
/* BUGS
/* The syntax of entries in
/* .I XCOMMANDS
/* is not checked rigorously.
/* DIAGNOSTICS
/* In case of error
/* .I opcom
/* prints an error message on standard error and terminates
/* with nonzero status.
/* AUTHOR(S)
/*
/* C.G.S.M. Braam
/* Eindhoven University of Technology
/* Computing Centre
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* BUG REPORTS TO
/* rccarel@eutrc3.UUCP
/* CREATION DATE
/* Wed Jan 4 14:12:59 MET 1989
/* LAST MODIFICATION
/* Tue Jan 17 13:15:08 MET 1989
/* VERSION/RELEASE
/* 1.3
/*--*/
#include <stdio.h>
#include "sysdep.h"
#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <varargs.h>
#include <ctype.h>
extern void exit ();
extern void perror ();
extern int errno;
extern char *sys_errlist [];
extern int sys_nerr;
extern int geteuid ();
extern int getgid ();
extern int setuid ();
extern struct group *getgrnam ();
extern struct passwd *getpwnam ();
extern struct passwd *getpwuid ();
extern char *malloc ();
extern int putenv ();
extern int system ();
#define WARN 0
#define ABORT 1
struct command {
char *name;
char path [1024];
char group [32];
char new_group [32];
char new_user [32];
};
void PERROR ();
int check_group ();
void error ();
void exec_cmnd ();
struct command *get_command ();
char *nextitem ();
void usage_error ();
void set_env ();
void set_ids ();
char orguser [32];
char *progname; /* used for diagnostics */
main (argc, argv)
int argc;
char **argv;
{
int fd;
struct command *command;
/* close all file descriptors > 2 */
for (fd = 3; fd <= _NFILE; fd++)
(void) close (fd);
if (progname = strrchr (*argv, '/'))
progname++;
else
progname = *argv;
argv++; argc--;
if (argc == 0)
usage_error ();
command = get_command (*argv);
set_ids (command->new_user, command->new_group);
exec_cmnd (command, argc-1, argv+1);
return (0); /* makes lint happy */
}
struct command *get_command (name)
char *name;
{
static char cmndbuf [BUFSIZ];
static struct command command;
int found = 0;
char ch,
*cmnd,
*pc,
*ptail,
*pt;
FILE *file;
if ((file = fopen (COMMANDS, "r")) == NULL)
error (ABORT, "cannot open %s for reading.", COMMANDS);
command.name = name;
while (fgets (cmndbuf, BUFSIZ, file) != NULL) {
for (cmnd = cmndbuf; isspace (*cmnd); cmnd++);
pt = command.path;
ptail = cmnd;
while (! (isspace (ch = *ptail) || (ch == ':') || (ch == 0))) {
*pt++ = ch;
ptail++;
}
*pt = 0;
while (isspace (*ptail))
ptail++;
if (*ptail != ':') /* invalid entry */
continue;
pt = command.path;
if ((pc = strrchr (pt, '/')) == NULL)
pc = pt;
else
pc++;
if (strcmp (name, pc) == 0) {
ptail = nextitem (ptail+1, command.group);
if ((found = check_group (command.group)))
break;
}
}
if (! found)
error (ABORT, "access denied.");
(void) fclose (file);
ptail = nextitem (ptail, command.new_user);
ptail = nextitem (ptail, command.new_group);
return (&command);
}
char *nextitem (pstart, target)
char *pstart,
*target;
{
char ch,
*ps = pstart,
*pt = target;
while (isspace (*ps)) ps++;
if (*ps == 0) {
*pt = 0;
return (ps);
}
for (ch = *ps; (ch != ':') & (ch != 0); ch = *++ps)
*pt++ = ch;
*pt-- = 0;
for (ch = *pt; isspace (ch); ch = *pt--)
*pt = 0;
if (*ps == 0)
return (ps);
else
return (ps+1);
}
int check_group (groupname)
char *groupname;
{
int found = 0;
char **gr_list;
struct group *group;
struct passwd *passwd;
if ((passwd = getpwuid (getuid ())) == NULL)
error (ABORT, "cannot find passwd entry for userid %d.", getuid ());
(void) strcpy (orguser, passwd->pw_name);
if ((group = getgrnam (groupname)) != NULL)
for (gr_list = group->gr_mem; *gr_list != NULL; gr_list++) {
if ((found = (strcmp (orguser, *gr_list) == 0)))
break;
}
return (found);
}
void set_ids (new_user, new_group)
char *new_user,
*new_group;
{
struct group *group;
struct passwd *passwd;
if (*new_group != 0) {
/* not empty, must be set before uid is set */
if ((group = getgrnam (new_group)) == NULL)
error (ABORT, "cannot find group entry for groupid %s.", new_group);
if (setgid (group->gr_gid) < 0)
PERROR (ABORT);
}
if (*new_user != 0) { /* not empty */
if ((passwd = getpwnam (new_user)) == NULL)
error (ABORT, "cannot find passwd entry for userid %s.", new_user);
if (setuid (passwd->pw_uid) < 0)
PERROR (ABORT);
} else if (setuid (getuid ()) < 0)
PERROR (ABORT);
}
void exec_cmnd (command, argc, argv)
struct command *command;
int argc;
char **argv;
{
unsigned cmnd_size = 0;
int i,
rslt;
struct stat prstat;
char
*cmnd,
*pa,
*pc;
set_env (command->name, command->group, command->new_user);
cmnd_size = strlen (command->path)+32;
for (i = 0; i < argc; i++)
cmnd_size += strlen (argv [i])+1;
pc = cmnd = malloc (cmnd_size+strlen (PROFILE));
if ((stat (PROFILE, &prstat) == 0) && (prstat.st_mode & 0400)) {
/* We must execute the profile */
(void) sprintf (pc, ". %s;", PROFILE);
pc += strlen (pc);
}
pa = command->path;
while (*pa != 0)
*pc++ = *pa++;
*pc++ = ' ';
while (argc-- > 0) {
pa = *argv++;
while (*pa != 0)
*pc++ = *pa++;
*pc++ = ' ';
}
*pc = 0; /* close string */
if ((rslt = system (cmnd)) < 0)
PERROR (ABORT);
exit (rslt);
}
void set_env (name, group, new_user)
char *name,
*group,
*new_user;
{
#define PUTENV(e) { if (putenv (e) < 0) PERROR (ABORT); }
static char envbuf [512];
char *penv = envbuf;
PUTENV ("IFS= \t\n");
PUTENV ("PATH=/");
(void) sprintf (penv, "ORGUSER=%s", orguser);
PUTENV (penv);
penv += strlen (penv)+1;
(void) sprintf (penv, "COMMAND=%s", name);
PUTENV (penv);
penv += strlen (penv)+1;
(void) sprintf (penv, "GROUP=%s", group);
PUTENV (penv);
penv += strlen (penv)+1;
if (*new_user == 0) {
(void) sprintf (penv, "USER=%s", orguser);
PUTENV (penv);
penv += strlen (penv)+1;
(void) sprintf (penv, "LOGNAME=%s", orguser);
PUTENV (penv);
} else {
(void) sprintf (penv, "USER=%s", new_user);
PUTENV (penv);
penv += strlen (penv)+1;
(void) sprintf (penv, "LOGNAME=%s", new_user);
PUTENV (penv);
}
}
void PERROR (why)
int why;
{
perror (progname);
if (why == ABORT)
exit (1);
}
void usage_error ()
{
error (ABORT, "usage: %s command [ arguments ]", progname);
}
/* error - barf and quit */
/* VARARGS1 */
void error (why, fmt, va_alist)
int why;
register char *fmt;
va_dcl
{
va_list s;
va_start(s);
(void) fprintf (stderr, "%s: ", progname);
for (/* void */; *fmt; fmt++) {
if (*fmt != '%') {
(void) putc(*fmt,stderr);
} else if (*++fmt == 's') {
(void) fputs(va_arg(s,char *),stderr);
} else if (*fmt == 'c') {
(void) putc(va_arg(s,int),stderr);
} else if (*fmt == 'u') {
(void) fprintf(stderr,"%u",va_arg(s,unsigned));
} else if (*fmt == 'd') {
(void) fprintf(stderr,"%d",va_arg(s,int));
}
}
va_end(s);
(void) fprintf (stderr, "\n");
if (why != WARN)
exit (why);
(void) fflush (stderr);
}