[27223] in Source-Commits
/svn/athena r26030 - in trunk/athena/lib/locker: . debian man src
daemon@ATHENA.MIT.EDU (Alexander Chernyakhovsky)
Sun Jun 2 00:57:35 2013
Date: Sun, 2 Jun 2013 00:57:28 -0400
From: Alexander Chernyakhovsky <achernya@MIT.EDU>
Message-Id: <201306020457.r524vS6T005736@drugstore.mit.edu>
To: source-commits@MIT.EDU
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Author: achernya
Date: 2013-06-02 00:57:27 -0400 (Sun, 02 Jun 2013)
New Revision: 26030
Added:
trunk/athena/lib/locker/Makefile.am
trunk/athena/lib/locker/debian/debathena-liblocker.install
trunk/athena/lib/locker/m4/
trunk/athena/lib/locker/man/Makefile.am
trunk/athena/lib/locker/src/
trunk/athena/lib/locker/src/Makefile.am
trunk/athena/lib/locker/src/afs.c
trunk/athena/lib/locker/src/attach.c
trunk/athena/lib/locker/src/attachtab.c
trunk/athena/lib/locker/src/conf.c
trunk/athena/lib/locker/src/detach.c
trunk/athena/lib/locker/src/liblocker.pc.in
trunk/athena/lib/locker/src/locker.h
trunk/athena/lib/locker/src/locker_private.h
trunk/athena/lib/locker/src/misc.c
trunk/athena/lib/locker/src/miscfs.c
trunk/athena/lib/locker/src/mount.c
trunk/athena/lib/locker/src/mountpoint.c
trunk/athena/lib/locker/src/mul.c
trunk/athena/lib/locker/src/nfs.c
trunk/athena/lib/locker/src/util.c
trunk/athena/lib/locker/src/zephyr.c
Removed:
trunk/athena/lib/locker/Makefile.in
trunk/athena/lib/locker/afs.c
trunk/athena/lib/locker/attach.c
trunk/athena/lib/locker/attachtab.c
trunk/athena/lib/locker/conf.c
trunk/athena/lib/locker/detach.c
trunk/athena/lib/locker/locker.h
trunk/athena/lib/locker/locker_private.h
trunk/athena/lib/locker/misc.c
trunk/athena/lib/locker/miscfs.c
trunk/athena/lib/locker/mount.c
trunk/athena/lib/locker/mountpoint.c
trunk/athena/lib/locker/mul.c
trunk/athena/lib/locker/nfs.c
trunk/athena/lib/locker/util.c
trunk/athena/lib/locker/zephyr.c
Modified:
trunk/athena/lib/locker/configure.ac
trunk/athena/lib/locker/debian/changelog
trunk/athena/lib/locker/debian/control
trunk/athena/lib/locker/debian/rules
Log:
In locker:
* Convert to dh7
* Update build system to use automake
* Provide a pkg-config file
* Switch from pioctl to k_pioctl
* Don't build for squeeze and lucid, OpenAFS 1.4 is too old
Added: trunk/athena/lib/locker/Makefile.am
===================================================================
--- trunk/athena/lib/locker/Makefile.am (rev 0)
+++ trunk/athena/lib/locker/Makefile.am 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,2 @@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src man
Modified: trunk/athena/lib/locker/configure.ac
===================================================================
--- trunk/athena/lib/locker/configure.ac 2013-06-02 04:23:37 UTC (rev 26029)
+++ trunk/athena/lib/locker/configure.ac 2013-06-02 04:57:27 UTC (rev 26030)
@@ -1,39 +1,53 @@
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT([liblocker], [10.0.2])
-AC_CONFIG_SRCDIR([locker.h])
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ([2.65])
+AC_INIT([liblocker], [10.1], [debathena@mit.edu])
+AM_INIT_AUTOMAKE([foreign -Wall])
+AM_MAINTAINER_MODE([enable])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([src/afs.c])
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
AC_PROG_CC
-AC_PROG_INSTALL
-AC_PROG_RANLIB
-AC_PROG_MKDIR_P
+# automake 1.12 seems to require this, but automake 1.11 doesn't recognize it
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+LT_INIT
-AC_ARG_ENABLE([nfs],
- [AS_HELP_STRING([--enable-nfs], [support for kNFS lockers (deprecated)])])
+# Checks for libraries.
+RRA_LIB_KRB5
+RRA_LIB_KAFS
-if test "$enable_nfs" = "yes"; then
- AC_DEFINE([ENABLE_NFS],[1],[Support for kNFS lockers (deprecated).])
+# Checks for header files.
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/mount.h sys/param.h sys/socket.h unistd.h])
- AC_PATH_PROG(MOUNT_CMD, mount, , ${PATH}:/sbin:/usr/sbin)
- AC_PATH_PROG(UMOUNT_CMD, umount, , ${PATH}:/sbin:/usr/sbin)
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
- AC_MSG_CHECKING(if rpcsvc/mount.h needs sys/fs/nfs.h)
- AC_TRY_COMPILE([
-#include <rpc/rpc.h>
-#include <rpcsvc/mount.h>
- ], , AC_MSG_RESULT(no), AC_TRY_COMPILE([
-#include <rpc/rpc.h>
-#include <sys/fs/nfs.h>
-#include <rpcsvc/mount.h>
- ], , AC_MSG_RESULT(yes)
- AC_DEFINE(NEED_SYS_FS_NFS_H),
- AC_MSG_ERROR(couldn't include rpcsvc/mount.h)))
+# Checks for library functions.
+AC_FUNC_FORK
+AC_FUNC_GETGROUPS
+AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([alarm dup2 ftruncate getcwd gethostbyaddr gethostbyname inet_ntoa memmove memset mkdir regcomp rmdir strchr strcspn strdup strerror strncasecmp strrchr strtol strtoul uname])
- ATHENA_KRB4_REQUIRED
-fi
+# More stuff
+PKG_CHECK_MODULES([HESIOD], [hesiod])
+AC_SUBST([HESIOD_CFLAGS])
+AC_SUBST([HESIOD_LIBS])
+PKG_CHECK_MODULES([ZEPHYR], [zephyr])
+AC_SUBST([ZEPHYR_CFLAGS])
+AC_SUBST([ZEPHYR_LIBS])
-ATHENA_KRB5_REQUIRED
-ATHENA_AFS_REQUIRED
-ATHENA_HESIOD_REQUIRED
-
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile
+ src/Makefile
+ src/liblocker.pc
+ man/Makefile
+])
AC_OUTPUT
Modified: trunk/athena/lib/locker/debian/changelog
===================================================================
--- trunk/athena/lib/locker/debian/changelog 2013-06-02 04:23:37 UTC (rev 26029)
+++ trunk/athena/lib/locker/debian/changelog 2013-06-02 04:57:27 UTC (rev 26030)
@@ -1,9 +1,17 @@
-debathena-liblocker (10.0.2-0debathena2) UNRELEASED; urgency=low
+debathena-liblocker (10.1-0debathena1) UNRELEASED; urgency=low
+ [ Jonathan Reed ]
* Switch from control.in to control (Trac: #561)
* Bump Standards-Version to 3.9.3
* Bump compat level to 7
+ [ Alexander Chernyakhovsky ]
+ * Convert to dh7
+ * Update build system to use automake
+ * Provide a pkg-config file
+ * Switch from pioctl to k_pioctl
+ * Don't build for squeeze and lucid, OpenAFS 1.4 is too old
+
-- Jonathan Reed <jdreed@mit.edu> Wed, 03 Apr 2013 14:01:56 -0400
debathena-liblocker (10.0.2-0debathena1) unstable; urgency=low
Modified: trunk/athena/lib/locker/debian/control
===================================================================
--- trunk/athena/lib/locker/debian/control 2013-06-02 04:23:37 UTC (rev 26029)
+++ trunk/athena/lib/locker/debian/control 2013-06-02 04:57:27 UTC (rev 26030)
@@ -2,8 +2,9 @@
Section: debathena/libs
Priority: extra
Maintainer: Debathena Project <debathena@mit.edu>
-Build-Depends: cdbs, debhelper, dh-buildinfo, automake1.9, autoconf, autotools-dev, debathena-aclocal, libopenafs-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev
+Build-Depends: debhelper (>= 7.0.50~), dh-autoreconf, debathena-aclocal (>= 1.1.3), libopenafs-dev, libkrb5-dev, libhesiod-dev, libzephyr-dev
Standards-Version: 3.9.3
+X-Debathena-No-Build: squeeze lucid
Package: debathena-liblocker
Architecture: all
Added: trunk/athena/lib/locker/debian/debathena-liblocker.install
===================================================================
--- trunk/athena/lib/locker/debian/debathena-liblocker.install (rev 0)
+++ trunk/athena/lib/locker/debian/debathena-liblocker.install 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1 @@
+debian/attach.conf etc/athena/
Modified: trunk/athena/lib/locker/debian/rules
===================================================================
--- trunk/athena/lib/locker/debian/rules 2013-06-02 04:23:37 UTC (rev 26029)
+++ trunk/athena/lib/locker/debian/rules 2013-06-02 04:57:27 UTC (rev 26030)
@@ -1,29 +1,6 @@
#!/usr/bin/make -f
+%:
+ dh $@ --with autoreconf
-DEB_AUTO_UPDATE_AUTOCONF = 2.50
-DEB_AUTO_UPDATE_ACLOCAL = 1.9
-
-include /usr/share/cdbs/1/rules/debhelper.mk
-include /usr/share/cdbs/1/class/autotools.mk
-
-debian/stamp-autotools-files: aclocal.m4 config.guess config.sub install-sh missing
-aclocal.m4:
- touch $@
-config.guess config.sub:
- cp /usr/share/misc/$@ $@
-install-sh missing:
- -automake-1.9 --foreign --add-missing
-
-DEB_CONFIGURE_EXTRA_FLAGS += --with-afs=/usr --disable-nfs --with-krb5 --with-hesiod
-DEB_DH_INSTALL_SOURCEDIR = $(DEB_DESTDIR)
-DEB_UPDATE_RCD_PARAMS = "start 65 S ."
-
-ifeq ($(DEB_BUILD_ARCH),amd64)
- CFLAGS += -fPIC
-endif
-
-common-install-indep::
- dh_install -pdebathena-liblocker debian/attach.conf etc/athena/
-
-clean::
- rm -f configure aclocal.m4 install-sh missing config.guess config.sub
+override_dh_installinit:
+ dh_installinit -- start 65 S .
Added: trunk/athena/lib/locker/man/Makefile.am
===================================================================
--- trunk/athena/lib/locker/man/Makefile.am (rev 0)
+++ trunk/athena/lib/locker/man/Makefile.am 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,23 @@
+dist_man3_MANS = \
+ locker_attach.3 \
+ locker_attach_attachent.3 \
+ locker_attach_explicit.3 \
+ locker_auth.3 \
+ locker_auth_to_cell.3 \
+ locker_auth_to_host.3 \
+ locker_check_host.3 \
+ locker_check_owner.3 \
+ locker_detach.3 \
+ locker_detach_attachent.3 \
+ locker_detach_explicit.3 \
+ locker_do_zsubs.3 \
+ locker_end.3 \
+ locker_free_attachent.3 \
+ locker_init.3 \
+ locker_iterate_attachtab.3 \
+ locker_read_attachent.3 \
+ locker_zsubs.3
+
+dist_man5_MANS = \
+ attach.conf.5 \
+ attachtab.5
Added: trunk/athena/lib/locker/src/Makefile.am
===================================================================
--- trunk/athena/lib/locker/src/Makefile.am (rev 0)
+++ trunk/athena/lib/locker/src/Makefile.am 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,27 @@
+# Disable deprecated kNFS lockers
+AM_CFLAGS=-DMOUNT_CMD=\"/bin/false\" -DUMOUNT_CMD=\"/bin/false\"
+
+include_HEADERS = locker.h
+
+lib_LTLIBRARIES = liblocker.la
+liblocker_la_SOURCES = \
+ afs.c \
+ attach.c \
+ attachtab.c \
+ conf.c \
+ detach.c \
+ locker.h \
+ locker_private.h \
+ misc.c \
+ miscfs.c \
+ mount.c \
+ mountpoint.c \
+ mul.c \
+ nfs.c \
+ util.c \
+ zephyr.c
+
+liblocker_la_LIBADD = @KRB5_LIBS@ @HESIOD_LIBS@ @ZEPHYR_LIBS@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = liblocker.pc
Copied: trunk/athena/lib/locker/src/afs.c (from rev 25923, trunk/athena/lib/locker/afs.c)
===================================================================
--- trunk/athena/lib/locker/src/afs.c (rev 0)
+++ trunk/athena/lib/locker/src/afs.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,537 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements AFS lockers. */
+
+static const char rcsid[] = "$Id: afs.c,v 1.16 2006-08-08 21:50:09 ghudson Exp $";
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <afs/stds.h>
+#include <afs/param.h>
+#include <afs/auth.h>
+#include <afs/cellconfig.h>
+#include <afs/ptserver.h>
+#include <afs/ptuser.h>
+#include <afs/venus.h>
+#include <rx/rxkad.h>
+
+/* This is defined in <afs/volume.h>, but it doesn't seem possible to
+ * include that without dragging in most of the rest of the afs
+ * includes as dependencies.
+ */
+#define VNAMESIZE 32
+
+#include <com_err.h>
+#include <krb5.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+/* Cheesy test for determining AFS 3.5. */
+#ifndef AFSCONF_CLIENTNAME
+#define AFS35
+#endif
+
+#ifdef AFS35
+#include <afs/dirpath.h>
+#else
+#define AFSDIR_CLIENT_ETC_DIRPATH AFSCONF_CLIENTNAME
+#endif
+
+/*
+ * Why doesn't AFS provide this prototype?
+ */
+/*extern int k_pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32); */
+
+static int afs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **at);
+static int afs_attach(locker_context context, locker_attachent *at,
+ char *mountoptions);
+static int afs_detach(locker_context context, locker_attachent *at);
+static int afs_auth(locker_context context, locker_attachent *at,
+ int mode, int op);
+static int afs_zsubs(locker_context context, locker_attachent *at);
+
+struct locker_ops locker__afs_ops = {
+ "AFS",
+ 0,
+ afs_parse,
+ afs_attach,
+ afs_detach,
+ afs_auth,
+ afs_zsubs
+};
+
+static int afs_get_cred(krb5_context context, char *name, char *inst, char *realm,
+ krb5_creds **creds);
+static int afs_maybe_auth_to_cell(locker_context context, char *name,
+ char *cell, int op, int force);
+
+static int afs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+ locker_attachent *at;
+ char *p, *dup = NULL, *lasts = NULL;
+ int status;
+
+ at = locker__new_attachent(context, &locker__afs_ops);
+ if (!at)
+ return LOCKER_ENOMEM;
+
+ if (!name)
+ {
+ /* This is an explicit description. */
+
+ if (strncmp(desc, "/afs/", 5))
+ {
+ locker__error(context, "%s: Path is not in AFS.\n", desc);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+
+ at->name = strdup(desc);
+ at->hostdir = strdup(desc);
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ {
+ p = strrchr(desc, '/') + 1;
+ at->mountpoint = malloc(strlen(context->afs_mount_dir) +
+ strlen(p) + 2);
+ if (at->mountpoint)
+ sprintf(at->mountpoint, "%s/%s", context->afs_mount_dir, p);
+ }
+ if (!at->name || !at->hostdir || !at->mountpoint)
+ goto mem_error;
+
+ at->mode = LOCKER_AUTH_READWRITE;
+ }
+ else
+ {
+ /* A Hesiod AFS description looks like:
+ * AFS /afs/dev.mit.edu/source/src-current w /mit/source
+ */
+
+ at->name = strdup(name);
+ if (!at->name)
+ goto mem_error;
+
+ dup = strdup(desc);
+ if (!dup)
+ goto mem_error;
+
+ /* Skip "AFS". */
+ if (!strtok_r(dup, " ", &lasts))
+ goto parse_error;
+
+ /* Hostdir */
+ at->hostdir = strtok_r(NULL, " ", &lasts);
+ if (!at->hostdir)
+ goto parse_error;
+ if (strncmp(at->hostdir, "/afs/", 5))
+ {
+ locker__error(context, "%s: Path \"%s\" is not in AFS.\n", name,
+ at->hostdir);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+ at->hostdir = strdup(at->hostdir);
+ if (!at->hostdir)
+ goto mem_error;
+
+ /* Auth mode */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p || *(p + 1))
+ goto parse_error;
+
+ switch (*p)
+ {
+ case 'r':
+ at->mode = LOCKER_AUTH_READONLY;
+ break;
+ case 'w':
+ at->mode = LOCKER_AUTH_READWRITE;
+ break;
+ case 'n':
+ at->mode = LOCKER_AUTH_NONE;
+ break;
+ default:
+ locker__error(context, "%s: Unrecognized auth mode '%c' in "
+ "description:\n%s\n", name, *p, desc);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+
+ /* Mountpoint */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p)
+ goto parse_error;
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(p);
+ if (!at->mountpoint)
+ goto mem_error;
+
+ free(dup);
+ dup = NULL;
+ }
+
+ status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_MOST,
+ &(at->mountpoint), &(at->buildfrom));
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+
+ *atp = at;
+ return LOCKER_SUCCESS;
+
+mem_error:
+ locker__error(context, "Out of memory parsing locker description.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+
+parse_error:
+ locker__error(context, "Could not parse locker description "
+ "\"%s\".\n", desc);
+ status = LOCKER_EPARSE;
+
+cleanup:
+ free(dup);
+ locker_free_attachent(context, at);
+ return status;
+}
+
+static int afs_attach(locker_context context, locker_attachent *at,
+ char *mountoptions)
+{
+ struct stat st1, st2;
+ struct ViceIoctl vio;
+ afs_int32 hosts[8]; /* AFS docs say VIOCWHEREIS won't return more than 8. */
+ uid_t uid = geteuid();
+ int status;
+
+ /* Make sure user can read the destination, and it's a directory. */
+ if (uid != context->user)
+ seteuid(context->user);
+ status = lstat(at->hostdir, &st1);
+ if (uid != context->user)
+ seteuid(uid);
+
+ if (status == -1)
+ {
+ if (errno == ETIMEDOUT)
+ {
+ locker__error(context, "%s: Connection timed out while trying to "
+ "attach locker.\nThis probably indicates a temporary "
+ "problem with the file server containing\n"
+ "this locker. Try again later.\n", at->name);
+ }
+ else
+ {
+ locker__error(context, "%s: Could not attach locker:\n%s for %s\n",
+ at->name, strerror(errno), at->hostdir);
+ }
+ return LOCKER_EATTACH;
+ }
+ if (!S_ISDIR(st1.st_mode) && !S_ISLNK(st1.st_mode))
+ {
+ locker__error(context, "%s: Could not attach locker:\n"
+ "%s is not a directory.\n", at->name, at->hostdir);
+ return LOCKER_EATTACH;
+ }
+
+ /* Make sure nothing is already mounted on our mountpoint. */
+ status = stat(at->mountpoint, &st2);
+ if (!status)
+ {
+ /* Assume the automounter took care of it */
+ }
+ else
+ {
+ status = symlink(at->hostdir, at->mountpoint);
+ if (status < 0)
+ {
+ locker__error(context, "%s: Could not attach locker:\n%s while "
+ "symlinking %s to %s\n", at->name, strerror(errno),
+ at->hostdir, at->mountpoint);
+ return LOCKER_EATTACH;
+ }
+ }
+
+ /* Find host that the locker is on, and update the attachent. */
+ memset(hosts, 0, sizeof(hosts));
+ vio.in_size = 0;
+ vio.out = (caddr_t)hosts;
+ vio.out_size = sizeof(hosts);
+ if (k_pioctl(at->hostdir, VIOCWHEREIS, &vio, 1) == 0)
+ {
+ /* Only record the hostaddr if the locker is on a single host.
+ * (We assume that if it's on multiple hosts, it can't fail,
+ * so we don't need to know what those hosts are.)
+ */
+ if (!hosts[1])
+ at->hostaddr.s_addr = hosts[0];
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+static int afs_detach(locker_context context, locker_attachent *at)
+{
+ int status;
+
+ /* Let the automounter manage the symlink */
+ /* status = unlink(at->mountpoint);
+ if (status < 0)
+ {
+ if (errno == ENOENT)
+ {
+ locker__error(context, "%s: Locker is not attached.\n", at->name);
+ return LOCKER_ENOTATTACHED;
+ }
+ else
+ {
+ locker__error(context, "%s: Could not detach locker:\n%s while "
+ "trying to unlink %s.\n", at->name, strerror(errno),
+ at->mountpoint);
+ return LOCKER_EDETACH;
+ }
+ }
+ */
+ return LOCKER_SUCCESS;
+}
+
+static int afs_auth(locker_context context, locker_attachent *at,
+ int mode, int op)
+{
+ char *cell, *p;
+ int status;
+
+ if (op != LOCKER_AUTH_AUTHENTICATE)
+ return LOCKER_SUCCESS;
+
+ /* We know (from afs_parse) that at->hostdir starts with "/afs/". */
+ cell = at->hostdir + 5;
+ /* Skip initial "." in the cell name (if this is a path to a rw volume). */
+ if (*cell == '.')
+ cell++;
+
+ p = strchr(cell, '/');
+ if (p)
+ *p = '\0';
+ status = afs_maybe_auth_to_cell(context, at->name, cell, op, 0);
+ if (p)
+ *p = '/';
+ return status;
+}
+
+int locker_auth_to_cell(locker_context context, char *name, char *cell, int op)
+{
+ return afs_maybe_auth_to_cell(context, name, cell, op, 1);
+}
+
+static int afs_maybe_auth_to_cell(locker_context context, char *name,
+ char *cell, int op, int force)
+{
+ uid_t uid = geteuid(), ruid = getuid();
+ pid_t pid;
+ int stat_loc;
+
+ if (op != LOCKER_AUTH_AUTHENTICATE)
+ return LOCKER_SUCCESS;
+
+ pid = fork();
+ if (pid == -1)
+ {
+ locker__error(context, "%s: Unable to fork: %s\n",
+ name, error_message(errno));
+ return LOCKER_EAUTH;
+ }
+ else if (pid == 0)
+ {
+ if (uid != ruid)
+ seteuid(ruid);
+
+ close(0);
+ close(1);
+ close(2);
+ open("/dev/null", O_RDWR);
+ dup2(0, 1);
+ dup2(0, 2);
+
+ if (-1 == execlp("aklog", "aklog", "-c", cell, NULL))
+ exit(errno);
+ }
+ else
+ {
+ waitpid(pid, &stat_loc, 0);
+
+ if (0 != WEXITSTATUS(stat_loc))
+ {
+ locker__error(context, "%s: Error acquiring tokens: %s\n",
+ name, error_message(WEXITSTATUS(stat_loc)));
+ return LOCKER_EAUTH;
+ }
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+static int afs_get_cred(krb5_context context, char *name, char *inst, char *realm,
+ krb5_creds **creds)
+{
+ krb5_creds increds;
+ krb5_principal client_principal = NULL;
+ krb5_ccache krb425_ccache = NULL;
+ krb5_error_code retval = 0;
+
+ memset(&increds, 0, sizeof(increds));
+ /* ANL - instance may be ptr to a null string. Pass null then */
+ retval = krb5_build_principal(context, &increds.server, strlen(realm),
+ realm, name,
+ (inst && strlen(inst)) ? inst : NULL,
+ NULL);
+ if (retval)
+ goto fail;
+
+ retval = krb5_cc_default(context, &krb425_ccache);
+ if (retval)
+ goto fail;
+
+ retval = krb5_cc_get_principal(context, krb425_ccache, &client_principal);
+ if (retval)
+ goto fail;
+
+ increds.client = client_principal;
+ increds.times.endtime = 0;
+ /* Ask for DES since that is what V4 understands */
+ increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+
+ retval = krb5_get_credentials(context, 0, krb425_ccache, &increds, creds);
+
+fail:
+ krb5_free_cred_contents(context, &increds);
+ if (krb425_ccache)
+ krb5_cc_close(context, krb425_ccache);
+ return(retval);
+}
+
+static int afs_zsubs(locker_context context, locker_attachent *at)
+{
+ struct ViceIoctl vio;
+ char *path, *last_component, *p, *subs[3];
+ char cell[MAXCELLCHARS + 1], vol[VNAMESIZE + 1];
+ char cellvol[MAXCELLCHARS + VNAMESIZE + 2];
+ afs_int32 hosts[8];
+ int status = 0, pstatus;
+ struct hostent *h;
+
+ subs[0] = cell;
+ subs[1] = cellvol;
+
+ path = strdup(at->hostdir);
+ if (!path)
+ {
+ locker__error(context, "Out of memory getting zephyr subscriptions.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ /* Walk down the path. At each level, add subscriptions for the cell,
+ * host, and volume where that path component lives.
+ */
+ p = path;
+ do
+ {
+ /* Move trailing NUL over one pathname component. */
+ *p = '/';
+ p = strchr(p + 1, '/');
+ if (p)
+ *p = '\0';
+
+ /* Get cell */
+ vio.in_size = 0;
+ vio.out = cell;
+ vio.out_size = sizeof(cell);
+ if (k_pioctl(path, VIOC_FILE_CELL_NAME, &vio, 1) != 0)
+ continue;
+
+ /* Get mountpoint name and generate cell:mountpoint. */
+ last_component = strrchr(path, '/');
+ if (last_component)
+ {
+ *last_component++ = '\0';
+ vio.in = last_component;
+ }
+ else
+ vio.in = "/";
+ vio.in_size = strlen(vio.in) + 1;
+ vio.out = vol;
+ vio.out_size = sizeof(vol);
+ pstatus = k_pioctl(path, VIOC_AFS_STAT_MT_PT, &vio, 1);
+ if (last_component)
+ *(last_component - 1) = '/';
+
+ if (pstatus != 0)
+ continue;
+
+ /* Get cell:volumname into cellvol, ignoring initial '#' or '%'. */
+ if (strchr(vol, ':'))
+ strcpy(cellvol, vol + 1);
+ else
+ sprintf(cellvol, "%s:%s", cell, vol + 1);
+
+ /* If there's only one site for this volume, add the hostname
+ * of the server to the subs list.
+ */
+ memset(hosts, 0, 2 * sizeof(*hosts));
+ vio.out = (caddr_t)hosts;
+ vio.out_size = sizeof(hosts);
+ if (k_pioctl(path, VIOCWHEREIS, &vio, 1) != 0)
+ continue;
+ if (!hosts[1])
+ {
+ h = gethostbyaddr((char *)&hosts[0], 4, AF_INET);
+ if (!h)
+ continue;
+ subs[2] = h->h_name;
+ status = locker__add_zsubs(context, subs, 3);
+ }
+ else
+ status = locker__add_zsubs(context, subs, 2);
+ }
+ while (status == LOCKER_SUCCESS && strlen(path) != strlen(at->hostdir));
+
+ free(path);
+ return status;
+}
+
+/* librxkad depends on this symbol in Transarc's des library, which we
+ * can't link with because of conflicts with our krb4 library. It never
+ * gets called though.
+ */
+void des_pcbc_init(void)
+{
+ abort();
+}
Copied: trunk/athena/lib/locker/src/attach.c (from rev 25923, trunk/athena/lib/locker/attach.c)
===================================================================
--- trunk/athena/lib/locker/src/attach.c (rev 0)
+++ trunk/athena/lib/locker/src/attach.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,517 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements attaching lockers. */
+
+static const char rcsid[] = "$Id: attach.c,v 1.13 2006-07-25 23:29:09 ghudson Exp $";
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+
+#include <hesiod.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static int attach_attachent(locker_context context, locker_attachent *at,
+ int authmode, int options, char *mountoptions);
+static int try_local_copy(locker_context context, locker_attachent *at);
+static int check_mountoptions(locker_context context, locker_attachent *at,
+ int authmode, int options, char **mountoptions);
+static int add_owner(locker_context context, locker_attachent *at,
+ uid_t user);
+
+int locker_attach(locker_context context, char *filesystem, char *mountpoint,
+ int authmode, int options, char *mountoptions,
+ locker_attachent **atp)
+{
+ int status, astatus = LOCKER_EATTACH, order;
+ locker_attachent *at;
+
+ if (!context->trusted)
+ {
+ if (mountpoint && !context->exp_mountpoint)
+ {
+ locker__error(context, "%s: You are not allowed to specify "
+ "an explicit mountpoint.\n", filesystem);
+ return LOCKER_EPERM;
+ }
+ }
+
+ /* Try each Hesiod entry for the named filesystem until we run out
+ * or succeed in attaching one.
+ */
+ for (order = 1; ; order++)
+ {
+ status = locker__lookup_attachent(context, filesystem,
+ mountpoint, order, &at);
+ if (LOCKER_LOOKUP_FAILURE(status))
+ break;
+ if (status)
+ continue;
+
+ astatus = status = locker_attach_attachent(context, at, authmode,
+ options, mountoptions);
+ if (LOCKER_ATTACH_SUCCESS(status))
+ {
+ if (atp)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+ return status;
+ }
+
+ locker_free_attachent(context, at);
+ }
+
+ return status == LOCKER_ENOENT ? astatus : status;
+}
+
+int locker_attach_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint, int authmode,
+ int options, char *mountoptions,
+ locker_attachent **atp)
+{
+ int status;
+ locker_attachent *at;
+
+ if (!context->trusted)
+ {
+ if (!context->exp_desc)
+ {
+ locker__error(context, "%s: You are not allowed to specify "
+ "an explicit locker description.\n", desc);
+ return LOCKER_EPERM;
+ }
+
+ if (mountpoint && !context->exp_mountpoint)
+ {
+ locker__error(context, "%s: You are not allowed to specify "
+ "an explicit mountpoint.\n", desc);
+ return LOCKER_EPERM;
+ }
+ }
+
+ status = locker__lookup_attachent_explicit(context, type, desc,
+ mountpoint, 1, &at);
+ if (status)
+ return status;
+
+ status = locker_attach_attachent(context, at, authmode,
+ options, mountoptions);
+
+ if (LOCKER_ATTACH_SUCCESS(status) && atp)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+
+ return status;
+}
+
+int locker_attach_attachent(locker_context context, locker_attachent *at,
+ int authmode, int options, char *mountoptions)
+{
+ int status = LOCKER_SUCCESS;
+ locker_attachent *ai;
+
+ if (!context->trusted)
+ {
+ if (options & LOCKER_ATTACH_OPT_OVERRIDE)
+ {
+ locker__error(context, "%s: You are not authorized to use the "
+ "override option.\n", at->name);
+ return LOCKER_EPERM;
+ }
+ if (options & LOCKER_ATTACH_OPT_LOCK)
+ {
+ locker__error(context, "%s: You are not authorized to use the "
+ "lock option.\n", at->name);
+ return LOCKER_EPERM;
+ }
+ if (options & LOCKER_ATTACH_OPT_ALLOW_SETUID)
+ {
+ locker__error(context, "%s: You are not authorized to use the "
+ "setuid option.\n", at->name);
+ return LOCKER_EPERM;
+ }
+ }
+
+ /* If this is a MUL locker, attach sublockers first. */
+ for (ai = at->next; ai && status == LOCKER_SUCCESS; ai = ai->next)
+ status = attach_attachent(context, ai, authmode, options, mountoptions);
+
+ if (!LOCKER_ATTACH_SUCCESS(status))
+ {
+ locker__error(context, "%s: MUL attach failed.\n", at->name);
+ return status;
+ }
+
+ return attach_attachent(context, at, authmode, options, mountoptions);
+}
+
+/* This is the routine that does all of the work of attaching a single
+ * filesystem.
+ */
+static int attach_attachent(locker_context context, locker_attachent *at,
+ int authmode, int options, char *mountoptions)
+{
+ int status;
+ char *origmountoptions = mountoptions;
+
+ if (!(options & LOCKER_ATTACH_OPT_OVERRIDE))
+ {
+ /* Make sure this locker is allowed. */
+ if (!locker__fs_ok(context, context->allow, at->fs, at->name))
+ {
+ locker__error(context, "%s: You are not allowed to attach this "
+ "locker.\n", at->name);
+ return LOCKER_EPERM;
+ }
+
+ /* Make sure this mountpoint is allowed. */
+ if (strcmp(at->fs->name, "MUL") &&
+ !locker__fs_ok(context, context->mountpoint, at->fs, at->mountpoint))
+ {
+ locker__error(context, "%s: You are not allowed to attach a "
+ "locker on %s\n", at->name, at->mountpoint);
+ return LOCKER_EPERM;
+ }
+ }
+
+ /* Authenticate. */
+ if (authmode == LOCKER_AUTH_DEFAULT)
+ authmode = at->mode;
+ if ((authmode != LOCKER_AUTH_NONE) &&
+ (!at->attached || (options & LOCKER_ATTACH_OPT_REAUTH)))
+ {
+ status = at->fs->auth(context, at, authmode, LOCKER_AUTH_AUTHENTICATE);
+ if (status != LOCKER_SUCCESS && authmode != LOCKER_AUTH_MAYBE_READWRITE)
+ return status;
+ }
+
+ if (!at->attached)
+ {
+ /* Check and update the mountoptions. */
+ if (locker__fs_ok(context, context->setuid, at->fs, at->name))
+ {
+ options |= LOCKER_ATTACH_OPT_ALLOW_SETUID;
+ at->flags &= ~LOCKER_FLAG_NOSUID;
+ }
+ status = check_mountoptions(context, at, authmode, options,
+ &mountoptions);
+ if (status != LOCKER_SUCCESS)
+ return status;
+
+ /* Build the mountpoint if all of the directories don't exist. */
+ status = locker__build_mountpoint(context, at);
+ if (status != LOCKER_SUCCESS)
+ {
+ free(mountoptions);
+ return status;
+ }
+
+ /* Attach the locker. Look for a local copy first. */
+ if (!(options & LOCKER_ATTACH_OPT_MASTER) && try_local_copy(context, at))
+ status = LOCKER_SUCCESS;
+ else
+ status = at->fs->attach(context, at, mountoptions);
+ free(mountoptions);
+ if (status == LOCKER_EALREADY)
+ {
+ if (context->keep_mount)
+ at->flags |= LOCKER_FLAG_KEEP;
+ }
+ else if (status != LOCKER_SUCCESS)
+ {
+ locker__remove_mountpoint(context, at);
+ return status;
+ }
+
+ /* Release the lock on the directory we have just created. */
+ locker__put_mountpoint(context, at);
+ }
+ else
+ status = LOCKER_EALREADY;
+
+ if (origmountoptions && status == LOCKER_EALREADY)
+ {
+ locker__error(context, "Warning: %s is already attached. "
+ "Ignoring mountoptions '%s'\n", at->name,
+ origmountoptions);
+ }
+
+ /* Update attachent on disk. */
+ at->attached = 1;
+ add_owner(context, at, context->user);
+ if (options & LOCKER_ATTACH_OPT_LOCK)
+ at->flags |= LOCKER_FLAG_LOCKED;
+ if (!(options & LOCKER_ATTACH_OPT_ALLOW_SETUID))
+ at->flags |= LOCKER_FLAG_NOSUID;
+ locker__update_attachent(context, at);
+
+ /* Record zephyr subscriptions. */
+ if (options & LOCKER_ATTACH_OPT_ZEPHYR)
+ at->fs->zsubs(context, at);
+
+ return status;
+}
+
+/* Look for a symlink at {context->local_dir}/{at->name}. If it
+ * exists, it should point to a local copy of the locker which has
+ * been created with athlsync(8) via /etc/athena/local-lockers. Copy
+ * this symlink instead of actually attaching the locker.
+ */
+static int try_local_copy(locker_context context, locker_attachent *at)
+{
+ char *path, linkbuf[MAXPATHLEN + 1];
+ int len;
+
+ /* Read the symlink, if it exists. */
+ path = malloc(strlen(context->local_dir) + 1 + strlen(at->name) + 1);
+ if (path == NULL)
+ return 0;
+ sprintf(path, "%s/%s", context->local_dir, at->name);
+ len = readlink(path, linkbuf, sizeof(linkbuf) - 1);
+ free(path);
+ if (len == -1)
+ return 0;
+ linkbuf[len] = '\0';
+
+ path = strdup(linkbuf);
+ if (path == NULL)
+ return 0;
+ if (symlink(path, at->mountpoint) == -1)
+ {
+ free(path);
+ return 0;
+ }
+ free(at->hostdir);
+ at->hostdir = path;
+ at->fs = locker__get_fstype(context, "LOC");
+ return 1;
+}
+
+/* This is a helper function used by check_mountoptions to determine
+ * if two strings affect the same option (either identically or
+ * oppositely). o1 and o2 are the option names, l1 and l2 are their
+ * lengths.
+ */
+static int same_option(char *o1, int l1, char *o2, int l2)
+{
+ int cmp;
+
+ /* If one is an explicit negation of the other, they're "the same". */
+ if ((l1 == l2 + 2) && !strncmp(o1, "no", 2) && !strncmp(o1 + 2, o2, l2))
+ return 1;
+ else if ((l2 == l1 + 2) && !strncmp(o2, "no", 2) && !strncmp(o1, o2 + 2, l1))
+ return 1;
+
+ cmp = strncmp(o1, o2, l1 < l2 ? l1 : l2);
+ if (cmp == 0)
+ cmp = l1 - l2;
+ if (cmp == 0)
+ return 1;
+
+ /* Make sure o1 comes first alphabetically to cut down on the number
+ * of comparisons.
+ */
+ if (cmp > 0)
+ {
+ char *tmp = o1;
+ int ltmp = l1;
+ o1 = o2;
+ l1 = l2;
+ o2 = tmp;
+ l2 = ltmp;
+ }
+
+ if (!strncmp(o1, "bg", l1) && !strncmp(o2, "fg", l2))
+ return 1;
+ else if (!strncmp(o1, "ro", l1) && !strncmp(o2, "rw", l2))
+ return 1;
+ else if (!strncmp(o1, "hard", l1) && !strncmp(o2, "soft", l2))
+ return 1;
+
+ /* They're different. */
+ return 0;
+}
+
+/* This function constructs a complete string of mount options for the
+ * filesystem based on the authmode, options, mountoptions, and
+ * attach.conf.
+ */
+static int check_mountoptions(locker_context context, locker_attachent *at,
+ int authmode, int options, char **mountoptions)
+{
+ char *mo, *req, *def, *allow, *p, *q;
+ int len;
+
+ req = locker__fs_data(context, context->reqopts, at->fs, at->name);
+ def = locker__fs_data(context, context->defopts, at->fs, at->name);
+ allow = locker__fs_data(context, context->allowopts, at->fs, at->name);
+
+ /* Malloc a string large enough to hold all necessary mount options. */
+ len = 1;
+ if (*mountoptions)
+ len += strlen(*mountoptions) + 1;
+ if (req)
+ len += strlen(req) + 1;
+ if (def)
+ len += strlen(def) + 1;
+ if (!(options & LOCKER_ATTACH_OPT_ALLOW_SETUID))
+ len += 7;
+ if (authmode != LOCKER_AUTH_NONE)
+ len += 3;
+ mo = malloc(len);
+ if (!mo)
+ {
+ locker__error(context, "Out of memory checking mountoptions.\n");
+ return LOCKER_ENOMEM;
+ }
+ *mo = '\0';
+
+ /* Later mountoptions will override earlier ones. So we copy them in
+ * in the order: defaults, authmode, mountoptions, setuid (from
+ * options), and finally the mountoptions specified by attach.conf.
+ * This means that an explicitly specified "ro" or "rw" will
+ * override the default locker mode, an explicitly specified "suid"
+ * will NOT override an enforced "nosuid", and nothing will override
+ * the attach.conf-mandated options. In addition to this, we have to
+ * verify that each option specified in mountoptions is allowed at
+ * all.
+ */
+
+ if (def)
+ sprintf(mo, "%s,", def);
+ if (authmode == LOCKER_AUTH_READONLY)
+ strcat(mo, "ro,");
+ else if (authmode != LOCKER_AUTH_NONE)
+ strcat(mo, "rw,");
+ p = mo + strlen(mo);
+ if (*mountoptions)
+ sprintf(p, "%s,", *mountoptions);
+
+ /* Interlude: check user-specified mountoptions */
+ while (p && *p)
+ {
+ /* Get the length of the option pointed to by p. */
+ len = strcspn(p, "=,");
+
+ /* See if this option appears in the allowed options list. */
+ q = allow;
+ while (q)
+ {
+ if (!strncmp(p, q, len))
+ break;
+
+ q = strchr(q, ',');
+ if (q)
+ q++;
+ }
+
+ if (!q)
+ {
+ /* Option not allowed. Silently discard it. */
+ q = strchr(p, ',');
+ if (q)
+ memmove(p, q + 1, strlen(q + 1) + 1);
+ else
+ *p = '\0';
+ }
+ else
+ {
+ p = strchr(p, ',');
+ if (p)
+ p++;
+ }
+ }
+
+ /* Now continue appending options. */
+ if (!(options & LOCKER_ATTACH_OPT_ALLOW_SETUID))
+ strcat(mo, "nosuid,");
+ if (req)
+ strcat(mo, req);
+
+ /* If mo ends with a comma, remove it. */
+ len = strlen(mo);
+ if (mo[len - 1] == ',')
+ mo[len - 1] = '\0';
+
+ /* Finally, go back through and remove duplicates and contradictions. */
+ p = mo;
+ while (p)
+ {
+ q = strchr(p, ',');
+ if (q)
+ {
+ /* Read through options, looking for a match for p. If p
+ * starts with "no", also look for a match without the "no".
+ * If p doesn't start with "no", look for a match with "no".
+ */
+ while (q)
+ {
+ q++;
+ if (same_option(p, strcspn(p, "=,"), q, strcspn(q, "=,")))
+ break;
+ q = strchr(q, ',');
+ }
+
+ /* If we found a match, delete the first occurrence. */
+ if (q)
+ {
+ q = strchr(p, ','); /* We know this won't return NULL here. */
+ memmove(p, q + 1, strlen(q + 1) + 1);
+ }
+ else
+ {
+ p = strchr(p, ',');
+ if (p)
+ p++;
+ }
+ }
+ else
+ break;
+ }
+
+ *mountoptions = mo;
+ return LOCKER_SUCCESS;
+}
+
+static int add_owner(locker_context context, locker_attachent *at, uid_t user)
+{
+ int i;
+ uid_t *new;
+
+ for (i = 0; i < at->nowners; i++)
+ {
+ if (at->owners[i] == user)
+ return LOCKER_SUCCESS;
+ }
+
+ new = realloc(at->owners, (at->nowners + 1) * sizeof(uid_t));
+ if (!new)
+ {
+ locker__error(context, "Out of memory adding new owner to "
+ "attachtab entry.\n");
+ return LOCKER_ENOMEM;
+ }
+ at->owners = new;
+ at->owners[at->nowners++] = user;
+ return LOCKER_SUCCESS;
+}
Copied: trunk/athena/lib/locker/src/attachtab.c (from rev 25923, trunk/athena/lib/locker/attachtab.c)
===================================================================
--- trunk/athena/lib/locker/src/attachtab.c (rev 0)
+++ trunk/athena/lib/locker/src/attachtab.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,1266 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements the attachtab directory,
+ * which contains files corresponding to attached (or formerly attached)
+ * lockers.
+ */
+
+static const char rcsid[] = "$Id: attachtab.c,v 1.11 2002-02-18 15:50:26 ghudson Exp $";
+
+#include "locker.h"
+#include "locker_private.h"
+
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Used internally by locker_iterate_attachtab */
+struct locker__dirent {
+ char *name;
+ time_t ctime;
+};
+
+static int delete_attachent(locker_context context, locker_attachent *at);
+static int get_attachent(locker_context context, char *name,
+ char *mountpoint, int create,
+ locker_attachent **atp);
+static int read_attachent(locker_context context, int kind,
+ char *name, locker_attachent **atp);
+static int lock_attachtab(locker_context context, int *lock);
+static void unlock_attachtab(locker_context context, int *lock);
+static int compare_locker__dirents(const void *a, const void *b);
+
+/* Public interface to locker__lookup_attachent. */
+int locker_read_attachent(locker_context context, char *name,
+ locker_attachent **atp)
+{
+ return locker__lookup_attachent(context, name, NULL, 0, atp);
+}
+
+/* Look up a locker by filesys name and return an attachent for it. If
+ * "which" is 0, only return an already-attached locker. Otherwise,
+ * "which" is the index of the Hesiod filesys entry for "name" to look
+ * up. (The caller can keep calling with successively higher values of
+ * "which" until it succeeds in attaching one, or
+ * locker__lookup_attachent returns a LOCKER_LOOKUP_FAILURE() status.
+ *
+ * name can be NULL iff mountpoint is non-NULL and which is 0.
+ */
+int locker__lookup_attachent(locker_context context, char *name,
+ char *mountpoint, int which,
+ locker_attachent **atp)
+{
+ int status, i, lock;
+ locker_attachent *at;
+ char **descs, *desc, *p;
+ void *cleanup;
+ struct locker_ops *fs;
+
+ status = lock_attachtab(context, &lock);
+ if (status != LOCKER_SUCCESS)
+ return status;
+
+ if (which < 2)
+ {
+ /* Look for a pre-attached locker. */
+ at = NULL;
+ status = get_attachent(context, name, mountpoint, 0, &at);
+ if (status != LOCKER_ENOTATTACHED)
+ {
+ unlock_attachtab(context, &lock);
+ if (status == LOCKER_SUCCESS)
+ *atp = at;
+ return status;
+ }
+ else if (!which)
+ {
+ unlock_attachtab(context, &lock);
+ locker__error(context, "%s: Not attached.\n",
+ name ? name : mountpoint);
+ return status;
+ }
+ }
+
+ /* It's not attached. Look up the locker description. */
+ status = locker_lookup_filsys(context, name, &descs, &cleanup);
+ if (status)
+ {
+ unlock_attachtab(context, &lock);
+ return status;
+ }
+
+ if (!descs[1])
+ {
+ /* If only one description, it won't have an order field. */
+ if (which == 1)
+ desc = descs[0];
+ else
+ desc = NULL;
+ }
+ else
+ {
+ /* Check each filesystem description until we find the one we want. */
+ for (i = 0, desc = NULL; descs[i]; i++)
+ {
+ p = strrchr(descs[i], ' ');
+ if (!p)
+ {
+ unlock_attachtab(context, &lock);
+ locker_free_filesys(context, descs, cleanup);
+ locker__error(context, "%s: Could not parse locker "
+ "description \"%s\".\n", name, descs[i]);
+ return LOCKER_EPARSE;
+ }
+
+ if (atoi(p + 1) == which)
+ {
+ desc = descs[i];
+ break;
+ }
+ }
+ }
+
+ if (!desc)
+ {
+ unlock_attachtab(context, &lock);
+ locker_free_filesys(context, descs, cleanup);
+ return LOCKER_ENOENT;
+ }
+
+ fs = locker__get_fstype(context, desc);
+ if (!fs)
+ {
+ unlock_attachtab(context, &lock);
+ locker__error(context, "%s: Unknown locker type in description "
+ "\"%s\".\n", name, desc);
+ locker_free_filesys(context, descs, cleanup);
+ return LOCKER_EPARSE;
+ }
+
+ status = fs->parse(context, name, desc, mountpoint, &at);
+ locker_free_filesys(context, descs, cleanup);
+ if (status)
+ {
+ unlock_attachtab(context, &lock);
+ return status;
+ }
+
+ if (mountpoint)
+ status = get_attachent(context, NULL, at->mountpoint, which != 0, &at);
+ else
+ status = get_attachent(context, name, at->mountpoint, which != 0, &at);
+ unlock_attachtab(context, &lock);
+ if (status == LOCKER_SUCCESS)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+
+ return status;
+}
+
+/* Look up a locker by explicit description and return an attachent
+ * for it. If "create" is 0, only return an already-attached locker.
+ */
+int locker__lookup_attachent_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint,
+ int create, locker_attachent **atp)
+{
+ struct locker_ops *fs;
+ locker_attachent *at;
+ int status, lock;
+
+ fs = locker__get_fstype(context, type);
+ if (!fs)
+ {
+ locker__error(context, "%s: Unknown locker type \"%s\".\n", desc, type);
+ return LOCKER_EPARSE;
+ }
+
+ status = fs->parse(context, NULL, desc, mountpoint, &at);
+ if (status)
+ return status;
+
+ status = lock_attachtab(context, &lock);
+ if (status != LOCKER_SUCCESS)
+ {
+ locker_free_attachent(context, at);
+ return status;
+ }
+ status = get_attachent(context, NULL, at->mountpoint, create, &at);
+ unlock_attachtab(context, &lock);
+ if (status == LOCKER_SUCCESS)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+
+ return status;
+}
+
+/* Delete an attachent file and its corresponding symlink, if any. */
+static int delete_attachent(locker_context context, locker_attachent *at)
+{
+ int status, lock;
+ char *path;
+
+ status = lock_attachtab(context, &lock);
+ if (status != LOCKER_SUCCESS)
+ return status;
+
+ if (at->flags & LOCKER_FLAG_NAMEFILE)
+ {
+ path = locker__attachtab_pathname(context, LOCKER_NAME, at->name);
+ if (!path)
+ {
+ locker__error(context, "Out of memory deleting attachent.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ if (unlink(path) == -1 && errno != ENOENT)
+ {
+ locker__error(context, "Could not delete file %s:\n%s.\n",
+ path, strerror(errno));
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+ free(path);
+ }
+
+ path = locker__attachtab_pathname(context, LOCKER_MOUNTPOINT,
+ at->mountpoint);
+ if (!path)
+ {
+ locker__error(context, "Out of memory deleting attachent.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ if (unlink(path) == -1)
+ {
+ locker__error(context, "Could not delete file %s:\n%s.\n",
+ path, strerror(errno));
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+ free(path);
+
+ unlock_attachtab(context, &lock);
+ return LOCKER_SUCCESS;
+
+cleanup:
+ free(path);
+ unlock_attachtab(context, &lock);
+ return status;
+}
+
+/* Free a locker_attachent and unlock any locks associated with it. */
+void locker_free_attachent(locker_context context, locker_attachent *at)
+{
+ if (at->mountpoint_file)
+ {
+ fclose(at->mountpoint_file);
+ if (!at->attached && at->mountpoint)
+ delete_attachent(context, at);
+ }
+ if (at->dirlockfd)
+ close(at->dirlockfd);
+ free(at->name);
+ free(at->mountpoint);
+ free(at->buildfrom);
+ free(at->hostdir);
+ free(at->owners);
+
+ if (at->next)
+ locker_free_attachent(context, at->next);
+
+ free(at);
+}
+
+
+/* Iterate through all attachent entries, calling the "test" function
+ * on each one, and then calling the "act" function on all entries for
+ * which the "test" function returns true. Holds an exclusive lock on
+ * the attachtab lock file through the duration of the call. Only
+ * returns an error if it was unable to begin iterating through the
+ * entries.
+ */
+int locker_iterate_attachtab(locker_context context,
+ locker_callback test, void *testarg,
+ locker_callback act, void *actarg)
+{
+ int status, lock;
+ char *path;
+ DIR *dir;
+ struct dirent *entry;
+ locker_attachent *at;
+ struct locker__dirent *files = NULL;
+ int nfiles = 0, filessize = 0, i;
+ struct stat st;
+
+ status = lock_attachtab(context, &lock);
+ if (status)
+ return status;
+
+ path = locker__attachtab_pathname(context, LOCKER_MOUNTPOINT, "");
+ if (!path)
+ {
+ unlock_attachtab(context, &lock);
+ locker__error(context, "Out of memory reading attachtab.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ dir = opendir(path);
+ if (!dir)
+ {
+ unlock_attachtab(context, &lock);
+ locker__error(context, "Could not read attachtab:\n%s opening "
+ "directory %s\n", strerror(errno), path);
+ free(path);
+ return LOCKER_EATTACHTAB;
+ }
+
+ while ((entry = readdir(dir)))
+ {
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (nfiles >= filessize)
+ {
+ struct locker__dirent *newfiles;
+ int newfilessize;
+
+ newfilessize = filessize ? 2 * filessize : 10;
+ newfiles = realloc(files, (newfilessize) * sizeof(*files));
+ if (!newfiles)
+ {
+ status = LOCKER_ENOMEM;
+ break;
+ }
+ files = newfiles;
+ filessize = newfilessize;
+ }
+
+ files[nfiles].name = malloc(strlen(path) + strlen(entry->d_name) + 1);
+ if (!files[nfiles].name)
+ {
+ status = LOCKER_ENOMEM;
+ break;
+ }
+ sprintf(files[nfiles].name, "%s%s", path, entry->d_name);
+
+ if (stat(files[nfiles].name, &st) != 0)
+ {
+ locker__error(context, "%s while reading attachtab entry\n\"%s\".\n",
+ strerror(errno), files[nfiles].name);
+ status = LOCKER_EATTACHTAB;
+ break;
+ }
+
+ files[nfiles++].ctime = st.st_ctime;
+ }
+ closedir(dir);
+ free(path);
+
+ if (status != LOCKER_SUCCESS)
+ {
+ if (status == LOCKER_ENOMEM)
+ locker__error(context, "Out of memory reading attachtab.\n");
+
+ unlock_attachtab(context, &lock);
+ goto cleanup;
+ }
+
+ /* Sort the entries. */
+ qsort(files, nfiles, sizeof(*files), compare_locker__dirents);
+
+ /* Unlock the attachtab directory, since callbacks might take a while. */
+ unlock_attachtab(context, &lock);
+
+ /* Now run through the callbacks. */
+ for (i = 0; i < nfiles; i++)
+ {
+ status = read_attachent(context, LOCKER_FULL_PATH, files[i].name, &at);
+ if (status == LOCKER_SUCCESS)
+ {
+ if (!test || test(context, at, testarg))
+ act(context, at, actarg);
+ locker_free_attachent(context, at);
+ }
+ }
+ status = LOCKER_SUCCESS;
+
+cleanup:
+ for (i = 0; i < nfiles; i++)
+ free(files[i].name);
+ free(files);
+
+ return status;
+}
+
+static int compare_locker__dirents(const void *a, const void *b)
+{
+ const struct locker__dirent *da = a, *db = b;
+
+ /* MUL lockers (which have spaces in their "mountpoint" names) are
+ * sorted before all other lockers. Other than that, lockers are
+ * sorted by attachent creation time.
+ */
+
+ if (strchr(da->name, ' '))
+ {
+ if (!strchr(db->name, ' '))
+ return -1;
+ }
+ else if (strchr(db->name, ' '))
+ return 1;
+
+ return (da->ctime < db->ctime) ? -1 : (da->ctime > db->ctime) ? 1 : 0;
+}
+
+
+/* Fetch the desired attachtab entry into a struct attachtab. name is
+ * the locker name and mountpoint is its mountpoint. If create is non-0
+ * an empty attachtab entry will be created if none exists.
+ *
+ * name may be NULL. mountpoint may be NULL if name is not. *atp should
+ * be a partially-filled in attachent if create is true. Otherwise it
+ * can be partially-filled in, or NULL.
+ */
+static int get_attachent(locker_context context, char *name,
+ char *mountpoint, int create,
+ locker_attachent **atp)
+{
+ locker_attachent *at = NULL;
+ int fd = 0;
+ FILE *fp = NULL;
+ int status;
+ char *path = NULL;
+ struct flock fl;
+ mode_t omask;
+
+ /* Try opening an existing file */
+ if (mountpoint)
+ status = read_attachent(context, LOCKER_MOUNTPOINT, mountpoint, &at);
+ else
+ status = read_attachent(context, LOCKER_NAME, name, &at);
+
+ if (status == LOCKER_SUCCESS)
+ {
+ /* If caller passed in both mountpoint and name, make sure they
+ * both matched.
+ */
+ if (mountpoint && name && strcmp(name, at->name))
+ {
+ locker__error(context, "%s: %s is already attached on %s.\n",
+ name, at->name, mountpoint);
+ locker_free_attachent(context, at);
+ return LOCKER_EMOUNTPOINTBUSY;
+ }
+
+ /* Otherwise, if no attachent was passed in, we've won. */
+ if (!*atp)
+ {
+ *atp = at;
+ return status;
+ }
+
+ /* Make sure the found attachent matches the passed-in attachent. */
+ if (strcmp(at->name, (*atp)->name) ||
+ strcmp(at->mountpoint, (*atp)->mountpoint) ||
+ strcmp(at->hostdir, (*atp)->hostdir) ||
+ at->fs != (*atp)->fs)
+ {
+ locker__error(context, "%s: %s is already attached on %s.\n",
+ (*atp)->name, at->name, at->mountpoint);
+ locker_free_attachent(context, at);
+ return LOCKER_EMOUNTPOINTBUSY;
+ }
+
+ /* Free the passed-in attachent and return the found one. */
+ locker_free_attachent(context, *atp);
+ *atp = at;
+ return LOCKER_SUCCESS;
+ }
+ else if (status != LOCKER_ENOTATTACHED)
+ return status;
+
+ /* If we were looking for something already attached, we lose. (But
+ * don't print an error: this might not be fatal.)
+ */
+ if (!create)
+ return LOCKER_ENOTATTACHED;
+
+ path = locker__attachtab_pathname(context, LOCKER_MOUNTPOINT, mountpoint);
+ if (!path)
+ return LOCKER_ENOMEM;
+
+ omask = umask(0);
+ fd = open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ umask(omask);
+ if (fd == -1)
+ {
+ locker__error(context, "Could not create attachtab file %s:\n%s.\n",
+ path, strerror(errno));
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+
+ fp = fdopen(fd, "r+");
+ if (!fp)
+ {
+ locker__error(context, "Could not create attachtab file %s:\n%s.\n",
+ path, strerror(errno));
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = fl.l_len = 0;
+ status = fcntl(fileno(fp), F_SETLKW, &fl);
+ if (status < 0)
+ {
+ locker__error(context, "Could not lock attachtab file %s:\n%s.\n",
+ path, strerror(errno));
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+
+ if (name)
+ {
+ char *npath;
+ npath = locker__attachtab_pathname(context, LOCKER_NAME, name);
+ if (!npath)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ unlink(npath);
+ if (symlink(path, npath) < 0)
+ {
+ locker__error(context, "Could not symlink %s\n to %s: %s.\n",
+ path, npath, strerror(errno));
+ free(npath);
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+ free(npath);
+ (*atp)->flags |= LOCKER_FLAG_NAMEFILE;
+ }
+
+ free(path);
+
+ (*atp)->mountpoint_file = fp;
+ return LOCKER_SUCCESS;
+
+cleanup:
+ if (fp || fd > 0)
+ {
+ unlink(path);
+ if (fp)
+ fclose(fp);
+ else
+ close(fd);
+ }
+ if (path)
+ free(path);
+ if (at)
+ free(at);
+ return status;
+}
+
+/* The format of a mountpoint file is:
+ *
+ * version (currently 1)
+ * hesiod or explicit name
+ * mountpoint
+ * fstype
+ * IP addr of host (or 0.0.0.0)
+ * path to locker
+ * auth mode
+ * flags
+ * # of owners:owner uid:owner uid:...
+ *
+ */
+
+/* Copy data from a locker_attachent into the corresponding file. */
+void locker__update_attachent(locker_context context, locker_attachent *at)
+{
+ int i;
+
+ if (at->attached)
+ {
+ sigset_t omask, mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGQUIT);
+ sigaddset(&mask, SIGTERM);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+
+ rewind(at->mountpoint_file);
+ fprintf(at->mountpoint_file, "1\n%s\n%s\n%s\n%s\n%s\n%c\n%d\n",
+ at->name, at->mountpoint, at->fs->name, inet_ntoa(at->hostaddr),
+ at->hostdir, at->mode, at->flags);
+
+ fprintf(at->mountpoint_file, "%d", at->nowners);
+ for (i = 0; i < at->nowners; i++)
+ fprintf(at->mountpoint_file, ":%ld", (long)at->owners[i]);
+ fprintf(at->mountpoint_file, "\n");
+ fflush(at->mountpoint_file);
+
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+ else
+ {
+ ftruncate(fileno(at->mountpoint_file), 0);
+ rewind(at->mountpoint_file);
+ }
+}
+
+/* Read the named attachtab file into a locker_attachent. */
+static int read_attachent(locker_context context, int kind, char *name,
+ locker_attachent **atp)
+{
+ FILE *fp;
+ char *path, *pmem = NULL, *buf = NULL, *p, *q;
+ int bufsize, status, i;
+ struct flock fl;
+ locker_attachent *at;
+ struct stat st1, st2;
+
+ if (kind != LOCKER_FULL_PATH)
+ {
+ path = pmem = locker__attachtab_pathname(context, kind, name);
+ if (!path)
+ return LOCKER_ENOMEM;
+ }
+ else
+ path = name;
+
+ /* Need to open it read/write so we can get an F_WRLCK. */
+ fp = fopen(path, "r+");
+ if (!fp)
+ {
+ if (errno == ENOENT)
+ {
+ free(pmem);
+ return LOCKER_ENOTATTACHED;
+ }
+
+ locker__error(context, "Could not open attachtab file %s:\n%s.\n",
+ path, strerror(errno));
+ free(pmem);
+ return LOCKER_EATTACHTAB;
+ }
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = fl.l_len = 0;
+ status = fcntl(fileno(fp), F_SETLKW, &fl);
+ if (status < 0)
+ {
+ fclose(fp);
+ locker__error(context, "Could not lock attachtab file %s:\n%s.\n",
+ path, strerror(errno));
+ free(pmem);
+ return LOCKER_EATTACHTAB;
+ }
+
+ /* The file might have been deleted while we were waiting on the lock.
+ * Worse yet, someone else might have created a new one after the one
+ * we're waiting for was deleted, but before the deleter gave up its
+ * lock. So check first that it's there, and second that it's still
+ * the right file.
+ */
+ if (stat(path, &st1) == -1)
+ {
+ fclose(fp);
+ if (errno == ENOENT)
+ {
+ free(pmem);
+ return LOCKER_ENOTATTACHED;
+ }
+ else
+ {
+ locker__error(context, "Could not stat attachent file %s:\n%s.\n",
+ path, strerror(errno));
+ free(pmem);
+ return LOCKER_EATTACHTAB;
+ }
+ }
+ if (fstat(fileno(fp), &st2) == -1)
+ {
+ fclose(fp);
+ locker__error(context, "Could not fstat attachent file %s:\n%s.\n",
+ path, strerror(errno));
+ free(pmem);
+ return LOCKER_EATTACHTAB;
+ }
+ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ {
+ fclose(fp);
+ free(pmem);
+ return LOCKER_ENOTATTACHED;
+ }
+ if (st1.st_size == 0)
+ {
+ /* "This can't happen." (Ha ha) */
+ unlink(path);
+ fclose(fp);
+ free(pmem);
+ return LOCKER_ENOTATTACHED;
+ }
+ free(pmem);
+
+ /* Start building the attachent. */
+ at = locker__new_attachent(context, NULL);
+ if (!at)
+ {
+ fclose(fp);
+ return LOCKER_ENOMEM;
+ }
+
+ at->mountpoint_file = fp;
+ at->attached = 1;
+
+ /* Read version number. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ if (atoi(buf) != 1)
+ {
+ locker__error(context, "Could not parse attachtab file %s:\n"
+ "unknown version number \"%s\".\n", name, buf);
+ status = LOCKER_EATTACHTAB;
+ goto cleanup2;
+ }
+
+ /* Read locker name. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->name = strdup(buf);
+ if (!at->name)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ /* Read mountpoint. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->mountpoint = strdup(buf);
+ if (!at->mountpoint)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ /* Read fstype. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->fs = locker__get_fstype(context, buf);
+ if (!at->fs)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ /* Read hostaddr. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->hostaddr.s_addr = inet_addr(buf);
+
+ /* Read hostdir. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->hostdir = strdup(buf);
+ if (!at->hostdir)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ /* Read mode */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->mode = buf[0];
+
+ /* Read flags */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->flags = atoi(buf);
+
+ /* Read list of owners. */
+ status = locker__read_line(fp, &buf, &bufsize);
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+ at->nowners = strtol(buf, &p, 10);
+ if (p == buf || (*p && *p != ':'))
+ {
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+ at->owners = malloc(at->nowners * sizeof(uid_t));
+ if (!at->owners)
+ {
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ for (i = 0, p++; i < at->nowners && p; i++, p = q + 1)
+ {
+ at->owners[i] = strtol(p, &q, 10);
+ if (p == q || (*q && *q != ':'))
+ {
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+ }
+ if (i < at->nowners)
+ {
+ status = LOCKER_EATTACHTAB;
+ goto cleanup;
+ }
+
+ free(buf);
+
+ /* If this is a MUL locker, use mul_parse to read in the other
+ * attachents.
+ */
+ if (!strcmp(at->fs->name, "MUL"))
+ {
+ locker_attachent *atm;
+
+ status = at->fs->parse(context, at->name, at->mountpoint, NULL, &atm);
+ if (status)
+ goto cleanup;
+
+ /* Swap the parsed attachent's MUL chain into the one we read off
+ * disk, and then dispose of the parsed one.
+ */
+ at->next = atm->next;
+ atm->next = NULL;
+ locker_free_attachent(context, atm);
+ }
+
+ *atp = at;
+ return LOCKER_SUCCESS;
+
+cleanup:
+ if (status == LOCKER_EATTACHTAB)
+ {
+ locker__error(context, "Invalid line in attachtab file %s:%s\n",
+ name, buf);
+ }
+ else if (status == LOCKER_EMOUNTPOINTBUSY)
+ locker__error(context, "%s: Mountpoint busy.\n", at->mountpoint);
+ else if (status == LOCKER_ENOMEM)
+ locker__error(context, "Out of memory reading attachtab file.\n");
+ else
+ {
+ locker__error(context, "Unexpected %s while reading attachtab "
+ "file %s.\n", status == LOCKER_EOF ? "end of file" :
+ "file error", name);
+ status = LOCKER_EATTACHTAB;
+ }
+cleanup2:
+ free(buf);
+ locker_free_attachent(context, at);
+ return status;
+}
+
+/* Lock the attachtab directory. This must be done in order to:
+ * - create an attachent
+ * - delete an attachent
+ * - create a symlink from mountpoints/ to lockers/
+ * - prevent other processes from doing the above, to guarantee
+ * a consistent view of the attachtab.
+ */
+static int lock_attachtab(locker_context context, int *lock)
+{
+ int status;
+ char *path;
+ struct flock fl;
+ mode_t o_umask;
+
+ /* If the attachtab is already locked (because we're reading a
+ * subcomponent of a MUL locker, for instance), just record an
+ * additional lock and return success.
+ */
+ if (context->locks)
+ {
+ context->locks++;
+ return LOCKER_SUCCESS;
+ }
+
+ path = locker__attachtab_pathname(context, LOCKER_LOCK, ".lock");
+ if (!path)
+ {
+ locker__error(context, "Out of memory in lock_attachtab.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ o_umask = umask(0);
+ *lock = open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ free (path);
+ umask(o_umask);
+ if (*lock < 0)
+ {
+ locker__error(context, "Could not open attachtab lock file: %s.\n",
+ strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = fl.l_len = 0;
+ status = fcntl(*lock, F_SETLKW, &fl);
+ if (status < 0)
+ {
+ close(*lock);
+ locker__error(context, "Could not lock attachtab: %s.\n",
+ strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+
+ context->locks++;
+ return LOCKER_SUCCESS;
+}
+
+static void unlock_attachtab(locker_context context, int *lock)
+{
+ if (--context->locks == 0)
+ close(*lock);
+}
+
+static char *kpath[] = {
+ ".", /* LOCK */
+ "locker", /* NAME */
+ "mountpoint", /* MOUNTPOINT */
+ "directory", /* DIRECTORY */
+};
+
+char *locker__attachtab_pathname(locker_context context,
+ int kind, char *name)
+{
+ int len;
+ char *path, *s, *d;
+
+ len = strlen(context->attachtab) + strlen(kpath[kind]) + strlen(name) + 3;
+ for (path = name; *path; path++)
+ {
+ if (*path == '/' || *path == '_')
+ len++;
+ }
+
+ path = malloc(len);
+ if (!path)
+ {
+ locker__error(context, "Out of memory reading attachent.\n");
+ return NULL;
+ }
+
+ sprintf(path, "%s/%s/", context->attachtab, kpath[kind]);
+ d = path + strlen(path);
+
+ for (s = name; *s; s++)
+ {
+ switch (*s)
+ {
+ case '/':
+ *d++ = '_';
+ *d++ = '=';
+ break;
+
+ case '_':
+ *d++ = '_';
+ /* fall through */
+
+ default:
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+
+ return path;
+}
+
+locker_attachent *locker__new_attachent(locker_context context,
+ struct locker_ops *type)
+{
+ locker_attachent *at;
+
+ at = malloc(sizeof(locker_attachent));
+ if (!at)
+ {
+ locker__error(context, "Out of memory creating attachent.\n");
+ return NULL;
+ }
+
+ memset(at, 0, sizeof(locker_attachent));
+ at->name = at->mountpoint = at->hostdir = at->buildfrom = NULL;
+ at->owners = NULL;
+ at->mountpoint_file = NULL;
+ at->next = NULL;
+
+ at->fs = type;
+ return at;
+}
+
+
+/* Convert an old attachtab file into a new attachtab directory */
+int locker_convert_attachtab(locker_context context, char *oattachtab)
+{
+ FILE *fp;
+ char *buf = NULL;
+ int bufsize, status;
+ char *p, *lasts = NULL, *host, *name;
+ int rmdir;
+ locker_attachent *at;
+ struct locker_ops *fs;
+
+ fp = fopen(oattachtab, "r");
+ if (!fp)
+ {
+ locker__error(context, "Could not open %s: %s.\n", oattachtab,
+ strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+
+ while ((status = locker__read_line(fp, &buf, &bufsize)) == LOCKER_SUCCESS)
+ {
+ /* Check attachtab version. */
+ if (strncmp(buf, "A1 ", 3))
+ {
+ locker__error(context, "Ignoring unrecognized attachtab line: %s\n",
+ buf);
+ continue;
+ }
+
+ /* Check if it's attached, attaching, or detaching. */
+ if (buf[4] != '+')
+ {
+ locker__error(context, "Ignoring not-fully-attached locker: %s\n",
+ buf);
+ continue;
+ }
+
+ /* Get fs type. */
+ p = strtok_r(buf + 5, " ", &lasts);
+ fs = locker__get_fstype(context, p);
+ if (!fs)
+ {
+ locker__error(context, "Ignoring unknown locker type \"%s\"\n", p);
+ continue;
+ }
+ at = locker__new_attachent(context, fs);
+ if (!at)
+ {
+ locker__error(context, "Out of memory.\n");
+ status = LOCKER_ENOMEM;
+ break;
+ }
+
+ /* Now start parsing. First name. */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ at->name = strdup(p);
+
+ /* Host */
+ host = strtok_r(NULL, " ", &lasts);
+
+ /* Directory */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ {
+ if (!strcmp(at->fs->name, "MUL"))
+ {
+ /* Old attachtab stores MUL components as hostdir. We store
+ * it as mountpoint.
+ */
+
+ char *q;
+ /* Convert commas to spaces */
+ for (q = p; *q; q++)
+ {
+ if (*q == ',')
+ *q = ' ';
+ }
+
+ at->mountpoint = strdup(p);
+ at->hostdir = strdup("");
+ }
+ else if (host && strcmp(host, "localhost"))
+ {
+ at->hostdir = malloc(strlen(host) + strlen(p) + 2);
+ if (at->hostdir)
+ sprintf(at->hostdir, "%s:%s", host, p);
+ }
+ else
+ at->hostdir = strdup(p);
+ }
+
+ /* IP addr */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ at->hostaddr.s_addr = inet_addr(p);
+
+ /* Number of directories to rm on detach.
+ * Needs special conversion later.
+ */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ rmdir = atoi(p);
+
+ /* Mountpoint */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p && strcmp(at->fs->name, "MUL"))
+ at->mountpoint = strdup(p);
+
+ /* Convert old flags to new flags */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ {
+ int oflags = atoi(p);
+ if (oflags & 0x1)
+ at->flags |= LOCKER_FLAG_NOSUID;
+ if (oflags & 0x2)
+ at->flags |= LOCKER_FLAG_LOCKED;
+ if (oflags & 0x8)
+ at->flags |= LOCKER_FLAG_KEEP;
+ }
+
+ /* Comma-separated list of owners */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ {
+ char *q = p;
+
+ do
+ {
+ at->nowners++;
+ q++;
+ }
+ while ((q = strchr(q, ',')));
+
+ at->owners = malloc(at->nowners * sizeof(uid_t));
+ if (at->owners)
+ {
+ int i;
+ for (i = 0; i < at->nowners; i++)
+ {
+ at->owners[i] = strtoul(p, &p, 10);
+ p++;
+ }
+ }
+ }
+
+ /* RVD drivenum -- Ignored */
+ p = strtok_r(NULL, " ", &lasts);
+
+ /* And mount mode */
+ p = strtok_r(NULL, " ", &lasts);
+ if (p)
+ at->mode = *p;
+
+ /* Make sure we got all that */
+ if (!p || !at->name || !at->hostdir || !at->mountpoint || !at->owners)
+ {
+ locker__error(context, "Parse error or out of memory.\n");
+ status = LOCKER_EATTACHTAB;
+ break;
+ }
+
+ at->attached = 1;
+ if (buf[3] == '0')
+ {
+ at->flags |= LOCKER_FLAG_NAMEFILE;
+ name = at->name;
+ }
+ else
+ name = NULL;
+
+ status = get_attachent(context, name, at->mountpoint, 1, &at);
+ if (status != LOCKER_SUCCESS)
+ {
+ locker__error(context, "Could not create attachent for %s.\n",
+ at->name);
+ locker_free_attachent(context, at);
+ continue;
+ }
+
+ locker__update_attachent(context, at);
+
+ /* Due to a bug in the old attach, rmdir will be "1" instead of "0"
+ * if you attach an AFS locker in an immediate subdir of "/".
+ */
+ if (rmdir == 1 && !strchr(at->mountpoint + 1, '/'))
+ rmdir--;
+
+ /* Now record the directories to delete on detach. */
+ while (rmdir--)
+ {
+ int fd;
+ char *file = locker__attachtab_pathname(context, LOCKER_DIRECTORY,
+ at->mountpoint);
+ if (!file)
+ {
+ locker__error(context, "Out of memory.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+
+ fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1 && errno != EEXIST)
+ {
+ locker__error(context, "Could not create directory data file "
+ "%s:\n%s.\n", file, strerror(errno));
+ free(file);
+ continue;
+ }
+ free(file);
+ close(fd);
+
+ p = strrchr(at->mountpoint, '/');
+ if (!p || p == at->mountpoint)
+ break;
+ *p = '\0';
+ }
+
+ locker_free_attachent(context, at);
+ }
+
+cleanup:
+ fclose(fp);
+ free(buf);
+
+ return status;
+}
Copied: trunk/athena/lib/locker/src/conf.c (from rev 25923, trunk/athena/lib/locker/conf.c)
===================================================================
--- trunk/athena/lib/locker/src/conf.c (rev 0)
+++ trunk/athena/lib/locker/src/conf.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,572 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements reading attach.conf. */
+
+static const char rcsid[] = "$Id: conf.c,v 1.10 2006-08-08 21:50:09 ghudson Exp $";
+
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <com_err.h>
+#include <hesiod.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+extern struct locker_ops locker__err_ops, locker__mul_ops, locker__afs_ops;
+extern struct locker_ops locker__nfs_ops, locker__ufs_ops, locker__loc_ops;
+
+#define LOCKER_ALL_FSTYPES (-1L)
+
+static void free_regexp_list(struct locker__regexp_list lst, int strings);
+
+static int parse_bool(locker_context context, char *line, void *val);
+static int parse_string(locker_context context, char *line, void *val);
+static int parse_trusted_list(locker_context context, char *line, void *val);
+static int parse_regex_list_yes(locker_context context, char *line, void *val);
+static int parse_regex_list_no(locker_context context, char *line, void *val);
+static int parse_regex_list(locker_context context, char *line,
+ struct locker__regexp_list *val, int flag);
+static int parse_fs_list(locker_context context, char *line, void *val);
+static int add_regexp(locker_context context, struct locker__regexp_list *val,
+ char *regexp);
+static int parse_obsolete(locker_context context, char *line, void *val);
+
+static struct opt_def {
+ char *name;
+ int (*parse)(locker_context, char *, void *);
+ size_t offset;
+} conf_options[] = {
+ /* Boolean options */
+ { "explicit", parse_bool, offsetof(struct locker_context, exp_desc) },
+ { "explicit-mntpt", parse_bool, offsetof(struct locker_context, exp_mountpoint) },
+ { "keep-mount", parse_bool, offsetof(struct locker_context, keep_mount) },
+ { "nfs-root-hack", parse_bool, offsetof(struct locker_context, nfs_root_hack) },
+ { "ownercheck", parse_bool, offsetof(struct locker_context, ownercheck) },
+ { "use-krb4", parse_bool, offsetof(struct locker_context, use_krb4) },
+
+ /* String options */
+ { "afs-mount-dir", parse_string, offsetof(struct locker_context, afs_mount_dir) },
+ { "attachtab", parse_string, offsetof(struct locker_context, attachtab) },
+ { "local-dir", parse_string, offsetof(struct locker_context, local_dir) },
+ { "nfs-mount-dir", parse_string, offsetof(struct locker_context, nfs_mount_dir) },
+
+ /* Trusted user list */
+ { "trusted", parse_trusted_list, offsetof(struct locker_context, trusted) },
+
+ /* Regexp list options */
+ { "allow", parse_regex_list_yes, offsetof(struct locker_context, allow) },
+ { "noallow", parse_regex_list_no, offsetof(struct locker_context, allow) },
+ { "mountpoint", parse_regex_list_yes, offsetof(struct locker_context, mountpoint) },
+ { "nomountpoint", parse_regex_list_no, offsetof(struct locker_context, mountpoint) },
+ { "setuid", parse_regex_list_yes, offsetof(struct locker_context, setuid) },
+ { "suid", parse_regex_list_yes, offsetof(struct locker_context, setuid) },
+ { "nosetuid", parse_regex_list_no, offsetof(struct locker_context, setuid) },
+ { "nosuid", parse_regex_list_no, offsetof(struct locker_context, setuid) },
+
+ /* Filesystem regexp and argument options */
+ { "allowoptions", parse_fs_list, offsetof(struct locker_context, allowopts) },
+ { "defoptions", parse_fs_list, offsetof(struct locker_context, defopts) },
+ { "filesystem", parse_fs_list, offsetof(struct locker_context, filesystem) },
+ { "options", parse_fs_list, offsetof(struct locker_context, reqopts) },
+
+ /* Obsolete options */
+ { "aklog", parse_obsolete, 0 },
+ { "debug", parse_obsolete, 0 },
+ { "fsck", parse_obsolete, 0 },
+ { "mtab", parse_obsolete, 0 },
+ { "ownerlist", parse_obsolete, 0 },
+ { "verbose", parse_obsolete, 0 },
+};
+
+static int noptions = sizeof(conf_options) / sizeof(struct opt_def);
+
+int locker_init(locker_context *contextp, uid_t user,
+ locker_error_fun errfun, void *errdata)
+{
+ locker_context context;
+ FILE *fp;
+ char *buf = NULL, *p, *q;
+ int i, size, status;
+
+ context = *contextp = malloc(sizeof(struct locker_context));
+ if (!context)
+ {
+ locker__error(context, "Out of memory reading attach.conf.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ /* Set defaults. */
+ memset(context, 0, sizeof(struct locker_context));
+ if (errfun)
+ {
+ context->errfun = errfun;
+ context->errdata = errdata;
+ }
+ else
+ context->errfun = NULL;
+ context->nfs_root_hack = context->exp_desc = context->exp_mountpoint = 1;
+ context->afs_mount_dir = strdup(LOCKER_AFS_MOUNT_DIR);
+ context->attachtab = strdup(LOCKER_PATH_ATTACHTAB);
+ context->local_dir = strdup(LOCKER_PATH_LOCAL);
+ if (!context->afs_mount_dir || !context->attachtab)
+ {
+ locker__error(context, "Out of memory reading attach.conf.\n");
+ locker_end(context);
+ return LOCKER_ENOMEM;
+ }
+ context->nfs_mount_dir = NULL;
+ context->user = user;
+ if (context->user == 0)
+ context->trusted = 1;
+ context->zsubs = NULL;
+
+ context->setuid.tab = NULL;
+ context->setuid.defflag = 1;
+ context->allow.tab = NULL;
+ context->allow.defflag = 1;
+ context->mountpoint.tab = NULL;
+ context->mountpoint.defflag = 1;
+ context->filesystem.tab = NULL;
+ context->reqopts.tab = NULL;
+ context->defopts.tab = NULL;
+ context->allowopts.tab = NULL;
+
+ /* Filesystem defaults. */
+ context->nfstypes = 6;
+ context->fstype = malloc(context->nfstypes * sizeof(struct locker_ops *));
+ if (!context->fstype)
+ {
+ locker__error(context, "Out of memory reading attach.conf.\n");
+ locker_end(context);
+ return LOCKER_ENOMEM;
+ }
+ context->fstype[0] = &locker__err_ops;
+ context->fstype[1] = &locker__mul_ops;
+ context->fstype[2] = &locker__afs_ops;
+ context->fstype[3] = &locker__nfs_ops;
+ context->fstype[4] = &locker__ufs_ops;
+ context->fstype[5] = &locker__loc_ops;
+ for (i = 0; i < context->nfstypes; i++)
+ context->fstype[i]->id = 1 << i;
+
+ fp = fopen(LOCKER_PATH_ATTACH_CONF, "r");
+ if (!fp)
+ {
+ locker__error(context, "%s while trying to open attach.conf.\n",
+ strerror(errno));
+ locker_end(context);
+ return LOCKER_EATTACHCONF;
+ }
+
+ while ((status = locker__read_line(fp, &buf, &size)) == 0)
+ {
+ if (!buf[0] || buf[0] == '#')
+ continue;
+
+ p = buf;
+ while (isspace((unsigned char)*p))
+ p++;
+ q = p;
+ while (*q && !isspace((unsigned char)*q))
+ q++;
+
+ for (i = 0; i < noptions; i++)
+ {
+ if (!strncmp(conf_options[i].name, p, q - p) &&
+ !conf_options[i].name[q - p])
+ break;
+ }
+ if (i == noptions)
+ {
+ locker__error(context, "Unrecognized attach.conf line:\n%s\n", buf);
+ locker_end(context);
+ free(buf);
+ fclose(fp);
+ return LOCKER_EATTACHCONF;
+ }
+ else
+ {
+ while (*q && isspace((unsigned char)*q))
+ q++;
+ status = conf_options[i].parse(context, q,
+ ((char *)context +
+ conf_options[i].offset));
+ }
+
+ if (status)
+ break;
+ }
+
+ free(buf);
+ fclose(fp);
+
+ if (status && status != LOCKER_EOF)
+ {
+ if (status == LOCKER_ENOMEM)
+ locker__error(context, "Out of memory reading attach.conf.\n");
+ else if (status == LOCKER_EFILE)
+ {
+ locker__error(context, "Error reading attach.conf:\n%s\n",
+ strerror(errno));
+ status = LOCKER_EATTACHCONF;
+ }
+ else
+ locker__error(context, "Bad attach.conf line: \"%s\"\n", buf);
+
+ locker_end(context);
+ return status;
+ }
+
+ status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_NONE,
+ &context->attachtab, NULL);
+ if (status)
+ {
+ locker_end(context);
+ return status;
+ }
+
+ /* Initialize Hesiod. */
+ if (hesiod_init(&context->hes_context) != 0)
+ {
+ locker__error(context, "Could not create locker context:\n"
+ "%s while initializing Hesiod.\n", strerror(errno));
+ locker_end(context);
+ return LOCKER_EHESIOD;
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+void locker_end(locker_context context)
+{
+ free(context->afs_mount_dir);
+ free(context->attachtab);
+ free(context->nfs_mount_dir);
+ free(context->local_dir);
+ free(context->fstype);
+ free_regexp_list(context->setuid, 0);
+ free_regexp_list(context->allow, 0);
+ free_regexp_list(context->mountpoint, 0);
+ free_regexp_list(context->filesystem, 1);
+ free_regexp_list(context->reqopts, 1);
+ free_regexp_list(context->defopts, 1);
+ free_regexp_list(context->allowopts, 1);
+
+ if (context->hes_context)
+ hesiod_end(context->hes_context);
+ locker__free_zsubs(context);
+
+ free(context);
+}
+
+static void free_regexp_list(struct locker__regexp_list lst, int strings)
+{
+ int i;
+
+ for (i = 0; i < lst.num; i++)
+ {
+ regfree(&(lst.tab[i].pattern));
+ if (strings)
+ free(lst.tab[i].data.string);
+ }
+ free(lst.tab);
+}
+
+static int parse_bool(locker_context context, char *line, void *val)
+{
+ int *boolval = val;
+
+ /* Nothing = yes */
+ if (!*line)
+ {
+ *boolval = 1;
+ return LOCKER_SUCCESS;
+ }
+
+ if (!strcmp(line, "on"))
+ *boolval = 1;
+ else if (!strcmp(line, "off"))
+ *boolval = 0;
+ else
+ {
+ locker__error(context, "Unrecognized boolean value \"%s\".\n", line);
+ return LOCKER_EATTACHCONF;
+ }
+ return LOCKER_SUCCESS;
+}
+
+static int parse_string(locker_context context, char *line, void *val)
+{
+ char **strval = val;
+
+ free(*strval);
+ *strval = strdup(line);
+
+ if (!*strval)
+ return LOCKER_ENOMEM;
+ return LOCKER_SUCCESS;
+}
+
+static int parse_trusted_list(locker_context context, char *line, void *val)
+{
+ int *trusted = val;
+ char *lasts = NULL;
+
+ for (line = strtok_r(line, " \t", &lasts); line;
+ line = strtok_r(NULL, " \t", &lasts))
+ {
+ if (isdigit((unsigned char)*line) && context->user == atoi(line))
+ *trusted = 1;
+ else
+ {
+ struct passwd *pw;
+
+ pw = getpwnam(line);
+ if (!pw)
+ continue;
+ if (pw->pw_uid == context->user)
+ *trusted = 1;
+ }
+ }
+ return LOCKER_SUCCESS;
+}
+
+static int parse_regex_list_yes(locker_context context, char *line, void *val)
+{
+ return parse_regex_list(context, line, val, 1);
+}
+
+static int parse_regex_list_no(locker_context context, char *line, void *val)
+{
+ return parse_regex_list(context, line, val, 0);
+}
+
+static int parse_regex_list(locker_context context, char *line,
+ struct locker__regexp_list *val, int flag)
+{
+ int status = LOCKER_SUCCESS;
+ char *data, *dup = strdup(line), *lasts = NULL;
+
+ if (!dup)
+ return LOCKER_ENOMEM;
+ for (data = strtok_r(dup, " \t", &lasts); data && !status;
+ data = strtok_r(NULL, " \t", &lasts))
+ {
+ status = add_regexp(context, val, data);
+ if (status == LOCKER_SUCCESS)
+ val->tab[val->num++].data.flag = flag;
+ }
+ free(dup);
+ return status;
+}
+
+static int parse_fs_list(locker_context context, char *line, void *val)
+{
+ int status;
+ char *data = strdup(line), *lasts = NULL;
+ struct locker__regexp_list *lst = val;
+
+ if (!data)
+ return LOCKER_ENOMEM;
+
+ line = strtok_r(data, " \t", &lasts);
+ if (!line || !lasts)
+ return LOCKER_EATTACHCONF;
+ for (line = lasts; isspace((unsigned char)*line); line++)
+ ;
+
+ status = add_regexp(context, lst, data);
+ if (status == LOCKER_SUCCESS)
+ {
+ lst->tab[lst->num].data.string = strdup(line);
+ if (!lst->tab[lst->num++].data.string)
+ status = LOCKER_ENOMEM;
+ }
+ free(data);
+ return status;
+}
+
+static int add_regexp(locker_context context, struct locker__regexp_list *lst,
+ char *regexp)
+{
+ int i, len, status;
+
+ /* Extend the array if we ran out of slots. */
+ if (lst->num >= lst->size - 1)
+ {
+ struct locker__regexp *new;
+ int nsize;
+
+ if (lst->size)
+ nsize = 2 * lst->size;
+ else
+ nsize = 5;
+ new = realloc(lst->tab, nsize * sizeof(struct locker__regexp));
+ if (!new)
+ return LOCKER_ENOMEM;
+ /* Zero out the newly-allocated parts, but not the old parts. */
+ memset(new + lst->size, 0,
+ (nsize - lst->size) * sizeof(struct locker__regexp));
+ lst->size = nsize;
+ lst->tab = new;
+ }
+
+ /* Check for {[-+]?^?fstype,fstype,...}: prefix. */
+ if (*regexp == '{')
+ {
+ int invert = 0;
+
+ if (*++regexp == '+')
+ {
+ regexp++;
+ lst->tab[lst->num].explicit = LOCKER_EXPLICIT;
+ }
+ else if (*regexp == '-')
+ {
+ regexp++;
+ lst->tab[lst->num].explicit = LOCKER_NOEXPLICIT;
+ }
+ else if (*regexp == '^')
+ {
+ regexp++;
+ invert = 1;
+ }
+
+ while (*regexp != '}')
+ {
+ for (i = 0; i < context->nfstypes; i++)
+ {
+ len = strlen(context->fstype[i]->name);
+ if (!strncasecmp(regexp, context->fstype[i]->name, len) &&
+ (regexp[len] == ',' || regexp[len] == '}'))
+ break;
+ }
+ if (i == context->nfstypes)
+ {
+ len = strcspn(regexp, " ,}");
+ locker__error(context, "Unrecognized filesystem type "
+ "\"%.*s\".\n", len, regexp);
+ return LOCKER_EATTACHCONF;
+ }
+
+ lst->tab[lst->num].fstypes |= context->fstype[i]->id;
+ regexp += len;
+ }
+ if (invert)
+ lst->tab[lst->num].fstypes ^= LOCKER_ALL_FSTYPES;
+
+ /* Skip "}" or "}:". */
+ regexp++;
+ if (*regexp == ':')
+ regexp++;
+ }
+ else
+ lst->tab[lst->num].fstypes = LOCKER_ALL_FSTYPES;
+
+ /* Now compile the normal regexp part. */
+ status = regcomp(&(lst->tab[lst->num].pattern), regexp, REG_NOSUB);
+ if (status)
+ {
+ char *errbuf;
+ int size = regerror(status, &(lst->tab[lst->num].pattern), NULL, 0);
+ errbuf = malloc(size);
+ if (!errbuf)
+ return LOCKER_ENOMEM;
+ else
+ {
+ regerror(status, &(lst->tab[lst->num].pattern), errbuf, size);
+ locker__error(context, "Could not parse regular expression "
+ "\"%s\":%s.\n", regexp, errbuf);
+ return LOCKER_EATTACHCONF;
+ }
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+static int parse_obsolete(locker_context context, char *line, void *val)
+{
+ locker__error(context, "Ignoring obsolete attach.conf option: %s\n",
+ line);
+ return LOCKER_SUCCESS;
+}
+
+void locker__error(locker_context context, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (context && context->errfun)
+ context->errfun(context->errdata, fmt, ap);
+ else
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+int locker__fs_ok(locker_context context, struct locker__regexp_list list,
+ struct locker_ops *fs, char *filesystem)
+{
+ int i;
+
+ for (i = 0; i < list.num; i++)
+ {
+ if (fs && !(list.tab[i].fstypes & fs->id))
+ continue;
+
+ if (regexec(&(list.tab[i].pattern), filesystem, 0, NULL, 0) == 0)
+ return list.tab[i].data.flag;
+ }
+
+ return list.defflag;
+}
+
+char *locker__fs_data(locker_context context, struct locker__regexp_list list,
+ struct locker_ops *fs, char *filesystem)
+{
+ int i;
+
+ for (i = 0; i < list.num; i++)
+ {
+ if (fs && !(list.tab[i].fstypes & fs->id))
+ continue;
+
+ if (regexec(&(list.tab[i].pattern), filesystem, 0, NULL, 0) == 0)
+ return list.tab[i].data.string;
+ }
+
+ return NULL;
+}
+
+struct locker_ops *locker__get_fstype(locker_context context, char *type)
+{
+ int i, len;
+
+ for (i = 0; i < context->nfstypes; i++)
+ {
+ len = strlen(context->fstype[i]->name);
+ if (!strncasecmp(type, context->fstype[i]->name, len) &&
+ (!type[len] || isspace((unsigned char)type[len])))
+ return context->fstype[i];
+ }
+ return NULL;
+}
Copied: trunk/athena/lib/locker/src/detach.c (from rev 25923, trunk/athena/lib/locker/detach.c)
===================================================================
--- trunk/athena/lib/locker/src/detach.c (rev 0)
+++ trunk/athena/lib/locker/src/detach.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,225 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements detaching lockers. */
+
+static const char rcsid[] = "$Id: detach.c,v 1.3 1999-12-27 18:13:16 danw Exp $";
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hesiod.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static int detach_attachent(locker_context context,
+ locker_attachent *at, int options);
+static void del_owner(locker_context context, locker_attachent *at,
+ uid_t user);
+static void clean_owners(locker_context context, locker_attachent *at);
+
+
+int locker_detach(locker_context context, char *filesystem, char *mountpoint,
+ int options, locker_attachent **atp)
+{
+ int status;
+ locker_attachent *at;
+
+ status = locker__lookup_attachent(context, filesystem, mountpoint, 0, &at);
+ if (status)
+ return status;
+
+ status = locker_detach_attachent(context, at, options);
+ if (LOCKER_DETACH_SUCCESS(status) && atp)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+ return status;
+}
+
+int locker_detach_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint, int options,
+ locker_attachent **atp)
+{
+ int status;
+ locker_attachent *at;
+
+ status = locker__lookup_attachent_explicit(context, type, desc,
+ mountpoint, 1, &at);
+ if (status)
+ return status;
+
+ status = locker_detach_attachent(context, at, options);
+ if (LOCKER_DETACH_SUCCESS(status) && atp)
+ *atp = at;
+ else
+ locker_free_attachent(context, at);
+ return status;
+}
+
+int locker_detach_attachent(locker_context context,
+ locker_attachent *at, int options)
+{
+ int status = LOCKER_SUCCESS;
+ locker_attachent *ai;
+
+ if (!context->trusted)
+ {
+ if (options & LOCKER_DETACH_OPT_UNLOCK)
+ {
+ locker__error(context, "%s: You are not authorized to use the "
+ "unlock option.\n", at->name);
+ return LOCKER_EPERM;
+ }
+
+ if (options & LOCKER_DETACH_OPT_OVERRIDE)
+ {
+ locker__error(context, "%s: You are not authorized to use the "
+ "override option.\n", at->name);
+ return LOCKER_EPERM;
+ }
+ }
+
+ /* If this is a MUL locker, detach sublockers first. */
+ for (ai = at->next; ai && status == LOCKER_SUCCESS; ai = ai->next)
+ status = detach_attachent(context, ai, options);
+
+ if (!LOCKER_DETACH_SUCCESS(status))
+ {
+ locker__error(context, "%s: MUL detach failed.\n", at->name);
+ return status;
+ }
+
+ status = detach_attachent(context, at, options);
+
+ return status;
+}
+
+/* This is the routine that does all of the work of attaching a single
+ * filesystem.
+ */
+static int detach_attachent(locker_context context,
+ locker_attachent *at, int options)
+{
+ int status, dstatus;
+
+ if (!context->trusted)
+ {
+ /* Don't allow a user to detach something he couldn't attach. */
+ if (!locker__fs_ok(context, context->allow, at->fs, at->name))
+ {
+ locker__error(context, "%s: You are not allowed to detach this "
+ "locker.\n", at->name);
+ return LOCKER_EPERM;
+ }
+ if (strcmp(at->fs->name, "MUL") &&
+ !locker__fs_ok(context, context->mountpoint, at->fs, at->mountpoint))
+ {
+ locker__error(context, "%s: You are not allowed to detach a "
+ "locker from %s.\n", at->name, at->mountpoint);
+ return LOCKER_EPERM;
+ }
+ }
+
+ /* Check locking. */
+ if (at->flags & LOCKER_FLAG_LOCKED &&
+ !(options & LOCKER_DETACH_OPT_UNLOCK))
+ {
+ locker__error(context, "%s: filesystem is locked.\n", at->name);
+ return LOCKER_EPERM;
+ }
+
+ if (options & LOCKER_DETACH_OPT_CLEAN)
+ {
+ clean_owners(context, at);
+ if (at->nowners)
+ {
+ locker__update_attachent(context, at);
+ return LOCKER_SUCCESS;
+ }
+ }
+ else
+ del_owner(context, at, context->user);
+
+ if (at->nowners && (context->ownercheck ||
+ (options & LOCKER_DETACH_OPT_OWNERCHECK)) &&
+ !(options & LOCKER_DETACH_OPT_OVERRIDE))
+ {
+ locker__error(context, "%s: Locker is wanted by others. Not detached.\n",
+ at->name);
+ dstatus = LOCKER_EINUSE;
+ }
+ else
+ {
+ if (!(at->flags & LOCKER_FLAG_KEEP))
+ {
+ /* Detach the locker. */
+ dstatus = at->fs->detach(context, at);
+ if (!LOCKER_DETACH_SUCCESS(dstatus))
+ return dstatus;
+
+ /* Remove any mountpoint components we created. */
+ status = locker__remove_mountpoint(context, at);
+ if (status != LOCKER_SUCCESS && status != LOCKER_EMOUNTPOINTBUSY)
+ return status;
+ }
+ else
+ dstatus = LOCKER_SUCCESS;
+
+ /* Mark the locker detached. */
+ at->attached = 0;
+ }
+ locker__update_attachent(context, at);
+
+ /* Unauthenticate. */
+ if (options & LOCKER_DETACH_OPT_UNAUTH)
+ at->fs->auth(context, at, LOCKER_AUTH_DEFAULT, LOCKER_AUTH_UNAUTHENTICATE);
+
+ /* Record zephyr unsubscriptions. */
+ if (options & LOCKER_DETACH_OPT_UNZEPHYR)
+ at->fs->zsubs(context, at);
+
+ return dstatus;
+}
+
+static void del_owner(locker_context context, locker_attachent *at,
+ uid_t user)
+{
+ int i;
+
+ for (i = 0; i < at->nowners; i++)
+ {
+ if (at->owners[i] == user)
+ {
+ at->owners[i] = at->owners[--at->nowners];
+ return;
+ }
+ }
+}
+
+static void clean_owners(locker_context context, locker_attachent *at)
+{
+ int i;
+
+ for (i = 0; i < at->nowners; )
+ {
+ if (!getpwuid(at->owners[i]))
+ at->owners[i] = at->owners[--at->nowners];
+ else
+ i++;
+ }
+}
Added: trunk/athena/lib/locker/src/liblocker.pc.in
===================================================================
--- trunk/athena/lib/locker/src/liblocker.pc.in (rev 0)
+++ trunk/athena/lib/locker/src/liblocker.pc.in 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE@
+Description: Project Athena's lockers library
+Version: @PACKAGE_VERSION@
+Requires: hesiod zephyr
+Libs: -L${libdir} -l@PACKAGE_NAME@
+Libs.private: @KRB5_LIBS@ @HESIOD_LIBS@ @ZEPHYR_LIBS@
+Cflags: -I${includedir}
Copied: trunk/athena/lib/locker/src/locker.h (from rev 25923, trunk/athena/lib/locker/locker.h)
===================================================================
--- trunk/athena/lib/locker/src/locker.h (rev 0)
+++ trunk/athena/lib/locker/src/locker.h 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,212 @@
+/* $Id: locker.h,v 1.5 2002-10-17 05:20:07 ghudson Exp $ */
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define LOCKER_SUCCESS 0 /* Success */
+
+/* Strictly internal errors */
+#define LOCKER_EFILE -1 /* from locker__read_line */
+#define LOCKER_EOF 1 /* from locker__read_line */
+#define LOCKER_ENOENT 2 /* No such file or directory. */
+
+/* Exported errors */
+#define LOCKER_EATTACHTAB 3 /* Error reading attachtab. */
+#define LOCKER_EHESIOD 4 /* Unexpected Hesiod error. */
+#define LOCKER_ENOMEM 5 /* Out of memory. */
+#define LOCKER_EPARSE 6 /* Could not parse fs description. */
+#define LOCKER_EPERM 7 /* Permission denied. */
+#define LOCKER_EUNKNOWN 8 /* Unknown locker. */
+
+#define LOCKER_EALREADY 9 /* Locker is already attached. */
+#define LOCKER_ENOTATTACHED 10 /* Locker is not attached. */
+
+#define LOCKER_EATTACH 11 /* Could not attach locker. */
+#define LOCKER_EATTACHCONF 12 /* Error reading attach.conf. */
+#define LOCKER_EAUTH 13 /* Could not authenticate. */
+#define LOCKER_EBADPATH 14 /* Unsafe path for mountpoint. */
+#define LOCKER_EDETACH 15 /* Could not detach locker. */
+#define LOCKER_EINUSE 16 /* Locker in use: not detached. */
+#define LOCKER_EMOUNTPOINT 17 /* Couldn't build mountpoint. */
+#define LOCKER_EMOUNTPOINTBUSY 18 /* Another locker is mounted there. */
+#define LOCKER_EZEPHYR 19 /* Zephyr-related error. */
+
+#define LOCKER_ATTACH_SUCCESS(stat) (stat == LOCKER_SUCCESS || stat == LOCKER_EALREADY)
+#define LOCKER_DETACH_SUCCESS(stat) (stat == LOCKER_SUCCESS || stat == LOCKER_ENOTATTACHED)
+#define LOCKER_LOOKUP_FAILURE(stat) (stat >= LOCKER_ENOENT && stat <= LOCKER_EUNKNOWN)
+
+/* Global context */
+typedef struct locker_context *locker_context;
+typedef int (*locker_error_fun)(void *, char *, va_list);
+
+struct locker_ops;
+
+/* The attachtab directory and entries */
+
+typedef struct locker_attachent {
+ /* Data from Hesiod (or other source) */
+ char *name, *mountpoint;
+ struct locker_ops *fs;
+ struct in_addr hostaddr;
+ char *hostdir;
+ int mode;
+
+ /* Additional data kept in the attachtab file for attached lockers */
+ int flags;
+ int nowners;
+ uid_t *owners;
+
+ /* Is the locker attached? */
+ int attached;
+ /* If the mountpoint doesn't exist, where do we start building it from? */
+ char *buildfrom;
+
+ /* Filesystem state */
+ FILE *mountpoint_file;
+ int dirlockfd;
+
+ /* Chaining for MUL lockers */
+ struct locker_attachent *next;
+} locker_attachent;
+
+/* struct locker_ops contains the pointers to filesystem-specific code
+ * and data. */
+struct locker_ops {
+ char *name;
+ int flags;
+ int (*parse)(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp);
+ int (*attach)(locker_context context, locker_attachent *at,
+ char *mountoptions);
+ int (*detach)(locker_context context, locker_attachent *at);
+ int (*auth)(locker_context context, locker_attachent *at,
+ int mode, int op);
+ int (*zsubs)(locker_context context, locker_attachent *at);
+
+ /* Set by locker_init. */
+ long id;
+};
+
+/* locker_ops flags */
+#define LOCKER_FS_NEEDS_MOUNTDIR (1 << 0)
+
+/* Attachent flags */
+#define LOCKER_FLAG_LOCKED (1 << 0)
+#define LOCKER_FLAG_KEEP (1 << 1)
+#define LOCKER_FLAG_NOSUID (1 << 2)
+#define LOCKER_FLAG_NAMEFILE (1 << 3)
+
+/* Attach / Detach options */
+#define LOCKER_ATTACH_OPT_OVERRIDE (1 << 0)
+#define LOCKER_ATTACH_OPT_LOCK (1 << 1)
+#define LOCKER_ATTACH_OPT_ALLOW_SETUID (1 << 2)
+#define LOCKER_ATTACH_OPT_ZEPHYR (1 << 3)
+#define LOCKER_ATTACH_OPT_REAUTH (1 << 4)
+#define LOCKER_ATTACH_OPT_MASTER (1 << 5)
+
+#define LOCKER_ATTACH_DEFAULT_OPTIONS ( LOCKER_ATTACH_OPT_REAUTH | LOCKER_ATTACH_OPT_ZEPHYR )
+
+#define LOCKER_DETACH_OPT_OVERRIDE (1 << 0)
+#define LOCKER_DETACH_OPT_UNLOCK (1 << 1)
+#define LOCKER_DETACH_OPT_UNZEPHYR (1 << 2)
+#define LOCKER_DETACH_OPT_UNAUTH (1 << 3)
+#define LOCKER_DETACH_OPT_OWNERCHECK (1 << 4)
+#define LOCKER_DETACH_OPT_CLEAN (1 << 5)
+
+#define LOCKER_DETACH_DEFAULT_OPTIONS ( LOCKER_DETACH_OPT_UNAUTH | LOCKER_DETACH_OPT_UNZEPHYR )
+
+/* Authentication modes */
+#define LOCKER_AUTH_DEFAULT 0
+#define LOCKER_AUTH_NONE 'n'
+#define LOCKER_AUTH_READONLY 'r'
+#define LOCKER_AUTH_READWRITE 'w'
+#define LOCKER_AUTH_MAYBE_READWRITE 'm'
+
+/* Authentication ops. These numbers cannot be changed: they
+ * correspond to the corresponding RPC mount call procedure numbers.
+ */
+enum { LOCKER_AUTH_AUTHENTICATE = 7, LOCKER_AUTH_UNAUTHENTICATE = 8,
+ LOCKER_AUTH_PURGE = 9, LOCKER_AUTH_PURGEUSER = 10 };
+
+/* Zephyr ops */
+enum { LOCKER_ZEPHYR_SUBSCRIBE, LOCKER_ZEPHYR_UNSUBSCRIBE };
+
+
+/* Callback function */
+typedef int (*locker_callback)(locker_context, locker_attachent *, void *);
+
+
+/* Context operations */
+int locker_init(locker_context *context, uid_t user,
+ locker_error_fun errfun, void *errdata);
+void locker_end(locker_context context);
+
+/* Attachtab operations */
+int locker_read_attachent(locker_context context, char *name,
+ locker_attachent **atp);
+int locker_iterate_attachtab(locker_context context,
+ locker_callback test, void *testarg,
+ locker_callback act, void *actarg);
+void locker_free_attachent(locker_context context, locker_attachent *at);
+
+int locker_check_owner(locker_context context, locker_attachent *at,
+ void *ownerp);
+int locker_check_host(locker_context context, locker_attachent *at,
+ void *addrp);
+int locker_convert_attachtab(locker_context context, char *oattachtab);
+
+/* Attaching lockers */
+int locker_attach(locker_context context, char *filesystem,
+ char *mountpoint, int auth, int options,
+ char *mountoptions, locker_attachent **atp);
+int locker_attach_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint, int auth, int options,
+ char *mountoptions, locker_attachent **atp);
+
+int locker_attach_attachent(locker_context context, locker_attachent *at,
+ int auth, int options, char *mountoptions);
+
+/* Detaching lockers */
+int locker_detach(locker_context context, char *filesystem,
+ char *mountpoint, int options, locker_attachent **atp);
+int locker_detach_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint, int options,
+ locker_attachent **atp);
+
+int locker_detach_attachent(locker_context context, locker_attachent *at,
+ int options);
+
+/* Other locker ops */
+int locker_auth(locker_context context, char *filesystem, int op);
+int locker_auth_to_cell(locker_context context, char *name, char *cell,
+ int op);
+int locker_auth_to_host(locker_context context, char *name, char *host,
+ int op);
+
+int locker_zsubs(locker_context context, char *filesystem);
+
+/* Lookup */
+int locker_lookup_filsys(locker_context context, char *name, char ***descs,
+ void **cleanup);
+void locker_free_filesys(locker_context context, char **descs, void *cleanup);
+
+/* Zephyr */
+int locker_do_zsubs(locker_context context, int op);
Copied: trunk/athena/lib/locker/src/locker_private.h (from rev 25923, trunk/athena/lib/locker/locker_private.h)
===================================================================
--- trunk/athena/lib/locker/src/locker_private.h (rev 0)
+++ trunk/athena/lib/locker/src/locker_private.h 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,140 @@
+/* $Id: locker_private.h,v 1.8 2006-08-08 21:50:10 ghudson Exp $ */
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+#include <stdarg.h>
+
+#define LOCKER_PATH_ATTACHTAB "/var/run/attachtab"
+#define LOCKER_PATH_ATTACH_CONF "/etc/athena/attach.conf"
+#define LOCKER_PATH_LOCAL "/var/athena/local-validated"
+
+#define LOCKER_AFS_MOUNT_DIR "/mit"
+#define LOCKER_UFS_MOUNT_DIR "/mnt"
+#define LOCKER_LOC_MOUNT_DIR "/mit"
+
+#define LOCKER_NFS_KSERVICE "rvdsrv"
+
+#define LOCKER_DEFAULT_GID 101
+
+#define LOCKER_MOUNT_TIMEOUT 20
+
+#define LOCKER_ZEPHYR_CLASS "filsrv"
+
+enum explstate { LOCKER_DONT_CARE, LOCKER_EXPLICIT, LOCKER_NOEXPLICIT };
+
+union locker__datum {
+ char *string;
+ int flag;
+};
+
+struct locker__regexp {
+ int fstypes;
+ enum explstate explicit;
+ regex_t pattern;
+ union locker__datum data;
+};
+
+struct locker__regexp_list {
+ struct locker__regexp *tab;
+ int size, num;
+ int defflag;
+};
+
+struct locker_context {
+ /* attach.conf variables */
+ int exp_desc, exp_mountpoint, keep_mount, nfs_root_hack, ownercheck;
+ int use_krb4;
+ char *afs_mount_dir, *attachtab, *nfs_mount_dir, *local_dir;
+ struct locker__regexp_list allow, setuid, mountpoint;
+ struct locker__regexp_list allowopts, defopts, filesystem, reqopts;
+
+ /* Defined fs types */
+ struct locker_ops **fstype;
+ int nfstypes;
+
+ /* error reporting function and its cookie */
+ locker_error_fun errfun;
+ void *errdata;
+
+ /* user we're acting on behalf of, and whether or not s/he is trusted */
+ uid_t user;
+ int trusted;
+
+ /* Hesiod context */
+ void *hes_context;
+
+ /* Queued zephyr subs */
+ char **zsubs;
+ int nzsubs;
+
+ /* Number of locks held on attachtab */
+ int locks;
+};
+
+/* "kind"s for locker__attachtab_pathname */
+#define LOCKER_LOCK 0
+#define LOCKER_NAME 1
+#define LOCKER_MOUNTPOINT 2
+#define LOCKER_DIRECTORY 3
+/* Already a full path: don't touch it. */
+#define LOCKER_FULL_PATH 4
+
+/* options for locker__canonicalize_path */
+#define LOCKER_CANON_CHECK_NONE 0
+#define LOCKER_CANON_CHECK_MOST 1
+#define LOCKER_CANON_CHECK_ALL 2
+
+/* Prototypes from attachtab.c */
+locker_attachent *locker__new_attachent(locker_context context,
+ struct locker_ops *type);
+int locker__lookup_attachent(locker_context context, char *name,
+ char *mountpoint, int create,
+ locker_attachent **atp);
+int locker__lookup_attachent_explicit(locker_context context, char *type,
+ char *desc, char *mountpoint,
+ int create, locker_attachent **atp);
+void locker__update_attachent(locker_context context, locker_attachent *at);
+char *locker__attachtab_pathname(locker_context context,
+ int kind, char *name);
+
+/* Prototypes from conf.c */
+int locker__fs_ok(locker_context context, struct locker__regexp_list list,
+ struct locker_ops *fs, char *filesystem);
+char *locker__fs_data(locker_context context, struct locker__regexp_list list,
+ struct locker_ops *fs, char *filesystem);
+struct locker_ops *locker__get_fstype(locker_context context, char *fstype);
+void locker__error(locker_context context, char *fmt, ...);
+
+/* Prototypes from mount.c */
+int locker__mount(locker_context context, locker_attachent *at,
+ char *mountoptions);
+int locker__unmount(locker_context context, locker_attachent *at);
+
+/* Prototypes from mountpoint.c */
+int locker__canonicalize_path(locker_context context, int check,
+ char **pathp, char **extp);
+int locker__build_mountpoint(locker_context context, locker_attachent *at);
+int locker__remove_mountpoint(locker_context context, locker_attachent *at);
+void locker__put_mountpoint(locker_context context, locker_attachent *at);
+
+/* Prototypes from util.c */
+int locker__read_line(FILE *fp, char **buf, int *bufsize);
+
+/* Prototypes from zephyr.c */
+int locker__add_zsubs(locker_context context, char **subs, int nsubs);
+void locker__free_zsubs(locker_context context);
Copied: trunk/athena/lib/locker/src/misc.c (from rev 25923, trunk/athena/lib/locker/misc.c)
===================================================================
--- trunk/athena/lib/locker/src/misc.c (rev 0)
+++ trunk/athena/lib/locker/src/misc.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,143 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It deals with miscellaneous
+ * public locker operations besides attaching and detaching.
+ */
+
+static const char rcsid[] = "$Id: misc.c,v 1.3 1999-10-30 19:32:51 danw Exp $";
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hesiod.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+int locker_auth(locker_context context, char *filesystem, int op)
+{
+ int status;
+ locker_attachent *at;
+
+ status = locker_read_attachent(context, filesystem, &at);
+ if (status)
+ return status;
+
+ status = at->fs->auth(context, at, LOCKER_AUTH_DEFAULT, op);
+
+ locker_free_attachent(context, at);
+ return status;
+}
+
+int locker_zsubs(locker_context context, char *filesystem)
+{
+ int status;
+ locker_attachent *at;
+
+ status = locker_read_attachent(context, filesystem, &at);
+ if (status)
+ return status;
+
+ status = at->fs->zsubs(context, at);
+
+ locker_free_attachent(context, at);
+ return status;
+}
+
+/* See if the owner list for the locker contains the uid pointed to by
+ * ownerp. (For use with locker_iterate_attachtab.)
+ */
+int locker_check_owner(locker_context context, locker_attachent *at,
+ void *ownerp)
+{
+ uid_t owner;
+ int i;
+
+ owner = *(uid_t *)ownerp;
+
+ for (i = 0; i < at->nowners; i++)
+ {
+ if (at->owners[i] == owner)
+ return 1;
+ }
+ return 0;
+}
+
+/* See if the locker is on the host pointed to by addrp. If *addrp is
+ * 0.0.0.0, always returns true. (For use with
+ * locker_iterate_attachtab.)
+ */
+int locker_check_host(locker_context context, locker_attachent *at,
+ void *addrp)
+{
+ struct in_addr *addr = addrp;
+ return !addr->s_addr || at->hostaddr.s_addr == addr->s_addr;
+}
+
+
+/* Look up a locker description (in Hesiod or attach.conf). */
+int locker_lookup_filsys(locker_context context, char *name, char ***descs,
+ void **cleanup)
+{
+ char *conffs;
+
+ /* Look for a locker defined in attach.conf. */
+ conffs = locker__fs_data(context, context->filesystem, NULL, name);
+ if (conffs)
+ {
+ *descs = malloc(2 * sizeof(char *));
+ if (!*descs)
+ {
+ locker__error(context, "Out of memory in looking up filesystem.\n");
+ return LOCKER_ENOMEM;
+ }
+ (*descs)[0] = conffs;
+ (*descs)[1] = NULL;
+ *cleanup = NULL;
+
+ return LOCKER_SUCCESS;
+ }
+ else
+ {
+ /* Otherwise, look for a locker in Hesiod--which might be an fsgroup. */
+ *descs = hesiod_resolve(context->hes_context, name, "filsys");
+ if (!*descs && errno == ENOENT)
+ {
+ locker__error(context, "%s: Locker unknown.\n", name);
+ return LOCKER_EUNKNOWN;
+ }
+ if (!*descs || !**descs)
+ {
+ if (*descs)
+ hesiod_free_list(context->hes_context, *descs);
+ locker__error(context, "%s: Could not look up Hesiod entry: %s.\n",
+ name, strerror(errno));
+ return LOCKER_EHESIOD;
+ }
+
+ *cleanup = context->hes_context;
+ return LOCKER_SUCCESS;
+ }
+}
+
+void locker_free_filesys(locker_context context, char **descs, void *cleanup)
+{
+ if (cleanup)
+ hesiod_free_list(cleanup, descs);
+ else
+ free(descs);
+}
Copied: trunk/athena/lib/locker/src/miscfs.c (from rev 25923, trunk/athena/lib/locker/miscfs.c)
===================================================================
--- trunk/athena/lib/locker/src/miscfs.c (rev 0)
+++ trunk/athena/lib/locker/src/miscfs.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,407 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements UFS and ERR lockers. */
+
+static const char rcsid[] = "$Id: miscfs.c,v 1.5 2006-07-25 23:29:09 ghudson Exp $";
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static int ufs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp);
+static int ufs_auth(locker_context context, locker_attachent *at,
+ int mode, int op);
+static int ufs_zsubs(locker_context context, locker_attachent *at);
+
+struct locker_ops locker__ufs_ops = {
+ "UFS",
+ LOCKER_FS_NEEDS_MOUNTDIR,
+ ufs_parse,
+ locker__mount,
+ locker__unmount,
+ ufs_auth,
+ ufs_zsubs
+};
+
+static int loc_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp);
+static int loc_attach(locker_context context, locker_attachent *at,
+ char *mountoptions);
+static int loc_detach(locker_context context, locker_attachent *at);
+static int loc_auth(locker_context context, locker_attachent *at,
+ int mode, int op);
+static int loc_zsubs(locker_context context, locker_attachent *at);
+
+struct locker_ops locker__loc_ops = {
+ "LOC",
+ 0,
+ loc_parse,
+ loc_attach,
+ loc_detach,
+ loc_auth,
+ loc_zsubs
+};
+
+static int err_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **at);
+
+struct locker_ops locker__err_ops = {
+ "ERR",
+ 0,
+ err_parse,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static int ufs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+ locker_attachent *at;
+ char *p, *dup = NULL, *lasts = NULL;
+ int status;
+
+ at = locker__new_attachent(context, &locker__ufs_ops);
+ if (!at)
+ return LOCKER_ENOMEM;
+
+ if (!name)
+ {
+ at->name = strdup(desc);
+ at->hostdir = strdup(desc);
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(LOCKER_UFS_MOUNT_DIR);
+ at->mode = LOCKER_AUTH_READWRITE;
+
+ if (!at->name || !at->hostdir || !at->mountpoint)
+ goto mem_error;
+ }
+ else
+ {
+ /* A Hesiod UFS description (if we had any) would look like:
+ * UFS /dev/dsk/c0t0d0s2 w /u1
+ */
+
+ at->name = strdup(name);
+ if (!at->name)
+ goto mem_error;
+
+ dup = strdup(desc);
+ if (!dup)
+ goto mem_error;
+
+ /* Skip "UFS". */
+ if (!strtok_r(dup, " ", &lasts))
+ goto parse_error;
+
+ /* Hostdir */
+ at->hostdir = strtok_r(NULL, " ", &lasts);
+ if (!at->hostdir)
+ goto parse_error;
+ at->hostdir = strdup(at->hostdir);
+ if (!at->hostdir)
+ goto mem_error;
+
+ /* Mount mode */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p || *(p + 1))
+ goto parse_error;
+
+ switch (*p)
+ {
+ case 'r':
+ at->mode = LOCKER_AUTH_READONLY;
+ break;
+ case 'w':
+ at->mode = LOCKER_AUTH_READWRITE;
+ break;
+ case 'n':
+ at->mode = LOCKER_AUTH_READWRITE;
+ break;
+ default:
+ locker__error(context, "%s: Unrecognized mount option '%c' in "
+ "description:\n%s\n", name, *p, desc);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+
+ /* Mountpoint */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p)
+ goto parse_error;
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(at->mountpoint);
+ if (!at->mountpoint)
+ goto mem_error;
+
+ free(dup);
+ dup = NULL;
+ }
+
+ status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_ALL,
+ &(at->mountpoint), &(at->buildfrom));
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+
+ *atp = at;
+ return LOCKER_SUCCESS;
+
+mem_error:
+ locker__error(context, "Out of memory parsing locker description.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+
+parse_error:
+ locker__error(context, "Could not parse locker description "
+ "\"%s\".\n", desc);
+ status = LOCKER_EPARSE;
+
+cleanup:
+ free(dup);
+ locker_free_attachent(context, at);
+ return status;
+}
+
+static int ufs_auth(locker_context context, locker_attachent *at,
+ int mode, int op)
+{
+ return LOCKER_SUCCESS;
+}
+
+static int ufs_zsubs(locker_context context, locker_attachent *at)
+{
+ return LOCKER_SUCCESS;
+}
+
+
+static int loc_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+ locker_attachent *at;
+ char *p, *dup = NULL, *lasts = NULL;
+ int status;
+
+ at = locker__new_attachent(context, &locker__loc_ops);
+ if (!at)
+ return LOCKER_ENOMEM;
+
+ if (!name)
+ {
+ at->name = strdup(desc);
+ at->hostdir = strdup(desc);
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(LOCKER_LOC_MOUNT_DIR);
+ at->mode = LOCKER_AUTH_READWRITE;
+
+ if (!at->name || !at->hostdir || !at->mountpoint)
+ goto mem_error;
+ }
+ else
+ {
+ /* A Hesiod LOC description (if we had any) would look like:
+ * LOC /u1/lockers/sipb w /mit/sipb
+ */
+
+ at->name = strdup(name);
+ if (!at->name)
+ goto mem_error;
+
+ dup = strdup(desc);
+ if (!dup)
+ goto mem_error;
+
+ /* Skip "LOC". */
+ if (!strtok_r(dup, " ", &lasts))
+ goto parse_error;
+
+ /* Hostdir */
+ at->hostdir = strtok_r(NULL, " ", &lasts);
+ if (!at->hostdir)
+ goto parse_error;
+ at->hostdir = strdup(at->hostdir);
+ if (!at->hostdir)
+ goto mem_error;
+
+ /* Mount mode */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p || *(p + 1))
+ goto parse_error;
+
+ switch (*p)
+ {
+ case 'r':
+ case 'w':
+ case 'n':
+ at->mode = LOCKER_AUTH_NONE;
+ break;
+ default:
+ locker__error(context, "%s: Unrecognized mount option '%c' in "
+ "description:\n%s\n", name, *p, desc);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+
+ /* Mountpoint */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p)
+ goto parse_error;
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(p);
+ if (!at->mountpoint)
+ goto mem_error;
+
+ free(dup);
+ dup = NULL;
+ }
+
+ status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_ALL,
+ &(at->mountpoint), &(at->buildfrom));
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+
+ *atp = at;
+ return LOCKER_SUCCESS;
+
+mem_error:
+ locker__error(context, "Out of memory parsing locker description.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+
+parse_error:
+ locker__error(context, "Could not parse locker description "
+ "\"%s\".\n", desc);
+ status = LOCKER_EPARSE;
+
+cleanup:
+ free(dup);
+ locker_free_attachent(context, at);
+ return status;
+}
+
+static int loc_attach(locker_context context, locker_attachent *at,
+ char *mountoptions)
+{
+ struct stat st1, st2;
+ uid_t uid = geteuid();
+ int status;
+
+ /* Make sure user can read the destination, and it's a directory. */
+ if (uid != context->user)
+ seteuid(context->user);
+ status = lstat(at->hostdir, &st1);
+ if (uid != context->user)
+ seteuid(uid);
+
+ if (status == -1)
+ {
+ locker__error(context, "%s: Could not attach locker:\n%s for %s\n",
+ at->name, strerror(errno), at->hostdir);
+ return LOCKER_EATTACH;
+ }
+ if (!S_ISDIR(st1.st_mode) && !S_ISLNK(st1.st_mode))
+ {
+ locker__error(context, "%s: Could not attach locker:\n"
+ "%s is not a directory.\n", at->name, at->hostdir);
+ return LOCKER_EATTACH;
+ }
+
+ /* Make sure nothing is already mounted on our mountpoint. */
+ status = stat(at->mountpoint, &st2);
+ if (!status && st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
+ {
+ locker__error(context, "%s: Locker is already attached.\n",
+ at->name);
+ return LOCKER_EALREADY;
+ }
+ else if (!status || errno != ENOENT)
+ {
+ locker__error(context, "%s: Could not attach locker:\n"
+ "Mountpoint %s is busy.\n", at->name, at->mountpoint);
+ return LOCKER_EMOUNTPOINTBUSY;
+ }
+
+ status = symlink(at->hostdir, at->mountpoint);
+ if (status < 0)
+ {
+ locker__error(context, "%s: Could not attach locker:\n%s while "
+ "symlinking %s to %s\n", at->name, strerror(errno),
+ at->hostdir, at->mountpoint);
+ return LOCKER_EATTACH;
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+static int loc_detach(locker_context context, locker_attachent *at)
+{
+ int status;
+
+ status = unlink(at->mountpoint);
+ if (status < 0)
+ {
+ if (errno == ENOENT)
+ {
+ locker__error(context, "%s: Locker is not attached.\n", at->name);
+ return LOCKER_ENOTATTACHED;
+ }
+ else
+ {
+ locker__error(context, "%s: Could not detach locker:\n%s while "
+ "trying to unlink %s.\n", at->name, strerror(errno),
+ at->mountpoint);
+ return LOCKER_EDETACH;
+ }
+ }
+ return LOCKER_SUCCESS;
+}
+
+static int loc_auth(locker_context context, locker_attachent *at,
+ int mode, int op)
+{
+ return LOCKER_SUCCESS;
+}
+
+static int loc_zsubs(locker_context context, locker_attachent *at)
+{
+ return LOCKER_SUCCESS;
+}
+
+
+static int err_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+ if (name)
+ locker__error(context, "%s: %s\n", name, desc + 4);
+ else
+ locker__error(context, "%s\n", desc);
+ return LOCKER_EATTACH;
+}
Copied: trunk/athena/lib/locker/src/mount.c (from rev 25923, trunk/athena/lib/locker/mount.c)
===================================================================
--- trunk/athena/lib/locker/src/mount.c (rev 0)
+++ trunk/athena/lib/locker/src/mount.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,260 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements routines to
+ * mount and unmount system-recognized filesystems.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static const char rcsid[] = "$Id: mount.c,v 1.3 1999-05-19 14:19:49 danw Exp $";
+
+static int domount(locker_context context, int mount,
+ locker_attachent *at, char **argv);
+static void cancel_mount(int sig);
+static volatile int cancel;
+
+
+int locker__mount(locker_context context, locker_attachent *at,
+ char *mountoptions)
+{
+ char *argv[6];
+
+ argv[0] = MOUNT_CMD;
+ argv[1] = "-o";
+ argv[2] = mountoptions;
+ argv[3] = at->hostdir;
+ argv[4] = at->mountpoint;
+ argv[5] = NULL;
+ return domount(context, 1, at, argv);
+}
+
+int locker__unmount(locker_context context, locker_attachent *at)
+{
+ char *argv[3];
+ int status;
+
+ argv[0] = UMOUNT_CMD;
+ argv[1] = at->mountpoint;
+ argv[2] = NULL;
+ status = domount(context, 0, at, argv);
+
+ if (status == LOCKER_EDETACH)
+ {
+ /* Check if the detach failed because the filesystem was already
+ * unmounted. (By seeing if the mountpoint directory isn't
+ * there, or if its st_dev matches its parent's st_dev.)
+ */
+ struct stat st1, st2;
+ char *parent, *p;
+
+ if (stat(at->mountpoint, &st1) == -1 && errno == ENOENT)
+ return LOCKER_SUCCESS;
+ parent = strdup(at->mountpoint);
+ if (!parent)
+ return LOCKER_EDETACH;
+
+ p = strrchr(parent, '/');
+ if (!p)
+ {
+ free(parent);
+ return LOCKER_EDETACH;
+ }
+ if (p == parent)
+ p++;
+ *p = '\0';
+ status = stat(parent, &st2);
+ free(parent);
+ if (status == -1)
+ return LOCKER_EDETACH;
+
+ if (st1.st_dev == st2.st_dev)
+ return LOCKER_SUCCESS;
+ else
+ return LOCKER_EDETACH;
+ }
+ else
+ return status;
+}
+
+static int domount(locker_context context, int mount,
+ locker_attachent *at, char **argv)
+{
+ pid_t pid;
+ int status, pstat, pipefds[2], bufsiz, nread, new, oldalarm;
+ char *buf = NULL;
+ sigset_t omask, mask;
+ struct sigaction sa, sa_chld, sa_int, sa_alrm;
+
+ if (pipe(pipefds) == -1)
+ {
+ locker__error(context, "%s: Could not open pipe for mount: %s.\n",
+ at->name, strerror(errno));
+ return mount ? LOCKER_EATTACH : LOCKER_EDETACH;
+ }
+
+ /* If the liblocker caller has set SIGCHLD's handler to SIG_IGN,
+ * waitpid won't work. So we set its handler to SIG_DFL after
+ * blocking it. This makes waitpid work but still prevents the
+ * caller from seeing SIGCHLDs.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &sa, &sa_chld);
+
+ /* Set SIGINT and SIGALRM to interrupt us nicely and then unblock
+ * them.
+ */
+ cancel = 0;
+ sa.sa_handler = cancel_mount;
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGALRM, &sa, &sa_alrm);
+ oldalarm = alarm(LOCKER_MOUNT_TIMEOUT);
+
+ sigdelset(&mask, SIGALRM);
+ sigdelset(&mask, SIGINT);
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+
+ switch (pid = fork())
+ {
+ case -1:
+ close(pipefds[0]);
+ close(pipefds[1]);
+ if (errno == ENOMEM)
+ {
+ locker__error(context, "Not enough memory to fork.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ else
+ {
+ locker__error(context, "%s: Could not fork to exec %s: %s.\n",
+ at->name, argv[0], strerror(errno));
+ status = mount ? LOCKER_EATTACH : LOCKER_EDETACH;
+ goto cleanup;
+ }
+
+ case 0:
+ setuid(0);
+ close(pipefds[0]);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ dup2(pipefds[1], STDOUT_FILENO);
+ dup2(pipefds[1], STDERR_FILENO);
+
+ execv(argv[0], argv);
+ exit(1);
+
+ default:
+ close(pipefds[1]);
+ }
+
+ /* Need to read the data out of the pipe first, in case mount blocks
+ * writing to it before it can exit.
+ */
+ bufsiz = nread = 0;
+
+ new = -1;
+ while (new != 0 && !cancel)
+ {
+ char *nbuf;
+
+ bufsiz += 1024;
+ nbuf = realloc(buf, bufsiz);
+ if (nbuf)
+ {
+ buf = nbuf;
+ new = read(pipefds[0], buf + nread, 1023);
+ }
+
+ if (!nbuf || new == -1)
+ {
+ /* We can't finish reading the buffer, but we need to wait for
+ * the child to exit.
+ */
+ free(buf);
+ buf = NULL;
+ break;
+ }
+ else
+ nread += new;
+ }
+ close(pipefds[0]);
+ if (buf)
+ buf[nread] = '\0';
+
+ do
+ {
+ if (cancel)
+ kill(pid, SIGKILL);
+ }
+ while (waitpid(pid, &pstat, 0) < 0 && errno == EINTR);
+
+ if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
+ status = LOCKER_SUCCESS;
+ else if (cancel == SIGALRM)
+ {
+ locker__error(context, "%s: %s timed out.\n", at->name,
+ mount ? "Mount" : "Unmount");
+ status = mount ? LOCKER_EATTACH : LOCKER_EDETACH;
+ }
+ else if (cancel == SIGINT)
+ {
+ locker__error(context, "%s: %s interrupted by user.\n", at->name,
+ mount ? "Mount" : "Unmount");
+ status = mount ? LOCKER_EATTACH : LOCKER_EDETACH;
+ }
+ else
+ {
+ locker__error(context, "%s: %s failed:\n%s", at->name,
+ mount ? "Mount" : "Unmount",
+ buf ? buf : "Unknown error.\n");
+ status = mount ? LOCKER_EATTACH : LOCKER_EDETACH;
+ }
+
+cleanup:
+ free(buf);
+ sigaction(SIGCHLD, &sa_chld, NULL);
+ sigaction(SIGINT, &sa_int, NULL);
+ alarm(0);
+ sigaction(SIGALRM, &sa_alrm, NULL);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ alarm(oldalarm);
+
+ return status;
+}
+
+static void cancel_mount(int sig)
+{
+ cancel = sig;
+}
Copied: trunk/athena/lib/locker/src/mountpoint.c (from rev 25923, trunk/athena/lib/locker/mountpoint.c)
===================================================================
--- trunk/athena/lib/locker/src/mountpoint.c (rev 0)
+++ trunk/athena/lib/locker/src/mountpoint.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,613 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It deals with canonicalizing and
+ * creating mountpoints, and the associated security issues.
+ */
+
+static const char rcsid[] = "$Id: mountpoint.c,v 1.11 2001-08-16 14:27:52 ghudson Exp $";
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+/* Include <sys/param.h> for MAXPATHLEN (and MAXSYMLINKS). We assume
+ * that if some future OS doesn't have a maximum path length then
+ * they'll also provide replacements for getcwd() and readlink() that
+ * don't require the caller to guess how large a buffer to provide.
+ */
+#include <sys/param.h>
+
+#define MODE_MASK (S_IRWXU | S_IRWXG | S_IRWXO)
+#define LOCKER_DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+#define BAD_MODE_BITS (S_IWGRP | S_IWOTH)
+
+static int mountpoint_mkdir(locker_context context, locker_attachent *at,
+ char *path);
+static int mountpoint_rmdir(locker_context context, locker_attachent *at,
+ char *path);
+
+static int get_dirlock(locker_context context, locker_attachent *at,
+ int type);
+static void release_dirlock(locker_context context, locker_attachent *at);
+
+/* Canonicalize a path and optionally make sure that it doesn't pass
+ * through any mountpoints or user-writable directories. *pathp must
+ * contain an allocated string, which may be freed and replaced with
+ * another allocated string containing the canonicalized path. If
+ * buildfromp is not NULL, *buildfromp is set to an allocated string
+ * containing the first ancestor directory of the canonicalized path
+ * which doesn't exist, or to NULL if the canonicalized path already
+ * exists.
+ */
+int locker__canonicalize_path(locker_context context, int check,
+ char **pathp, char **buildfromp)
+{
+ char *path, *buildfrom = NULL, *cur, *end, *p;
+ struct stat st;
+ int nlinks = 0, status = 0;
+ dev_t last_dev = 0;
+ uid_t uid = geteuid();
+
+ path = *pathp;
+
+ /* If it doesn't start with '/', prepend cwd. */
+ if (path[0] != '/')
+ {
+ char cwdbuf[MAXPATHLEN], *newpath;
+
+ if (!getcwd(cwdbuf, sizeof(cwdbuf)))
+ {
+ locker__error(context, "Could not retrieve current working "
+ "directory:\n%s.\n", strerror(errno));
+ free(path);
+ *pathp = NULL;
+ return LOCKER_EBADPATH;
+ }
+ if (!strcmp(cwdbuf, "/"))
+ *cwdbuf = '\0'; /* Avoid generating "//foo". */
+
+ newpath = malloc(strlen(cwdbuf) + strlen(path) + 2);
+ if (!newpath)
+ {
+ free(path);
+ *pathp = NULL;
+ locker__error(context, "Out of memory canonicalizing mountpoint.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ sprintf(newpath, "%s/%s", cwdbuf, path);
+ free(path);
+ path = newpath;
+
+ /* Don't need to canonicalize cwd part, so skip that. */
+ cur = path + strlen(cwdbuf) + 1;
+ }
+ else
+ cur = path + 1;
+
+ /* Remove trailing slash. */
+ p = strrchr(path, '/');
+ if (p && !*(p + 1) && p > path)
+ *p = '\0';
+
+ if (uid != context->user)
+ seteuid(context->user);
+
+ /* Expand symlinks. */
+ do
+ {
+ end = strchr(cur, '/');
+ if (end)
+ *end = '\0';
+
+ /* cur points to the character after a '/'. Everything before cur is
+ * canonicalized. If cur points to the final component, end is NULL.
+ * Otherwise, end points to a '\0' that is covering the next '/'
+ * after cur.
+ */
+
+ /* Handle special cases. */
+ if (!*cur || !strcmp(cur, "."))
+ {
+ /* "." can't be final path component (since we might not have
+ * wanted to resolve the final path component, and now it's
+ * too late.
+ */
+ if (!end)
+ {
+ locker__error(context, "Path cannot end with \".\" (%s).\n",
+ path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+
+ /* Copy the next component over this one. */
+ strcpy(cur, end + 1);
+ continue;
+ }
+ else if (!strcmp(cur, ".."))
+ {
+ /* ".." can't be final path component for similar reasons
+ * to above.
+ */
+ if (!end)
+ {
+ locker__error(context, "%s: Path cannot end with \"..\" (%s).\n",
+ path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+
+ /* Remove this component and the previous one. */
+ cur -= 2;
+ while (cur > path && *cur != '/')
+ cur--;
+
+ if (cur < path)
+ cur++; /* "/.." == "/" */
+
+ cur++; /* Leave a trailing "/", because end just
+ * got its leading "/" stripped off
+ */
+
+ /* Copy the next component over the previous one. */
+ strcpy(cur, end + 1);
+ continue;
+ }
+
+ /* Don't resolve the final component unless we need to check it. */
+ if (!end && (check != LOCKER_CANON_CHECK_ALL))
+ break;
+
+ /* Check if current component is a symlink. */
+ if (lstat(path, &st) < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /* The rest of the path doesn't exist. */
+ buildfrom = strdup(path);
+ if (!buildfrom)
+ {
+ locker__error(context, "Out of memory canonicalizing "
+ "mountpoint.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ if (end)
+ *end = '/';
+ break;
+ }
+ else
+ {
+ locker__error(context, "Could not canonicalize path:\n"
+ "%s for %s\n", strerror(errno), path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+ }
+ else if (!end && !S_ISDIR(st.st_mode))
+ {
+ locker__error(context, "Final path component is not a directory "
+ "in \"%s\".\n", path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+ else if (S_ISLNK(st.st_mode))
+ {
+ char linkbuf[MAXPATHLEN], *newpath;
+ int len;
+
+ if (++nlinks > MAXSYMLINKS)
+ {
+ locker__error(context, "Too many levels of symlinks "
+ "while canonicalizing path \"%s\".\n",
+ path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+
+ len = readlink(path, linkbuf, sizeof(linkbuf));
+ if (len == -1)
+ {
+ locker__error(context, "Could not canonicalize mountpoint:\n"
+ "%s while reading symlink %s\n", strerror(errno),
+ path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+
+ if (linkbuf[0] == '/')
+ {
+ /* It's absolute, so replace existing path with it. */
+ newpath = malloc(len + strlen(end + 1) + 2);
+ if (!newpath)
+ {
+ locker__error(context, "Out of memory canonicalizing "
+ "mountpoint.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ sprintf(newpath, "%.*s/%s", len, linkbuf, end + 1);
+ free(path);
+ path = newpath;
+ /* And start over from the top. */
+ cur = path + 1;
+ }
+ else
+ {
+ /* Add this in to existing path. */
+ *cur = '\0';
+ newpath = malloc(strlen(path) + len + strlen(end + 1) + 3);
+ if (!newpath)
+ {
+ locker__error(context, "Out of memory canonicalizing "
+ "mountpoint.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+ }
+ sprintf(newpath, "%s%.*s/%s", path, len, linkbuf, end + 1);
+ /* cur is effectively unchanged. */
+ cur = newpath + (cur - path);
+ free(path);
+ path = newpath;
+ }
+ }
+ else
+ {
+ if (check != LOCKER_CANON_CHECK_NONE)
+ {
+ /* Check that we can build in this directory. */
+ if (last_dev && st.st_dev != last_dev)
+ {
+ locker__error(context, "Cannot attach locker on %s:\n"
+ "directory %s is not on root filesystem.\n",
+ *pathp, path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+ else if (st.st_uid != 0)
+ {
+ locker__error(context, "Cannot attach locker on %s:\n"
+ "directory %s is not owned by root.\n",
+ *pathp, path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+ else if (st.st_mode & BAD_MODE_BITS)
+ {
+ locker__error(context, "Cannot attach locker on %s:\n"
+ "directory %s is group/other writable.\n",
+ *pathp, path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+
+ last_dev = st.st_dev;
+ }
+
+ /* Replace *end, update cur. */
+ if (end)
+ {
+ *end = '/';
+ cur = end + 1;
+ }
+ }
+ }
+ while (end);
+
+ if (check != LOCKER_CANON_CHECK_NONE)
+ {
+ int len = strlen(context->attachtab);
+ if (!strncmp(context->attachtab, path, len) &&
+ (path[len] == '\0' || path[len] == '/'))
+ {
+ locker__error(context, "Cannot attach locker on %s:\n"
+ "directory passes through attachtab directory.\n",
+ *pathp, path);
+ status = LOCKER_EBADPATH;
+ goto cleanup;
+ }
+ }
+
+ /* Remove trailing slash. */
+ p = strrchr(path, '/');
+ if (p && !*(p + 1) && p > path)
+ *p = '\0';
+
+ *pathp = path;
+ if (buildfromp)
+ *buildfromp = buildfrom;
+ else
+ free(buildfrom);
+
+cleanup:
+ if (uid != context->user)
+ seteuid(uid);
+ if (status)
+ {
+ free(path);
+ *pathp = NULL;
+ free(buildfrom);
+ }
+ return status;
+}
+
+/* Create any directories needed to attach something to the named
+ * mountpoint. Record the fact that we created the directory so that
+ * we know to delete it later.
+ */
+int locker__build_mountpoint(locker_context context, locker_attachent *at)
+{
+ char *q;
+ int status;
+
+ status = get_dirlock(context, at, F_RDLCK);
+ if (status)
+ return status;
+
+ if (at->buildfrom)
+ {
+ /* Create any remaining directories. */
+ q = at->mountpoint + (strrchr(at->buildfrom, '/') - at->buildfrom);
+ while (!status)
+ {
+ q = strchr(q + 1, '/');
+ if (q)
+ *q = '\0';
+ else if (!(at->fs->flags & LOCKER_FS_NEEDS_MOUNTDIR))
+ break;
+ status = mountpoint_mkdir(context, at, at->mountpoint);
+ if (q)
+ *q = '/';
+ else
+ break;
+ }
+ }
+
+ /* We do not release the dirlock now, to guarantee that no one
+ * else deletes our directories before we're done mounting
+ * the filesystem. It will be released by locker_free_attachent().
+ */
+
+ return status;
+}
+
+/* Remove any directories we created as part of attaching a locker */
+int locker__remove_mountpoint(locker_context context, locker_attachent *at)
+{
+ char *p, *q;
+ int status;
+
+ p = strrchr(at->mountpoint, '/');
+
+ /* If no '/', it must be a MUL locker. */
+ if (!p)
+ return LOCKER_SUCCESS;
+
+ status = get_dirlock(context, at, F_WRLCK);
+ if (status)
+ return status;
+
+ status = mountpoint_rmdir(context, at, at->mountpoint);
+ if (status == LOCKER_ENOENT)
+ status = LOCKER_SUCCESS;
+ while (!status && (q = p) && (q != at->mountpoint))
+ {
+ *q = '\0';
+ p = strrchr(at->mountpoint, '/');
+ status = mountpoint_rmdir(context, at, at->mountpoint);
+ *q = '/';
+ }
+
+ release_dirlock(context, at);
+
+ if (status == LOCKER_ENOENT || status == LOCKER_EMOUNTPOINTBUSY)
+ return LOCKER_SUCCESS;
+ else
+ return status;
+}
+
+/* Unlock the mountpoint created by locker__build_mountpoint(). */
+void locker__put_mountpoint(locker_context context, locker_attachent *at)
+{
+ release_dirlock(context, at);
+}
+
+/* Lock the dirlock file. type should be F_RDLCK if you are creating
+ * directories and F_WRLCK if you are deleting them. A process that creates
+ * directories should hold onto the lock until it has actually finished
+ * trying to attach the locker, so that some other detach procedure doesn't
+ * remove those directories out from under it.
+ */
+static int get_dirlock(locker_context context, locker_attachent *at, int type)
+{
+ int status;
+ char *lock;
+ struct flock fl;
+ mode_t o_umask;
+
+ lock = locker__attachtab_pathname(context, LOCKER_LOCK, ".dirlock");
+ if (!lock)
+ return LOCKER_ENOMEM;
+
+ o_umask = umask(0);
+ at->dirlockfd = open(lock, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
+ free(lock);
+ umask(o_umask);
+ if (at->dirlockfd < 0)
+ {
+ at->dirlockfd = 0;
+ locker__error(context, "%s: Could not %s mountpoint:\n"
+ "%s while opening directory lock file.\n", at->name,
+ at->attached ? "remove" : "create", strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+ fl.l_type = type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = fl.l_len = 0;
+ status = fcntl(at->dirlockfd, F_SETLKW, &fl);
+ if (status < 0)
+ {
+ close(at->dirlockfd);
+ at->dirlockfd = 0;
+ locker__error(context, "%s: Could not %s mountpoint:\n"
+ "%s while locking directory lock file.\n", at->name,
+ at->attached ? "remove" : "create", strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+
+ return LOCKER_SUCCESS;
+}
+
+static void release_dirlock(locker_context context, locker_attachent *at)
+{
+ close(at->dirlockfd);
+ at->dirlockfd = 0;
+}
+
+static int mountpoint_mkdir(locker_context context, locker_attachent *at,
+ char *path)
+{
+ char *file;
+ struct stat st;
+ mode_t omask;
+ int status;
+
+ file = locker__attachtab_pathname(context, LOCKER_DIRECTORY, path);
+ if (!file)
+ {
+ locker__error(context, "Out of memory building mountpoint.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ if (access(file, F_OK) != 0 || lstat(path, &st) != 0)
+ {
+ int fd;
+
+ /* Need to create the dirfile and the directory. If we get killed
+ * in between the two steps, we'd rather have a dirfile that
+ * doesn't correspond to a directory than a directory that we
+ * don't know is our fault. So do the dirfile first.
+ */
+
+ fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ {
+ free(file);
+ locker__error(context, "Could not create directory data file "
+ "%s:\n%s.\n", file, strerror(errno));
+ return LOCKER_EATTACHTAB;
+ }
+ close(fd);
+
+ /* Make directory. */
+ omask = umask(0);
+ status = mkdir(path, LOCKER_DIR_MODE);
+ umask(omask);
+ if (status == -1)
+ {
+ if (errno == EEXIST)
+ {
+ locker__error(context, "%s: Directory should not exist: %s\n",
+ at->name, path);
+ }
+ else
+ {
+ locker__error(context, "%s: Could not create directory %s:\n"
+ "%s.\n", at->name, path, strerror(errno));
+ }
+ unlink(file);
+ free(file);
+ return LOCKER_EMOUNTPOINT;
+ }
+ }
+ else
+ {
+ if (!S_ISDIR(st.st_mode) || st.st_uid != 0 ||
+ (st.st_mode & MODE_MASK) != LOCKER_DIR_MODE)
+ {
+ locker__error(context, "%s: Directory \"%s\" has changed.\n",
+ at->name, path);
+ unlink(file);
+ free(file);
+ return LOCKER_EMOUNTPOINT;
+ }
+ }
+
+ free(file);
+ return LOCKER_SUCCESS;
+}
+
+static int mountpoint_rmdir(locker_context context, locker_attachent *at,
+ char *path)
+{
+ char *file;
+ struct stat st;
+
+ file = locker__attachtab_pathname(context, LOCKER_DIRECTORY, path);
+ if (!file)
+ {
+ locker__error(context, "Out of memory removing mountpoint.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ if (access(file, F_OK) != 0)
+ {
+ free(file);
+ return LOCKER_ENOENT;
+ }
+
+ /* Make sure directory exists and looks like we built it. */
+ if (lstat(path, &st) == -1)
+ {
+ locker__error(context, "%s: Could not check directory %s:\n%s.\n",
+ at->name, path, strerror(errno));
+ unlink(file);
+ free(file);
+ return LOCKER_EMOUNTPOINT;
+ }
+
+ if (!S_ISDIR(st.st_mode) || st.st_uid != 0 ||
+ (st.st_mode & MODE_MASK) != LOCKER_DIR_MODE)
+ {
+ locker__error(context, "%s: Directory \"%s\" has changed.\n",
+ at->name, path);
+ unlink(file);
+ free(file);
+ return LOCKER_EMOUNTPOINT;
+ }
+
+ if (rmdir(path) == -1)
+ {
+ free(file);
+ if (errno == ENOTEMPTY || errno == EEXIST)
+ return LOCKER_EMOUNTPOINTBUSY;
+ locker__error(context, "%s: Could not remove mountpoint component "
+ "%s:\n%s.\n", at->name, path, strerror(errno));
+ return LOCKER_EMOUNTPOINT;
+ }
+
+ unlink(file);
+ free(file);
+ return LOCKER_SUCCESS;
+}
Copied: trunk/athena/lib/locker/src/mul.c (from rev 25923, trunk/athena/lib/locker/mul.c)
===================================================================
--- trunk/athena/lib/locker/src/mul.c (rev 0)
+++ trunk/athena/lib/locker/src/mul.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,157 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements some of the code for
+ * MUL lockers. (Most of the code for MUL lockers is special-cased
+ * into attachtab.c, attach.c, and detach.c.)
+ */
+
+static const char rcsid[] = "$Id: mul.c,v 1.3 1999-09-22 22:25:08 danw Exp $";
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static int mul_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **at);
+static int mul_attach(locker_context context, locker_attachent *at,
+ char *mountoptions);
+static int mul_detach(locker_context context, locker_attachent *at);
+static int mul_auth(locker_context context, locker_attachent *at,
+ int mode, int op);
+static int mul_zsubs(locker_context context, locker_attachent *at);
+
+struct locker_ops locker__mul_ops = {
+ "MUL",
+ 0,
+ mul_parse,
+ mul_attach,
+ mul_detach,
+ mul_auth,
+ mul_zsubs
+};
+
+static int mul_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+ int status;
+ char *p, *dup, *lasts = NULL;
+ locker_attachent *at, *attmp;
+
+ if (!name)
+ {
+ locker__error(context, "Cannot explicitly specify MUL locker.\n");
+ return LOCKER_EPARSE;
+ }
+
+ if (mountpoint)
+ {
+ locker__error(context, "%s: Explicit mountpoint is meaningless for "
+ "MUL locker.\n", name);
+ return LOCKER_EPARSE;
+ }
+
+ at = locker__new_attachent(context, &locker__mul_ops);
+ if (!at)
+ return LOCKER_ENOMEM;
+
+ /* Skip "MUL". (But if this is called from read_attachent, the "MUL"
+ * won't be there.)
+ */
+ if (!strncmp(desc, "MUL ", 4))
+ {
+ p = desc + 4;
+ while (isspace((unsigned char)*p))
+ p++;
+ }
+ else
+ p = desc;
+
+ at->name = strdup(name);
+ at->mountpoint = strdup(p);
+ at->hostdir = strdup("");
+ at->mode = '-';
+ dup = strdup(p);
+ if (!at->name || !at->mountpoint || !at->hostdir || !dup)
+ {
+ locker_free_attachent(context, at);
+ locker__error(context, "Out of memory parsing locker description.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ /* Read list of locker names. */
+ for (p = strtok_r(dup, " ", &lasts); p; p = strtok_r(NULL, " ", &lasts))
+ {
+ status = locker__lookup_attachent(context, p, NULL, 1, &attmp);
+ if (status)
+ break;
+
+ if (attmp->fs == at->fs)
+ {
+ locker__error(context, "%s: Cannot have MUL locker \"%s\" as a "
+ "component of a MUL locker.\n", at->name,
+ attmp->name);
+ locker_free_attachent(context, attmp);
+ status = LOCKER_EPARSE;
+ break;
+ }
+
+ attmp->next = at->next;
+ at->next = attmp;
+ }
+
+ free(dup);
+
+ if (status)
+ {
+ for (; at; at = attmp)
+ {
+ attmp = at->next;
+ locker_free_attachent(context, at);
+ }
+ }
+ else
+ *atp = at;
+
+ return status;
+}
+
+static int mul_attach(locker_context context, locker_attachent *at,
+ char *mountoptions)
+{
+ return LOCKER_SUCCESS;
+}
+
+static int mul_detach(locker_context context, locker_attachent *at)
+{
+ return LOCKER_SUCCESS;
+}
+
+static int mul_auth(locker_context context, locker_attachent *at,
+ int mode, int op)
+{
+ return LOCKER_SUCCESS;
+}
+
+static int mul_zsubs(locker_context context, locker_attachent *at)
+{
+ return LOCKER_SUCCESS;
+}
Copied: trunk/athena/lib/locker/src/nfs.c (from rev 25923, trunk/athena/lib/locker/nfs.c)
===================================================================
--- trunk/athena/lib/locker/src/nfs.c (rev 0)
+++ trunk/athena/lib/locker/src/nfs.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,438 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements NFS lockers. */
+
+static const char rcsid[] = "$Id: nfs.c,v 1.5 2006-07-25 23:29:09 ghudson Exp $";
+
+#ifdef ENABLE_NFS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#ifdef NEED_SYS_FS_NFS_H
+#include <sys/fs/nfs.h>
+#endif
+#include <rpcsvc/mount.h>
+
+#include <krb.h>
+
+#endif /* ENABLE_NFS */
+
+#include "locker.h"
+#include "locker_private.h"
+
+#ifdef ENABLE_NFS
+static bool_t xdr_krbtkt(XDR *xdrs, KTEXT authp);
+#endif /* ENABLE_NFS */
+
+static int nfs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **at);
+static int nfs_auth(locker_context context, locker_attachent *at,
+ int mode, int op);
+static int nfs_zsubs(locker_context context, locker_attachent *at);
+
+struct locker_ops locker__nfs_ops = {
+ "NFS",
+ LOCKER_FS_NEEDS_MOUNTDIR,
+ nfs_parse,
+ locker__mount,
+ locker__unmount,
+ nfs_auth,
+ nfs_zsubs
+};
+
+static int nfs_parse(locker_context context, char *name, char *desc,
+ char *mountpoint, locker_attachent **atp)
+{
+#ifdef ENABLE_NFS
+ locker_attachent *at;
+ struct hostent *h;
+ char *dup;
+ char *p, *host, *dir, *lasts = NULL;
+ int status;
+
+ at = locker__new_attachent(context, &locker__nfs_ops);
+ if (!at)
+ return LOCKER_ENOMEM;
+
+ dup = strdup(desc);
+ if (!dup)
+ goto mem_error;
+
+ if (!name)
+ {
+ /* It's an explicit description: host:path. */
+
+ at->name = strdup(desc);
+ if (!at->name)
+ goto mem_error;
+
+ if (!(p = strchr(dup, ':')))
+ {
+ locker__error(context, "%s: No \":\" in description.\n", desc);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+
+ *p = '\0';
+ host = dup;
+ dir = p + 1;
+ at->mode = LOCKER_AUTH_READWRITE;
+ }
+ else
+ {
+ /* A hesiod NFS description looks like:
+ * NFS /u1/bitbucket JASON.MIT.EDU w /mit/bitbucket
+ */
+
+ at->name = strdup(name);
+ if (!at->name)
+ goto mem_error;
+
+ /* Skip "NFS". */
+ if (!strtok_r(dup, " ", &lasts))
+ goto parse_error;
+
+ /* Directory on remote host */
+ dir = strtok_r(NULL, " ", &lasts);
+ if (!dir)
+ goto parse_error;
+
+ /* Remote host */
+ host = strtok_r(NULL, " ", &lasts);
+ if (!host)
+ goto parse_error;
+
+ /* Mount mode */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p || *(p + 1))
+ goto parse_error;
+ switch (*p)
+ {
+ case 'r':
+ at->mode = LOCKER_AUTH_READONLY;
+ break;
+ case 'm':
+ at->mode = LOCKER_AUTH_MAYBE_READWRITE;
+ break;
+ case 'w':
+ at->mode = LOCKER_AUTH_READWRITE;
+ break;
+ case 'n':
+ at->mode = LOCKER_AUTH_NONE;
+ break;
+ default:
+ locker__error(context, "%s: Unrecognized mount option '%c' in\n"
+ "\"%s\".\n", name, *p, desc);
+ return LOCKER_EPARSE;
+ }
+
+ /* Mountpoint */
+ p = strtok_r(NULL, " ", &lasts);
+ if (!p)
+ goto parse_error;
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ at->mountpoint = strdup(p);
+ if (!at->mountpoint)
+ goto mem_error;
+ }
+
+ /* Canonicalize hostname and build hostdir. */
+ h = gethostbyname(host);
+ if (!h)
+ {
+ locker__error(context, "%s: Could not resolve hostname %s.\n",
+ name ? name : desc, host);
+ status = LOCKER_EPARSE;
+ goto cleanup;
+ }
+ memcpy(&at->hostaddr, h->h_addr, sizeof(at->hostaddr));
+
+ at->hostdir = malloc(strlen(h->h_name) + strlen(dir) + 2);
+ if (!at->hostdir)
+ goto mem_error;
+ sprintf(at->hostdir, "%s:%s", h->h_name, dir);
+
+ if (!at->mountpoint)
+ {
+ if (mountpoint)
+ at->mountpoint = strdup(mountpoint);
+ else
+ {
+ /* Generate a default mountpoint. This defaults to
+ * /hostname/hostdir where "hostname" is the canonical
+ * hostname, in lowercase, up to the first dot, and hostdir
+ * is the path to the NFS locker on that host. BUT, if
+ * nfs_mount_dir is set, its value is prepended, and if
+ * nfs_root_hack is set, "root" is appended if hostdir is
+ * "/".
+ */
+ char *mount_dir = context->nfs_mount_dir ?
+ context->nfs_mount_dir : "";
+ int root_hack = context->nfs_root_hack && !strcmp(dir, "/");
+ int hostlen = strcspn(host, ".");
+
+ at->mountpoint = malloc(strlen(mount_dir) + 1 + hostlen +
+ strlen(dir) + (root_hack ? 5 : 1));
+ if (at->mountpoint)
+ {
+ sprintf(at->mountpoint, "%s/%.*s%s%s", mount_dir, hostlen,
+ host, dir, root_hack ? "root" : "");
+ }
+
+ for (p = at->mountpoint + strlen(mount_dir) + 1; *p != '/'; p++)
+ *p = tolower(*p);
+ }
+ if (!at->mountpoint)
+ goto mem_error;
+ }
+
+ status = locker__canonicalize_path(context, LOCKER_CANON_CHECK_ALL,
+ &(at->mountpoint), &(at->buildfrom));
+ if (status != LOCKER_SUCCESS)
+ goto cleanup;
+
+ free(dup);
+ *atp = at;
+ return LOCKER_SUCCESS;
+
+mem_error:
+ locker__error(context, "Out of memory parsing locker description.\n");
+ status = LOCKER_ENOMEM;
+ goto cleanup;
+
+parse_error:
+ locker__error(context, "Could not parse locker description "
+ "\"%s\".\n", desc);
+ status = LOCKER_EPARSE;
+
+cleanup:
+ free(dup);
+ locker_free_attachent(context, at);
+ return status;
+#else /* ENABLE_NFS */
+ return LOCKER_EPARSE;
+#endif /* ENABLE_NFS */
+}
+
+static int nfs_auth(locker_context context, locker_attachent *at,
+ int mode, int op)
+{
+#ifdef ENABLE_NFS
+ int status, len;
+ char *host;
+
+ len = strcspn(at->hostdir, ":");
+ host = malloc(len + 1);
+ if (!host)
+ {
+ locker__error(context, "Out of memory authenticating to host.\n");
+ return LOCKER_ENOMEM;
+ }
+ memcpy(host, at->hostdir, len);
+ host[len] = '\0';
+
+ status = locker_auth_to_host(context, at->name, host, op);
+ free(host);
+ return status;
+#else /* ENABLE_NFS */
+ return LOCKER_EAUTH;
+#endif /* ENABLE_NFS */
+}
+
+int locker_auth_to_host(locker_context context, char *name, char *host,
+ int op)
+{
+#ifdef ENABLE_NFS
+ int status, len;
+ struct timeval timeout;
+ CLIENT *cl;
+ struct utsname uts;
+ struct passwd *pw;
+ gid_t gids[NGRPS];
+ KTEXT_ST authent;
+ enum clnt_stat rpc_stat;
+
+ if (op == LOCKER_AUTH_PURGE && !context->trusted)
+ {
+ locker__error(context, "%s: You are not allowed to use the "
+ "'purge all host mappings' option.\n", name);
+ return LOCKER_EPERM;
+ }
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 20;
+
+ /* Get an RPC handle. */
+ cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp");
+ if (!cl)
+ {
+ locker__error(context, "%s: server %s not responding.\n", name, host);
+ return LOCKER_EATTACH;
+ }
+ auth_destroy(cl->cl_auth);
+
+ /* Create authunix authentication. */
+ uname(&uts);
+ pw = getpwuid(context->user);
+ len = getgroups(NGRPS, gids);
+ cl->cl_auth = authunix_create(uts.nodename, context->user,
+ pw ? pw->pw_gid : LOCKER_DEFAULT_GID,
+ len, gids);
+
+ /* Mapping and user purging are the only Kerberos-authenticated
+ * functions.
+ */
+ if (op == LOCKER_AUTH_AUTHENTICATE || op == LOCKER_AUTH_PURGEUSER)
+ {
+ char *realm, *instance, *src, *dst;
+
+ realm = (char *) krb_realmofhost(host);
+ instance = malloc(strcspn(host, ".") + 1);
+
+ for (src = host, dst = instance; *src && *src != '.'; )
+ *dst++ = tolower(*src++);
+ *dst = '\0';
+
+ status = krb_mk_req(&authent, LOCKER_NFS_KSERVICE, instance, realm, 0);
+ free(instance);
+ if (status != KSUCCESS)
+ {
+ auth_destroy(cl->cl_auth);
+ clnt_destroy(cl);
+ if (status == KDC_PR_UNKNOWN)
+ {
+ locker__error(context, "%s: (warning) Host %s isn't registered "
+ "with Kerberos.%s\n", name, host,
+ op == LOCKER_AUTH_AUTHENTICATE ?
+ " Mapping failed." : "");
+ return LOCKER_SUCCESS;
+ }
+ else
+ {
+ locker__error(context, "%s: Could not get Kerberos ticket for "
+ "NFS authentication:\n%s.\n", name,
+ krb_err_txt[status]);
+ return LOCKER_EAUTH;
+ }
+ }
+
+ rpc_stat = clnt_call(cl, op, (xdrproc_t)xdr_krbtkt, (caddr_t)&authent,
+ (xdrproc_t)xdr_void, 0, timeout);
+ }
+ else
+ rpc_stat = clnt_call(cl, op, (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void,
+ 0, timeout);
+
+ auth_destroy(cl->cl_auth);
+ clnt_destroy(cl);
+
+ if (rpc_stat != RPC_SUCCESS)
+ {
+ switch (rpc_stat)
+ {
+ case RPC_TIMEDOUT:
+ locker__error(context, "%s: Timeout while contacting mount "
+ "daemon on %s.\n", name, host);
+ return LOCKER_EATTACH;
+
+ case RPC_PMAPFAILURE:
+ case RPC_PROGUNAVAIL:
+ case RPC_PROGNOTREGISTERED:
+ locker__error(context, "%s: No mount daemon on %s.\n", name, host);
+ return LOCKER_EATTACH;
+
+ case RPC_AUTHERROR:
+ locker__error(context, "%s: Authentication failed to host %s.\n",
+ name, host);
+ return LOCKER_EAUTH;
+
+ case RPC_PROCUNAVAIL:
+ locker__error(context, "%s: (warning) Mount daemon on %s doesn't "
+ "understand UID maps.\n", name, host);
+ return LOCKER_SUCCESS;
+
+ default:
+ locker__error(context, "%s: System error contacting server %s.\n",
+ name, host);
+ return LOCKER_EAUTH;
+ }
+ }
+
+ return LOCKER_SUCCESS;
+#else /* ENABLE_NFS */
+ return LOCKER_EAUTH;
+#endif /* ENABLE_NFS */
+}
+
+/* XDR for sending a Kerberos ticket - sends the whole KTEXT block,
+ * but this is very old lossage, and nothing that can really be fixed
+ * now.
+ */
+
+#ifdef ENABLE_NFS
+
+static bool_t xdr_krbtkt(XDR *xdrs, KTEXT authp)
+{
+ KTEXT_ST auth;
+
+ auth = *authp;
+ auth.length = htonl(authp->length);
+ return xdr_opaque(xdrs, (caddr_t)&auth, sizeof(KTEXT_ST));
+}
+
+#endif /* ENABLE_NFS */
+
+static int nfs_zsubs(locker_context context, locker_attachent *at)
+{
+#ifdef ENABLE_NFS
+ int len, status;
+ char *subs[2];
+
+ subs[0] = at->hostdir;
+
+ len = strchr(at->hostdir, ':') - at->hostdir;
+ subs[1] = malloc(len + 1);
+ if (!subs[1])
+ {
+ free(subs[0]);
+ free(subs);
+ locker__error(context, "Out of memory getting Zephyr subscriptions.\n");
+ return LOCKER_ENOMEM;
+ }
+ memcpy(subs[1], at->hostdir, len);
+ subs[1][len] = '\0';
+
+ status = locker__add_zsubs(context, subs, 2);
+ free(subs[1]);
+ return status;
+#else /* ENABLE_NFS */
+ return LOCKER_EPARSE;
+#endif
+}
Copied: trunk/athena/lib/locker/src/util.c (from rev 25923, trunk/athena/lib/locker/util.c)
===================================================================
--- trunk/athena/lib/locker/src/util.c (rev 0)
+++ trunk/athena/lib/locker/src/util.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,71 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It implements various utility
+ routines. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+static const char rcsid[] = "$Id: util.c,v 1.1 1999-02-26 19:04:54 danw Exp $";
+
+/* This is an internal function. Its contract is to read a line from a
+ * file into a dynamically allocated buffer, zeroing the trailing newline
+ * if there is one. The calling routine may call locker__read_line multiple
+ * times with the same buf and bufsize pointers; *buf will be reallocated
+ * and *bufsize adjusted as appropriate. The initial value of *buf
+ * should be NULL. After the calling routine is done reading lines, it
+ * should free *buf. This function returns 0 if a line was successfully
+ * read, 1 if the file ended, and -1 if there was an I/O error or if it
+ * ran out of memory.
+ */
+
+int locker__read_line(FILE *fp, char **buf, int *bufsize)
+{
+ char *newbuf;
+ int offset = 0, len;
+
+ if (*buf == NULL)
+ {
+ *buf = malloc(128);
+ if (!*buf)
+ return -1;
+ *bufsize = 128;
+ }
+
+ while (1)
+ {
+ if (!fgets(*buf + offset, *bufsize - offset, fp))
+ return (offset != 0) ? 0 : (ferror(fp)) ? -1 : 1;
+ len = offset + strlen(*buf + offset);
+ if ((*buf)[len - 1] == '\n')
+ {
+ (*buf)[len - 1] = 0;
+ return 0;
+ }
+ offset = len;
+
+ /* Allocate more space. */
+ newbuf = realloc(*buf, *bufsize * 2);
+ if (!newbuf)
+ return -1;
+ *buf = newbuf;
+ *bufsize *= 2;
+ }
+}
Copied: trunk/athena/lib/locker/src/zephyr.c (from rev 25923, trunk/athena/lib/locker/zephyr.c)
===================================================================
--- trunk/athena/lib/locker/src/zephyr.c (rev 0)
+++ trunk/athena/lib/locker/src/zephyr.c 2013-06-02 04:57:27 UTC (rev 26030)
@@ -0,0 +1,139 @@
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of liblocker. It deals with zephyr subscriptions
+ * pertaining to lockers.
+ */
+
+static const char rcsid[] = "$Id: zephyr.c,v 1.7 2003-11-04 19:21:12 ghudson Exp $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <com_err.h>
+#include <zephyr/zephyr.h>
+
+#include "locker.h"
+#include "locker_private.h"
+
+/* Magic number taken from zctl sources. */
+#define ZEPHYR_MAXONEPACKET 7
+
+int locker_do_zsubs(locker_context context, int op)
+{
+ int wgport;
+ ZSubscription_t zsubs[ZEPHYR_MAXONEPACKET];
+ int i, j, status, retval;
+ uid_t uid = geteuid();
+
+ if (!context->zsubs)
+ return LOCKER_SUCCESS;
+
+ /* Initialize Zephyr. (This can fail.) */
+ status = ZInitialize();
+ if (status)
+ {
+ locker__error(context, "Could not initialize Zephyr library: %s.\n",
+ error_message(status));
+ return LOCKER_EZEPHYR;
+ }
+
+ wgport = ZGetWGPort();
+ if (wgport == -1)
+ {
+ locker__free_zsubs(context);
+ return LOCKER_EZEPHYR;
+ }
+
+ for (j = 0; j < ZEPHYR_MAXONEPACKET; j++)
+ {
+ zsubs[j].zsub_recipient = "*";
+ zsubs[j].zsub_class = LOCKER_ZEPHYR_CLASS;
+ }
+
+ /* seteuid since Zephyr ops may touch ticket file. */
+ if (uid != context->user)
+ seteuid(context->user);
+
+ retval = LOCKER_SUCCESS;
+ for (i = 0; i < context->nzsubs; i += j)
+ {
+ for (j = 0; j < ZEPHYR_MAXONEPACKET && i + j < context->nzsubs; j++)
+ zsubs[j].zsub_classinst = context->zsubs[i + j];
+
+ if (op == LOCKER_ZEPHYR_SUBSCRIBE)
+ status = ZSubscribeToSansDefaults(zsubs, j, wgport);
+ else
+ status = ZUnsubscribeTo(zsubs, j, wgport);
+ if (status)
+ {
+ locker__error(context, "Error while %ssubscribing:\n%s.\n",
+ op == LOCKER_ZEPHYR_SUBSCRIBE ? "" : "un",
+ error_message(status));
+ retval = LOCKER_EZEPHYR;
+ break;
+ }
+ }
+
+ if (uid != context->user)
+ seteuid(uid);
+
+ locker__free_zsubs(context);
+ ZClosePort();
+ return retval;
+}
+
+int locker__add_zsubs(locker_context context, char **subs, int nsubs)
+{
+ int newnzsubs = context->nzsubs + nsubs, i;
+ char **newzsubs;
+
+ newzsubs = realloc(context->zsubs, newnzsubs * sizeof(char *));
+ if (!newzsubs)
+ {
+ locker__error(context, "Out of memory recording Zephyr subscriptions.\n");
+ return LOCKER_ENOMEM;
+ }
+
+ context->zsubs = newzsubs;
+ for (i = 0; i < nsubs; i++)
+ {
+ context->zsubs[context->nzsubs + i] = strdup(subs[i]);
+ if (!context->zsubs[context->nzsubs + i])
+ {
+ locker__error(context, "Out of memory recording Zephyr "
+ "subscriptions.\n");
+ while (i--)
+ free(context->zsubs[context->nzsubs + i]);
+ return LOCKER_ENOMEM;
+ }
+ }
+ context->nzsubs += nsubs;
+
+ return LOCKER_SUCCESS;
+}
+
+void locker__free_zsubs(locker_context context)
+{
+ int i;
+
+ for (i = 0; i < context->nzsubs; i++)
+ free(context->zsubs[i]);
+ free(context->zsubs);
+
+ context->nzsubs = 0;
+ context->zsubs = NULL;
+}