home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume20 / opcom / opcom.c < prev    next >
C/C++ Source or Header  |  1989-10-22  |  9KB  |  426 lines

  1. /*++
  2. /* NAME
  3. /*      opcom 8
  4. /* SUMMARY
  5. /*      execute an operator command.
  6. /* SYNOPSIS
  7. /*    .fi
  8. /*    .B opcom 
  9. /*     command [ arguments ]
  10. /* DESCRIPTION
  11. /*    .I Opcom
  12. /*    enables users belonging to a special group (as defined in /etc/group)
  13. /*    to execute a limited set of commands with another userid (e.g. root)
  14. /*    or groupid. The file
  15. /*    .I XCOMMANDS
  16. /*    describes which commands are allowed for which groups and which
  17. /*    userid (groupid) must be used.
  18. /*    .br
  19. /*    .I Command
  20. /*    is a valid operator command, if it matches an entry in
  21. /*    .I XCOMMANDS.
  22. /*    Those entries have the following form:
  23. /*    
  24. /*    path-name : operator-group : [ new-userid ] [ : [ new-groupid ]]
  25. /*    
  26. /*    .I Command
  27. /*    matches an entry, if it is the basename of 
  28. /*    .I path-name
  29. /*    and if the user executing
  30. /*    .I opcom
  31. /*    is a member of the group
  32. /*    .I operator-group
  33. /*    (as defined in /etc/group).
  34. /*    If
  35. /*    .I command
  36. /*    matches more than one entry, the first matching entry is selected.
  37. /*    This allows multiple levels of privilege.
  38. /*    .br
  39. /*    If no match is found,
  40. /*    .I opcom
  41. /*    aborts with the message "access denied.".
  42. /*
  43. /*    .I Command
  44. /*    is executed with the given
  45. /*    .I arguments.
  46. /*    The environment is the current environment with the following
  47. /*    exceptions:
  48. /*    .br
  49. /*    If
  50. /*    .I user-id (group-id)
  51. /*    is not empty, the effective and real userid (groupid) are set to
  52. /*    .I user-id (group-id).
  53. /*    .br
  54. /*    If
  55. /*    .I user-id (group-id)
  56. /*    is empty, the effective and real userid (groupid)
  57. /*    are set to the real userid (groupid).
  58. /*
  59. /*    The following environment variables are set:
  60. /*    .IP \- 2.4
  61. /*    COMMAND to
  62. /*    .I command.
  63. /*    .IP \-
  64. /*    GROUP to
  65. /*    .I operator-group.
  66. /*    .IP \-
  67. /*    IFS to blank, tab and new line.
  68. /*    .IP \-
  69. /*    ORGUSER to the login name of the real userid of the invoker of
  70. /*    .I opcom.
  71. /*    .IP \-
  72. /*    PATH to /
  73. /*    .IP \-
  74. /*    USER and LOGNAME to the login name of the real userid executing
  75. /*    .I command.
  76. /*    .RE
  77. /*
  78. /*    If the script 
  79. /*    .I XPROFILE
  80. /*    exists, this script will be executed
  81. /*    within the shell, that executes
  82. /*    .I command.
  83. /*    So changes to the environment (e.g. PATH) can be put there.
  84. /* FILES
  85. /*    XCOMMANDS
  86. /*    XPROFILE
  87. /*    /etc/group
  88. /* CAVEAT
  89. /*    Beware of Trojan horses: don't allow commands with shell escapes.
  90. /* BUGS
  91. /*    The syntax of entries in
  92. /*    .I XCOMMANDS
  93. /*    is not checked rigorously.
  94. /* DIAGNOSTICS
  95. /*    In case of error
  96. /*    .I opcom
  97. /*    prints an error message on standard error and terminates
  98. /*    with nonzero status.
  99. /* AUTHOR(S)
  100. /*
  101. /*      C.G.S.M. Braam
  102. /*      Eindhoven University of Technology
  103. /*      Computing Centre
  104. /*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  105. /* BUG REPORTS TO
  106. /*    rccarel@eutrc3.UUCP
  107. /* CREATION DATE
  108. /*    Wed Jan  4 14:12:59 MET 1989
  109. /* LAST MODIFICATION
  110. /*    Tue Jan 17 13:15:08 MET 1989
  111. /* VERSION/RELEASE
  112. /*    1.3
  113. /*--*/
  114.  
  115. #include <stdio.h>
  116. #include "sysdep.h"
  117. #include <grp.h>
  118. #include <pwd.h>
  119. #include <sys/types.h>
  120. #include <sys/stat.h>
  121. #include <varargs.h>
  122. #include <ctype.h>
  123.  
  124. extern void exit ();
  125. extern void perror ();
  126.  
  127. extern int errno;
  128. extern char *sys_errlist [];
  129. extern int sys_nerr;
  130.  
  131. extern int geteuid ();
  132. extern int getgid ();
  133. extern int setuid ();
  134. extern struct group *getgrnam ();
  135. extern struct passwd *getpwnam ();
  136. extern struct passwd *getpwuid ();
  137. extern char *malloc ();
  138. extern int putenv ();
  139. extern int system ();
  140.  
  141. #define WARN    0
  142. #define ABORT    1
  143.  
  144. struct command {
  145.     char *name;
  146.     char path [1024];
  147.     char group [32];
  148.     char new_group [32];
  149.     char new_user [32];
  150. };
  151.  
  152. void PERROR ();
  153. int check_group ();
  154. void error ();
  155. void exec_cmnd ();
  156. struct command *get_command ();
  157. char *nextitem ();
  158. void usage_error ();
  159. void set_env ();
  160. void set_ids ();
  161.  
  162. char orguser [32];
  163. char *progname;                /* used for diagnostics */
  164.  
  165. main (argc, argv)
  166. int argc;
  167. char **argv;
  168. {
  169.     int fd;
  170.     struct command *command;
  171.  
  172.     /* close all file descriptors > 2 */
  173.     for (fd = 3; fd <= _NFILE; fd++)
  174.     (void) close (fd);
  175.     if (progname = strrchr (*argv, '/'))
  176.     progname++;
  177.     else
  178.     progname = *argv;
  179.     argv++; argc--;
  180.  
  181.     if (argc == 0)
  182.     usage_error ();
  183.  
  184.     command = get_command (*argv);
  185.     set_ids (command->new_user, command->new_group);
  186.     exec_cmnd (command, argc-1, argv+1);
  187.     return (0);    /* makes lint happy    */
  188. }
  189.  
  190. struct command *get_command (name)
  191. char *name;
  192. {
  193.     static char cmndbuf [BUFSIZ];
  194.     static struct command command;
  195.     int found = 0;
  196.     char ch,
  197.      *cmnd,
  198.      *pc,
  199.      *ptail,
  200.      *pt;
  201.     FILE *file;
  202.  
  203.     if ((file = fopen (COMMANDS, "r")) == NULL)
  204.     error (ABORT, "cannot open %s for reading.", COMMANDS);
  205.     command.name = name;
  206.     while (fgets (cmndbuf, BUFSIZ, file) != NULL) {
  207.     for (cmnd = cmndbuf; isspace (*cmnd); cmnd++);
  208.     pt = command.path;
  209.     ptail = cmnd;
  210.     while (! (isspace (ch = *ptail) || (ch == ':') || (ch == 0))) {
  211.         *pt++ = ch;
  212.         ptail++;
  213.     }
  214.     *pt = 0;
  215.     while (isspace (*ptail))
  216.         ptail++;
  217.     if (*ptail != ':')    /* invalid entry    */
  218.         continue;
  219.     pt = command.path;
  220.     if ((pc = strrchr (pt, '/')) == NULL)
  221.         pc = pt;
  222.     else
  223.         pc++;
  224.     if (strcmp (name, pc) == 0) {
  225.         ptail = nextitem (ptail+1, command.group);
  226.         if ((found = check_group (command.group)))
  227.         break;
  228.     }
  229.     }
  230.     if (! found)
  231.     error (ABORT, "access denied.");
  232.     (void) fclose (file);
  233.     ptail = nextitem (ptail, command.new_user);
  234.     ptail = nextitem (ptail, command.new_group);
  235.     return (&command);
  236. }
  237.  
  238. char *nextitem (pstart, target)
  239. char *pstart,
  240.      *target;
  241. {
  242.     char ch,
  243.      *ps = pstart,
  244.      *pt = target;
  245.  
  246.      while (isspace (*ps)) ps++;
  247.      if (*ps == 0) {
  248.         *pt = 0;
  249.         return (ps);
  250.     }
  251.     for (ch = *ps; (ch != ':') & (ch != 0); ch = *++ps)
  252.         *pt++ = ch;
  253.     *pt-- = 0;
  254.     for (ch = *pt; isspace (ch); ch = *pt--)
  255.         *pt = 0;
  256.     if (*ps == 0)
  257.         return (ps);
  258.     else
  259.         return (ps+1);
  260. }
  261.  
  262. int check_group (groupname)
  263. char *groupname;
  264. {
  265.     int found = 0;
  266.     char **gr_list;
  267.     struct group *group;
  268.     struct passwd *passwd;
  269.  
  270.     if ((passwd = getpwuid (getuid ())) == NULL)
  271.     error (ABORT, "cannot find passwd entry for userid %d.", getuid ());
  272.     (void) strcpy (orguser, passwd->pw_name);
  273.     if ((group = getgrnam (groupname)) != NULL)
  274.     for (gr_list = group->gr_mem; *gr_list != NULL; gr_list++) {
  275.         if ((found = (strcmp (orguser, *gr_list) == 0)))
  276.         break;
  277.     }
  278.     return (found);
  279. }
  280.  
  281. void set_ids (new_user, new_group)
  282. char *new_user,
  283.      *new_group;
  284. {
  285.     struct group *group;
  286.     struct passwd *passwd;
  287.  
  288.     if (*new_group != 0) {
  289.     /* not empty, must be set before uid is set     */
  290.     if ((group = getgrnam (new_group)) == NULL)
  291.         error (ABORT, "cannot find group entry for groupid %s.", new_group);
  292.     if (setgid (group->gr_gid) < 0)
  293.         PERROR (ABORT);
  294.     }
  295.     if (*new_user != 0) {    /* not empty     */
  296.     if ((passwd = getpwnam (new_user)) == NULL)
  297.         error (ABORT, "cannot find passwd entry for userid %s.", new_user);
  298.     if (setuid (passwd->pw_uid) < 0)
  299.         PERROR (ABORT);
  300.     } else if (setuid (getuid ()) < 0)
  301.     PERROR (ABORT);
  302. }
  303.  
  304. void exec_cmnd (command, argc, argv)
  305. struct command *command;
  306. int argc;
  307. char **argv;
  308. {
  309.     unsigned cmnd_size = 0;
  310.     int i,
  311.     rslt;
  312.     struct stat prstat;
  313.     char 
  314.      *cmnd,
  315.      *pa,
  316.      *pc;
  317.  
  318.     set_env (command->name, command->group, command->new_user);
  319.     cmnd_size = strlen (command->path)+32;
  320.     for (i = 0; i < argc; i++)
  321.     cmnd_size += strlen (argv [i])+1;
  322.     pc = cmnd = malloc (cmnd_size+strlen (PROFILE));
  323.     if ((stat (PROFILE, &prstat) == 0) && (prstat.st_mode & 0400)) {
  324.     /* We must execute the profile */
  325.     (void) sprintf (pc, ". %s;", PROFILE);
  326.     pc += strlen (pc);
  327.     }
  328.     pa = command->path;
  329.     while (*pa != 0)
  330.     *pc++ = *pa++;
  331.     *pc++ = ' ';
  332.     while (argc-- > 0) {
  333.     pa = *argv++;
  334.     while (*pa != 0)
  335.         *pc++ = *pa++;
  336.     *pc++ = ' ';
  337.     }
  338.     *pc = 0;    /* close string    */
  339.  
  340.     if ((rslt = system (cmnd)) < 0)
  341.     PERROR (ABORT);
  342.     exit (rslt);
  343. }
  344.  
  345. void set_env (name, group, new_user)
  346. char *name,
  347.      *group,
  348.      *new_user;
  349. {
  350. #define PUTENV(e)    { if (putenv (e) < 0) PERROR (ABORT); }
  351.     static char envbuf [512];
  352.     char *penv = envbuf;
  353.  
  354.     PUTENV ("IFS= \t\n");
  355.     PUTENV ("PATH=/");
  356.     (void) sprintf (penv, "ORGUSER=%s", orguser);
  357.     PUTENV (penv);
  358.     penv += strlen (penv)+1;
  359.     (void) sprintf (penv, "COMMAND=%s", name);
  360.     PUTENV (penv);
  361.     penv += strlen (penv)+1;
  362.     (void) sprintf (penv, "GROUP=%s", group);
  363.     PUTENV (penv);
  364.     penv += strlen (penv)+1;
  365.     if (*new_user == 0) {
  366.     (void) sprintf (penv, "USER=%s", orguser);
  367.     PUTENV (penv);
  368.     penv += strlen (penv)+1;
  369.     (void) sprintf (penv, "LOGNAME=%s", orguser);
  370.     PUTENV (penv);
  371.     } else {
  372.     (void) sprintf (penv, "USER=%s", new_user);
  373.     PUTENV (penv);
  374.     penv += strlen (penv)+1;
  375.     (void) sprintf (penv, "LOGNAME=%s", new_user);
  376.     PUTENV (penv);
  377.     }
  378. }
  379.  
  380. void PERROR (why)
  381. int why;
  382. {
  383.     perror (progname);
  384.     if (why == ABORT)
  385.     exit (1);
  386. }
  387.  
  388. void usage_error ()
  389. {
  390.     error (ABORT, "usage: %s command [ arguments ]", progname);
  391. }
  392.  
  393. /* error - barf and quit */
  394.  
  395. /* VARARGS1 */
  396.  
  397. void error (why, fmt, va_alist)
  398. int why;
  399. register char *fmt;
  400. va_dcl
  401. {
  402.     va_list s;
  403.  
  404.     va_start(s);
  405.  
  406.     (void) fprintf (stderr, "%s: ", progname);
  407.     for (/* void */; *fmt; fmt++) {
  408.     if (*fmt != '%') {
  409.         (void) putc(*fmt,stderr);
  410.     } else if (*++fmt == 's') {
  411.         (void) fputs(va_arg(s,char *),stderr);
  412.     } else if (*fmt == 'c') {
  413.         (void) putc(va_arg(s,int),stderr);
  414.     } else if (*fmt == 'u') {
  415.         (void) fprintf(stderr,"%u",va_arg(s,unsigned));
  416.     } else if (*fmt == 'd') {
  417.         (void) fprintf(stderr,"%d",va_arg(s,int));
  418.     }
  419.     }
  420.     va_end(s);
  421.     (void) fprintf (stderr, "\n");
  422.     if (why != WARN)
  423.     exit (why);
  424.     (void) fflush (stderr);
  425. }
  426.