mkdir -p $PKGROOT/Library
mkdir -p $PKGROOT/Library/PreferencePanes
+ mkdir -p $PKGROOT/Library/Security/SecurityAgentPlugins
chown root${SEP}admin $PKGROOT
- chmod 775 $PKGROOT $PKGROOT/Library $PKGROOT/Library/PreferencePanes
+ chmod 755 $PKGROOT $PKGROOT/Library $PKGROOT/Library/PreferencePanes $PKGROOT/Library/Security/SecurityAgentPlugins
(cd $BINDEST/tools && pax -rw OpenAFS.prefPane $PKGROOT/Library/PreferencePanes)
+ (cd $BINDEST/tools && pax -rw aklog.bundle $PKGROOT/Library/Security/SecurityAgentPlugins)
mkdir -p $PKGROOT/Library/OpenAFS/Tools
(cd $BINDEST && pax -rw * $PKGROOT/Library/OpenAFS/Tools)
cd $RESSRC
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ BFB1A01A1032470E00FAF9DB /* aklog.c in Sources */ = {isa = PBXBuildFile; fileRef = BFB1A0191032470E00FAF9DB /* aklog.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 8D5B49B6048680CD000E48DA /* aklog.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = aklog.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ BFB1A0191032470E00FAF9DB /* aklog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aklog.c; sourceTree = "<group>"; };
+ BFB1A01B1032471800FAF9DB /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D5B49B3048680CD000E48DA /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 089C166AFE841209C02AAC07 /* aklogAuthPlugin */ = {
+ isa = PBXGroup;
+ children = (
+ BFB1A01B1032471800FAF9DB /* README */,
+ BFB1A0191032470E00FAF9DB /* aklog.c */,
+ 8D5B49B7048680CD000E48DA /* Info.plist */,
+ 19C28FB8FE9D52D311CA2CBB /* Products */,
+ );
+ name = aklogAuthPlugin;
+ sourceTree = "<group>";
+ };
+ 19C28FB8FE9D52D311CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D5B49B6048680CD000E48DA /* aklog.bundle */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8D5B49AC048680CD000E48DA /* AklogAuthPlugin */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "AklogAuthPlugin" */;
+ buildPhases = (
+ 8D5B49AF048680CD000E48DA /* Resources */,
+ 8D5B49B1048680CD000E48DA /* Sources */,
+ 8D5B49B3048680CD000E48DA /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = AklogAuthPlugin;
+ productInstallPath = "$(HOME)/Library/Bundles";
+ productName = aklogAuthPlugin;
+ productReference = 8D5B49B6048680CD000E48DA /* aklog.bundle */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 089C1669FE841209C02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "AklogAuthPlugin" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 089C166AFE841209C02AAC07 /* aklogAuthPlugin */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D5B49AC048680CD000E48DA /* AklogAuthPlugin */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D5B49AF048680CD000E48DA /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D5B49B1048680CD000E48DA /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BFB1A01A1032470E00FAF9DB /* aklog.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB913B08733D840010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "ARCHS[sdk=macosx10.4u]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.5]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.6]" = "$(ARCHS_STANDARD_32_64_BIT)";
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = AklogAuthPlugin_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "$(HOME)/Library/Bundles";
+ PRODUCT_NAME = aklog;
+ WRAPPER_EXTENSION = bundle;
+ };
+ name = Debug;
+ };
+ 1DEB913C08733D840010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "ARCHS[sdk=macosx10.4u]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.5]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.6]" = "$(ARCHS_STANDARD_32_64_BIT)";
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = AklogAuthPlugin_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "$(HOME)/Library/Bundles";
+ PRODUCT_NAME = aklog;
+ WRAPPER_EXTENSION = bundle;
+ };
+ name = Release;
+ };
+ 1DEB913F08733D840010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "ARCHS[sdk=macosx10.4u]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.5]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.6]" = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx10.6;
+ };
+ name = Debug;
+ };
+ 1DEB914008733D840010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "ARCHS[sdk=macosx10.4u]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.5]" = "$(ARCHS_STANDARD_32_BIT)";
+ "ARCHS[sdk=macosx10.6]" = "$(ARCHS_STANDARD_32_64_BIT)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ ONLY_ACTIVE_ARCH = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx10.6;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "AklogAuthPlugin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB913B08733D840010E9CD /* Debug */,
+ 1DEB913C08733D840010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "AklogAuthPlugin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB913F08733D840010E9CD /* Debug */,
+ 1DEB914008733D840010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
--- /dev/null
+#ifdef __OBJC__
+ #import <Cocoa/Cocoa.h>
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>aklog</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleName</key>
+ <string>aklog</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.openafs.authorization.aklog</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+</dict>
+</plist>
--- /dev/null
+Setup:
+
+http://support.apple.com/kb/TA20987 explains how to configure loginwindow
+to do Kerberos. After you have done so and it works, you can add this as
+aklog:CELLNAME,privileged
+
+after loginwindow:success and before HomeDirMechanism:login,privileged
+
+e.g.
+change
+<string>loginwindow:success</string>
+<string>HomeDirMechanism:login,privileged</string>
+
+to
+
+<string>loginwindow:success</string>
+<string>aklog:andrew.cmu.edu,privileged</string>
+<string>HomeDirMechanism:login,privileged</string>
+
+in the system.login.console section of /etc/authorization.
+
+The following is from Apple's ROT13 plugin:
+
+Note: The preferred way to modify the /etc/authorization file is to use
+the Authorization APIs in <Security/AuthorizationDB.h>. This is always
+how it should be done in shipping products, as there may have been other
+modifications to the /etc/authorization file. A code snippet to do this
+is:
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/AuthorizationDB.h>
+
+#define LOGIN_RIGHT "system.login.console"
+
+int main(int argc, char *argv[])
+{
+ CFDictionaryRef login_dict;
+ OSStatus status;
+ AuthorizationRef authRef;
+
+ status = AuthorizationCreate(NULL, NULL, 0, &authRef);
+ if (status) exit(1);
+
+ status = AuthorizationRightGet(LOGIN_RIGHT, &login_dict);
+ if (status) exit(1);
+
+ CFArrayRef arrayRef;
+ if (!CFDictionaryGetValueIfPresent(login_dict, CFSTR("mechanisms"),
+ &arrayRef))
+ exit(1);
+
+ CFMutableArrayRef newMechanisms = CFArrayCreateMutableCopy(NULL, 0,
+ arrayRef);
+ if (!newMechanisms)
+ exit(1);
+
+ CFIndex index = CFArrayGetFirstIndexOfValue(newMechanisms,
+ CFRangeMake(0, CFArrayGetCount(newMechanisms)), CFSTR("authinternal"));
+
+ if (index == -1)
+ exit(1);
+
+ CFArraySetValueAtIndex(newMechanisms, index, CFSTR("newmech"));
+
+ CFMutableDictionaryRef new_login_dict
+ = CFDictionaryCreateMutableCopy(NULL, 0, login_dict);
+
+ CFDictionarySetValue(new_login_dict, CFSTR("mechanisms"), newMechanisms);
+
+ status = AuthorizationRightSet(authRef, LOGIN_RIGHT, new_login_dict,
+ NULL, NULL, NULL);
+
+ if (status) exit(1);
+}
--- /dev/null
+/*
+ *
+ * aklog auth plugin, Taken from rot13 with guidance from NullAuthPlugin
+ * Copyright (c) 2010 Your File System Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/kauth.h>
+
+#include <Security/AuthorizationTags.h>
+#include <Security/AuthorizationPlugin.h>
+#include <DirectoryService/DirectoryService.h>
+
+typedef struct PluginRef
+{
+ const AuthorizationCallbacks *callbacks;
+} PluginRef;
+
+typedef struct MechanismRef
+{
+ const PluginRef *plugin;
+ AuthorizationEngineRef engine;
+ char *mechanismArg;
+} MechanismRef;
+
+static OSStatus do_aklog(char *cell)
+{
+ /*
+ * The first draft used aklog source inline. In an rxgk
+ * universe, that code should be encapsulated in a library
+ * we call. In this version we simply fork aklog.
+ * This function should be replaced with calls to a "libaklog"
+ */
+
+ char *aklogCmd;
+ if (cell) {
+ asprintf(&aklogCmd, "/usr/bin/aklog %s", cell);
+ if (aklogCmd)
+ return system(aklogCmd);
+ else
+ return -1;
+ }
+
+ return system("/usr/bin/aklog");
+}
+
+static OSStatus invokeAklog(MechanismRef *mechanism)
+{
+ AuthorizationContextFlags contextFlags;
+ const AuthorizationValue *value;
+ OSStatus status;
+ uid_t uid = 0;
+ gid_t gid = 0;
+
+ /* a list of context values appears in the Null sample plugin */
+ status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine,
+ kDS1AttrUniqueID,
+ &contextFlags,
+ &value);
+
+ /* This and the group are strings. I don't know why. */
+ if (!status)
+ uid = atoi(value->data);
+ else
+ goto failed;
+
+ status = mechanism->plugin->callbacks->GetContextValue(mechanism->engine,
+ kDS1AttrPrimaryGroupID,
+ &contextFlags,
+ &value);
+ if (!status)
+ gid = atoi(value->data);
+ else
+ goto failed;
+
+ /* in a PAGless universe, this trick works */
+ status = pthread_setugid_np(uid, gid);
+ if (status == 0) {
+ status = do_aklog(mechanism->mechanismArg);
+ pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
+ if (status)
+ goto failed;
+ }
+
+ status =
+ mechanism->plugin->callbacks->SetResult(mechanism->engine,
+ kAuthorizationResultAllow);
+
+ if (!status)
+ return errAuthorizationSuccess;
+
+failed:
+ return errAuthorizationInternal;
+}
+
+static OSStatus pluginDestroy(AuthorizationPluginRef inPlugin)
+{
+ /* seems to not be called. can't do cleanup? */
+ PluginRef *plugin = (PluginRef *)inPlugin;
+ free(plugin);
+ return 0;
+}
+
+static OSStatus mechanismCreate(AuthorizationPluginRef inPlugin,
+ AuthorizationEngineRef inEngine,
+ AuthorizationMechanismId mechanismId,
+ AuthorizationMechanismRef *outMechanism)
+{
+ const PluginRef *plugin = (const PluginRef *)inPlugin;
+
+ MechanismRef *mechanism = calloc(1, sizeof(MechanismRef));
+
+ mechanism->plugin = plugin;
+ mechanism->engine = inEngine;
+ /*
+ * consider supporting a variant which backgrounds aklog and returns
+ * success where tokens are desired but not critical.
+ */
+ mechanism->mechanismArg = strdup(mechanismId);
+
+ *outMechanism = mechanism;
+
+ return 0;
+}
+
+
+static OSStatus mechanismInvoke(AuthorizationMechanismRef inMechanism)
+{
+ MechanismRef *mechanism = (MechanismRef *)inMechanism;
+ OSStatus status;
+
+ status = invokeAklog(mechanism);
+ if (status)
+ return errAuthorizationInternal;
+
+ /* mark success */
+ return mechanism->plugin->callbacks->SetResult(mechanism->engine, kAuthorizationResultAllow);
+}
+
+
+/**
+ * Since a authorization result is provided within invoke, we don't have to
+ * cancel a long(er) term operation that might have been spawned.
+ * A timeout could be done here.
+ */
+static OSStatus mechanismDeactivate(AuthorizationMechanismRef inMechanism)
+{
+ return 0;
+}
+
+
+static OSStatus mechanismDestroy(AuthorizationMechanismRef inMechanism)
+{
+ MechanismRef *mechanism = (MechanismRef *)inMechanism;
+ free(mechanism->mechanismArg);
+ free(mechanism);
+
+ return 0;
+}
+
+
+AuthorizationPluginInterface pluginInterface =
+{
+ kAuthorizationPluginInterfaceVersion, /* UInt32 version; */
+ pluginDestroy,
+ mechanismCreate,
+ mechanismInvoke,
+ mechanismDeactivate,
+ mechanismDestroy
+};
+
+
+/**
+ * Entry point for all plugins. Plugin and the host loading it exchange interfaces.
+ * Normally you'd allocate resources shared amongst all mechanisms here.
+ * When a plugin is created it may not necessarily be used, so be conservative
+ */
+OSStatus AuthorizationPluginCreate(const AuthorizationCallbacks *callbacks,
+ AuthorizationPluginRef *outPlugin,
+ const AuthorizationPluginInterface **outPluginInterface)
+{
+ PluginRef *plugin = calloc(1, sizeof(PluginRef));
+
+ plugin->callbacks = callbacks;
+ *outPlugin = (AuthorizationPluginRef) plugin;
+ *outPluginInterface = &pluginInterface;
+ return 0;
+}
.PHONY: all afscell
-all: OpenAFS.prefPane afssettings afscell growlagent
+all: OpenAFS.prefPane afssettings afscell growlagent aklog.bundle
AFSPreference/build/Release/OpenAFS.prefPane: OpenAFS.prefPane
afscell/build/Release/afscell.bundle: afscell
echo Not building AFS prefPane for ${SYS_NAME} ;; \
esac
+aklog.bundle:
+ @case ${SYS_NAME} in \
+ *_darwin_100 ) \
+ xcodebuild -sdk macosx10.6 -project ${srcdir}/AklogAuthPlugin/AklogAuthPlugin.xcodeproj SYMDIR=`pwd`/AklogAuthPlugin/build;; \
+ *_darwin_90 ) \
+ xcodebuild -sdk macosx10.5 -project ${srcdir}/AklogAuthPlugin/AklogAuthPlugin.xcodeproj SYMDIR=`pwd`/AklogAuthPlugin/build;; \
+ *_darwin_80 ) \
+ xcodebuild -sdk macosx10.4 -project ${srcdor}/AklogAuthPlugin/AklogAuthPlugin.xcodeproj SYMDIR=`pwd`/AklogAuthPlugin/build;; \
+ * ) \
+ echo Not building AklogAuthPlugin for ${SYS_NAME} ;; \
+ esac
+
growlagent:
cd growlagent && $(MAKE) all
${DEST}/etc/afssettings \
${DEST}/installer/afscell.bundle \
${DEST}/installer/InstallerSections.plist \
- ${DEST}/tools/OpenAFS.prefPane
+ ${DEST}/tools/OpenAFS.prefPane \
+ ${DEST}/tools/aklog.bundle
cd growlagent && $(MAKE) dest
${DESTDIR}${sbindir}/afssettings: afssettings
${DEST}/etc/afssettings: afssettings
${INSTALL} $? $@
+${DEST}/tools/aklog.bundle: AklogAuthPlugin/build/Release/aklog.bundle
+ -mkdir -p ${DEST}/tools
+ rm -rf ${DEST}/tools/aklog.bundle
+ cp -R $? $@
+
${DEST}/installer/afscell.bundle: afscell/build/Release/afscell.bundle
- mkdir -p ${DEST}/installer
+ -mkdir -p ${DEST}/installer
rm -rf ${DEST}/installer/afscell.bundle
cp -R $? $@
${INSTALL} $? $@
${DEST}/tools/OpenAFS.prefPane: AFSPreference/build/Release/OpenAFS.prefPane
- mkdir -p ${DEST}/tools
+ -mkdir -p ${DEST}/tools
rm -rf ${DEST}/tools/OpenAFS.prefPane
cp -R $? $@
clean:
$(RM) -rf OpenAFS.prefPane
$(RM) -rf AFSPreference/build
+ $(RM) -rf AklogAuthPlugin/build
$(RM) -rf afscell/build
$(RM) -f *.o core afssettings AFS_component_version_number.c
cd growlagent && $(MAKE) clean