/* ============= Zugriff auf E/A-Ports für ein Userprogramm =============
 *
 * Gestattet einem User-Programm den Zugriff auf E/A-Ports und zwar
 * nur auf lp0/1/2 and ttyS0/1/2/3.
 * Gleichzeitig wird die Priorität angepasst.
 *
 * AUFRUF: ./io_perm ./userprogramm param1 param2 ...  
 *
 * - setgid und setuid nehmen die Root-Privilegien weg
 * - setpriority setzt die Laufzeitpriorität
 * - die Kommandozeile wird (bis auf den ersten Parameter)
 *   an das userprogramm weitergegeben
 * - Muss SUID root sein (chmod 4711 io_perm)
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/resource.h>

#define lp0   0x378       /* LPT port base addresses. */
#define lp1   0x278
#define lp2   0x3BC
#define lp_length 3

#define ttyS0 0x3F8       /* COM port base addresses. */
#define ttyS1 0x2F8
#define ttyS2 0x3E8
#define ttyS3 0x2E8
#define ttyS_length 8

int main(int argc, char *argv[])
  { 
  if ( argc < 2)
    {
    fprintf(stderr,"IO_PERM: Kein Userprogramm angegeben, Abbruch.\n");
    exit(1);
    }
  
  /*--- Prozess-Prioritaet: 0=normal, -20=hoechste, +20=niedrigste */
  setpriority(PRIO_PROCESS, 0, 0);

  /*--- Ports freigeben und Root-Privilegien loeschen.*/  
  if (ioperm(lp0, lp_length, 1)) perror("IO_PERM: Failed ioperm lp0"); 
  if (ioperm(lp1, lp_length, 1)) perror("IO_PERM: Failed ioperm lp1"); 
  if (ioperm(lp2, lp_length, 1)) perror("IO_PERM: Failed ioperm lp2"); 
      
  if (ioperm(ttyS0, ttyS_length, 1)) perror("IO_PERM: Failed ioperm ttyS0"); 
  if (ioperm(ttyS1, ttyS_length, 1)) perror("IO_PERM: Failed ioperm ttyS1"); 
  if (ioperm(ttyS2, ttyS_length, 1)) perror("IO_PERM: Failed ioperm ttyS2"); 
  if (ioperm(ttyS3, ttyS_length, 1)) perror("IO_PERM: Failed ioperm ttyS3"); 
      
  setgid(getgid());
  setuid(getuid());  
  
  /* Userprogramm ausfuehren, Parameter uebergeben */
  execvp(argv[1], &argv[1]);

  /* Oops! */
  perror("IO_PERM: execv failed");
  fprintf(stderr, "IO_PERM: Userprogramm war %s.\n", argv[1]);
  exit(1);
  }
 

