SUMMARY: Mounting/Umounting CDs

From: Rob Naccarato <naccarat_at_viking.sheridanc.on.ca>
Date: Mon, 23 Oct 1995 12:25:19 -0400

Many thanks to those who responded to my query. I am amazed at how fast
people emailed me solutions to this.
This summary is long because I have included all code that was sent to
me (at the request of Jim Wright <jwright_at_phy.ucsf.edu>). Hopefully this
will find its way into a FAQ somewhere.

 My original question:

Any suggestions on how to allow non-root access/non-group system users
access to mount and umount cds?

 My implemented solution:

We already have a "sudo" utility that we use here called "super". It allows
scripts to be run as root with security. It limits who is allowed to execute
what based on uid or gid. I have no idea where the sources come from,
although the author's email address is Will Deich <will_at_surya.caltech.edu>.

I simply took the scripts from #2 shown below and adapted them for use under
super. It has worked out quite well. Here are my mountcd and umountcd
scripts:

-----mountcd-----
#!/bin/sh
#
# mount local cdrom

PROG=`basename $0`
if [ X$SUPERCMD = X ] ; then exec /usr/local/etc/super $PROG "$_at_" ; fi

usage() {
cat <<-END
        Use:
            $prog

        Purpose:
                Allows non-root user to mount cds

        Argument: None.

END
}


MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz4c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 0 ]
then
        /usr/bin/echo "${PROG}: CD-ROM already mounted"
        exit 1
fi

#local customization
/usr/sbin/mount -rd /dev/rz4c /cdrom 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (Read-Only file system)"
        exit 0
fi

/usr/sbin/mount -t ufs -o ro /dev/rz4c /cdrom 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (as UFS file system)"
        exit 0
fi

/usr/sbin/mount -t cdfs -o ro -o rrip /dev/rz4c /cdrom 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (CDFS file system)"
        exit 0
fi

/usr/bin/echo "Unable to mount CD-ROM"
exit 1
-----end mountcd-----

-----umountcd-----
#!/bin/sh
#
# unmount local cdrom, eject

PROG=`basename $0`
if [ X$SUPERCMD = X ] ; then exec /usr/local/etc/super $PROG "$_at_" ; fi

usage() {
cat <<-END
        Use:
            $prog

        Purpose:
                Allows non-root users to umount cds

        Argument: None.

END
}

MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz4c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 1 ]
then
        /usr/bin/echo "${PROG}: No CD-ROM mounted"
        exit 1
fi

/usr/sbin/umount /cdrom
-----end umountcd-----

 Short Summary:

1. Use public domain software cdmount.
   (From roddy_at_visual-ra.swmed.edu (Roddy McColl)
2. Use sudo with shell scripts.
   Jim Wright <jwright_at_phy.ucsf.edu>
3. Try chmod u+s `which mount`
   From agahmed_at_ns2.emirates.net.ae (Amr Galal Fahim)
4. Adapt and compile this C code.
   From Gyula Szokoly <szgyula_at_skysrv.Pha.Jhu.EDU>
5. Get mountcd and umountcd.
   From mclaughl_at_nssdc.gsfc.nasa.gov
6. Use the Automounter.
   From Andreas Priebe <apriebe_at_aip.de>
7. Change protections on /dev/rz4c (cd device file).
   From GLADNEY_at_stsci.edu
8. Use sudo with shell scripts.
   From "P.Thanigasalam" <P.Thanigasalam_at_cranfield.ac.uk>
9. Write a short C program that mounts/umounts and make it suid root.
   From Hellebo Knut <Knut.Hellebo_at_nho.hydro.com>


 Detailed Suggested solutions:

=====================
1. From roddy_at_visual-ra.swmed.edu (Roddy McColl)

There is a public domain program called cdmount which you can use.
Here it is including my mods to make it work under OSF. You will have
to edit it so your device address is correct.

Note: You must be root to install the thing properly since it's setuid.

----------------------- cdmount.c (also cdumount.c) ---------------------

/*
** Subsystem: User Level mount for CD-ROM
** File Name: cdmount.c
**
** This software is Copyright (c) 1991 by Kent Landfield.
**
** Permission is hereby granted to copy, distribute or otherwise
** use any part of this package as long as you do not try to make
** money from it or pretend that you wrote it. This copyright
** notice must be maintained in any copy made.
**
** Use of this software constitutes acceptance for use in an AS IS
** condition. There are NO warranties with regard to this software.
** In no event shall the author be liable for any damages whatsoever
** arising out of or in connection with the use or performance of this
** software. Any use of this software is at the user's own risk.
**
** If you make modifications to this software that you feel
** increases it usefulness for the rest of the community, please
** email the changes, enhancements, bug fixes as well as any and
** all ideas to me. This software is going to be maintained and
** enhanced as deemed necessary by the community.
**
** Kent Landfield
** sparky!kent
** kent_at_sparky.imd.sterling.com
*/
#if !defined(lint) && !defined(SABER)
static char SID[] = "_at_(#)cdmount.c 1.2 8/19/91";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/*#define MOUNT "/etc/mount"*/
#define MOUNT "/sbin/mount"
/*#define UMOUNT "/etc/umount"*/
#define UMOUNT "/sbin/umount"
/*#define EJECT "/usr/bin/eject"*/
#define MOUNTPOINT "/cdrom"
/*#define MOUNTDEVICE "/dev/sr0"*/
/*#define MOUNTDEVICE "/dev/rz4c"*/
#define MOUNTDEVICE "/dev/rz12c"

void usage(progname)
char *progname;
{
    (void) fprintf(stderr, "\nusage: %s [ -cdhv ]\
\n\noptions:\n\
      -c mount the cdfs CD_ROM Filesystem\n\
      -d show the mount command without executing it\n\
      -h mount an ISO 9660 or High Sierra CD_ROM Filesystem\n\
      -v show the mount command and execute it\n\
\n", progname);
}

int main(argc, argv)
int argc;
char **argv;
{
    int getopt();
    char *strrchr();

    extern char *optarg;
    extern int optind;
    extern int opterr;

    char *cp;
    char cmd[256];
    int rc;
    int cdfs;
    int debug;
    int iso9660;
    struct stat stb;

    if ((cp = strrchr(argv[0],'/')) != NULL)
        ++cp;
    else
        cp = argv[0];

    /*
    ** Setup IFS for system() protection...
    */
    if (putenv("IFS= \t\n") != 0) {
         (void) fprintf(stderr,"%s: IFS putenv failed...\n", cp);
         return(1);
    }

    /*
    ** Setup PATH for execlp() protection...
    */
    if (putenv("PATH=/etc:/usr/etc:/bin:/sbin:/usr/bin") != 0) {
         (void) fprintf(stderr,"%s: PATH putenv failed...\n", cp);
         return(1);
    }

    /*
    ** If the user is requesting to mount a CD..
    */
    if (strcmp(cp, "cdmount") == 0) {
        cdfs = 0;
        iso9660 = 0;
        opterr = 0;
        debug = 0;
        /*
        ** Assure that the mount point is there and in a
        ** directory and not a symbolic link ..
        */
        if (lstat(MOUNTPOINT, &stb) != 0) {
            (void) fprintf(stderr, "%s: mount point missing\n", MOUNTPOINT);
            return(1);
        }
        if ((stb.st_mode & S_IFMT) != S_IFDIR) {
            (void) fprintf(stderr, "%s: invalid mount point\n", MOUNTPOINT);
            return(1);
        }

        if (argc > 1) {
            while ((rc = getopt(argc, argv, "dhv")) != EOF) {
                switch (rc) {
                  case 'c':
                    /*
                     ** mount the cdfs type CD_ROM
                     ** which is supposed to be ISO 9660
                     */
                    cdfs++;
                    break;
                  case 'd': /* debugging - does not run command. */
                    debug = 1;
                    break;
                  case 'v': /* verbose - runs command. */
                    debug = 2;
                    break;
                  case 'h':
                    /*
                     ** mount an ISO 9660 Standard or High
                     ** Sierra Standard CD-ROM filesystem.
                     */
                    iso9660++;
                    break;
                  default:
                    usage(cp);
                    return(1);
                }
            }
        }

        if (cdfs && iso9660) {
            (void) fprintf(stderr,"%s: Cannot use ISO9660 and CDFS\n", cp);
            return(1);
        }
            
        /* build the command line.. */
        
        if (cdfs)
            (void) sprintf(cmd, "%s -r -t cdfs -o nosuid %s %s",
                           MOUNT, MOUNTDEVICE, MOUNTPOINT);
        else if (iso9660)
            (void) sprintf(cmd, "%s -r -t hsfs -o nosuid %s %s",
                           MOUNT, MOUNTDEVICE, MOUNTPOINT);
        else
            (void) sprintf(cmd, "%s -r -o nosuid %s %s",
                           MOUNT, MOUNTDEVICE, MOUNTPOINT);
        if (debug)
            (void) fprintf(stderr, "%s\n", cmd);
        if (debug != 1)
            rc = system(cmd);
    }

    /*
    ** The user is requesting to dismount a CD...
    */
    else if (strcmp(cp, "cdumount") == 0) {
#ifdef EJECT
        (void) sprintf(cmd, "%s %s && %s %s",
                       UMOUNT, MOUNTDEVICE, EJECT, MOUNTDEVICE);
#else
        (void) sprintf(cmd, "%s %s",
                       UMOUNT, MOUNTDEVICE);
#endif
        rc = system(cmd);
        if (!rc)
            fprintf(stderr,
                    "%s: Note: You must manually eject the CD-ROM\n", cp);
    }

    /*
    ** Improperly named/linked executables, I'm confused...
    */
    else {
        (void) fprintf(stderr, "%s: I don't know who I am... ? \n", cp);
        rc = 1;
    }
    
    return(rc >> 8);
}

--------------------- Makefile.cdmount ---------------------------

##########################################################
#
# _at_(#)Makefile 1.1 8/17/91 - CDmount
#
# This software is Copyright (c) 1991 by Kent Landfield.
#
# Permission is hereby granted to copy, distribute or otherwise
# use any part of this package as long as you do not try to make
# money from it or pretend that you wrote it. This copyright
# notice must be maintained in any copy made.
#
# Use of this software constitutes acceptance for use in an AS IS
# condition. There are NO warranties with regard to this software.
# In no event shall the author be liable for any damages whatsoever
# arising out of or in connection with the use or performance of this
# software. Any use of this software is at the user's own risk.
#
# If you make modifications to this software that you feel
# increases it usefulness for the rest of the community, please
# email the changes, enhancements, bug fixes as well as any and
# all ideas to me. This software is going to be maintained and
# enhanced as deemed necessary by the community.
#
# Kent Landfield
# sparky!kent
# kent_at_sparky.imd.sterling.com
#
##########################################################

DESTDIR=/usr/local/bin
MANDIR=/usr/man/manl

all: cdmount cdumount

cdmount:
        $(CC) $(CFLAGS) -o cdmount cdmount.c

cdumount: cdmount.c
        chown root cdmount
        chgrp bin cdmount
        chmod u+s cdmount
        rm -f cdumount
        ln cdmount cdumount

install: all
        _at_echo "install according to local conventions"
        install -c -s -o root -g bin -m 6755 cdmount $(DESTDIR)
        rm -f $(DESTDIR)/cdumount
        ln $(DESTDIR)/cdmount $(DESTDIR)/cdumount
        install -c -o bin -g bin -m 0644 cdmount.1 $(MANDIR)/cdmount.l
        install -c -o bin -g bin -m 0644 cdumount.1 $(MANDIR)/cdumount.l
        
clean:
        rm -f cdmount cdumount

print:
        cprint Makefile | lpr -Plw
        cprint README | lpr -Plw
        cprint cdmount.c | lpr -Plw
        psroff -man cdmount.1
        psroff -man cdumount.1

=====================
2. From Jim Wright <jwright_at_phy.ucsf.edu>

i've answered this question two or three times, and i don't think
any of the summaries have included the scripts. when you summarize
please include them and perhaps this question will go away.

anyway, i use the "sudo" program to allow people to execute these
scripts as root. archie should be able to show you where you can
get sudo. the two scripts below are "cdmount" and "cdumount".
they have been working for me for quite some time now.

========== begin cdmount ==========
#!/bin/sh
#
# mount local cdrom

RUNAS=`/usr/bin/whoami`
WHO=`/usr/bin/logname`
PROG=`/usr/bin/basename $0`

if [ "$RUNAS" != "root" ]
then
        /usr/bin/echo "usage: sudo $PROG"
        exit 1
fi

MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz4c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 0 ]
then
        /usr/bin/echo "${PROG}: CD-ROM already mounted"
        exit 1
fi

/usr/sbin/mount -t ufs -o ro /dev/rz4c /cdrom 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (as UFS file system)"
        exit 0
fi

/usr/sbin/mount -t cdfs -o ro -o rrip /dev/rz4c /cdrom 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (CDFS file system)"
        exit 0
fi

/usr/bin/echo "Unable to mount CD-ROM"
exit 1
========== end cdmount ==========

========== begin cdumount ==========
#!/bin/sh
#
# unmount local cdrom, eject

RUNAS=`/usr/bin/whoami`
WHO=`/usr/bin/logname`
PROG=`/usr/bin/basename $0`

if [ "$RUNAS" != "root" ]
then
        /usr/bin/echo "usage: sudo $PROG"
        exit 1
fi

MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz4c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 1 ]
then
        /usr/bin/echo "${PROG}: No CD-ROM mounted"
        exit 1
fi

/usr/sbin/umount /cdrom
/sbin/scu -f /dev/rrz4c eject
========== end cdumount ==========

=====================
3. From agahmed_at_ns2.emirates.net.ae (Amr Galal Fahim)

You could try this while logged in as root :
        # chmod u+s `which mount`
This will set the SETUID mode for the mount command. Any user would be able
to mount/unmount CDs. Take Care !! Any user can also mount/unmount any other
file system.

=====================
4. From Gyula Szokoly <szgyula_at_skysrv.Pha.Jhu.EDU>

  You can always write a 10 line C code which uses 'system()' to (u)mount
the CD and make it setuid root. People are quite reluctant to use
setuid shell scripts (which would be nice for this purpose).
  I used to have one such code, but I lost it somewhere. I have a different
one, which dials out on a modem. If it helps, I attach it. It does a bit
more, it has an 'access' file, too (i.e. only some people can use it and only
on specific machines...

Gyula

#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>

#define ACCESSFILE "/opt/etc/dialAccess.txt"

main(int argc,char **argv)
{
  char fname[L_tmpnam];
  FILE *file;
  int count = 0;
  char comline[200];
  char buf[200];
  char tmpHostname[MAXHOSTNAMELEN];
  uid_t tmpUserId;
  char hostname[MAXHOSTNAMELEN];
  uid_t userId;
  char allowed = 0;

/* getting the user ID and the hostname */
  if(0 != gethostname(hostname,200))
  {
    fprintf(stderr,"Error geting hostname\n");
    exit(1);
  }
  userId = getuid();

/* Checking if the user is allowed to run this program on the host */
  file = fopen(ACCESSFILE,"r");
  if(NULL == file)
  {
    perror(ACCESSFILE);
    exit(1);
  }
  while(!feof(file))
  {
    if(NULL == fgets(buf,200,file)) buf[0] = 0;
    if(strlen(buf) > 5)
    {
      if(2 != sscanf(buf," %d %s ",&tmpUserId,tmpHostname))
      {
        fprintf(stderr,"Error parsing line in %s:\n\t%s\n",ACCESSFILE,buf);
        fclose(file);
      }
      if((tmpUserId == userId) && (!strcmp(tmpHostname,hostname))) allowed = 1;
    }
  }
  fclose(file);
  if(!allowed)
  {
    fprintf(stderr,"You are not allowed to use this program on
%s.\n",hostname);
    fprintf(stderr,"If you think this is an error, edit %s and add the line\n",
                     ACCESSFILE);
    fprintf(stderr,"\n%d %s\n",userId,hostname);
    exit(1);
  }

/* Try to suid root -- kermit barks otherwise */
  if(0 != setuid(0))
  {
    if(errno == EPERM)
    {
      fprintf(stderr,"Make sure this program is setuid root!\n");
      exit(1);
    }
    fprintf(stderr,"Setuid failled (I have no idea why!)\n");
    exit(1);
  }
/* Checking if everything is OK -- i.e. one argument, the number to be called
*/
  if(argc != 2)
  {
    fprintf(stderr,"USAGE:\n\tdialNumber NNNNNNN\n");
    exit(1);
  }
/* Creating a temp file and open it -- allow for (unlikely) race conditions */
  do
  {
    tmpnam(fname);
    file = fopen(fname,"w");
    count++;
  } while((count < 10) && (NULL == file));
  if(count == 10)
  {
    fprintf(stderr,"Too many tries to create temp file -- giving up\n");
    exit(1);
  }
/* Creating the kermit script */
  fprintf(file,"set line /dev/tty00\n");
  fprintf(file,"set speed 38400\n");
  fprintf(file,"set modem-dialer unknown\n");
  fprintf(file,"set dial init \\{13}\n");
  fprintf(file,"set dial dial-command \\{13}at%%s\\{13}\n");
  fprintf(file,"set parity none\n");
  fprintf(file,"o atdt 9%s\\{13}\n",argv[1]);
  fprintf(file,"sleep 4\n");
  fprintf(file,"o \\{13}atz\\{13}\n");
  fprintf(file,"exit\n");
  fclose(file);
/* Stopping the getty on the modem line */
  if(access("/etc/inittab.nomodem",R_OK) || access("/etc/inittab.modem",R_OK)
||
     access("/etc/inittab",W_OK) )
  {
    fprintf(stderr,"OUTCH!!!!\nProblem with /etc/inittab*\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    exit(1);
  }
  if(0 != system("/bin/cp /etc/inittab.nomodem /etc/inittab"))
  {
    fprintf(stderr,"OUTCH!!!!\n");
    fprintf(stderr,"Manipulating /etc/inittab* failled.\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    unlink(fname);
    exit(1);
  }
  if(0 != system("/sbin/init q"))
  {
    fprintf(stderr,"OUTCH!!!!\n");
    fprintf(stderr,"init q failled.\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    unlink(fname);
    exit(1);
  }

  sprintf(comline,"/opt/bin/kermit -y %s",fname);
  if(0 != system(comline))
  {
    fprintf(stderr,"Kermit command failled\n");
    exit(1);
  }
  unlink(fname);

/* Starting the getty on the modem line */
  if(access("/etc/inittab.nomodem",R_OK) || access("/etc/inittab.modem",R_OK)
||
     access("/etc/inittab",W_OK) )
  {
    fprintf(stderr,"OUTCH!!!!\nProblem with /etc/inittab*\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    exit(1);
  }
  if(0 != system("/bin/cp /etc/inittab.modem /etc/inittab"))
  {
    fprintf(stderr,"OUTCH!!!!\n");
    fprintf(stderr,"Manipulating /etc/inittab* failled.\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    exit(1);
  }
  if(0 != system("/sbin/init q"))
  {
    fprintf(stderr,"OUTCH!!!!\n");
    fprintf(stderr,"init q failled.\n");
    fprintf(stderr,"Contact Gyula NOW!\n");
    exit(1);
  }
}

=====================
5. From mclaughl_at_nssdc.gsfc.nasa.gov

Sure. There's are two programs called
mountcd and umountcd. If you'd like, I
can put them on one of our ftp servers.

=====================
6. From Andreas Priebe <apriebe_at_aip.de>

We use the automounter amd for this task.
To mount a CD simply cd to the directory (or otherwise open a file there),
to dismount you have to cd elsewhere (ie. close all opened files) and
wait while amd dismounts the CD automatically (usually 5 mins).

If you are running amd anyway it is a quick hack (I can provide you
with our configuration files, if you wish).

The main drawback of this solution, I think, is the long time to wait
for dismount.

=====================
7. From GLADNEY_at_stsci.edu

I have changed the protection scheme on /dev/rz4c (internal CD on my alpha 3000
model 600) to 666. This allows me to mount and umount the cd without becoming
root.

=====================
8. From "P.Thanigasalam" <P.Thanigasalam_at_cranfield.ac.uk>

One extremely effective way of doing this is to get hold of a program 'sudo'
which allows normal users to run specified programs as root. There is a
permissions configuration file to handle this. Then you get hold of scripts
(see below) to do the mount for you.

The script is executed by typing:
> sudo cdmount
or
> sudo cdumount

I can't take too much credit for this as my assistant did most of the
donkey-work with assistance from this mailing list.


****************************************************************************
CD MOUNT SCRIPT
****************************************************************************
#!/bin/sh
#
# mount local cdrom

RUNAS=`/usr/bin/whoami`
WHO=`/usr/bin/logname`
PROG=`/usr/bin/basename $0`

if [ "$RUNAS" != "root" ]
then
        /usr/bin/echo "usage: sudo $PROG"
        exit 1
fi

MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz1c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 0 ]
then
        /usr/bin/echo "${PROG}: CD-ROM already mounted on /mnt"
        exit 1
fi

/usr/sbin/mount -t ufs -rd /dev/rz1c /mnt 2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (as UFS file system) on /mnt"
        exit 0
fi

/usr/sbin/mount -t cdfs -r -o rrip,noversion,nodefperm /dev/rz1c /mnt
2>/dev/null
if [ $? -eq 0 ]
then
        /usr/bin/echo "CD-ROM mounted (CDFS file system) on /mnt"
        exit 0
fi

/usr/bin/echo "Unable to mount CD-ROM on /mnt"
exit 1


****************************************************************************
CD UNMOUNT SCRIPT
****************************************************************************
#!/bin/sh
#
# unmount local cdrom, eject

RUNAS=`/usr/bin/whoami`
WHO=`/usr/bin/logname`
PROG=`/usr/bin/basename $0`

if [ "$RUNAS" != "root" ]
then
        /usr/bin/echo "usage: sudo $PROG"
        exit 1
fi

MOUNTED=`/usr/sbin/mount | /usr/bin/grep "/dev/rz1c" | /usr/bin/wc -l`
if [ $MOUNTED -ne 1 ]
then
        /usr/bin/echo "${PROG}: No CD-ROM mounted"
        exit 1
fi

/usr/sbin/umount /mnt
/sbin/scu -f /dev/rrz1c eject

=====================
9. From Hellebo Knut <Knut.Hellebo_at_nho.hydro.com>

Write a simple C program (NOT a suid shellscript !!!!!) that execs a mount on
the specified dev. Make the executable suid. You're home.


Rob Naccarato
rob.naccarato_at_sheridanc.on.ca
Received on Mon Oct 23 1995 - 18:45:15 NZDT

This archive was generated by hypermail 2.4.0 : Wed Nov 08 2023 - 11:53:46 NZDT