I wrote this program for our local linux lab and I figure I'd release it
now, since it seems to work and I can't find any blatantly obvious security
holes in it.  This program must be run setuid root, because it has to
send signals to the automounter.  Essentially what it does is look at the
/var/run/automount.*.pid file and send a SIGUSR1 to the pid specified in
that file.  I think it does sufficient checks to make sure that the file
it's reading from is geniune and at the worst it's only sending SIGUSR1,
not anything dangerous like SIGKILL or SIGTERM.  Feel free to inlcude this
in the next distribution of autofs, or use it in your own lab.

I know it kind of replicates the functionality of the timeout option, but
we have users who don't want to wait for the timeout to kick in or who
dislike the continual mounting and unmounting of disks necessary at a short
timeout.  This program solves those problems as it unmounts all disks that
are not being used immediately without killing the mounts of any disk thats
being actually used.  I hope you find it useful.  Enjoy!

---unmount.c---

/* ------------------------------------------------------------------------ *
 *
 * unmount.c -- A program which unmounts automounted disks under linux
 *
 *   Copyright 1998 Ted Cabeen - All Rights Reserved
 * 
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 *   USA; either version 2 of the License, or (at your option) any later
 *   version.
 *   
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 * ----------------------------------------------------------------------- */

 #include <sys/types.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
 #include <glob.h>

extern int errno;

int globnames(glob_t* filenames)
{
/* Here we get the list of pid files in the /var/run directory */

  int globerror;

  globerror = glob("/var/run/automount.*.pid", 0, NULL, filenames); 
  switch(globerror)
    {
    case GLOB_NOSPACE:   
      perror("Glob ran out of memory");
      return -1;
      
    case GLOB_ABORTED:
      perror("Glob read error");
      return -1;

    case GLOB_NOMATCH:
      perror("No automount pid files");
      return -1;
    
    default:
      return 0;
    }
}

int checkfile(char* filename)
{

/* This function checks to make sure the pid file is owned by root, and
   is not group or world writeable */

  struct stat status;   
  int error;

  error = stat(filename, &status);
  if (error == -1)
    {
      perror("problem stating pid file");
      return -1;
    }
  if(status.st_uid != 0 || (status.st_mode & S_IWGRP ) != 0 || 
     (status.st_mode & S_IWOTH) != 0)
    {
      errno = EPERM;
      perror("pid file not owned by root or has incorrect permissions");
      return -1;
    }
  return 0;
}

int checkpid(FILE* pidfile, pid_t* pid)
{

/*  This function checks the process to make sure it's the automounter and
    provides the pid. */

  FILE* statfile;
  char procarea[20]; 
  char pname[20];
  int error;

  fscanf(pidfile, "%u", pid);
  error = snprintf(procarea, 20, "%s%u%s", "/proc/", *pid, "/stat");
  if(error == -1)
    {
      errno = ESRCH;
      perror("Invalid PID");
      return -1;
    }
  statfile = fopen(procarea, "r");
  if (statfile == NULL) 
    {
      perror("fopen (automount stat)");
      return -1;
    }
  fscanf(statfile, "%d", pid);
  fscanf(statfile, "%s", &pname);
  if (strncmp(pname, "(automount)", 11) != 0)
    {
      errno = EPERM;
      perror("Process is not the automounter");
      return -1;
    }
  return 0;
}


int main()
{
  glob_t filenames;
  FILE* pidfile;
  pid_t pid;
  int error, i;

  error = globnames(&filenames);
  if(error != 0)
    return error;

  for(i = 0; i < filenames.gl_pathc; i++)
    {
      pidfile = fopen(filenames.gl_pathv[i], "r");
      if(pidfile == NULL)
        {
          perror("fopen (Initial PID)");
          return -1;
        }
      error = checkfile(filenames.gl_pathv[i]);
      if(error != 0)
        return error;
      error = checkpid(pidfile, &pid);
      if (error != 0)
        return error;
      error = kill(pid, SIGUSR1);
      if (error == -1)
        {
          perror("kill");
          return -1;
        }
      fclose(pidfile);
    }
  return 0;
}

--
Ted Cabeen            http://fnord.rh.uchicago.edu          [EMAIL PROTECTED]
Check Website or finger for PGP Public Key        [EMAIL PROTECTED]
"I have taken all knowledge to be my province." -F. Bacon   [EMAIL PROTECTED]
"Human kind cannot bear very much reality."-T.S.Eliot [EMAIL PROTECTED]

Reply via email to