Re: TPE diff against 2.6.8 with 2.6.9-rc3 patches

From: Niki Rahimi (narahimi@private)
Date: Fri Oct 08 2004 - 19:50:08 PDT


 I apologize. This is not reversed plus adds tpe.txt to Documentation 
directory.

diff -Naur linux-2.6.8/Documentation/tpe.txt 
linux-2.6.8tpe/Documentation/tpe.txt
--- linux-2.6.8/Documentation/tpe.txt   1969-12-31 16:00:00.000000000 
-0800
+++ linux-2.6.8tpe/Documentation/tpe.txt        2004-10-08 
14:47:57.000000000 -0700
@@ -0,0 +1,52 @@
+Trusted Path Execution LSM
+Copyright (C) 2003 IBM Corp. <narahimi@private>
+Author: Niki A. Rahimi
+This file is distributed according to the GNU General Public License.
+This module was tested on the Linux kernel 2.5.59.
+
+The purpose of the Trusted Path Execution Linux Security Module is to 
enable a
+check in the Linux kernel to limit the running of executables in trusted 
paths
+so that the potential for malicious code to be run on the system is 
reduced.
+A trusted path is one in which the parent directory of a file is owned by 
root
+and is neither group nor other writeable. 
+The module relies on a kernel hook which checks to see if the given path 
is
+trusted or not. This check takes place directly upon an attempt to 
execute the
+code. 
+The module also creates a Trusted Path access control list and utilizes a 

+userspace tool to add or remove users to the list. A user on the list is 
+considered trusted. By default, root is hard coded onto this list.
+Thus if user A attempts to run an executable in path A, the following 
scenarios
+can play out:
+
+1. Trusted user, trusted path = User is able to run the executable.
+2. Trusted user, untrusted path  =  User is able to run the executable.
+3. Untrusted user, trusted path = User is able to run the executable.
+4. Untrusted user, untrusted path = User is not able to run the 
executable.
+
+In short, if the path and user are both untrusted, execution will be 
denied.
+
+In order to actually modify the access control list for TPE, the module 
uses
+a sysfs subsystem called tpefs. The tpefs contains two files; add and del
+Performing read and write operations on the aforementioned files creates 
a user
+to system interface that will alter the trusted list. See "Modifying the 
+Trusted List" below for the methods of altering the list using these 
files.
+Note: The two file approach was utilized rather than a single file in 
order to
+keep the code and administration of the module simple for both the kernel 
and
+the user.
+
+Installation: 
+1. Recompile the kernel to include LSM and TPE as a module.
+2. mount -t sysfs sysfs <mountpoint>
+3. insmod tpe.o
+4. See "Modifying the Trusted List" below  for instructions on how to 
add/delete
+users to/from the list.
+
+Modifying the Trusted List:
+Adding a user: echo <uid> > <mountpoint>/tpefs/add
+Deleting a user: echo <uid> > <mountpoint>/tpefs/del
+Show list to userspace: cat <mountpoint>/tpefs/add
+
+Note: The above methods utilizing echo and cat are good examples of how 
to
+alter the list. If the user is so interested, they may utilize other 
methods
+of read/write on the files in order to perform similar actions on the 
list.
+One example might be doing a "more <mountpoint>/tpefs/add" in order to 
show the list.
diff -Naur linux-2.6.8/security/Kconfig linux-2.6.8tpe/security/Kconfig
--- linux-2.6.8/security/Kconfig        2004-10-08 14:54:33.000000000 
-0700
+++ linux-2.6.8tpe/security/Kconfig     2004-10-08 14:47:31.000000000 
-0700
@@ -44,6 +44,20 @@
 
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_TPE
+       tristate "Trusted Path Execution (EXPERIMENTAL)"
+       depends SECURITY && EXPERIMENTAL
+       help
+        The TPE module enforces a check on the running of executables.
+        It will not allow execution if the program is located in a 
+        "trusted path" and the current user is "untrusted". A trusted
+        path is one which is root owned an neither group nor other
+        writeable. A user is considered trusted if their uid is added 
+        to a trusted list in memory. Root is trusted, by default.
+        Contact Niki A. Rahimi <narahimi@private> for more info.
+
+        If you're unsure, answer N.
+
 source security/selinux/Kconfig
 
 endmenu
diff -Naur linux-2.6.8/security/Makefile linux-2.6.8tpe/security/Makefile
--- linux-2.6.8/security/Makefile       2004-08-13 22:37:26.000000000 
-0700
+++ linux-2.6.8tpe/security/Makefile    2004-10-08 14:47:36.000000000 
-0700
@@ -14,4 +14,5 @@
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)    += commoncap.o capability.o
+obj-$(CONFIG_SECURITY_TPE)             += tpe.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += commoncap.o root_plug.o
diff -Naur linux-2.6.8/security/tpe.c linux-2.6.8tpe/security/tpe.c
--- linux-2.6.8/security/tpe.c  1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.8tpe/security/tpe.c       2004-10-08 14:47:16.000000000 
-0700
@@ -0,0 +1,375 @@
+/*
+ * Trusted Path Execution Security Module
+ *
+ * This module is an attempt to bring Trusted Path Execution (TPE) to the
+ * Linux kernel. TPE originated as a kernel patch to OpenBSD 2.4 by
+ * route|daemon9 and Mike Schifman (see Phrack 54). We have modified the 
+ * original project to fit within the constraints of the LSM framework
+ * and so it should be noted that this is not the same project. Also,
+ * the module makes use of a pseudo filesystem approach created by
+ * Greg Kroah-Hartman for his work on pcihotplug. 
+ *
+ * Also, thanks and credit to Serge Hallyn for his help on getting the 
bugs 
+ * out of this module. 
+ *
+ * Copyright (C) 1998 route|daemon9 and Mike D. Schiffman
+ * Copyright (C) 2001-2002  Greg Kroah-Hartman <greg@private>
+ * Copyright (C) 2003 IBM Corp. <narahimi@private>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * Alternatively, this program is free software; you can redistribute it 
and/or
+ * modify it under the terms of the GNU General Public License as 
published by
+ * the Free Software Foundation; either version 2 of the License, or (at 
your
+ * option) any later version.*
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/skbuff.h> 
+#include <linux/netlink.h> 
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/pagemap.h>
+#include <linux/namei.h> 
+#include <linux/vfs.h>
+#include <linux/mount.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "tpe.h"
+
+static int secondary;
+static spinlock_t tpe_acl_lock = SPIN_LOCK_UNLOCKED;
+
+/*  Insertion sort the list. */
+static void tpe_sort (int low, int high)  /* (list low element, list high 
element) */
+{
+       int i,j,n;
+       /* Standard insertion sort. */
+       for (i = low + 1; i <= high; i++) {
+               if (tpe_acl[i] < tpe_acl[low]) {
+                       tpe_acl[low] ^= tpe_acl[i];
+                       tpe_acl[i] ^= tpe_acl[low];
+                       tpe_acl[low] ^= tpe_acl[i];
+               } 
+       }
+
+       for (i = low + 2; i <= high; i++) {
+               j = i;
+               n = tpe_acl[i];
+               while (n < tpe_acl[j - 1]) {
+                       tpe_acl[j] = tpe_acl[j - 1];
+                       j--;
+               }
+               tpe_acl[j] = n;
+       }
+}
+
+/*  Attempt to add a candidate to the list.  */
+static int tpe_add (uid_t add_candidate)
+{
+       int retval = -EINVAL;
+
+       /* Full list. */
+       if (tpe_acl_candidates == (TPE_ACL_SIZE - 2)) {
+               printk(KERN_INFO "Unable to add user %d. List is full.\n",
+                                 add_candidate);
+               goto out;
+       }
+ 
+       if (add_candidate == 0) {
+               printk(KERN_INFO "tpe: Invalid userid. Cannot add.\n");
+               goto out;
+       }
+
+       /* Don't add duplicates */
+       if ((tpe_search(add_candidate)) == NACK) {
+               /* Add to the end of the list, then sort. */
+               tpe_acl_candidates++;
+               tpe_acl[tpe_acl_candidates] = add_candidate;
+               tpe_acl[tpe_acl_candidates + 1] = '\0'; /* terminate array 
*/
+               tpe_sort(0, tpe_acl_candidates);
+               printk(KERN_INFO "tpe: UID %d added to trust list\n",
+                                 add_candidate);
+       } else {
+               printk(KERN_INFO "tpe: duplicate UID %d not added\n",
+                                 add_candidate);
+               goto out;
+       }
+       retval = 0;
+out:
+       return retval;
+} 
+ 
+/*  Attempt to remove a candidate from the list.  Only fails if the entry 
is */
+/*  not there. */
+static int tpe_remove (uid_t rem_candidate)
+{
+       int n;
+       int retval = -EINVAL;
+       if (tpe_acl_candidates == 0) {
+               /* Empty list */
+               goto out;
+       }
+       if (rem_candidate == 0) {
+               printk(KERN_INFO "tpe: Invalid userid. Cannot remove.\n");
+               goto out;
+       }
+ 
+       n = tpe_search(rem_candidate);
+       if (n != NACK) {
+               /* Remove candidate (mark slot as unused), resort the 
list. */
+               tpe_acl[n] = TPE_INITIALIZER;
+               tpe_acl_candidates--;
+               tpe_sort(0, tpe_acl_candidates);
+               printk(KERN_INFO "tpe: UID %d removed from trust list\n",
+                                 rem_candidate);
+               retval = 0;
+               goto out;
+       }
+       /* Not found. */
+       printk(KERN_INFO "tpe: UID %d not found in trust list\n",
+                         rem_candidate);
+out:
+       return retval;
+}
+
+/* Beginning of a sysfs subsystem for tpe */
+static struct subsystem tpefs_subsys;
+
+struct tpe_list {
+       char *name;
+ 
+       struct list_head        slot_list;
+       struct kobject          kobj;
+};
+ 
+struct tpefs_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct tpe_list *, char *);
+       ssize_t (*store)(struct tpe_list *, const char *, size_t);
+};
+
+static ssize_t tpefs_attr_show(struct kobject *kobj, struct attribute 
*attr,
+char *buf)
+{
+       struct tpe_list *list = container_of(kobj, struct tpe_list, kobj);
+       struct tpefs_attribute *attribute = container_of(attr, struct
+       tpefs_attribute, attr);
+       return attribute->show ? attribute->show(list, buf) : 0;
+}
+
+static ssize_t tpefs_attr_store(struct kobject *kobj, struct attribute 
*attr,
+const char *buf, size_t len)
+{
+       struct tpe_list *list = container_of(kobj, struct tpe_list, kobj);
+       struct tpefs_attribute *attribute = container_of(attr, struct
+       tpefs_attribute, attr);
+       return attribute->store ? attribute->store(list, buf, len) : 0;
+}
+
+static struct sysfs_ops tpefs_sysfs_ops = {
+       .show = tpefs_attr_show,
+       .store = tpefs_attr_store,
+};
+
+static struct kobj_type tpefs_ktype = {
+       .sysfs_ops = &tpefs_sysfs_ops
+};
+
+static decl_subsys(tpefs, &tpefs_ktype, NULL);
+
+static ssize_t trustedlistadd_read_file (struct tpe_list *list, char 
*buf)
+{
+       int i;
+       int retval = 0;
+       char *user = NULL;
+       char buffer[400];
+
+       user = (char *)__get_free_page(GFP_KERNEL);
+       if (!user)
+               return -ENOMEM;
+
+       if (tpe_acl == NULL) {
+               printk(KERN_INFO "empty acl list\n");
+               return -ENODATA; 
+       }
+
+       buffer[0] = '\0';
+       printk(KERN_INFO "%d trusted user(s): \n", tpe_acl_candidates);
+       spin_lock(&tpe_acl_lock);
+       for (i=0; i < tpe_acl_candidates; i++) {
+               printk(KERN_INFO "%d ", tpe_acl[i]);
+               retval = sprintf(user, "%d\n", tpe_acl[i]); 
+               strcat(buffer, user);
+       }
+       printk(KERN_INFO "\n");
+       spin_unlock(&tpe_acl_lock);
+ 
+       retval = snprintf(buf, 4096, "%s\n", buffer);
+
+       free_page((unsigned long)user);
+       return retval;
+}
+
+static ssize_t trustedlistadd_write_file (struct tpe_list *list, const 
char *buf,
+size_t count)
+{
+       int retval; 
+       unsigned long add_candidate;
+
+       add_candidate = simple_strtoul(buf, NULL, 10); 
+
+       printk(KERN_INFO "value of add_candidate is %d.\n", 
(int)add_candidate);
+       spin_lock(&tpe_acl_lock);
+       retval = tpe_add(add_candidate);
+       spin_unlock(&tpe_acl_lock);
+       if (retval) {
+               return retval;
+       } 
+       return count;
+
+}
+
+struct tpefs_attribute tpefs_listadd_attr = {
+       .attr = {.name = "add", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+       .show = trustedlistadd_read_file,
+       .store = trustedlistadd_write_file
+};
+ 
+static ssize_t trustedlistdel_write_file (struct tpe_list *list, const 
char *buf,
+size_t count)
+{
+       int retval; 
+       unsigned long rem_candidate;
+
+       rem_candidate = simple_strtoul(buf, NULL, 10);
+ 
+       printk(KERN_INFO "value of rem_candidate is %d.\n", 
(int)rem_candidate);
+       spin_lock(&tpe_acl_lock);
+       retval = tpe_remove(rem_candidate);
+       spin_unlock(&tpe_acl_lock);
+       if (retval) {
+               return retval;
+       } 
+       return count;
+
+}
+
+struct tpefs_attribute tpefs_listdel_attr = {
+       .attr = {.name = "del", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+       .store = trustedlistdel_write_file
+};
+ 
+/* Module code */
+
+static int tpe_bprm_set_security (struct linux_binprm *bprm)
+{
+       uid_t pthuid = bprm->file->f_dentry->d_parent->d_inode->i_uid; 
+       mode_t pthmode = bprm->file->f_dentry->d_parent->d_inode->i_mode;
+       if((!TRUSTED_PATH(pthmode, pthuid)) && 
(!TRUSTED_USER(current->euid))) {
+                       printk (KERN_INFO "An attempt to run an executable 
"
+                               "by an untrusted user was made in an 
untrusted "
+                               "path. Access denied.\n");
+                       return -EACCES;
+       } 
+       return 0;
+}
+
+struct security_operations tpe_security_ops = {
+        bprm_set_security:              tpe_bprm_set_security,
+};
+
+#if defined(CONFIG_SECURITY_TPE_MODULE)
+#define MY_NAME THIS_MODULE->name
+#else
+#define MY_NAME "tpe"
+#endif
+
+static int __init tpe_module_init (void)
+{
+       int retval;
+       /* register ourselves with the security framework */
+       if (register_security (&tpe_security_ops)) {
+               printk (KERN_INFO
+                       "Failure registering tpe module with the 
kernel\n");
+               /* try registering with primary module */
+               if (mod_reg_security (MY_NAME, &tpe_security_ops)) {
+                       printk (KERN_INFO "Failure registering tpe module 
"
+                               "with primary security module.\n");
+                       return -EINVAL;
+               }
+               secondary = 1;
+       }
+ 
+       /* register tpe subsystem */
+       printk(KERN_INFO "registering tpe subsystem.\n");
+       retval = subsystem_register(&tpefs_subsys);
+       if (retval) {
+               printk(KERN_INFO "subsystem_register failed with %d\n", 
retval);
+               return retval;
+       }
+ 
+       sysfs_create_file(&tpefs_subsys.kset.kobj, 
&tpefs_listadd_attr.attr);
+       sysfs_create_file(&tpefs_subsys.kset.kobj, 
&tpefs_listdel_attr.attr);
+ 
+       printk(KERN_INFO "tpe LSM initialized\n");
+       tpe_init();
+       printk(KERN_INFO "Trusted path execution initialized.\n");
+       return 0;
+}
+
+static void __exit tpe_exit (void)
+{
+       sysfs_remove_file(&tpefs_subsys.kset.kobj, 
&tpefs_listadd_attr.attr);
+       sysfs_remove_file(&tpefs_subsys.kset.kobj, 
&tpefs_listdel_attr.attr);
+       subsystem_unregister(&tpefs_subsys); 
+ 
+       /* remove ourselves from the security framework */
+       if (secondary) {
+               if (mod_unreg_security (MY_NAME, &tpe_security_ops))
+                       printk (KERN_INFO "Failure unregistering tpe 
module "
+                               "with primary module.\n");
+                       return;
+       }
+ 
+       if (unregister_security (&tpe_security_ops)) {
+               printk (KERN_INFO
+                       "Failure unregistering tpe module with the 
kernel\n");
+       }
+       printk(KERN_INFO "tpe LSM removed\n");
+
+}
+
+module_init (tpe_module_init);
+module_exit (tpe_exit);
+
+MODULE_DESCRIPTION("LSM implementation of Trusted Path Execution");
+MODULE_LICENSE("Dual BSD/GPL");
diff -Naur linux-2.6.8/security/tpe.h linux-2.6.8tpe/security/tpe.h
--- linux-2.6.8/security/tpe.h  1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.8tpe/security/tpe.h       2004-10-08 14:47:22.000000000 
-0700
@@ -0,0 +1,112 @@
+/*
+ *  Trusted path ACL implementation created as a Loadable Security 
Module.
+ *  This project is an abstraction of the original Trusted Path Execution
+ *  patch to OpenBSD, which was created by route|daemon9 and Mike 
Schiffman. 
+ *  For the original OpenBSD write-up, see Phrack Magazine, issue 54, 
+ *  article 6 at http://www.phrack.com.
+ *
+ *  A path is considered trusted if the parent directory is owned by root
+ *  and is neither group nor world writeable. A user is considered 
trusted
+ *  if she/he is on the kernels trust list, as created by this module. An
+ *  untrusted user attempting to run an executable in an untrusted path 
+ *  will be denied execution.
+ *
+ *  Copyright (c) 1998 route|daemon9 and Mike D. Schiffman
+ *  Copyright (c) 2003 IBM Corp. <narahimi@private>
+ *  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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * Alternatively, this program is free software; you can redistribute it 
and/or
+ * modify it under the terms of the GNU General Public License as 
published by
+ * the Free Software Foundation; either version 2 of the License, or (at 
your
+ * option) any later version.*
+ */
+
+#ifndef __TPE_H
+#define __TPE_H
+
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+/*
+ *  syscall stuff
+ */
+#define TPE_ACL_SIZE    82      /* Maximum number of users in the list 
+                                * plus two. This was an original
+                                * component of TPE. This will be 
+                                * fixed later on.
+                                */ 
+ 
+#define TPE_INITIALIZER -1      /* A UID that isn't used */
+
+#define ACK             1       /* positive acknowledgement */
+#define NACK            -1      /* negative acknowledgement */
+#define DUP            3       /* duplicate id return for tpe_add */
+
+/*
+ *  Verify the path. 
+ */
+#define TRUSTED_PATH(mode, uid) \
+(!(mode & (S_IWGRP | S_IWOTH)) && (uid == 0))
+
+static uid_t tpe_acl[TPE_ACL_SIZE];    /* trusted user list */
+static int tpe_acl_candidates;         /* number of users on the list */
+
+/*
+ * Verify the user. This macro is passed the user's ID from the 
+ * tpe_bprm_set_security hook. 
+ */
+
+#define TRUSTED_USER(UID) (tpe_verify(UID) == ACK)
+
+/*  Initialize the array with default values (TPE_INITIALIZER). */
+
+static inline void tpe_init (void)
+{
+       memset(tpe_acl, TPE_INITIALIZER, sizeof(uid_t) * TPE_ACL_SIZE);
+       printk(KERN_INFO "tpe_acl list created\n");
+       tpe_acl_candidates = 1;
+       tpe_acl[0] = 0;
+}
+
+/*  Locate a uid in the list */
+static inline int tpe_search (uid_t candidate)
+{ 
+       int i;
+       for (i = 0; i < tpe_acl_candidates; i++) {
+               if (candidate == tpe_acl[i]) {
+                       return i;
+               }
+       }
+       return NACK;
+}
+
+/*  Verify a candidate user. */
+static inline int tpe_verify (uid_t candidate)
+{
+       if ((tpe_search(candidate)) != NACK) { 
+               return (ACK);
+       }
+       return (NACK);
+}
+#endif  /* __TPE_H */



This archive was generated by hypermail 2.1.3 : Mon Oct 11 2004 - 11:36:59 PDT