/* ncpumount - Disconnects from permanent ncp connections Copyright (c) 1995 by Volker Lendecke Copyright (c) 2001 by Patrick Pollet Copyright (c) 2002 by Petr Vandrovec 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; 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Revision history: 0.00 1995 Volker Lendecke Initial revision. 1.00 1999, November 20 Petr Vandrovec Added license. 0.00(ncplogout) 2001, Feb 27 Patrick Pollet Initial revision. 1.00(ncplogout) 2001, March 10 Patrick Pollet Added test for installation as suidroot Added emission of word "failed" in every error line to make parsing easier from TCL/tk Corrected #218: testing memory after malloc() Corrected #238: NWCXIsSameServer() should not be called in theServer=NULL) Corrected #264: should not ignore error from NWCXGetPermConnInfo() Corrected #365: if -a, no -T nor -S allowed no -T and -S option Corrected #368: use a #define instead of 125 128 ... 1.02 2002, January 20 Petr Vandrovec Merged ncpumount and ncplogout, polished... /etc/mtab~ lock is now always removed when failure occurs with lock held. Use lockf() on /etc/mtab~ like util-linux do, and retry lock attempt couple of times. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "private/libintl.h" #define _(X) X static char *progname; static int is_ncplogout = 0; static void usage(void) { printf(_("usage: %s [options]\n"), progname); printf(_("usage: %s mount-point\n"), progname); } static void help(void) { printf(_("\n" "usage: %s [options]\n" " %s mount-point\n"), progname, progname); printf(_("\n" "mount-point Disconnect specified mount-point\n" "-a Disconnect all my connections (NDS and Bindery)\n" "-S servername Disconnect all connections (NDS and/or Bindery) to specified\n" " server\n" "-T treename Disconnect all NDS connections to specified tree\n" "-g Disconnect all connections to Netware for all users! (only\n" " root can use this flag)\n" "-h Print this help text\n" "\n")); } static void veprintf(const char* message, va_list ap) { if (is_ncplogout) { fprintf(stderr, "failed:"); } vfprintf(stderr, message, ap); } static void eprintf(const char* message, ...) { va_list ap; va_start(ap, message); veprintf(message, ap); va_end(ap); } static void alarmSignal(int sig) { (void)sig; } static void enableAlarm(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = alarmSignal; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGALRM); sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); } static int __clearMtab (const char* mount_points[], unsigned int numEntries) { // main logic from ncpumount.c struct mntent *mnt; FILE *mtab; FILE *new_mtab; #define MOUNTED_TMP MOUNTED".tmp" if ((mtab = setmntent(MOUNTED, "r")) == NULL){ eprintf(_("Can't open %s: %s\n"), MOUNTED, strerror(errno)); return 1; } if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL){ eprintf(_("Can't open %s: %s\n"), MOUNTED_TMP, strerror(errno)); endmntent(mtab); return 1; } while ((mnt = getmntent(mtab)) != NULL) { unsigned int i=0; int found=0; while (imnt_dir, mount_points[i]); i++; } if (!found) { addmntent(new_mtab, mnt); } } endmntent(mtab); if (fchmod(fileno(new_mtab), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0){ eprintf(_("Error changing mode of %s: %s\n"), MOUNTED_TMP, strerror(errno)); return 1; } endmntent(new_mtab); if (rename(MOUNTED_TMP, MOUNTED) < 0){ eprintf(_("Cannot rename %s to %s: %s\n"), MOUNTED, MOUNTED_TMP, strerror(errno)); return 1; } return 0; } static int clearMtab (const char* mount_points[], unsigned int numEntries) { int fd; int err; int retries = 10; if (!numEntries) return 0; /* don't waste time ! */ while ((fd = open(MOUNTED "~", O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) { struct timespec tm; if (errno != EEXIST || retries == 0) { eprintf(_("Can't get %s~ lock file: %s\n"), MOUNTED, strerror(errno)); return 1; } fd = open(MOUNTED "~", O_RDWR); if (fd != -1) { alarm(10); err = lockf(fd, F_LOCK, 0); alarm(0); close(fd); if (err) { eprintf(_("Can't lock lock file %s~: %s\n"), MOUNTED, _("Lock timed out")); return 1; } tm.tv_sec = 0; tm.tv_nsec = 20000000; nanosleep(&tm, NULL); } retries--; } alarm(1); lockf(fd, F_LOCK, 0); alarm(0); close(fd); err = __clearMtab(mount_points, numEntries); if ((unlink(MOUNTED "~") == -1) && (err == 0)){ eprintf(_("Can't remove %s~"), MOUNTED); return 1; } return err; } static int do_umount(const char *mount_point) { int fid = open(mount_point, O_RDONLY, 0); uid_t mount_uid; if (fid == -1) { eprintf(_("Could not open %s: %s\n"), mount_point, strerror(errno)); return -1; } if (ncp_get_mount_uid(fid, &mount_uid) != 0) { close(fid); eprintf(_("%s probably not ncp-filesystem\n"), mount_point); return -1; } if ((getuid() != 0) && (mount_uid != getuid())) { close(fid); eprintf(_("You are not allowed to umount %s\n"), mount_point); return -1; } close(fid); if (umount(mount_point) != 0) { eprintf(_("Could not umount %s: %s\n"), mount_point, strerror(errno)); return -1; } return 0; } static NWCCODE processServer(NWCONN_HANDLE conn, const char *theServer, const char* mount_points[], unsigned int * numEntries) { /* close the connection if any error or just before trying do_umount(). Caller does not have to do it */ NWCCODE err; char buffer[PATH_MAX + 1]; if (!conn) return 0; // already seen buffer[0]=0; err = NWCCGetConnInfo(conn,NWCC_INFO_MOUNT_POINT, sizeof(buffer), buffer); NWCCCloseConn(conn); if (err) { eprintf(_("NWCC_INFO_MOUNT_POINT failed: %s\n"), strnwerror(err)); return -1; } /* Connection must be closed before doing do_umount, otherwise umount will fail */ err = do_umount(buffer); if (!err) { char * aux=strdup(buffer); if (!aux) { eprintf(_("Not enough memory for strdup()\n")); return ENOMEM; } mount_points[(*numEntries)++]= aux; printf(_("Successfully logged out from %s\n"), theServer); } return err; } static NWCCODE processBindServers(NWCONN_HANDLE conns[], unsigned int curEntries, const char * theServer, const char* mount_points[], unsigned int * numEntries) { unsigned int i; for (i=0; i