]> andersk Git - moira.git/blobdiff - incremental/winad/winad.c
Build shared libmoira via libtool.
[moira.git] / incremental / winad / winad.c
index 9b3688fb48629c85a084be8fd68c0544d5052310..88d29083fb815d73202a5b6067f4b3bf2e1c37a3 100755 (executable)
 /* $Header$
-/* test parameters for creating a user account - done 
- * users 10 10 a_chen 31275 sh cmd Lastname Firstname Middlename 0 950000000 STAFF a_chen 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF
- * users 10 10 a_chen 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF a_chen 31275 sh cmd Lastname Firstname Middlename 1 950000000 STAFF
- *   login, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type
+/* winad.incr arguments example
  *
- * test parameters for deactivating/deleting a user account - done
- * users 10 10 a_chen 31275 sh cmd Lastname Firstname Middlename 1 950000000 STAFF a_chen 31275 sh cmd Lastname Firstname Middlename 3 950000000 STAFF 
- * users 10 10 a_chen 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF a_chen 31275 sh cmd Lastname Firstname Middlename 3 950000000 STAFF 
- *   login, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type
- * comment: clearid is the MIT ID
+ * arguments when moira creates the account - ignored by winad.incr since the 
+ * account is unusable. users 0 11 #45198 45198 /bin/cmd cmd Last First Middle
+ * 0 950000001 2000 121049
  *
- * test parameters for reactivating a user account - done
- * users 10 10 testacc 31275 sh cmd Lastname Firstname Middlename 3 950000000 STAFF testacc 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF 
- *   login, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type
+ * login, unix_uid, shell, winconsoleshell, last, 
+ * first, middle, status, mitid, type, moiraid
  *
- * test parameters for updating user account info - done
- * users 10 10 testacc 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF testacc 31275 sh cmd newLastname Firstname Middlename 2 950000000 STAFF 
- * users 10 10 6_d0006 950 sh cmd Lastname Firstname Middlename 1 900012345 STAFF 6_d0006 950 sh cmd Lastname Firstname Middlename 1 950012345 STAFF
- *   login, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type
- *   currently, if the unix_id doesn't change, only the U_UID or U_MITID fields will be updated
+ * arguments for creating or updating a user account 
+ * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
+ * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
+ * First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
+ * users 11 11 #45206 45206 /bin/cmd cmd Last First Middle 0 950000001 STAFF
+ * 121058  PathToHomeDir PathToProfileDir newuser 45206 /bin/cmd cmd Last
+ * First Middle 2 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
  *
- * test parameters for changing user name - testing
- * users 10 10 a_chen 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF testacc1 31275 sh cmd Lastname Firstname Middlename 2 950000000 STAFF
- * users 10 10 testacc 31275 sh cmd Lastname Firstname Middlename 1 950000000 STAFF testacc1 31275 sh cmd Lastname Firstname Middlename 1 950000000 STAFF
- *   login, unix_uid, shell, winconsoleshell, last, first, middle, status, clearid, type
+ * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
+ * mitid, type, moiraid
  *
- * test parameters for add member to group/list - done
- * imembers 0 10 pismere-team USER dtanner 1 1 0 1 1 -1 1
- *   list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, gid
+ * arguments for deactivating/deleting a user account
+ * users 11 11 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
+ * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
+ * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
+ * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
+ * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
+ * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
+ * 
+ * login, unix_uid, shell, winconsoleshell, last, first, middle, status,
+ * mitid, type, moiraid
+ *
+ * arguments for reactivating a user account
+ * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
+ * 121058 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
+ * 121058
+ * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
+ * 121058 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF 12105
+ *
+ * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
+ * mitid, type, moiraid
+ *
+ * arguments for changing user name
+ * users 11 11 oldusername 45206 /bin/cmd cmd Last First Middle 1 950000001 
+ * STAFF 121058 PathToHomeDir PathToProfileDir newusername 45206 /bin/cmd cmd 
+ * Last First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
+ *
+ * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
+ * mitid, type, moiraid
+ *
+ * arguments for expunging a user
+ * users 11 0 username 45198 /bin/cmd cmd Last First Middle 0 950000001 2000
+ * 121049
+ *
+ * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
+ * mitid, type, moiraid
+ *
+ * arguments for creating a "special" group/list
+ * list 0 11 listname 1 1 0 0 0 -1 NONE 0 description 92616
+ *
+ * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraid
+ * 
+ * arguments for creating a "mail" group/list
+ * list 0 11 listname 1 1 0 1 0 -1 NONE 0 description 92616
+ *
+ * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraid
+ *
+ * arguments for creating a "group" group/list
+ * list 0 11 listname 1 1 0 0 1 -1 NONE 0 description 92616
+ * 
+ * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraid
+ *
+ * arguments for creating a "group/mail" group/list
+ * list 0 11 listname 1 1 0 1 1 -1 NONE 0 description 92616
+ *
+ * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraid
+ *
+ * arguments to add a USER member to group/list
+ * imembers 0 12 listname USER userName 1 1 0 0 0 -1 1 92616 121047
  *
- * test parameters for remove member from group/list - done
- * imembers 10 0 pismere-team USER dtanner 1 1 0 1 1 -1 1
- *   list_name, user_type, name, active, publicflg, hidden, maillist, grouplist, gid
+ * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
+ * gid, userStatus, moiraListId, moiraUserId
  *
- * test parameters for creating and/or populating a group/list - done
- * list 0 10 pismere-team 1 1 0 1 0 -1 USER 95260 description
- *   name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, acl_id, description
+ * arguments to add a STRING or KERBEROS member to group/list
+ * imembers 0 10 listname STRING stringName 1 1 0 0 0 -1 92616
+ * imembers 0 10 listlistnameName KERBEROS kerberosName 1 1 0 0 0 -1 92616
+ *
+ * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
+ * gid, moiraListId
+ *
+ * NOTE: group members of type LIST are ignored.
+ *
+ * arguments to remove a USER member to group/list
+ * imembers 12 0 listname USER userName 1 1 0 0 0 -1 1 92616 121047
+ * 
+ * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
+ * gid, userStatus, moiraListId, moiraUserId
+ *
+ * arguments to remove a STRING or KERBEROS member to group/list
+ * imembers 10 0 listname STRING stringName 1 1 0 0 0 -1 92616
+ * imembers 10 0 listname KERBEROS kerberosName 1 1 0 0 0 -1 92616
+ *
+ * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
+ * gid, moiraListId
+ *
+ * NOTE: group members of type LIST are ignored.
+ *
+ * arguments for renaming a group/list
+ * list 11 11 oldlistname 1 1 0 0 0 -1 NONE 0 description 92616 newlistname 1
+ * 1 0 0 0 -1 description 0 92616
  * 
- * test parameters for deleting a group/list - done
- * list 10 0 pismere-team 1 1 0 1 0 -1 USER 95260 description
- *   name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, acl_id, description
+ * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraListId
  *
- * test parameters for renaming a group/list - done
- *  list 10 10 adtestlist 1 1 0 1 0 -1 USER 95260 description pismere-team 1 1 0 1 1 -1 USER 95260 description
- *  list 10 10 pismere-team 1 1 0 1 1 -1 USER 95260 description adtestlist1 1 1 0 1 0 -1 USER 95260 description
- *   name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, acl_id, description
+ * arguments for deleting a group/list
+ * list 11 0 listname 1 1 0 0 0 -1 NONE 0 description 92616
  *
- * test parameters for adding a file system - done
- *   filesys 0 11 addusr5 AFS ATHENA.MIT.EDU /afs/athena.mit.edu/user/a/d/addusr5 /mit/addusr5 w UserLocker addusr5 wheel 1 HOMEDIR
+ * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
+ * acl_id, description, moiraListId
+ *
+ * arguments for adding a file system
+ * filesys 0 12 username AFS ATHENA.MIT.EDU 
+ * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
+ * wheel 1 HOMEDIR 101727
+ *
+ * arguments for deleting a file system
+ * filesys 12 0 username AFS ATHENA.MIT.EDU 
+ * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
+ * wheel 1 HOMEDIR 101727
+ *
+ * arguments when moira creates a container (OU).
+ * containers 0 8 machines/test/bottom description location contact USER
+ * 105316 2222 [none]
+ *
+ * arguments when moira deletes a container (OU).
+ * containers 8 0 machines/test/bottom description location contact USER 
+ * 105316 2222 groupname
+ *
+ * arguments when moira modifies a container information (OU).
+ * containers 8 8 machines/test/bottom description location contact USER 
+ * 105316 2222 groupname machines/test/bottom description1 location contact 
+ * USER 105316 2222 groupname
+ *
+ * arguments when moira adds a machine from an OU
+ * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
+ * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
+ *
+ * arguments when moira removes a machine from an OU
+ * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
+ * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
  *
- * test parameters for deleting a file system - done
- *   filesys 11 0 addusr8 AFS ATHENA.MIT.EDU /afs/athena.mit.edu/user/a/d/addusr8 /mit/addusr8 w none dtanner wheel 1 HOMEDIR
 */
+
 #include <mit-copyright.h>
+
 #ifdef _WIN32
+#include <winsock2.h>
 #include <windows.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <lmaccess.h>
 #endif
+
 #include <hesiod.h>
 #include <string.h>
 #include <ldap.h>
 #include <moira_site.h>
 #include <mrclient.h>
 #include <krb5.h>
-#include <krb.h>
 #include <gsssasl.h>
-#include <gssldap.h>
+#include <gssldap.h> 
 #include "kpasswd.h"
 
 #ifdef _WIN32
 #include <sys/utsname.h>
 #include <unistd.h>
 
-#define WINADCFG "/moira/winad/winad.cfg"
+#define CFG_PATH "/moira/winad/"
+#define WINADCFG "winad.cfg"
 #define strnicmp(A,B,C) strncasecmp(A,B,C)
 #define UCHAR unsigned char
 
 #define UF_WORKSTATION_TRUST_ACCOUNT    0x1000
 #define UF_SERVER_TRUST_ACCOUNT         0x2000
 
+#define OWNER_SECURITY_INFORMATION       (0x00000001L)
+#define GROUP_SECURITY_INFORMATION       (0x00000002L)
+#define DACL_SECURITY_INFORMATION        (0x00000004L)
+#define SACL_SECURITY_INFORMATION        (0x00000008L)
+
 #ifndef BYTE
 #define BYTE unsigned char
 #endif
@@ -143,6 +254,10 @@ typedef struct _SID {
 #define WINADCFG "winad.cfg"
 #endif
 
+#ifndef CFG_PATH
+#define CFG_PATH ""
+#endif 
+
 #define AFS "/afs/"
 #define WINAFS "\\\\afs\\all\\"
 
@@ -152,8 +267,11 @@ typedef struct _SID {
 #define ADS_GROUP_TYPE_UNIVERSAL_GROUP      0x00000008
 #define ADS_GROUP_TYPE_SECURITY_ENABLED     0x80000000
 
-#define QUERY_VERSION -1
-#define PRIMARY_REALM "ATHENA.MIT.EDU"
+#define QUERY_VERSION   -1
+#define PRIMARY_REALM   "ATHENA.MIT.EDU"
+#define PRIMARY_DOMAIN  "win.mit.edu"
+#define PRODUCTION_PRINCIPAL "sms"
+#define TEST_PRINCIPAL       "smstest"
 
 #define SUBSTITUTE  1
 #define REPLACE     2
@@ -174,6 +292,36 @@ typedef struct _SID {
 #define MOIRA_STRINGS   0x4
 #define MOIRA_LISTS     0x8
 
+#define CHECK_GROUPS    1
+#define CLEANUP_GROUPS  2
+
+#define AD_NO_GROUPS_FOUND        -1
+#define AD_WRONG_GROUP_DN_FOUND   -2
+#define AD_MULTIPLE_GROUPS_FOUND  -3
+#define AD_INVALID_NAME           -4
+#define AD_LDAP_FAILURE           -5
+#define AD_INVALID_FILESYS        -6
+#define AD_NO_ATTRIBUTE_FOUND     -7
+#define AD_NO_OU_FOUND            -8
+#define AD_NO_USER_FOUND          -9
+
+/* container arguments */
+#define CONTAINER_NAME       0
+#define CONTAINER_DESC       1
+#define CONTAINER_LOCATION   2
+#define CONTAINER_CONTACT    3
+#define CONTAINER_TYPE       4
+#define CONTAINER_ID         5
+#define CONTAINER_ROWID      6
+#define CONTAINER_GROUP_NAME 7
+
+/*mcntmap arguments*/
+#define OU_MACHINE_NAME        0
+#define OU_CONTAINER_NAME      1
+#define OU_MACHINE_ID          2
+#define OU_CONTAINER_ID        3
+#define OU_CONTAINER_GROUP     4
+
 typedef struct lk_entry {
   int     op;
   int     length;
@@ -190,89 +338,219 @@ typedef struct lk_entry {
 #define STOP_FILE "/moira/winad/nowinad"
 #define file_exists(file) (access((file), F_OK) == 0)
 
+#define N_SD_BER_BYTES   5
 #define LDAP_BERVAL struct berval
 #define MAX_SERVER_NAMES 32
 
+#define HIDDEN_GROUP                "HiddenGroup.g"
+#define HIDDEN_GROUP_WITH_ADMIN     "HiddenGroupWithAdmin.g"
+#define NOT_HIDDEN_GROUP            "NotHiddenGroup.g"
+#define NOT_HIDDEN_GROUP_WITH_ADMIN "NotHiddenGroupWithAdmin.g"
+
+#define ADDRESS_LIST_PREFIX "CN=MIT Directory,CN=All Address Lists,\
+CN=Address Lists Container,CN=Massachusetts Institute of Technology,\
+CN=Microsoft Exchange,CN=Services,CN=Configuration,"
+
 #define ADD_ATTR(t, v, o)              \
   mods[n] = malloc(sizeof(LDAPMod));   \
-  mods[n]->mod_op = o; \
+  mods[n]->mod_op = o;                 \
   mods[n]->mod_type = t;               \
   mods[n++]->mod_values = v
 
+#define DEL_ATTR(t, o)                         \
+  DelMods[i] = malloc(sizeof(LDAPMod));        \
+  DelMods[i]->mod_op = o;              \
+  DelMods[i]->mod_type = t;            \
+  DelMods[i++]->mod_values = NULL
+
+#define DOMAIN_SUFFIX   "MIT.EDU"
+#define DOMAIN  "DOMAIN:"
+#define PRINCIPALNAME  "PRINCIPAL:"
+#define SERVER  "SERVER:"
+#define MSSFU   "SFU:"
+#define SFUTYPE "30"
+#define GROUP_SUFFIX "GROUP_SUFFIX:"
+#define GROUP_TYPE   "GROUP_TYPE:"
+#define SET_GROUP_ACE    "SET_GROUP_ACE:"
+#define SET_PASSWORD "SET_PASSWORD:"
+#define EXCHANGE "EXCHANGE:"
+#define PROCESS_MACHINE_CONTAINER "PROCESS_MACHINE_CONTAINER:"
+#define MAX_DOMAINS 10
+char DomainNames[MAX_DOMAINS][128];
+
 LK_ENTRY *member_base = NULL;
-LK_ENTRY *sid_base = NULL;
-LK_ENTRY **sid_ptr = NULL;
+
+char   PrincipalName[128];
 static char tbl_buf[1024];
-char  kerberos_ou[] = "OU=kerberos, OU=moira";
-char  contact_ou[] = "OU=strings, OU=moira";
-char  user_ou[] = "OU=users, OU=moira";
-char  group_ou_distribution[] = "OU=mail, OU=lists, OU=moira";
-char  group_ou_root[] = "OU=lists, OU=moira";
-char  group_ou_security[] = "OU=group, OU=lists, OU=moira";
-char  group_ou_neither[] = "OU=special, OU=lists, OU=moira";
-char  group_ou_both[] = "OU=mail, OU=group, OU=lists, OU=moira";
+char  kerberos_ou[] = "OU=kerberos,OU=moira";
+char  contact_ou[] = "OU=strings,OU=moira";
+char  user_ou[] = "OU=users,OU=moira";
+char  group_ou_distribution[] = "OU=mail,OU=lists,OU=moira";
+char  group_ou_root[] = "OU=lists,OU=moira";
+char  group_ou_security[] = "OU=group,OU=lists,OU=moira";
+char  group_ou_neither[] = "OU=special,OU=lists,OU=moira";
+char  group_ou_both[] = "OU=mail,OU=group,OU=lists,OU=moira";
+char  orphans_machines_ou[] = "OU=Machines,OU=Orphans";
+char  orphans_other_ou[] = "OU=Other,OU=Orphans";
+char  security_template_ou[] = "OU=security_templates";
 char *whoami;
 char ldap_domain[256];
-int  mr_connections = 0;
-int  callback_rc;
-int  UserReactivate = 0;
+char *ServerList[MAX_SERVER_NAMES];
 char default_server[256];
 static char tbl_buf[1024];
+char group_suffix[256];
+char exchange_acl[256];
+int  mr_connections = 0;
+int  callback_rc;
+int  UseSFU30 = 0;
+int  UseGroupSuffix = 1;
+int  UseGroupUniversal = 0;
+int  SetGroupAce = 1;
+int  SetPassword = 1;
+int  Exchange = 0;
+int  ProcessMachineContainer = 1;
+int  UpdateDomainList;
 
 extern int set_password(char *user, char *password, char *domain);
 
+int ad_get_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
+                char *group_membership, char *MoiraId, char *attribute,
+                LK_ENTRY **linklist_base, int *linklist_count,
+                char *rFilter);
 void AfsToWinAfs(char* path, char* winPath);
 int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, 
                char *Win2kPassword, char *Win2kUser, char *default_server,
-               int connect_to_kdc);
+               int connect_to_kdc, char **ServerList);
 void ad_kdc_disconnect();
-void check_winad(void);
-int filesys_process(LDAP *ldap_handle, char *dn_path, char *fs_name, 
-                    char *fs_type, char *fs_pack, int operation);
+int ad_server_connect(char *connectedServer, char *domain);
+int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
+                    char *attribute_value, char *attribute, char *user_name);
+int BEREncodeSecurityBits(ULONG uBits, char *pBuffer);
+int checkADname(LDAP *ldap_handle, char *dn_path, char *Name);
+int check_winad(void);
+int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, 
+              char *MoiraId);
+/* containers */
+int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
+                       char *distinguishedName, int count, char **av);
+void container_check(LDAP *ldap_handle, char *dn_path, char *name);
+int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av);
+int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av);
+int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
+                                   char *distinguishedName, int count, 
+                                   char **av);
+void container_get_dn(char *src, char *dest);
+void container_get_name(char *src, char *dest);
+int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName);
+int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
+                    char **before, int afterc, char **after);
+int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
+                    char **before, int afterc, char **after);
+
+int GetAceInfo(int ac, char **av, void *ptr);
 int get_group_membership(char *group_membership, char *group_ou, 
                          int *security_flag, char **av);
+int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
+                  char *machine_ou, char *pPtr);
+int Moira_container_group_create(char **after);
+int Moira_container_group_delete(char **before);
+int Moira_groupname_create(char *GroupName, char *ContainerName,
+                          char *ContainerRowID);
+int Moira_container_group_update(char **before, char **after);
+int Moira_process_machine_container_group(char *MachineName, char* groupName,
+                                         int DeleteMachine);
+int Moira_addGroupToParent(char *origContainerName, char *GroupName);
+int Moira_getContainerGroup(int ac, char **av, void *ptr);
+int Moira_getGroupName(char *origContainerName, char *GroupName,
+                      int ParentFlag);
+int Moira_setContainerGroup(char *ContainerName, char *GroupName);
+int ProcessAce(LDAP *ldap_handle, char *dn_path, char *group_name, char *Type,
+               int UpdateGroup, int *ProcessGroup, char *maillist);
+int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
+                  char *group_name, char *group_ou, char *group_membership, 
+                  int group_security_flag, int type, char *maillist);
 int process_lists(int ac, char **av, void *ptr);
+int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
+                        char *TargetGroupName, int HiddenGroup, 
+                        char *AceType, char *AceName);
+int ProcessMachineName(int ac, char **av, void *ptr);
+int ReadConfigFile(char *DomainName);
+int ReadDomainList();
+void StringTrim(char *StringToTrim);
+int save_query_info(int argc, char **argv, void *hint);
 int user_create(int ac, char **av, void *ptr);
-int user_change_status(LDAP *ldap_handle, char *dn_path, char *user_name, int operation);
-int user_delete(LDAP *ldap_handle, char *dn_path, char *u_name);
+int user_change_status(LDAP *ldap_handle, char *dn_path, 
+                       char *user_name, char *MoiraId, int operation);
+int user_delete(LDAP *ldap_handle, char *dn_path, 
+                char *u_name, char *MoiraId);
 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
-                char *user_name, char *Uid, char *MitId, int State);
+                char *user_name);
 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
-                char *uid, char *MitId);
+                char *uid, char *MitId, char *MoiraId, int State,
+                char *WinHomeDir, char *WinProfileDir, char *first,
+               char *middle, char *last);
+void change_to_lower_case(char *ptr);
 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou);
+int contact_remove_email(LDAP *ld, char *bind_path,
+                        LK_ENTRY **linklist_entry, int linklist_current);
 int group_create(int ac, char **av, void *ptr);
 int group_delete(LDAP *ldap_handle, char *dn_path, 
-                 char *group_name, char *group_membership);
+                 char *group_name, char *group_membership, char *MoiraId);
 int group_rename(LDAP *ldap_handle, char *dn_path, 
                  char *before_group_name, char *before_group_membership, 
-                 char *before_group_ou, int before_security_flag, char *before_desc,
-                 char *after_group_name, char *after_group_membership, 
-                 char *after_group_ou, int after_security_flag, char *after_desc);
+                 char *before_group_ou, int before_security_flag, 
+                char *before_desc, char *after_group_name, 
+                char *after_group_membership, char *after_group_ou, 
+                int after_security_flag, char *after_desc,
+                 char *MoiraId, char *filter, char *maillist);
+int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name);
+int machine_GetMoiraContainer(int ac, char **av, void *ptr);
+int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
+                               char *machine_name, char *container_name);
+int machine_move_to_ou(LDAP *ldap_handle, char *dn_path, 
+                      char *MoiraMachineName, char *DestinationOu);
+int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
+                   char *group_name, char *group_ou, char *group_membership, 
+                   int group_security_flag, int updateGroup, char *maillist);
 int member_list_build(int ac, char **av, void *ptr);
 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
-                        char *group_ou, char *group_membership, 
-                        char *user_name, char *pUserOu);
+              char *group_ou, char *group_membership, 
+              char *user_name, char *pUserOu, char *MoiraId);
 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
                   char *group_ou, char *group_membership, char *user_name,
-                  char *pUserOu);
+                  char *pUserOu, char *MoiraId);
+int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
+                   char *group_ou, char *group_membership, 
+                   int group_security_flag, char *MoiraId);
+int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
+                    char *DistinguishedName,
+                     char *WinHomeDir, char *WinProfileDir,
+                     char **homedir_v, char **winProfile_v,
+                     char **drives_v, LDAPMod **mods, 
+                     int OpType, int n);
 int sid_update(LDAP *ldap_handle, char *dn_path);
+void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n);
 int check_string(char *s);
-void convert_b_to_a(char *string, UCHAR *binary, int length);
-int mr_connect_cl(char *server, char *client, int version, int auth);
+int check_container_name(char* s);
 
+int mr_connect_cl(char *server, char *client, int version, int auth);
+void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
+                 char **before, int beforec, char **after, int afterc);
 void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
-             char **before, int beforec, char **after, int afterc);
+               char **before, int beforec, char **after, int afterc);
 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
              char **before, int beforec, char **after, int afterc);
 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
              char **before, int beforec, char **after, int afterc);
 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
                char **before, int beforec, char **after, int afterc);
+void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
+                char **before, int beforec, char **after, int afterc);
 int linklist_create_entry(char *attribute, char *value,
                           LK_ENTRY **linklist_entry);
 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
                    char **attr_array, LK_ENTRY **linklist_base, 
-                   int *linklist_count);
+                   int *linklist_count, unsigned long ScopeType);
 void linklist_free(LK_ENTRY *linklist_base);
 
 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
@@ -294,6 +572,13 @@ void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry,
 int moira_disconnect(void);
 int moira_connect(void);
 void print_to_screen(const char *fmt, ...);
+int GetMachineName(char *MachineName);
+int tickets_get_k5();
+int destroy_cache(void);
+int dest_tkt(void);
+
+int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB,
+                char **homeServerName);
 
 int main(int argc, char **argv)
 {
@@ -301,452 +586,552 @@ int main(int argc, char **argv)
   int             beforec;
   int             afterc;
   int             i;
+  int             j;
+  int            k;
+  int             OldUseSFU30;
   char            *table;
   char            **before;
   char            **after;
   LDAP            *ldap_handle;
-  FILE            *fptr;
   char            dn_path[256];
-
+  char            *orig_argv[64];
+  
   whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
-
+  
   if (argc < 4)
     {
-      com_err(whoami, 0, "%s", "argc < 4");
+      com_err(whoami, 0, "Unable to process %s", "argc < 4");
       exit(1);
     }
-  beforec = atoi(argv[2]);
-  afterc = atoi(argv[3]);
-
-  if (argc < (4 + beforec + afterc))
+  
+  if (argc < (4 + atoi(argv[2]) + atoi(argv[3])))
     {
-      com_err(whoami, 0, "%s", "argc < (4 + breforec + afterc)");
+      com_err(whoami, 0, "Unable to process %s", 
+             "argc < (4 + beforec + afterc)");
       exit(1);
     }
 
-  table = argv[1];
-  before = &argv[4];
-  after = &argv[4 + beforec];
+  if (!strcmp(argv[1], "filesys"))
+    exit(0);
 
   for (i = 1; i < argc; i++)
     {
       strcat(tbl_buf, argv[i]);
       strcat(tbl_buf, " ");
     }
-  com_err(whoami, 0, "%s", tbl_buf);
 
-  check_winad();
+  com_err(whoami, 0, "%s", tbl_buf);
 
-  memset(ldap_domain, '\0', sizeof(ldap_domain));
-  if ((fptr = fopen(WINADCFG, "r")) != NULL)
+  if (check_winad())
     {
-      fread(ldap_domain, sizeof(char), sizeof(ldap_domain), fptr);
-      fclose(fptr);
+      com_err(whoami, 0, "%s failed", "check_winad()");
+      exit(1);
     }
-  if (strlen(ldap_domain) == 0)
-    strcpy(ldap_domain, "win.mit.edu");
+
   initialize_sms_error_table();
   initialize_krb_error_table();
 
-  memset(default_server, '\0', sizeof(default_server));
-  memset(dn_path, '\0', sizeof(dn_path));
-  if (ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", default_server, 1))
+  UpdateDomainList = 0;
+  memset(DomainNames, '\0', sizeof(DomainNames[0]) * MAX_DOMAINS);
+
+  if (ReadDomainList())
     {
-      com_err(whoami, 0, "cannot connect to any server in domain %s", ldap_domain);
+      com_err(whoami, 0, "%s failed", "ReadDomainList()");
       exit(1);
     }
 
-  for (i = 0; i < (int)strlen(table); i++)
-    table[i] = tolower(table[i]);
-  if (!strcmp(table, "users"))
-    do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after,
-            afterc);
-  else if (!strcmp(table, "list"))
-    do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
-            afterc);
-  else if (!strcmp(table, "imembers"))
-    do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
-              afterc);
-  else if (!strcmp(table, "filesys"))
-    do_filesys(ldap_handle, dn_path, ldap_domain, before, beforec, after,
-               afterc);
-/*
-  else if (!strcmp(table, "quota"))
-    do_quota(before, beforec, after, afterc);
-*/
+  for (i = 0; i < argc; i++)
+     orig_argv[i] = NULL;
 
-  ad_kdc_disconnect();
-  rc = ldap_unbind_s(ldap_handle);
+  for (k = 0; k < MAX_DOMAINS; k++)
+    {
+      if (strlen(DomainNames[k]) == 0)
+       continue;
+      for (i = 0; i < argc; i++)
+       {
+         if (orig_argv[i] != NULL)
+           free(orig_argv[i]);
+         orig_argv[i] = strdup(argv[i]);
+       }
+
+      memset(PrincipalName, '\0', sizeof(PrincipalName));
+      memset(ldap_domain, '\0', sizeof(ldap_domain));
+      memset(ServerList, '\0', sizeof(ServerList[0]) * MAX_SERVER_NAMES);
+      memset(default_server, '\0', sizeof(default_server));
+      memset(dn_path, '\0', sizeof(dn_path));
+      memset(group_suffix, '\0', sizeof(group_suffix));
+      memset(exchange_acl, '\0', sizeof(exchange_acl));
+
+      UseSFU30 = 0;
+      UseGroupSuffix = 1;
+      UseGroupUniversal = 0;
+      SetGroupAce = 1;
+      SetPassword = 1;
+      Exchange = 0;
+      ProcessMachineContainer = 1;
+
+      sprintf(group_suffix, "%s", "_group");
+      sprintf(exchange_acl, "%s", "exchange-acl");
+
+      beforec = atoi(orig_argv[2]);
+      afterc = atoi(orig_argv[3]);
+      table = orig_argv[1];
+      before = &orig_argv[4];
+      after = &orig_argv[4 + beforec];
+
+      if (afterc == 0)
+       after = NULL;
+
+      if (beforec == 0)
+       before = NULL;
+
+      if (ReadConfigFile(DomainNames[k]))
+       continue;
+
+      OldUseSFU30 = UseSFU30;
+
+      for (i = 0; i < 5; i++)
+       {
+         ldap_handle = (LDAP *)NULL;
+         if (!(rc = ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", 
+                               default_server, 1, ServerList)))
+           {
+             com_err(whoami, 0, "connected to domain %s", DomainNames[k]);
+             break;
+           }
+       }
+
+      if ((rc) || (ldap_handle == NULL))
+       {
+         critical_alert(whoami, "incremental",
+                        "winad.incr cannot connect to any server in "
+                        "domain %s", DomainNames[k]);
+         continue;
+       }
+
+      for (i = 0; i < (int)strlen(table); i++)
+       table[i] = tolower(table[i]);
+
+      if (!strcmp(table, "users"))
+       do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+               afterc);
+      else if (!strcmp(table, "list"))
+       do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+               afterc);
+      else if (!strcmp(table, "imembers"))
+       do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+                 afterc);
+      else if (!strcmp(table, "containers"))
+       do_container(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+                    afterc);
+      else if (!strcmp(table, "mcntmap"))
+       do_mcntmap(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+                  afterc);
+      
+      ad_kdc_disconnect();
+
+      for (i = 0; i < MAX_SERVER_NAMES; i++)
+       {
+         if (ServerList[i] != NULL)
+           {
+             free(ServerList[i]);
+             ServerList[i] = NULL;
+           }
+       }
+      
+      rc = ldap_unbind_s(ldap_handle);
+    }
+  
   exit(0);
 }
 
-void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
-             char **before, int beforec, char **after, int afterc)
+void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
+                char **before, int beforec, char **after, int afterc)
 {
-  long  rc;
-  char  *av[3];
-  char  *call_args[7];
-  int   acreate;
-  int   atype;
-  int   bcreate;
-  int   btype;
-  int   abort_flag;
-
-  abort_flag = 0;
+  char    MoiraContainerName[128];
+  char    ADContainerName[128];
+  char    MachineName[1024];
+  char    OriginalMachineName[1024];
+  long    rc;
+  int     DeleteMachine;
+  char    MoiraContainerGroup[64];
 
-  if (afterc < FS_CREATE)
-    atype = acreate = 0;
+  if (!ProcessMachineContainer)
+    {
+      com_err(whoami, 0, "Process machines and containers disabled, skipping");
+      return;
+    }
+  
+  DeleteMachine = 0;
+  memset(ADContainerName, '\0', sizeof(ADContainerName));
+  memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
+  
+  if ((beforec == 0) && (afterc == 0))
+    return;
+  
+  if (rc = moira_connect())
+    {
+      critical_alert(whoami, "AD incremental",
+                    "Error contacting Moira server : %s",
+                    error_message(rc));
+      return;
+    }
+  
+  if ((beforec != 0) && (afterc == 0)) /*remove a machine*/
+    {
+      strcpy(OriginalMachineName, before[OU_MACHINE_NAME]);
+      strcpy(MachineName, before[OU_MACHINE_NAME]);
+      strcpy(MoiraContainerGroup, before[OU_CONTAINER_GROUP]);
+      DeleteMachine = 1;
+      com_err(whoami, 0, "removing machine %s from %s", 
+             OriginalMachineName, before[OU_CONTAINER_NAME]);
+    }
+  else if ((beforec == 0) && (afterc != 0)) /*add a machine*/
+    {
+      strcpy(OriginalMachineName, after[OU_MACHINE_NAME]);
+      strcpy(MachineName, after[OU_MACHINE_NAME]);
+      strcpy(MoiraContainerGroup, after[OU_CONTAINER_GROUP]);
+      com_err(whoami, 0, "adding machine %s to container %s", 
+             OriginalMachineName, after[OU_CONTAINER_NAME]);
+    }
   else
     {
-      atype = !strcmp(after[FS_TYPE], "AFS");
-      acreate = atoi(after[FS_CREATE]);
+      moira_disconnect();
+      return;
+    }
+  
+  rc = GetMachineName(MachineName);
+
+  if (strlen(MachineName) == 0)
+    {
+      moira_disconnect();
+      com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
+             OriginalMachineName);
+      return;
     }
 
-  if (beforec < FS_CREATE)
+  Moira_process_machine_container_group(MachineName, MoiraContainerGroup,
+                                       DeleteMachine);
+
+  if (machine_check(ldap_handle, dn_path, MachineName))
     {
-      if (acreate == 0 || atype == 0)
-        goto cleanup;
-      com_err(whoami, 0, "Processing filesys %s", after[FS_NAME]);
-      abort_flag = 0;
-      while (1)
-      {
-        if ((rc = filesys_process(ldap_handle, dn_path, after[FS_NAME], 
-                    after[FS_TYPE], after[FS_PACK], LDAP_MOD_ADD)) != LDAP_NO_SUCH_OBJECT)
-          {
-            if (rc != LDAP_SUCCESS)
-              com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-            break;
-          }
-        if (abort_flag == 1)
-          break;
-        sleep(1);
-        abort_flag = 1;
-        if (rc = moira_connect())
-          {
-            critical_alert("AD incremental",
-                           "Error contacting Moira server : %s",
-                           error_message(rc));
-            return;
-          }
-        av[0] = after[FS_NAME];
-        call_args[0] = (char *)ldap_handle;
-        call_args[1] = dn_path;
-        call_args[2] = (char *)MEMBER_ACTIVATE;
-        call_args[3] = NULL;
-        sid_base = NULL;
-        sid_ptr = &sid_base;
-        callback_rc = 0;
-        if (rc = mr_query("get_user_account_by_login", 1, av, user_create,
-                          call_args))
-          {
-            moira_disconnect();
-            com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-            break;
-          }
-        if (callback_rc)
-          {
-            moira_disconnect();
-            com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-            break;
-          }
-        if (sid_base != NULL)
-          {
-            sid_update(ldap_handle, dn_path);
-            linklist_free(sid_base);
-            sid_base = NULL;
-          }
-        moira_disconnect();
-      }
-      goto cleanup;
+      com_err(whoami, 0, "Unable to find machine %s (alias %s) in AD.", 
+             OriginalMachineName, MachineName);
+      moira_disconnect();
+      return;
     }
 
-  btype = !strcmp(before[FS_TYPE], "AFS");
-  bcreate = atoi(before[FS_CREATE]);
-  if (afterc < FS_CREATE)
+  memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
+  machine_get_moira_container(ldap_handle, dn_path, MachineName, 
+                             MoiraContainerName);
+
+  if (strlen(MoiraContainerName) == 0)
     {
-      if (btype && bcreate)
-        {
-          if (rc = filesys_process(ldap_handle, dn_path, before[FS_NAME], 
-                      before[FS_TYPE], before[FS_PACK], LDAP_MOD_DELETE))
-            {
-              com_err(whoami, 0, "Couldn't delete filesys %s", before[FS_NAME]);
-            }
-        }
+      com_err(whoami, 0, "Unable to fine machine %s (alias %s) container "
+             "in Moira - moving to orphans OU.",
+             OriginalMachineName, MachineName);
+      machine_move_to_ou(ldap_handle, dn_path, MachineName, 
+                        orphans_machines_ou);
+      moira_disconnect();
+      return;
+    }
+
+  container_get_dn(MoiraContainerName, ADContainerName);
+
+  if (MoiraContainerName[strlen(MoiraContainerName) - 1] != '/')
+    strcat(MoiraContainerName, "/");
+
+  container_check(ldap_handle, dn_path, MoiraContainerName);
+  machine_move_to_ou(ldap_handle, dn_path, MachineName, ADContainerName);
+  moira_disconnect();
+  return;
+}
+
+void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
+                 char **before, int beforec, char **after, int afterc)
+{
+  long rc;
+
+  if (!ProcessMachineContainer)
+    {
+      com_err(whoami, 0, "Process machines and containers disabled, skipping");
       return;
     }
 
-  if (!acreate)
+  if ((beforec == 0) && (afterc == 0))
     return;
 
-  if (!atype && !btype)
+  if (rc = moira_connect())
     {
-      if (strcmp(before[FS_TYPE], "ERR") || strcmp(after[FS_TYPE], "ERR"))
-        {
-          com_err(whoami, 0, "Filesystem %s or %s is not AFS",
-                  before[FS_NAME], after[FS_NAME]);
-          return;
-        }
+      critical_alert(whoami, "AD incremental", "Error contacting Moira server : %s",
+                    error_message(rc));
+      return;
+    }
+
+  if ((beforec != 0) && (afterc == 0)) /*delete a new container*/
+    {
+      com_err(whoami, 0, "deleting container %s", before[CONTAINER_NAME]);
+      container_delete(ldap_handle, dn_path, beforec, before);
+      Moira_container_group_delete(before);
+      moira_disconnect();
+      return;
+    }
+
+  if ((beforec == 0) && (afterc != 0)) /*create a container*/
+    {
+      com_err(whoami, 0, "creating container %s", after[CONTAINER_NAME]);
+      container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
+      container_create(ldap_handle, dn_path, afterc, after);
+      Moira_container_group_create(after);
+      moira_disconnect();
+      return;
+    }
+
+  if (strcasecmp(before[CONTAINER_NAME], after[CONTAINER_NAME]))
+    {
+      com_err(whoami, 0, "renaming container %s to %s", 
+             before[CONTAINER_NAME], after[CONTAINER_NAME]);
+      container_rename(ldap_handle, dn_path, beforec, before, afterc, after);
+      Moira_container_group_update(before, after);
+      moira_disconnect();
+      return;
     }
-  com_err(whoami, 0, "Processing filesys %s", after[FS_NAME]);
-  abort_flag = 0;
-  while (1)
-  {
-    if ((rc = filesys_process(ldap_handle, dn_path, after[FS_NAME], 
-                    after[FS_TYPE], after[FS_PACK], LDAP_MOD_ADD)) != LDAP_NO_SUCH_OBJECT)
-      {
-        if (rc != LDAP_SUCCESS)
-          com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-        break;
-      }
-    if (abort_flag == 1)
-      break;
-    sleep(1);
-    abort_flag = 1;
-    if (rc = moira_connect())
-      {
-        critical_alert("AD incremental",
-                       "Error contacting Moira server : %s",
-                       error_message(rc));
-        return;
-      }
-    av[0] = after[FS_NAME];
-    call_args[0] = (char *)ldap_handle;
-    call_args[1] = dn_path;
-    call_args[2] = (char *)MEMBER_ACTIVATE;
-    call_args[3] = NULL;
-    sid_base = NULL;
-    sid_ptr = &sid_base;
-    callback_rc = 0;
-    if (rc = mr_query("get_user_account_by_login", 1, av, user_create,
-                      call_args))
-      {
-        moira_disconnect();
-        com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-        break;
-      }
-    if (callback_rc)
-      {
-        moira_disconnect();
-        com_err(whoami, 0, "Couldn't process filesys %s", after[FS_NAME]);
-        break;
-      }
-    if (sid_base != NULL)
-      {
-        sid_update(ldap_handle, dn_path);
-        linklist_free(sid_base);
-        sid_base = NULL;
-      }
-    moira_disconnect();
-  }
 
-cleanup:
+  com_err(whoami, 0, "updating container %s information", 
+         after[CONTAINER_NAME]);
+  container_update(ldap_handle, dn_path, beforec, before, afterc, after);
+  Moira_container_group_update(before, after);
+  moira_disconnect();
   return;
 }
+
+#define L_LIST_DESC 9
+#define L_LIST_ID   10
+
 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
              char **before, int beforec, char **after, int afterc)
 {
-  int   agid;
-  int   bgid;
-  int   ahide;
-  int   bhide;
-  int   apublic;
-  int   bpublic;
-  int   bgroup;
-  int   agroup;
-  int   amaillist;
-  int   bmaillist;
-  int   bstatus;
-  int   astatus;
+  int   updateGroup;
+  int   ProcessGroup;
   long  rc;
-  char  *av[3];
-  char  *call_args[7];
-  char  group_membership[1];
+  char  group_membership[6];
+  char  list_id[32];
   int   security_flag;
+  char  filter[128];
   char  group_ou[256];
+  char  before_list_id[32];
   char  before_group_membership[1];
   int   before_security_flag;
   char  before_group_ou[256];
-  char  *pUserOu;
   LK_ENTRY *ptr = NULL;
 
   if (beforec == 0 && afterc == 0)
     return;
 
-  astatus = bstatus = 0;
-  ahide = bhide = 0;
-  apublic = bpublic = 0;
-  amaillist = bmaillist = 0;
-  agid = 0;
-  bgid = 0;
-
-  if (beforec > L_GID && atoi(before[L_ACTIVE]))
-    {
-      bgid = atoi(before[L_GID]);
-      bstatus = atoi(before[L_ACTIVE]);
-      bhide = atoi(before[L_HIDDEN]);
-      bpublic = atoi(before[L_PUBLIC]);
-      bmaillist = atoi(before[L_MAILLIST]);
-      bgroup = atoi(before[L_GROUP]);
+  memset(list_id, '\0', sizeof(list_id));
+  memset(before_list_id, '\0', sizeof(before_list_id));
+  memset(before_group_ou, '\0', sizeof(before_group_ou));
+  memset(before_group_membership, '\0', sizeof(before_group_membership));
+  memset(group_ou, '\0', sizeof(group_ou));
+  memset(group_membership, '\0', sizeof(group_membership));
+  updateGroup = 0;
+
+  if (beforec > L_GID)
+    {
+      if (beforec < L_LIST_ID)
+        return;
+      if (beforec > L_LIST_DESC)
+        {
+          strcpy(before_list_id, before[L_LIST_ID]);
+        }
       before_security_flag = 0;
-      memset(before_group_ou, '\0', sizeof(before_group_ou));
-      memset(before_group_membership, '\0', sizeof(before_group_membership));
-      get_group_membership(before_group_membership, before_group_ou, &before_security_flag, before);
-    }
-  if (afterc > L_GID && atoi(after[L_ACTIVE]))
-    {
-      agid = atoi(after[L_GID]);
-      astatus = atoi(after[L_ACTIVE]);
-      ahide = atoi(after[L_HIDDEN]);
-      apublic = atoi(after[L_PUBLIC]);
-      amaillist = atoi(after[L_MAILLIST]);
-      agroup = atoi(after[L_GROUP]);
+      get_group_membership(before_group_membership, before_group_ou, 
+                          &before_security_flag, before);
+    }
+
+  if (afterc > L_GID)
+    {
+      if (afterc < L_LIST_ID)
+        return;
+      if (afterc > L_LIST_DESC)
+        {
+          strcpy(list_id, after[L_LIST_ID]);
+        }
       security_flag = 0;
-      memset(group_ou, '\0', sizeof(group_ou));
-      memset(group_membership, '\0', sizeof(group_membership));
       get_group_membership(group_membership, group_ou, &security_flag, after);
     }
-  if (agid == 0 && bgid == 0)
+  
+  if ((beforec == 0) && (afterc == 0)) /*this case should never happen*/
     return;
 
-  if (agid && bgid)
+  updateGroup = 0;
+  
+  if (beforec)
     {
-      if ((strcmp(after[L_NAME], before[L_NAME])) || 
-         ((!strcmp(after[L_NAME], before[L_NAME])) && 
-          (strcmp(before_group_ou, group_ou))))
-       {
-          if (astatus && bstatus)
+      updateGroup = 1;
+
+      if ((rc = process_group(ldap_handle, dn_path, before_list_id, 
+                             before[L_NAME], before_group_ou, 
+                             before_group_membership, 
+                              before_security_flag, CHECK_GROUPS,
+                             before[L_MAILLIST])))
+        {
+          if (rc == AD_NO_GROUPS_FOUND)
+            updateGroup = 0;
+          else
             {
-              com_err(whoami, 0, "Changing list name from %s to %s",
-                      before[L_NAME], after[L_NAME]);
-              if ((strlen(before_group_ou) == 0) || (strlen(before_group_membership) == 0) ||
-                  (strlen(group_ou) == 0) || (strlen(group_membership) == 0))
+              if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
+                 (rc == AD_MULTIPLE_GROUPS_FOUND))
+                {
+                  rc = process_group(ldap_handle, dn_path, before_list_id, 
+                                    before[L_NAME], before_group_ou, 
+                                    before_group_membership, 
+                                     before_security_flag, CLEANUP_GROUPS,
+                                    before[L_MAILLIST]);
+                }
+              if ((rc != AD_NO_GROUPS_FOUND) && (rc != 0))
                 {
-                  com_err(whoami, 0, "%s", "couldn't find the group OU's");
+                  com_err(whoami, 0, "Unable to process list %s",
+                          before[L_NAME]);
                   return;
                 }
-              if ((rc = group_rename(ldap_handle, dn_path, 
-                                     before[L_NAME], before_group_membership, 
-                                     before_group_ou, before_security_flag, before[9],
-                                     after[L_NAME], group_membership, 
-                                     group_ou, security_flag, after[9])) != LDAP_NO_SUCH_OBJECT)
+              if (rc == AD_NO_GROUPS_FOUND)
+                updateGroup = 0;
+            }
+        }
+    }
+  
+  if ((beforec != 0) && (afterc != 0))
+    {
+      if (((strcmp(after[L_NAME], before[L_NAME])) || 
+          ((!strcmp(after[L_NAME], before[L_NAME])) && 
+           (strcmp(before_group_ou, group_ou)))) &&
+          (updateGroup == 1))
+        {
+          com_err(whoami, 0, "Changing list name from %s to %s",
+                  before[L_NAME], after[L_NAME]);
+
+          if ((strlen(before_group_ou) == 0) || 
+             (strlen(before_group_membership) == 0) ||
+              (strlen(group_ou) == 0) || (strlen(group_membership) == 0))
+            {
+              com_err(whoami, 0, "%s", "Unable to find the group OU's");
+              return;
+            }
+
+          memset(filter, '\0', sizeof(filter));
+
+          if ((rc = group_rename(ldap_handle, dn_path, 
+                                 before[L_NAME], before_group_membership, 
+                                 before_group_ou, before_security_flag, 
+                                before[L_LIST_DESC], after[L_NAME], 
+                                group_membership, group_ou, security_flag, 
+                                after[L_LIST_DESC],
+                                 list_id, filter, after[L_MAILLIST])))
+            {
+              if (rc != AD_NO_GROUPS_FOUND)
                 {
-                  if (rc != LDAP_SUCCESS)
-                    com_err(whoami, 0, "Could not change list name from %s to %s",
-                                    before[L_NAME], 
-                                    after[L_NAME]);
+                  com_err(whoami, 0, 
+                         "Unable to change list name from %s to %s",
+                          before[L_NAME], after[L_NAME]);
                   return;
                 }
-              bgid = 0;
+              updateGroup = 0;
             }
-          if (!agid)
-            return;
+          beforec = 0;
         }
       else
-        bgid = 0;
+        beforec = 0;
     }
-
-  if (bgid)
+  
+  if (beforec)
     {
-      if ((strlen(before_group_ou) == 0) || (strlen(before_group_membership) == 0))
+      if ((strlen(before_group_ou) == 0) || 
+         (strlen(before_group_membership) == 0))
         {
-          com_err(whoami, 0, "couldn't find the group OU for group %s", before[L_NAME]);
+          com_err(whoami, 0, 
+                 "Unable to find the group OU for group %s", before[L_NAME]);
           return;
         }
+
       com_err(whoami, 0, "Deleting group %s", before[L_NAME]);
-      rc = group_delete(ldap_handle, dn_path, before[L_NAME], before_group_membership);
+      rc = group_delete(ldap_handle, dn_path, before[L_NAME], 
+                        before_group_membership, before_list_id);
       return;
     }
-  if (agid)
+
+  if (afterc)
     {
-      com_err(whoami, 0, "Creating group %s", after[L_NAME]);
+      if (!updateGroup)
+        {
+          com_err(whoami, 0, "Creating group %s", after[L_NAME]);
+
+          if (rc = process_group(ldap_handle, dn_path, list_id, after[L_NAME], 
+                                  group_ou, group_membership, 
+                                  security_flag, CHECK_GROUPS,
+                                after[L_MAILLIST]))
+            {
+              if (rc != AD_NO_GROUPS_FOUND)
+                {
+                  if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
+                     (rc == AD_MULTIPLE_GROUPS_FOUND))
+                    {
+                      rc = process_group(ldap_handle, dn_path, list_id, 
+                                        after[L_NAME], 
+                                         group_ou, group_membership, 
+                                         security_flag, CLEANUP_GROUPS,
+                                        after[L_MAILLIST]);
+                    }
+
+                  if (rc)
+                    {
+                      com_err(whoami, 0, 
+                             "Unable to create list %s", after[L_NAME]);
+                      return;
+                    }
+                }
+            }
+        }
+      else
+        com_err(whoami, 0, "Updating group %s information", after[L_NAME]);
 
       if (rc = moira_connect())
         {
-          critical_alert("AD incremental",
-                         "Error contacting Moira server : %s",
+          critical_alert(whoami, "AD incremental",
+                         "Error contactng Moira server : %s",
                          error_message(rc));
           return;
         }
 
-      av[0] = after[L_NAME];
-      call_args[0] = (char *)ldap_handle;
-      call_args[1] = dn_path;
-      call_args[2] = after[L_NAME];
-      call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
-      call_args[4] = NULL;
-      sid_base = NULL;
-      sid_ptr = &sid_base;
-      callback_rc = 0;
-      if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
-        {
-          moira_disconnect();
-          com_err(whoami, 0, "Couldn't create list %s : %s", after[L_NAME], error_message(rc));
-          return;
-        }
-      if (callback_rc)
-        {
-          moira_disconnect();
-          com_err(whoami, 0, "Couldn't create list %s", after[L_NAME]);
-          return;
-        }
+      ProcessGroup = 0;
+
+      if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 0, 
+                    &ProcessGroup, after[L_MAILLIST]))
+        return;
 
-      if (sid_base != NULL)
+      if (ProcessGroup)
         {
-          sid_update(ldap_handle, dn_path);
-          linklist_free(sid_base);
-          sid_base = NULL;
+          if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 1, 
+                        &ProcessGroup, after[L_MAILLIST]))
+            return;
         }
 
-      sleep(1);
-      com_err(whoami, 0, "Populating group %s", after[L_NAME]);
-      av[0] = after[L_NAME];
-      call_args[0] = (char *)ldap_handle;
-      call_args[1] = dn_path;
-      call_args[2] = after[L_NAME];
-      call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
-      call_args[4] = NULL;
-      member_base = NULL;
-      if (rc = mr_query("get_end_members_of_list", 1, av,
-                        member_list_build, call_args))
+      if (make_new_group(ldap_handle, dn_path, list_id, after[L_NAME], 
+                         group_ou, group_membership, security_flag, 
+                        updateGroup, after[L_MAILLIST]))
         {
           moira_disconnect();
-          com_err(whoami, 0, "Couldn't populate list %s : %s", 
-                  after[L_NAME], error_message(rc));
           return;
         }
-      if (member_base != NULL)
+
+      if (atoi(after[L_ACTIVE]))
         {
-          ptr = member_base;
-          while (ptr != NULL)
-            {
-              if (!strcasecmp(ptr->type, "LIST"))
-                {
-                  ptr = ptr->next;
-                  continue;
-                }
-              pUserOu = user_ou;
-              if (!strcasecmp(ptr->type, "STRING"))
-                {
-                  if (contact_create(ldap_handle, dn_path, ptr->member, contact_ou))
-                    return;
-                  pUserOu = contact_ou;
-                }
-              else if (!strcasecmp(ptr->type, "KERBEROS"))
-                {
-                  if (contact_create(ldap_handle, dn_path, ptr->member, kerberos_ou))
-                    return;
-                  pUserOu = kerberos_ou;
-                }
-              rc = member_add(ldap_handle, dn_path, after[L_NAME],
-                              group_ou, group_membership, ptr->member, pUserOu);
-              ptr = ptr->next;
-            }
-          linklist_free(member_base);
-          member_base = NULL;
+          populate_group(ldap_handle, dn_path, after[L_NAME], group_ou, 
+                         group_membership, security_flag, list_id);
         }
+
       moira_disconnect();
     }
-
   return;
 }
 
@@ -756,50 +1141,139 @@ void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
 #define LM_EXTRA_MAILLIST (LM_END+3)
 #define LM_EXTRA_GROUP    (LM_END+4)
 #define LM_EXTRA_GID      (LM_END+5)
-#define LM_EXTRA_END      (LM_END+6)
+#define LMN_LIST_ID       (LM_END+6)
+#define LM_LIST_ID        (LM_END+7)
+#define LM_USER_ID        (LM_END+8)
+#define LM_EXTRA_END      (LM_END+9)
 
 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
                char **before, int beforec, char **after, int afterc)
 {
+  LK_ENTRY *group_base;
+  int group_count;
+  char  filter[128];
+  char *attr_array[3];
   char  group_name[128];
   char  user_name[128];
   char  user_type[128];
-  int   rc;
+  char  moira_list_id[32];
+  char  moira_user_id[32];
   char  group_membership[1];
-  int   security_flag;
   char  group_ou[256];
+  char  machine_ou[256];
+  char  member[256];
   char  *args[16];
   char  **ptr;
+  char  *av[7];
+  char  *call_args[7];
   char  *pUserOu;
+  char  *s;
+  char  NewMachineName[1024];
+  int   security_flag;
+  int   rc;
+  int   ProcessGroup;
+  char  *save_argv[U_END];
 
   pUserOu = NULL;
   ptr = NULL;
+  memset(moira_list_id, '\0', sizeof(moira_list_id));
+  memset(moira_user_id, '\0', sizeof(moira_user_id));
+
   if (afterc)
     {
-      if (afterc < LM_EXTRA_END)
+      if (afterc < LM_EXTRA_GID)
         return;
+
       if (!atoi(after[LM_EXTRA_ACTIVE]))
-        return;
+        {
+         com_err(whoami, 0, 
+                 "Unable to add %s to group %s : group not active", 
+                 after[2], after[0]);
+         return;
+        }
+
       ptr = after;
+
+      if (!strcasecmp(ptr[LM_TYPE], "LIST"))
+       return;
+
       strcpy(user_name, after[LM_MEMBER]);
       strcpy(group_name, after[LM_LIST]);
       strcpy(user_type, after[LM_TYPE]);
 
+      if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
+        {
+          if (afterc > LM_EXTRA_GROUP)
+            {
+              strcpy(moira_list_id, after[LMN_LIST_ID]);
+              strcpy(moira_user_id, after[LM_LIST_ID]);
+            }
+        }
+      else if (!strcasecmp(ptr[LM_TYPE], "USER"))
+        {
+          if (afterc > LMN_LIST_ID)
+            {
+              strcpy(moira_list_id, after[LM_LIST_ID]);
+              strcpy(moira_user_id, after[LM_USER_ID]);
+            }
+        }
+      else
+        {
+          if (afterc > LM_EXTRA_GID)
+            strcpy(moira_list_id, after[LMN_LIST_ID]);
+        }
     }
   else if (beforec)
     {
-      if (beforec < LM_EXTRA_END)
+      if (beforec < LM_EXTRA_GID)
         return;
       if (!atoi(before[LM_EXTRA_ACTIVE]))
+        {
+          com_err(whoami, 0, 
+                 "Unable to add %s to group %s : group not active", 
+                 before[2], before[0]);
           return;
+        }
+
       ptr = before;
+
+      if (!strcasecmp(ptr[LM_TYPE], "LIST"))
+       return;
+
       strcpy(user_name, before[LM_MEMBER]);
       strcpy(group_name, before[LM_LIST]);
       strcpy(user_type, before[LM_TYPE]);
+
+      if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
+        {
+          if (beforec > LM_EXTRA_GROUP)
+            {
+              strcpy(moira_list_id, before[LMN_LIST_ID]);
+              strcpy(moira_user_id, before[LM_LIST_ID]);
+            }
+        }
+      else if (!strcasecmp(ptr[LM_TYPE], "USER"))
+        {
+          if (beforec > LMN_LIST_ID)
+            {
+              strcpy(moira_list_id, before[LM_LIST_ID]);
+              strcpy(moira_user_id, before[LM_USER_ID]);
+            }
+        }
+      else
+        {
+          if (beforec > LM_EXTRA_GID)
+            strcpy(moira_list_id, before[LMN_LIST_ID]);
+        }
     }
 
   if (ptr == NULL)
-    return;
+    {
+      com_err(whoami, 0, 
+             "Unable to process group : beforec = %d, afterc = %d", 
+             beforec, afterc);
+      return;
+    }
 
   args[L_NAME] = ptr[LM_LIST];
   args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE];
@@ -812,196 +1286,503 @@ void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
   security_flag = 0;
   memset(group_ou, '\0', sizeof(group_ou));
   get_group_membership(group_membership, group_ou, &security_flag, args);
+
   if (strlen(group_ou) == 0)
     {
-      com_err(whoami, 0, "couldn't find the group OU for group %s", group_name);
+      com_err(whoami, 0, "Unable to find the group OU for group %s", 
+             group_name);
       return;
     }
 
-  rc = 0;
-  if (beforec)
+  if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, 
+                        group_ou, group_membership, security_flag, 
+                        CHECK_GROUPS, args[L_MAILLIST]))
     {
-      if (!strcasecmp(ptr[LM_TYPE], "LIST"))
+      if (rc != AD_NO_GROUPS_FOUND)
+        {
+          if (rc = process_group(ldap_handle, dn_path, moira_list_id, 
+                                group_name, group_ou, group_membership, 
+                                security_flag, CLEANUP_GROUPS,
+                                args[L_MAILLIST]))
+            {
+              if (rc != AD_NO_GROUPS_FOUND)
+                {
+                  if (afterc)
+                    com_err(whoami, 0, "Unable to add %s to group %s - " 
+                           "unable to process group", user_name, group_name);
+                  else
+                    com_err(whoami, 0, "Unable to remove %s from group %s - "
+                           "unable to process group", user_name, group_name);
+                  return;
+                }
+            }
+        }
+    }
+
+  if (rc == AD_NO_GROUPS_FOUND)
+    {
+      if (rc = moira_connect())
+        {
+          critical_alert(whoami, "AD incremental",
+                         "Error contacting Moira server : %s",
+                         error_message(rc));
+          return;
+        }
+      
+      com_err(whoami, 0, "creating group %s", group_name);
+      ProcessGroup = 0;
+
+      if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 0, 
+                    &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
         return;
 
-      com_err(whoami, 0, "Removing user %s from list %s", user_name, group_name);
-      pUserOu = user_ou;
-      if (!strcasecmp(ptr[LM_TYPE], "STRING"))
+      if (ProcessGroup)
         {
-          if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], contact_ou))
+          if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 1, 
+                        &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
             return;
-          pUserOu = contact_ou;
         }
-      else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
+
+      if (make_new_group(ldap_handle, dn_path, moira_list_id, ptr[LM_LIST], 
+                         group_ou, group_membership, security_flag, 0,
+                        ptr[LM_EXTRA_MAILLIST]))
         {
-          if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], kerberos_ou))
-            return;
-          pUserOu = kerberos_ou;
+          moira_disconnect();
+          return;
         }
-      rc = member_remove(ldap_handle, dn_path, group_name,
-                       group_ou, group_membership, ptr[LM_MEMBER], pUserOu);
+
+      if (atoi(ptr[LM_EXTRA_ACTIVE]))
+        {
+          populate_group(ldap_handle, dn_path, ptr[LM_LIST], group_ou, 
+                         group_membership, security_flag, moira_list_id);
+        }
+
+      moira_disconnect();
     }
-  else
-    {
-      if (!strcasecmp(ptr[LM_TYPE], "LIST"))
-        return;
 
-      com_err(whoami, 0, "Adding user %s to list %s", user_name, group_name);
+  rc = 0;
+
+  if (beforec)
+    {
+      com_err(whoami, 0, "removing user %s from list %s", user_name, 
+             group_name);
       pUserOu = user_ou;
+
+      if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
+        {
+          memset(machine_ou, '\0', sizeof(machine_ou));
+         memset(NewMachineName, '\0', sizeof(NewMachineName));
+          if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], 
+                            machine_ou, NewMachineName))
+            return;
+         if (ptr[LM_MEMBER] != NULL)     
+           free(ptr[LM_MEMBER]);
+         ptr[LM_MEMBER] = strdup(NewMachineName);
+          pUserOu = machine_ou;
+        }
+
       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
         {
+         strcpy(member, ptr[LM_MEMBER]);
+
+         if (Exchange) 
+           {
+             if((s = strchr(member, '@')) == (char *) NULL)
+               { 
+                 strcat(member, "@mit.edu");
+                 
+                 if (ptr[LM_MEMBER] != NULL)
+                   free(ptr[LM_MEMBER]);
+                 ptr[LM_MEMBER] = strdup(member);
+               }
+         
+             if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
+               {
+                 s = strrchr(member, '.');
+                 *s = '\0';
+                 strcat(s, ".mit.edu");
+                 
+                 if (ptr[LM_MEMBER] != NULL)
+                   free(ptr[LM_MEMBER]);
+                 ptr[LM_MEMBER] = strdup(member);
+               }
+           }
+
           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], contact_ou))
             return;
+
           pUserOu = contact_ou;
         }
       else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
+       {
+         if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
+                            kerberos_ou))
+           return;
+
+         pUserOu = kerberos_ou;
+       }
+      if (rc = member_remove(ldap_handle, dn_path, group_name,
+                            group_ou, group_membership, ptr[LM_MEMBER], 
+                            pUserOu, moira_list_id))
+       com_err(whoami, 0, "Unable to remove %s from group %s", user_name, 
+               group_name);
+      
+      if (!strcasecmp(ptr[LM_TYPE], "STRING"))
+       {
+         if (rc = moira_connect())
+           {
+             critical_alert(whoami, "AD incremental",
+                            "Error contacting Moira server : %s",
+                            error_message(rc));
+             return;
+           }
+         
+         if (rc = populate_group(ldap_handle, dn_path, group_name,
+                                 group_ou, group_membership, security_flag,
+                                 moira_list_id))
+           com_err(whoami, 0, "Unable to remove %s from group %s",
+                   user_name, group_name);
+         moira_disconnect();
+       }
+      return;
+    }
+  
+  com_err(whoami, 0, "Adding %s to list %s", user_name, group_name);
+  pUserOu = user_ou;
+  
+  if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
+    {
+      memset(machine_ou, '\0', sizeof(machine_ou));
+      memset(NewMachineName, '\0', sizeof(NewMachineName));
+
+      if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], machine_ou, 
+                        NewMachineName))
+        return;
+
+      if (ptr[LM_MEMBER] != NULL)
+       free(ptr[LM_MEMBER]);
+
+      ptr[LM_MEMBER] = strdup(NewMachineName);
+      pUserOu = machine_ou;
+    }
+  else if (!strcasecmp(ptr[LM_TYPE], "STRING"))
+    {
+      strcpy(member, ptr[LM_MEMBER]);
+
+      if (Exchange) 
+       {
+         if((s = strchr(member, '@')) == (char *) NULL)
+           { 
+             strcat(member, "@mit.edu");
+             
+             if (ptr[LM_MEMBER] != NULL)
+               free(ptr[LM_MEMBER]);
+             ptr[LM_MEMBER] = strdup(member);
+           }
+         
+         if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
+           {
+             s = strrchr(member, '.');
+             *s = '\0';
+             strcat(s, ".mit.edu");
+             
+             if (ptr[LM_MEMBER] != NULL)
+               free(ptr[LM_MEMBER]);
+             ptr[LM_MEMBER] = strdup(member);
+           }
+       }
+      
+      if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], contact_ou))
+        return;
+
+      pUserOu = contact_ou;
+    }
+  else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
+    {
+      if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], kerberos_ou))
+        return;
+
+      pUserOu = kerberos_ou;
+    }
+  else if (!strcasecmp(ptr[LM_TYPE], "USER"))
+    {
+      if ((rc = check_user(ldap_handle, dn_path, ptr[LM_MEMBER], 
+                           moira_user_id)) == AD_NO_USER_FOUND)
+        {
+          if (rc = moira_connect())
+            {
+              critical_alert(whoami, "AD incremental", 
+                             "Error connection to Moira : %s",
+                             error_message(rc));
+              return;
+            }
+
+          com_err(whoami, 0, "creating user %s", ptr[LM_MEMBER]);
+          av[0] = ptr[LM_MEMBER];
+          call_args[0] = (char *)ldap_handle;
+          call_args[1] = dn_path;
+          call_args[2] = moira_user_id;
+          call_args[3] = NULL;
+         
+          callback_rc = 0;
+
+         if (Exchange)
+           {
+             group_count = 0;
+             group_base = NULL;
+         
+             sprintf(filter, "(&(objectClass=group)(cn=%s))", ptr[LM_MEMBER]);
+             attr_array[0] = "cn";
+             attr_array[1] = NULL;
+             if ((rc = linklist_build(ldap_handle, dn_path, filter, 
+                                      attr_array, &group_base, &group_count,
+                                      LDAP_SCOPE_SUBTREE)) != 0)
+               {
+                 com_err(whoami, 0, "Unable to process user %s : %s",
+                         ptr[LM_MEMBER], ldap_err2string(rc));
+                 return;
+               }
+             
+             if (group_count)
+               {
+                 com_err(whoami, 0, "Object already exists with name %s",
+                         ptr[LM_MEMBER]);
+                 return;
+               }
+         
+             linklist_free(group_base);
+             group_count = 0;
+             group_base = NULL;
+           }
+
+          if (rc = mr_query("get_user_account_by_login", 1, av, 
+                            save_query_info, save_argv))
+            {
+              moira_disconnect();
+              com_err(whoami, 0, "Unable to create user %s : %s",
+                      ptr[LM_MEMBER], error_message(rc));
+              return;
+            }
+
+         if (rc = user_create(U_END, save_argv, call_args)) 
+           {
+              moira_disconnect();
+              com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
+              return;
+           }
+
+          if (callback_rc)
+            {
+              moira_disconnect();
+              com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
+              return;
+            }
+        }
+      else
         {
-          if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], kerberos_ou))
+          if (rc != 0)
             return;
-          pUserOu = kerberos_ou;
         }
-      rc = member_add(ldap_handle, dn_path, group_name,
-                      group_ou, group_membership, ptr[LM_MEMBER], pUserOu);
+      pUserOu = user_ou;
     }
-  if (rc)
+  
+  if (rc = member_add(ldap_handle, dn_path, group_name,
+                     group_ou, group_membership, ptr[LM_MEMBER],
+                     pUserOu, moira_list_id))
+    com_err(whoami, 0, "Unable to add %s to group %s", user_name, group_name);
+  
+  if (!strcasecmp(ptr[LM_TYPE], "STRING"))
     {
-      if (afterc)
-        com_err(whoami, 0, "Couldn't add %s to group %s", user_name, group_name);
-      else
-        com_err(whoami, 0, "Couldn't remove %s to group %s", user_name, group_name);
+      if (rc = moira_connect())
+       {
+         critical_alert(whoami, "AD incremental",
+                        "Error contacting Moira server : %s",
+                        error_message(rc));
+         return;
+       }
+      
+      if (rc = populate_group(ldap_handle, dn_path, group_name,
+                             group_ou, group_membership, security_flag,
+                             moira_list_id))
+       com_err(whoami, 0, "Unable to add %s to group %s",
+               user_name, group_name);
+      
+      moira_disconnect();
     }
+
   return;
 }
 
 
+#define U_USER_ID    10
+#define U_HOMEDIR    11
+#define U_PROFILEDIR 12
+
 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
              char **before, int beforec, char **after, 
              int afterc)
 {
+  LK_ENTRY *group_base;
+  int   group_count;
+  char  filter[128];
+  char  *attr_array[3];
   int   rc;
-  char  *av[2];
-  char  *call_args[6];
-  int   astate;
-  int   bstate;
+  char  *av[7];
+  char  after_user_id[32];
+  char  before_user_id[32];
+  char  *call_args[7];
+  char  *save_argv[U_END];
 
   if ((beforec == 0) && (afterc == 0))
     return;
 
-  astate = 0;
-  bstate = 0;
-  if (afterc > U_STATE)
-    astate = atoi(after[U_STATE]);
-  if (beforec > U_STATE)
-    bstate = atoi(before[U_STATE]);
+  memset(after_user_id, '\0', sizeof(after_user_id));
+  memset(before_user_id, '\0', sizeof(before_user_id));
 
-  if (astate == 2)
-    astate = 1;
-  if (bstate == 2)
-    bstate = 1;
+  if (beforec > U_USER_ID)
+    strcpy(before_user_id, before[U_USER_ID]);
 
-  if ((bstate == 0) && (astate == 0))
+  if (afterc > U_USER_ID)
+    strcpy(after_user_id, after[U_USER_ID]);
+
+  if ((beforec == 0) && (afterc == 0)) /*this case should never happen */
     return;
 
-  if (astate == bstate)
+  if ((beforec == 0) && (afterc != 0)) 
     {
-      if (!strcmp(before[U_NAME], after[U_NAME]))
-        {
-          com_err(whoami, 0, "Updating user %s info", before[U_NAME]);
-          rc = user_update(ldap_handle, dn_path, before[U_NAME],
-                           before[U_UID], before[U_MITID]);
-          return;
-        }
-      else
-        {
-          com_err(whoami, 0, "Changing user %s to %s", before[U_NAME],
-                  after[U_NAME]);
-          if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], 
-                after[U_NAME], after[U_UID], after[U_MITID], 
-                atoi(after[U_STATE]))) != LDAP_NO_SUCH_OBJECT)
-            {
-              if (rc != LDAP_SUCCESS)
-                {
-                  com_err(whoami, 0, "Could not change user %s to %s : %s",
-                          before[U_NAME], 
-                          after[U_NAME], error_message(rc));
-                }
-              return;
-            }
-        }
-      bstate = 0;
+      /*this case only happens when the account*/
+      /*account is first created but not usable*/
+
+      com_err(whoami, 0, "Unable to process user %s because the user account "
+             "is not yet usable", after[U_NAME]);
+      return;
     }
 
-  if (bstate == 1)
-    {
-      com_err(whoami, 0, "Deactivate user %s in the AD", before[U_NAME]);
+  /*this case only happens when the account is expunged */
 
-      if ((rc = user_change_status(ldap_handle, dn_path, before[U_NAME], 
-                                   MEMBER_DEACTIVATE)) != LDAP_SUCCESS)
+  if ((beforec != 0) && (afterc == 0)) 
+    {                                 
+      if (atoi(before[U_STATE]) == 0)
         {
-          com_err(whoami, 0, "Couldn't deactivate user %s in the AD", before[U_NAME]);
+          com_err(whoami, 0, "expunging user %s from AD", before[U_NAME]);
+          user_delete(ldap_handle, dn_path, before[U_NAME], before_user_id);
+        }
+      else
+        {
+          com_err(whoami, 0, "Unable to process because user %s has been "
+                 "previously expungeded", before[U_NAME]);
         }
       return;
     }
 
-  if (astate == 1)
+  /*process anything that gets here*/
+
+  if ((rc = check_user(ldap_handle, dn_path, before[U_NAME], 
+                       before_user_id)) == AD_NO_USER_FOUND)
     {
+      if (!check_string(after[U_NAME]))
+        return;
+
       if (rc = moira_connect())
         {
-          critical_alert("AD incremental", 
+          critical_alert(whoami, "AD incremental", 
                          "Error connection to Moira : %s",
                          error_message(rc));
           return;
         }
-      com_err(whoami, 0, "Creating/Reactivating user %s", after[U_NAME]);
 
+      com_err(whoami, 0, "creating user %s", after[U_NAME]);
+      
       av[0] = after[U_NAME];
       call_args[0] = (char *)ldap_handle;
       call_args[1] = dn_path;
-      call_args[2] = (char *)MEMBER_ACTIVATE;
+      call_args[2] = after_user_id;
       call_args[3] = NULL;
-      sid_base = NULL;
-      sid_ptr = &sid_base;
-      UserReactivate = 0;
       callback_rc = 0;
-      if (rc = mr_query("get_user_account_by_login", 1, av, user_create,
-                        call_args))
+
+      if (Exchange) 
+       {
+         group_count = 0;
+         group_base = NULL;
+         
+         sprintf(filter, "(&(objectClass=group)(cn=%s))", after[U_NAME]);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+         
+         if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
+                                  &group_base, &group_count,
+                                  LDAP_SCOPE_SUBTREE)) != 0)
+           {
+             com_err(whoami, 0, "Unable to process user %s : %s",
+                     after[U_NAME], ldap_err2string(rc));
+             return;
+           }
+         
+         if (group_count >= 1)
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     after[U_NAME]);
+             return;
+           }
+      
+         linklist_free(group_base);
+         group_count = 0;
+         group_base = NULL;
+       }
+
+      if (rc = mr_query("get_user_account_by_login", 1, av,
+                        save_query_info, save_argv))
         {
           moira_disconnect();
-          com_err(whoami, 0, "Couldn't create/activate user %s : %s",
+          com_err(whoami, 0, "Unable to create user %s : %s",
                   after[U_NAME], error_message(rc));
           return;
         }
+
+      if (rc = user_create(U_END, save_argv, call_args)) 
+       {
+          com_err(whoami, 0, "Unable to create user %s : %s",
+                  after[U_NAME], error_message(rc));
+         return;
+       }
+      
       if (callback_rc)
         {
           moira_disconnect();
-          com_err(whoami, 0, "Couldn't create/activate user %s", after[U_NAME]);
+          com_err(whoami, 0, "Unable to create user %s", after[U_NAME]);
           return;
         }
-      sleep(1);
-      if (sid_base != NULL)
-        {
-          sid_update(ldap_handle, dn_path);
-          linklist_free(sid_base);
-        }
-      if (UserReactivate)
+
+      return;
+    }
+  else
+    {
+      if (rc != 0)
+        return;
+    }
+
+  if (strcmp(before[U_NAME], after[U_NAME]))
+    {
+      if ((check_string(before[U_NAME])) && (check_string(after[U_NAME])))
         {
-          av[0] = "ruser";
-          av[1] = after[U_NAME];
-          call_args[0] = (char *)ldap_handle;
-          call_args[1] = dn_path;
-          call_args[2] = after[U_NAME];
-          call_args[3] = user_ou;
-          rc = mr_query("get_lists_of_member", 2, av, process_lists,
-                          call_args);
-          if (rc && rc != MR_NO_MATCH)
+          com_err(whoami, 0, "changing user %s to %s", 
+                  before[U_NAME], after[U_NAME]);
+
+          if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], 
+                                after[U_NAME])) != LDAP_SUCCESS)
             {
-              com_err(whoami, 0, "Couldn't retrieve membership of user %s: %s",
-                      after[U_NAME], error_message(rc));
+              return;
             }
         }
-      moira_disconnect();
     }
 
+  com_err(whoami, 0, "updating user %s information", after[U_NAME]);
+  rc = user_update(ldap_handle, dn_path, after[U_NAME],
+                   after[U_UID], after[U_MITID], 
+                  after_user_id, atoi(after[U_STATE]),
+                   after[U_HOMEDIR], after[U_PROFILEDIR],
+                  after[U_FIRST], after[U_MIDDLE], after[U_LAST]);
+
   return;
 }
 
@@ -1012,14 +1793,16 @@ int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count,
   LK_ENTRY    *linklist_ptr;
   int         i;
   char        *cPtr;
-
-  if (((*modvalues) = calloc(1, (modvalue_count + 1) * sizeof(char *)))
-      == NULL)
+  
+  if (((*modvalues) = calloc(1, 
+                            (modvalue_count + 1) * sizeof(char *))) == NULL)
     {
       return(1);
     }
+
   for (i = 0; i < (modvalue_count + 1); i++)
     (*modvalues)[i] = NULL;
+
   if (modvalue_count != 0)
     {
       linklist_ptr = linklist_base;
@@ -1028,7 +1811,7 @@ int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count,
           if ((oldValue != NULL) && (newValue != NULL))
             {
               if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue))
-                 != (char *)NULL)
+                 != (char *)NULL)
                 {
                   if (type == REPLACE)
                     {
@@ -1042,8 +1825,9 @@ int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count,
                     {
                       if (((*modvalues)[i] = calloc(1, 
                                         (int)(cPtr - linklist_ptr->value) + 
-                                        (linklist_ptr->length - strlen(oldValue)) + 
-                                        strlen(newValue) + 1)) == NULL)
+                                              (linklist_ptr->length - 
+                                              strlen(oldValue)) + 
+                                              strlen(newValue) + 1)) == NULL)
                         return(1);
                       memset((*modvalues)[i], '\0', 
                              (int)(cPtr - linklist_ptr->value) + 
@@ -1053,7 +1837,8 @@ int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count,
                              (int)(cPtr - linklist_ptr->value));
                       strcat((*modvalues)[i], newValue);
                       strcat((*modvalues)[i], 
-     &linklist_ptr->value[(int)(cPtr - linklist_ptr->value) + strlen(oldValue)]);
+                            &linklist_ptr->value[(int)(cPtr - 
+                                    linklist_ptr->value) + strlen(oldValue)]);
                     }
                 }
               else
@@ -1081,7 +1866,7 @@ int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count,
 
 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
                    char **attr_array, LK_ENTRY **linklist_base,
-                   int *linklist_count)
+                   int *linklist_count, unsigned long ScopeType)
 {
   ULONG       rc;
   LDAPMessage *ldap_entry;
@@ -1090,17 +1875,22 @@ int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp,
   ldap_entry = NULL;
   (*linklist_base) = NULL;
   (*linklist_count) = 0;
-  if ((rc = ldap_search_s(ldap_handle, dn_path, LDAP_SCOPE_SUBTREE, 
-                          search_exp, attr_array, 0, &ldap_entry))
-      != LDAP_SUCCESS)
-    return(0);
-  rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, linklist_count);
+
+  if ((rc = ldap_search_s(ldap_handle, dn_path, ScopeType, 
+                          search_exp, attr_array, 0, 
+                         &ldap_entry)) != LDAP_SUCCESS)
+      {
+        if (rc != LDAP_SIZELIMIT_EXCEEDED)
+          return(0);
+      }
+
+  rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, 
+                       linklist_count);
 
   ldap_msgfree(ldap_entry);
   return(rc);
 }
 
-
 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
                      LK_ENTRY **linklist_base, int *linklist_count)
 {
@@ -1110,7 +1900,7 @@ int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry,
 
   if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL)
     return(0);
-
+  
   memset(distinguished_name, '\0', sizeof(distinguished_name));
   get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
 
@@ -1122,19 +1912,21 @@ int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry,
     {
       memset(distinguished_name, '\0', sizeof(distinguished_name));
       get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
-
-      if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name,
-                                    linklist_base)) != 0)
+      
+      if ((rc = retrieve_attributes(ldap_handle, ldap_entry, 
+                                   distinguished_name, linklist_base)) != 0)
         return(rc);
     }
 
   linklist_ptr = (*linklist_base);
   (*linklist_count) = 0;
+
   while (linklist_ptr != NULL)
     {
       ++(*linklist_count);
       linklist_ptr = linklist_ptr->next;
     }
+
   return(0);
 }
 
@@ -1145,7 +1937,9 @@ int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry,
   BerElement  *ptr;
 
   ptr = NULL;
-  if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, &ptr)) != NULL)
+
+  if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, 
+                                       &ptr)) != NULL)
     {
       retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name,
                       linklist_current);
@@ -1158,7 +1952,9 @@ int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry,
           ldap_memfree(Attribute);
         }
     }
+
   ldap_ber_free(ptr, 0);
+
   return(0);
 }
 
@@ -1173,6 +1969,7 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
   LK_ENTRY    *linklist_previous;
   LDAP_BERVAL **ber_value;
   DWORD       ber_length;
+
 #ifdef LDAP_DEBUG
   SID         *sid;
   GUID        *guid;
@@ -1185,68 +1982,81 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
 
   use_bervalue = 0;
   memset(temp, '\0', sizeof(temp));
+
   if ((!strcmp(Attribute, "objectSid")) ||
       (!strcmp(Attribute, "objectGUID")))
     use_bervalue = 1;
-
+  
   if (use_bervalue)
     {
       ber_value = ldap_get_values_len(ldap_handle, ldap_entry, Attribute);
       Ptr = (void **)ber_value;
       str_value = NULL;
-      }
+    }
   else
     {
       str_value = ldap_get_values(ldap_handle, ldap_entry, Attribute);
       Ptr = (void **)str_value;
       ber_value = NULL;
     }
+
   if (Ptr != NULL)
     {
       for (; *Ptr; Ptr++) 
         {
           if ((linklist_previous = calloc(1, sizeof(LK_ENTRY))) == NULL)
             return(1);
+
           memset(linklist_previous, '\0', sizeof(LK_ENTRY));
           linklist_previous->next = (*linklist_current);
           (*linklist_current) = linklist_previous;
-
+         
           if (((*linklist_current)->attribute = calloc(1, 
-                                               strlen(Attribute) + 1)) == NULL)
+                                             strlen(Attribute) + 1)) == NULL)
             return(1);
+
           memset((*linklist_current)->attribute, '\0', strlen(Attribute) + 1);
           strcpy((*linklist_current)->attribute, Attribute);
+
           if (use_bervalue)
             {
               ber_length = (*(LDAP_BERVAL **)Ptr)->bv_len;
+
               if (((*linklist_current)->value = calloc(1, ber_length)) == NULL)
                 return(1);
+
               memset((*linklist_current)->value, '\0', ber_length);
-              memcpy((*linklist_current)->value, (*(LDAP_BERVAL **)Ptr)->bv_val, 
-                                                  ber_length);
+              memcpy((*linklist_current)->value, 
+                    (*(LDAP_BERVAL **)Ptr)->bv_val, ber_length);
               (*linklist_current)->length = ber_length;
             }
           else
             {
               if (((*linklist_current)->value = calloc(1, 
-                                                  strlen(*Ptr) + 1)) == NULL)
+                                                   strlen(*Ptr) + 1)) == NULL)
                 return(1);
+
               memset((*linklist_current)->value, '\0', strlen(*Ptr) + 1);
               (*linklist_current)->length = strlen(*Ptr);
               strcpy((*linklist_current)->value, *Ptr);
             }
+
           (*linklist_current)->ber_value = use_bervalue;
+
           if (((*linklist_current)->dn = calloc(1, 
-                                      strlen(distinguished_name) + 1)) == NULL)
+                                     strlen(distinguished_name) + 1)) == NULL)
             return(1);
-          memset((*linklist_current)->dn, '\0', strlen(distinguished_name) + 1);
+
+          memset((*linklist_current)->dn, '\0', 
+                strlen(distinguished_name) + 1);
           strcpy((*linklist_current)->dn, distinguished_name);
 
 #ifdef LDAP_DEBUG
           if (!strcmp(Attribute, "objectGUID"))
             {
               guid = (GUID *)((*linklist_current)->value);
-              sprintf(temp, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
+              sprintf(temp, 
+                     "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
                       guid->Data1, guid->Data2, guid->Data3, 
                       guid->Data4[0], guid->Data4[1], guid->Data4[2], 
                       guid->Data4[3], guid->Data4[4], guid->Data4[5], 
@@ -1256,6 +2066,7 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
           else if (!strcmp(Attribute, "objectSid"))
             {
               sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val);
+
 #ifdef _WIN32
               print_to_screen("        Revision = %d\n", sid->Revision);
               print_to_screen("        SID Identifier Authority:\n");
@@ -1267,7 +2078,7 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
               else if (sid_auth->Value[2])
                 print_to_screen("            SECURITY_LOCAL_SID_AUTHORITY\n");
               else if (sid_auth->Value[3])
-                print_to_screen("            SECURITY_CREATOR_SID_AUTHORITY\n");
+                print_to_screen("           SECURITY_CREATOR_SID_AUTHORITY\n");
               else if (sid_auth->Value[5])
                 print_to_screen("            SECURITY_NT_AUTHORITY\n");
               else
@@ -1290,6 +2101,7 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
             {
               intValue = atoi(*Ptr);
               print_to_screen("     %20s : %ld\n",Attribute, intValue);
+
               if (!memcmp(Attribute, "userAccountControl", 
                           strlen("userAccountControl")))
                 {
@@ -1334,12 +2146,16 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
             }
 #endif /*LDAP_DEBUG*/
         }
+
       if (str_value != NULL)
         ldap_value_free(str_value);
+
       if (ber_value != NULL)
         ldap_value_free_len(ber_value);
     }
+
   (*linklist_current) = linklist_previous;
+
   return(0);
 }
 
@@ -1350,31 +2166,24 @@ int moira_connect(void)
 
   if (!mr_connections++)
     {
+
 #ifdef _WIN32
       memset(HostName, '\0', sizeof(HostName));
       strcpy(HostName, "ttsp");
       rc = mr_connect_cl(HostName, "winad.incr", QUERY_VERSION, 1);
-/*det
-      rc = mr_connect(HostName);
-*/
 #else
       struct utsname uts;
       uname(&uts);
       rc = mr_connect_cl(uts.nodename, "winad.incr", QUERY_VERSION, 1);
-/*
-      rc = mr_connect(uts.nodename);
-*/
 #endif /*WIN32*/
-/*det
-      if (!rc)
-        rc = mr_auth("winad.incr");
-*/
+
       return rc;
     }
+
   return 0;
 }
 
-void check_winad(void)
+int check_winad(void)
 {
   int i;
   
@@ -1382,13 +2191,16 @@ void check_winad(void)
     {
       if (i > 30)
         {
-          critical_alert("AD incremental",
+          critical_alert(whoami, "AD incremental",
                          "WINAD incremental failed (%s exists): %s",
                          STOP_FILE, tbl_buf);
-          exit(1);
+          return(1);
         }
+
       sleep(60);
     }
+
+  return(0);
 }
 
 int moira_disconnect(void)
@@ -1398,6 +2210,7 @@ int moira_disconnect(void)
     {
       mr_disconnect();
     }
+
   return 0;
 }
 
@@ -1405,10 +2218,12 @@ void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry,
                             char *distinguished_name)
 {
   char    *CName;
-
+  
   CName = ldap_get_dn(ldap_handle, ldap_entry);
+
   if (CName == NULL)
     return;
+
   strcpy(distinguished_name, CName);
   ldap_memfree(CName);
 }
@@ -1417,10 +2232,12 @@ int linklist_create_entry(char *attribute, char *value,
                           LK_ENTRY **linklist_entry)
 {
   (*linklist_entry) = calloc(1, sizeof(LK_ENTRY));
+
   if (!(*linklist_entry))
     {
       return(1);
     }
+
   memset((*linklist_entry), '\0', sizeof(LK_ENTRY));
   (*linklist_entry)->attribute = calloc(1, strlen(attribute) + 1);
   memset((*linklist_entry)->attribute, '\0', strlen(attribute) + 1);
@@ -1430,6 +2247,7 @@ int linklist_create_entry(char *attribute, char *value,
   strcpy((*linklist_entry)->value, value);
   (*linklist_entry)->length = strlen(value);
   (*linklist_entry)->next = NULL;
+
   return(0);
 }
 
@@ -1448,18 +2266,21 @@ int get_group_membership(char *group_membership, char *group_ou,
 {
   int  maillist_flag;
   int  group_flag;
-
+  
   maillist_flag = atoi(av[L_MAILLIST]);
   group_flag = atoi(av[L_GROUP]);
+
   if (security_flag != NULL)
     (*security_flag) = 0;
-
+  
   if ((maillist_flag) && (group_flag))
     {
       if (group_membership != NULL)
         group_membership[0] = 'B';
+
       if (security_flag != NULL)
         (*security_flag) = 1;
+
       if (group_ou != NULL)
         strcpy(group_ou, group_ou_both);
     }
@@ -1467,8 +2288,10 @@ int get_group_membership(char *group_membership, char *group_ou,
     {
       if (group_membership != NULL)
         group_membership[0] = 'S';
+
       if (security_flag != NULL)
         (*security_flag) = 1;
+
       if (group_ou != NULL)
         strcpy(group_ou, group_ou_security);
     }
@@ -1476,6 +2299,7 @@ int get_group_membership(char *group_membership, char *group_ou,
     {
       if (group_membership != NULL)
         group_membership[0] = 'D';
+
       if (group_ou != NULL)
         strcpy(group_ou, group_ou_distribution);
     }
@@ -1483,323 +2307,995 @@ int get_group_membership(char *group_membership, char *group_ou,
     {
       if (group_membership != NULL)
         group_membership[0] = 'N';
+
       if (group_ou != NULL)
         strcpy(group_ou, group_ou_neither);
     }
+
   return(0);
 }
 
 int group_rename(LDAP *ldap_handle, char *dn_path, 
                  char *before_group_name, char *before_group_membership, 
-                 char *before_group_ou, int before_security_flag, char *before_desc,
-                 char *after_group_name, char *after_group_membership, 
-                 char *after_group_ou, int after_security_flag, char *after_desc)
+                 char *before_group_ou, int before_security_flag, 
+                char *before_desc, char *after_group_name, 
+                char *after_group_membership, char *after_group_ou, 
+                int after_security_flag, char *after_desc,
+                 char *MoiraId, char *filter, char *maillist)
 {
   LDAPMod   *mods[20];
   char      old_dn[512];
   char      new_dn[512];
   char      new_dn_path[512];
   char      sam_name[256];
-  char      filter_exp[4096];
+  char      mail[256];
+  char      mail_nickname[256];
+  char      proxy_address[256];
+  char      address_book[256];
   char      *attr_array[3];
+  char      *mitMoiraId_v[] = {NULL, NULL};
   char      *name_v[] = {NULL, NULL};
-  char      *desc_v[] = {NULL, NULL};
   char      *samAccountName_v[] = {NULL, NULL};
+  char      *groupTypeControl_v[] = {NULL, NULL};
+  char      *mail_v[] = {NULL, NULL};
+  char      *proxy_address_v[] = {NULL, NULL};
+  char      *mail_nickname_v[] = {NULL, NULL};
+  char      *report_to_originator_v[] = {NULL, NULL};
+  char      *address_book_v[] = {NULL, NULL};
+  char      *legacy_exchange_dn_v[] = {NULL, NULL};
+  u_int     groupTypeControl;
+  char      groupTypeControlStr[80];
+  char      contact_mail[256];
   int       n;
   int       i;
   int       rc;
   LK_ENTRY  *group_base;
   int       group_count;
+  int       MailDisabled = 0;
+  char      search_filter[1024];
 
+  if(UseGroupUniversal)
+    groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
+  else
+    groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
+     
   if (!check_string(before_group_name))
     {
-      com_err(whoami, 0, "invalid LDAP list name %s", before_group_name);
-      return(-1);
+      com_err(whoami, 0, 
+             "Unable to process invalid LDAP list name %s", 
+             before_group_name);
+      return(AD_INVALID_NAME);
     }
+
   if (!check_string(after_group_name))
     {
-      com_err(whoami, 0, "invalid LDAP list name %s", after_group_name);
-      return(-1);
+      com_err(whoami, 0, 
+             "Unable to process invalid LDAP list name %s", after_group_name);
+      return(AD_INVALID_NAME);
     }
 
-  sprintf(filter_exp, "(sAMAccountName=%s_zZx%c)", before_group_name, before_group_membership[0]);
-  attr_array[0] = "distinguishedName";
+  if (Exchange) 
+    {
+      if(atoi(maillist)) 
+       {
+         group_count = 0;
+         group_base = NULL;
+         
+         sprintf(search_filter, "(&(objectClass=user)(cn=%s))", 
+                 after_group_name);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+
+         if ((rc = linklist_build(ldap_handle, dn_path, search_filter, 
+                                  attr_array, &group_base, &group_count,
+                                  LDAP_SCOPE_SUBTREE)) != 0)
+         {
+           com_err(whoami, 0, "Unable to process group %s : %s",
+                   after_group_name, ldap_err2string(rc));
+           return(rc);
+         }
+         
+         if (group_count)
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     after_group_name);
+             MailDisabled++;
+           }
+       
+         linklist_free(group_base);
+         group_base = NULL;
+         group_count = 0;
+       }
+    }
+
+  group_count = 0;
+  group_base = NULL;
+
+  if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, 
+                        before_group_membership, 
+                        MoiraId, "distinguishedName", &group_base, 
+                        &group_count, filter))
+    return(rc);
+
+  if (group_count == 0)
+    {
+      return(AD_NO_GROUPS_FOUND);
+    }
+
+  if (group_count != 1)
+    {
+      com_err(whoami, 0, "Unable to process multiple groups with "
+             "MoiraId = %s exist in the AD", MoiraId);
+      return(AD_MULTIPLE_GROUPS_FOUND);
+    }
+
+  strcpy(old_dn, group_base->value);
+
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+  attr_array[0] = "sAMAccountName";
   attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
     {
-      com_err(whoami, 0, "LDAP server unable to get list %s dn : %s",
+      com_err(whoami, 0, "Unable to get list %s dn : %s",
               after_group_name, ldap_err2string(rc));
       return(rc);
     }
+
   if (group_count != 1)
     {
-      com_err(whoami, 0, "LDAP server unable to find list %s in AD",
-              after_group_name);
-      callback_rc = LDAP_NO_SUCH_OBJECT;
-      return(-1);
+      com_err(whoami, 0,
+              "Unable to get sAMAccountName for group %s", 
+              before_group_name);
+      return(AD_LDAP_FAILURE);
     }
-  strcpy(old_dn, group_base->value);
+  
+  strcpy(sam_name, group_base->value);
   linklist_free(group_base);
   group_base = NULL;
   group_count = 0;
-
+  
   sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path);
   sprintf(new_dn, "cn=%s", after_group_name);
+  sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain));
+  sprintf(contact_mail, "%s@mit.edu", after_group_name); 
+  sprintf(proxy_address, "SMTP:%s@%s", after_group_name, 
+         lowercase(ldap_domain));
+  sprintf(mail_nickname, "%s", after_group_name);
+  
   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path,
                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "Couldn't rename list from %s to %s : %s",
-              after_group_name, after_group_name, ldap_err2string(rc));
+      com_err(whoami, 0, "Unable to rename list from %s to %s : %s",
+              before_group_name, after_group_name, ldap_err2string(rc));
       return(rc);
     }
 
-  sprintf(sam_name, "%s_zZx%c", after_group_name, after_group_membership[0]);
   name_v[0] = after_group_name;
+
+  if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], 
+              group_suffix, strlen(group_suffix)))
+    {
+      sprintf(sam_name, "%s%s", after_group_name, group_suffix);
+    }
+  else
+    {
+      com_err(whoami, 0, 
+             "Unable to rename list from %s to %s : sAMAccountName not found",
+              before_group_name, after_group_name);
+      return(rc);
+    }
+
   samAccountName_v[0] = sam_name;
-  desc_v[0] = after_desc;
+
+  if (after_security_flag)
+    groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
+
+  sprintf(groupTypeControlStr, "%ld", groupTypeControl);
+  groupTypeControl_v[0] = groupTypeControlStr;
+  mitMoiraId_v[0] = MoiraId;
+
+  sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
+  rc = attribute_update(ldap_handle, new_dn, after_desc, "description", 
+                       after_group_name);
   n = 0;
   ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE);
   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
-  if (strlen(after_desc) == 0)
-    desc_v[0] = NULL;
-  ADD_ATTR("description", desc_v, LDAP_MOD_REPLACE);
+  ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
+  ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE);
+
+  if (Exchange)
+    {
+      if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) 
+       {
+         mail_nickname_v[0] = mail_nickname;
+         proxy_address_v[0] = proxy_address;
+         mail_v[0] = mail;
+         report_to_originator_v[0] = "TRUE";
+
+         ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("reportToOriginator", report_to_originator_v, 
+                  LDAP_MOD_REPLACE);
+       } 
+      else 
+       {
+         mail_nickname_v[0] = NULL;
+         proxy_address_v[0] = NULL;
+         mail_v[0] = NULL;
+         legacy_exchange_dn_v[0] = NULL;
+         address_book_v[0] = NULL;
+         report_to_originator_v[0] = NULL;
+
+         ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("reportToOriginator", report_to_originator_v, 
+                  LDAP_MOD_REPLACE);
+       }
+    }
+  else
+    {
+      if(atoi(maillist) && email_isvalid(contact_mail)) 
+       {
+         mail_v[0] = contact_mail;
+         ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+       }
+    }
+
   mods[n] = NULL;
-  sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
+
   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "After renaming, couldn't modify list data for %s : %s",
+      com_err(whoami, 0, 
+             "Unable to modify list data for %s after renaming: %s",
               after_group_name, ldap_err2string(rc));
     }
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
   return(rc);
 }
 
 int group_create(int ac, char **av, void *ptr)
 {
   LDAPMod *mods[20];
-  LK_ENTRY  *group_base;
   char new_dn[256];
   char group_ou[256];
   char new_group_name[256];
   char sam_group_name[256];
   char cn_group_name[256];
+  char mail[256];
+  char contact_mail[256];
+  char mail_nickname[256];
+  char proxy_address[256];
+  char address_book[256];
   char *cn_v[] = {NULL, NULL};
   char *objectClass_v[] = {"top", "group", NULL};
   char info[256];
   char *samAccountName_v[] = {NULL, NULL};
-  char *managedBy_v[] = {NULL, NULL};
   char *altSecurityIdentities_v[] = {NULL, NULL};
+  char *member_v[] = {NULL, NULL};
   char *name_v[] = {NULL, NULL};
   char *desc_v[] = {NULL, NULL};
   char *info_v[] = {NULL, NULL};
+  char *mitMoiraId_v[] = {NULL, NULL};
   char *groupTypeControl_v[] = {NULL, NULL};
+  char *mail_v[] = {NULL, NULL};
+  char *proxy_address_v[] = {NULL, NULL};
+  char *mail_nickname_v[] = {NULL, NULL};
+  char *report_to_originator_v[] = {NULL, NULL};
+  char *address_book_v[] = {NULL, NULL};
+  char *legacy_exchange_dn_v[] = {NULL, NULL};
   char groupTypeControlStr[80];
   char group_membership[1];
   int  i;
   int  security_flag;
-  u_int groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
+  u_int groupTypeControl;
   int  n;
   int  rc;
+  int  updateGroup;
+  int  MailDisabled = 0;
+  char **call_args;
+  LK_ENTRY *group_base;
   int  group_count;
-  char filter_exp[256];
+  char filter[1024];
   char *attr_array[3];
-  char **call_args;
-
+  
   call_args = ptr;
 
-  if (!atoi(av[L_ACTIVE]))
-    return(1);
+  if(UseGroupUniversal)
+    groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
+  else 
+    groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
+
   if (!check_string(av[L_NAME]))
     {
-      com_err(whoami, 0, "invalid LDAP list name %s", av[L_NAME]);
-      return(1);
+      com_err(whoami, 0, "Unable to process invalid LDAP list name %s", 
+             av[L_NAME]);
+      return(AD_INVALID_NAME);
     }
 
+  updateGroup = (int)call_args[4];
   memset(group_ou, 0, sizeof(group_ou));
   memset(group_membership, 0, sizeof(group_membership));
   security_flag = 0;
-  get_group_membership(group_membership, group_ou, &security_flag, av);
 
-  if (security_flag)
-    groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
-  sprintf(groupTypeControlStr, "%ld", groupTypeControl);
-  groupTypeControl_v[0] = groupTypeControlStr;
+  get_group_membership(group_membership, group_ou, &security_flag, av);
 
   strcpy(new_group_name, av[L_NAME]);
-  strcpy(cn_group_name, av[L_NAME]);
-  sprintf(sam_group_name, "%s_zZx%c", av[L_NAME], group_membership[0]);
+  sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
+  sprintf(contact_mail, "%s@mit.edu", av[L_NAME]);
+  sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain));
+  sprintf(mail_nickname, "%s", av[L_NAME]);
 
-  samAccountName_v[0] = sam_group_name;
-  name_v[0] = new_group_name;
-  cn_v[0] = new_group_name;
+  if (security_flag)
+    groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
+  
+  sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix);
 
-  sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
-  n = 0;
-  ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
-  ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
-  ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
-  ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
-  ADD_ATTR("name", name_v, LDAP_MOD_ADD);
-  if (strlen(av[L_DESC]) != 0)
-    {
-      desc_v[0] = av[L_DESC];
-      ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
-    }
-  ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
-  if (strlen(av[L_ACE_NAME]) != 0)
+  if (!updateGroup)
     {
-      sprintf(info, "The Administrator of this list is the LIST: %s", av[L_ACE_NAME]);
-      info_v[0] = info;
-      ADD_ATTR("info", info_v, LDAP_MOD_ADD);
-    }
-  mods[n] = NULL;
+      sprintf(groupTypeControlStr, "%ld", groupTypeControl);
+      groupTypeControl_v[0] = groupTypeControlStr;
 
-  rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
+      strcpy(cn_group_name, av[L_NAME]);
+      
+      samAccountName_v[0] = sam_group_name;
+      name_v[0] = new_group_name;
+      cn_v[0] = new_group_name;
 
-  for (i = 0; i < n; i++)
-    free(mods[i]);
-  if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
-    {
-      com_err(whoami, 0, "Unable to create list %s in AD : %s",
-              av[L_NAME], ldap_err2string(rc));
-      callback_rc = rc;
-      return(rc);
-    }
-  if (rc == LDAP_ALREADY_EXISTS)
-    {
       n = 0;
-      desc_v[0] = av[L_DESC];
-      if (strlen(av[L_DESC]) == 0)
-        desc_v[0] = NULL;
-      ADD_ATTR("description", desc_v, LDAP_MOD_REPLACE);
+      ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
+      ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
+      ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
+      ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
+      ADD_ATTR("name", name_v, LDAP_MOD_ADD);
+      
+      if (Exchange)
+       {
+         if(atoi(av[L_MAILLIST])) 
+           {
+             group_count = 0;
+             group_base = NULL;
+             
+             sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
+             attr_array[0] = "cn";
+             attr_array[1] = NULL;
+             
+             if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
+                                      filter, attr_array, &group_base, 
+                                      &group_count,
+                                      LDAP_SCOPE_SUBTREE)) != 0)
+               {
+                 com_err(whoami, 0, "Unable to process group %s : %s",
+                         av[L_NAME], ldap_err2string(rc));
+                 return(rc);
+               }
+             
+             if (group_count)
+               {
+                 com_err(whoami, 0, "Object already exists with name %s",
+                         av[L_NAME]);
+                 MailDisabled++;
+               }
+       
+             linklist_free(group_base);
+             group_base = NULL;
+             group_count = 0;
+           }
+         
+         if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
+           {
+             mail_nickname_v[0] = mail_nickname;
+             report_to_originator_v[0] = "TRUE";
+
+             ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
+             ADD_ATTR("reportToOriginator", report_to_originator_v, 
+                      LDAP_MOD_ADD);
+           }
+       }
+      else
+       {
+         if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
+           {
+             mail_v[0] = contact_mail;
+             ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
+           }
+       }
+      
+      if (strlen(av[L_DESC]) != 0)
+       {
+         desc_v[0] = av[L_DESC];
+         ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
+       }
+      
+      ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
+      
+      if (strlen(av[L_ACE_NAME]) != 0)
+        {
+          sprintf(info, "The Administrator of this list is: %s", 
+                 av[L_ACE_NAME]);
+          info_v[0] = info;
+          ADD_ATTR("info", info_v, LDAP_MOD_ADD);
+        }
+
+      if (strlen(call_args[5]) != 0)
+        {
+          mitMoiraId_v[0] = call_args[5];
+          ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD);
+        }
+
       mods[n] = NULL;
-      rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
+      
+      rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
+      
       for (i = 0; i < n; i++)
         free(mods[i]);
+
+      if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
+        {
+          com_err(whoami, 0, "Unable to create list %s in AD : %s",
+                  av[L_NAME], ldap_err2string(rc));
+          callback_rc = rc;
+          return(rc);
+        }
     }
-  sprintf(filter_exp, "(sAMAccountName=%s)", sam_group_name);
-  attr_array[0] = "objectSid";
-  attr_array[1] = NULL;
-  group_count = 0;
-  group_base = NULL;
-  if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], filter_exp, attr_array, 
-                           &group_base, &group_count)) == LDAP_SUCCESS)
+
+  if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup))
     {
-      if (group_count == 1)
+      rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], 
+                           "description", av[L_NAME]);
+      sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]);
+      rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", 
+                           av[L_NAME]);
+      n = 0;
+
+      if (strlen(call_args[5]) != 0)
         {
-          (*sid_ptr) = group_base;
-          (*sid_ptr)->member = strdup(av[L_NAME]);
-          (*sid_ptr)->type = (char *)GROUPS;
-          sid_ptr = &(*sid_ptr)->next;
+          mitMoiraId_v[0] = call_args[5];
+          ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
         }
+
+      if (!(atoi(av[L_ACTIVE])))
+        {
+          member_v[0] = NULL;
+          ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
+        }
+   
+      if (Exchange)
+       {
+         if(atoi(av[L_MAILLIST])) 
+           {
+             group_count = 0;
+             group_base = NULL;
+             
+             sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
+             attr_array[0] = "cn";
+             attr_array[1] = NULL;
+             
+             if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
+                                      filter, attr_array, &group_base, 
+                                      &group_count,
+                                      LDAP_SCOPE_SUBTREE)) != 0)
+               {
+                 com_err(whoami, 0, "Unable to process group %s : %s",
+                         av[L_NAME], ldap_err2string(rc));
+                 return(rc);
+               }
+             
+             if (group_count)
+               {
+                 com_err(whoami, 0, "Object already exists with name %s",
+                         av[L_NAME]);
+                 MailDisabled++;
+               }
+             
+             linklist_free(group_base);
+             group_base = NULL;
+             group_count = 0;
+           }
+
+         if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
+           {
+             mail_nickname_v[0] = mail_nickname;
+             report_to_originator_v[0] = "TRUE";
+
+             ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
+             ADD_ATTR("reportToOriginator", report_to_originator_v, 
+                      LDAP_MOD_REPLACE);
+           } 
+         else 
+           {
+             mail_v[0] = NULL;
+             mail_nickname_v[0] = NULL;
+             proxy_address_v[0] = NULL;
+             legacy_exchange_dn_v[0] = NULL;
+             address_book_v[0] = NULL;
+             report_to_originator_v[0] = NULL;
+
+             ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
+             ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
+             ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+             ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, 
+                      LDAP_MOD_REPLACE);
+             ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
+             ADD_ATTR("reportToOriginator", report_to_originator_v, 
+                      LDAP_MOD_REPLACE);
+           }
+       }
       else
+       {
+         if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
+           {
+             mail_v[0] = contact_mail;
+             ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+           }
+         else
+           {
+             mail_v[0] = NULL;
+             ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+           }
+       }
+   
+      mods[n] = NULL;
+      rc = LDAP_SUCCESS;
+
+      if (n != 0)
         {
-          if (group_base != NULL)
-            linklist_free(group_base);
+          rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
+
+          for (i = 0; i < n; i++)
+              free(mods[i]);
+
+          if (rc != LDAP_SUCCESS)
+            {
+              com_err(whoami, 0, "Unable to update list %s in AD : %s",
+                      av[L_NAME], ldap_err2string(rc));
+              callback_rc = rc;
+              return(rc);
+            }
         }
     }
-  else
-    {
-      if (group_base != NULL)
-        linklist_free(group_base);
-    }
+
+  ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], 
+                       atoi(av[L_HIDDEN]),  av[L_ACE_TYPE], av[L_ACE_NAME]);
+
   return(LDAP_SUCCESS);
 }
 
-int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, char *group_membership)
+int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
+                        char *TargetGroupName, int HiddenGroup, 
+                        char *AceType, char *AceName)
 {
-  LK_ENTRY  *group_base;
-  char      *attr_array[3];
-  char      filter_exp[1024];
-  char      sam_group_name[256];
-  char      temp[512];
-  int       group_count;
-  int       rc;
+  char          filter_exp[1024];
+  char          *attr_array[5];
+  char          search_path[512];
+  char          root_ou[128];
+  char          TemplateDn[512];
+  char          TemplateSamName[128];
+  char          TargetDn[512];
+  char          TargetSamName[128];
+  char          AceSamAccountName[128];
+  char          AceDn[256];
+  unsigned char AceSid[128];
+  unsigned char UserTemplateSid[128];
+  char          acBERBuf[N_SD_BER_BYTES];
+  char          GroupSecurityTemplate[256];
+  char          hide_addres_lists[256];
+  char          address_book[256];
+  char          *hide_address_lists_v[] = {NULL, NULL};
+  char          *address_book_v[] = {NULL, NULL};
+  int           AceSidCount;
+  int           UserTemplateSidCount;
+  int           group_count;
+  int           n;
+  int           i;
+  int           rc;
+  int           nVal;
+  ULONG         dwInfo;
+  int           array_count = 0;
+  LDAPMod       *mods[20];
+  LK_ENTRY      *group_base;
+  LDAP_BERVAL   **ppsValues;
+  LDAPControl sControl = {"1.2.840.113556.1.4.801",
+                          { N_SD_BER_BYTES, acBERBuf },
+                          TRUE
+                         };
+  LDAPControl *apsServerControls[] = {&sControl, NULL};
+  LDAPMessage *psMsg;
+
+  dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
+    DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+  BEREncodeSecurityBits(dwInfo, acBERBuf);
+
+  sprintf(search_path, "%s,%s", group_ou_root, dn_path);
+  sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+  group_count = 0;
+  group_base = NULL;
 
-  if (!check_string(group_name))
+  if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
+                          &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE) != 0))
+    return(1);
+
+  if (group_count != 1)
     {
-      com_err(whoami, 0, "invalid LDAP list name %s", group_name);
-      return(-1);
+      linklist_free(group_base);
+      return(1);
     }
-  rc = 1;
+
+  strcpy(TargetDn, group_base->dn);
+  strcpy(TargetSamName, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
   group_count = 0;
+
+  UserTemplateSidCount = 0;
+  memset(UserTemplateSid, '\0', sizeof(UserTemplateSid));
+  memset(AceSamAccountName, '\0', sizeof(AceSamAccountName));
+  memset(AceSid, '\0', sizeof(AceSid));
+  AceSidCount = 0;
   group_base = NULL;
-  attr_array[0] = "distinguishedName";
-  attr_array[1] = NULL;
-  strcpy(sam_group_name, group_name);
-  sprintf(temp, "%s,%s", group_ou_root, dn_path);
-  sprintf(filter_exp, "(sAMAccountName=%s_zZx%c)", group_name, group_membership[0]);
-  if (linklist_build(ldap_handle, temp, filter_exp, attr_array, 
-                           &group_base, &group_count) != 0)
-    return(-1);
-  if (group_count == 1)
+  group_count = 0;
+
+  if (strlen(AceName) != 0)
     {
-      if ((rc = ldap_delete_s(ldap_handle, group_base->value)) != LDAP_SUCCESS)
+      if (!strcmp(AceType, "LIST"))
+        {
+          sprintf(AceSamAccountName, "%s%s", AceName, group_suffix);
+          strcpy(root_ou, group_ou_root);
+        }
+      else if (!strcmp(AceType, "USER"))
         {
+          sprintf(AceSamAccountName, "%s", AceName);
+          strcpy(root_ou, user_ou);
+        }
+
+      if (strlen(AceSamAccountName) != 0)
+        {
+          sprintf(search_path, "%s", dn_path);
+          sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
+          attr_array[0] = "objectSid";
+          attr_array[1] = NULL;
+          group_count = 0;
+          group_base = NULL;
+
+          if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
+                                  attr_array, &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE) != 0))
+            return(1);
+          if (group_count == 1)
+            {
+              strcpy(AceDn, group_base->dn);
+              AceSidCount = group_base->length;
+              memcpy(AceSid, group_base->value, AceSidCount);
+            }
           linklist_free(group_base);
-          com_err(whoami, 0, "Unable to delete list %s from AD : %s",
-                  group_name, ldap_err2string(rc));
-          return(-1);
+          group_base = NULL;
+          group_count = 0;
         }
-      linklist_free(group_base);
     }
-  else
+
+  if (AceSidCount == 0)
     {
-      linklist_free(group_base);
-      com_err(whoami, 0, "Unable to find list %s in AD.", group_name);
-      return(-1);
+      com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not "
+             "have an AD SID.", TargetGroupName, AceName, AceType);
+      com_err(whoami, 0, "   Non-admin security group template will be used.");
     }
+  else
+    {
+      sprintf(search_path, "%s,%s", security_template_ou, dn_path);
+      sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
+      attr_array[0] = "objectSid";
+      attr_array[1] = NULL;
 
-  return(0);
-}
+      group_count = 0;
+      group_base = NULL;
 
-int process_lists(int ac, char **av, void *ptr)
-{
-  int   rc;
-  int   security_flag;
-  char  group_ou[256];
-  char  group_membership[2];
-  char  **call_args;
+      if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
+                              attr_array, &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE) != 0))
+        return(1);
 
-  call_args = ptr;
+      if ((rc != 0) || (group_count != 1))
+        {
+          com_err(whoami, 0, "Unable to process user security template: %s", 
+                 "UserTemplate");
+          AceSidCount = 0;
+        }
+      else
+        {
+          UserTemplateSidCount = group_base->length;
+          memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount);
+        }
+      linklist_free(group_base);
+      group_base = NULL;
+      group_count = 0;
+    }
 
-  security_flag = 0;
-  memset(group_ou, '\0', sizeof(group_ou));
-  memset(group_membership, '\0', sizeof(group_membership));
-  get_group_membership(group_membership, group_ou, &security_flag, av);
-  rc = member_add((LDAP *)call_args[0], (char *)call_args[1], av[L_NAME],
-                  group_ou, group_membership, call_args[2],  (char *)call_args[3]);
-  if (rc)
+  if (HiddenGroup)
     {
-      com_err(whoami, 0, "Couldn't add %s to group %s", call_args[2], av[L_NAME]);
+      if (AceSidCount == 0)
+        {
+          strcpy(GroupSecurityTemplate, HIDDEN_GROUP);
+          sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP);
+        }
+      else
+        {
+          strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN);
+          sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN);
+        }
+    }
+  else
+    {
+      if (AceSidCount == 0)
+        {
+          strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP);
+          sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP);
+        }
+      else
+        {
+          strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN);
+          sprintf(filter_exp, "(sAMAccountName=%s)", 
+                 NOT_HIDDEN_GROUP_WITH_ADMIN);
+        }
     }
-  return(0);
-}
 
-int member_list_build(int ac, char **av, void *ptr)
-{
-  LK_ENTRY  *linklist;
-  char      temp[1024];
-  char      **call_args;
+  sprintf(search_path, "%s,%s", security_template_ou, dn_path);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+  group_count = 0;
+  group_base = NULL;
 
-  call_args = ptr;
+  if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
+                          &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE) != 0))
+    return(1);
 
-  strcpy(temp, av[ACE_NAME]);
-  if (!check_string(temp))
-    return(0);
-  if (!strcmp(av[ACE_TYPE], "USER"))
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      com_err(whoami, 0, "Unable to process group security template: %s - "
+             "security not set", GroupSecurityTemplate);
+      return(1);
+    }
+
+  strcpy(TemplateDn, group_base->dn);
+  strcpy(TemplateSamName, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+  
+  sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName);
+  rc = ldap_search_ext_s(ldap_handle,
+                         TemplateDn,
+                         LDAP_SCOPE_SUBTREE,
+                         filter_exp,
+                         NULL,
+                         0,
+                         apsServerControls,
+                         NULL,
+                         NULL,
+                         0,
+                         &psMsg);
+
+  if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
+    {
+      com_err(whoami, 0, "Unable to find group security template: %s - "
+             "security not set", GroupSecurityTemplate);
+      return(1);
+    }
+
+  ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
+
+  if (ppsValues == NULL)
+    {
+      com_err(whoami, 0, "Unable to find group security descriptor for group "
+             "%s - security not set", GroupSecurityTemplate);
+      return(1);
+    }
+  
+  if (AceSidCount != 0)
+    {
+      for (nVal = 0; ppsValues[nVal] != NULL; nVal++)
+        {
+          for (i = 0; 
+              i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++)
+            {
+              if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, 
+                         UserTemplateSidCount))
+                {
+                  memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount);
+                  break;
+                }
+            }
+        }
+    }
+
+  n = 0;
+  ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, 
+          LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+
+  if (Exchange)
+    {
+      if(HiddenGroup) 
+       {
+         hide_address_lists_v[0] = "TRUE";
+         address_book_v[0] = NULL;
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
+                  LDAP_MOD_REPLACE);
+         ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
+       } else {
+         hide_address_lists_v[0] = NULL;
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
+                  LDAP_MOD_REPLACE);
+       }
+    }
+
+  mods[n] = NULL;
+
+  rc = ldap_modify_s(ldap_handle, TargetDn, mods);
+
+  for (i = 0; i < n; i++)
+    free(mods[i]);
+
+  ldap_value_free_len(ppsValues);
+  ldap_msgfree(psMsg);
+
+  if (rc != LDAP_SUCCESS)
+    {
+      com_err(whoami, 0, "Unable to set security settings for group %s : %s",
+              TargetGroupName, ldap_err2string(rc));
+
+      if (AceSidCount != 0)
+        {
+          com_err(whoami, 0, 
+                 "Trying to set security for group %s without admin.",
+                  TargetGroupName);
+
+          if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, 
+                                        HiddenGroup, "", ""))
+            {
+              com_err(whoami, 0, "Unable to set security for group %s.",
+                      TargetGroupName);
+              return(rc);
+            }
+        }
+      return(rc);
+    }
+
+  return(rc);
+}
+
+int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, 
+                 char *group_membership, char *MoiraId)
+{
+  LK_ENTRY  *group_base;
+  char      temp[512];
+  char      filter[128];
+  int       group_count;
+  int       rc;
+
+  if (!check_string(group_name))
+    {
+      com_err(whoami, 0, 
+             "Unable to process invalid LDAP list name %s", group_name);
+      return(AD_INVALID_NAME);
+    }
+
+  memset(filter, '\0', sizeof(filter));
+  group_count = 0;
+  group_base = NULL;
+  sprintf(temp, "%s,%s", group_ou_root, dn_path);
+
+  if (rc = ad_get_group(ldap_handle, temp, group_name, 
+                        group_membership, MoiraId, 
+                        "distinguishedName", &group_base, 
+                        &group_count, filter))
+    return(rc);
+
+  if (group_count == 1)
+    {
+      if ((rc = ldap_delete_s(ldap_handle, group_base->value)) != LDAP_SUCCESS)
+        {
+          linklist_free(group_base);
+          com_err(whoami, 0, "Unable to delete list %s from AD : %s",
+                  group_name, ldap_err2string(rc));
+          return(rc);
+        }
+      linklist_free(group_base);
+    }
+  else
+    {
+      linklist_free(group_base);
+      com_err(whoami, 0, "Unable to find list %s in AD.", group_name);
+      return(AD_NO_GROUPS_FOUND);
+    }
+  
+  return(0);
+}
+
+int BEREncodeSecurityBits(ULONG uBits, char *pBuffer)
+{
+    *pBuffer++ = 0x30;
+    *pBuffer++ = 0x03;
+    *pBuffer++ = 0x02;
+    *pBuffer++ = 0x00;
+    return(N_SD_BER_BYTES);
+}
+
+int process_lists(int ac, char **av, void *ptr)
+{
+  int   rc;
+  int   security_flag;
+  char  group_ou[256];
+  char  group_membership[2];
+  char  **call_args;
+
+  call_args = ptr;
+
+  security_flag = 0;
+  memset(group_ou, '\0', sizeof(group_ou));
+  memset(group_membership, '\0', sizeof(group_membership));
+  get_group_membership(group_membership, group_ou, &security_flag, av);
+  rc = member_add((LDAP *)call_args[0], (char *)call_args[1], av[L_NAME],
+                  group_ou, group_membership, call_args[2], 
+                  (char *)call_args[3], "");
+  return(0);
+}
+
+int member_list_build(int ac, char **av, void *ptr)
+{
+  LK_ENTRY  *linklist;
+  char      temp[1024];
+  char      **call_args;
+  char      *s;
+  call_args = ptr;
+  
+  strcpy(temp, av[ACE_NAME]);
+
+  if (!check_string(temp))
+    return(0);
+
+  if (!strcmp(av[ACE_TYPE], "USER"))
     {
       if (!((int)call_args[3] & MOIRA_USERS))
         return(0);
     }
   else if (!strcmp(av[ACE_TYPE], "STRING"))
     {
+      if (Exchange)
+       {
+         if((s = strchr(temp, '@')) == (char *) NULL) 
+           {
+             strcat(temp, "@mit.edu");
+           }
+         
+         if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6))
+           {
+             s = strrchr(temp, '.');
+             *s = '\0';
+             strcat(s, ".mit.edu");
+           }
+       }
+      
       if (!((int)call_args[3] & MOIRA_STRINGS))
         return(0);
+
       if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou))
         return(0);
+
     }
   else if (!strcmp(av[ACE_TYPE], "LIST"))
     {
@@ -1810,19 +3306,25 @@ int member_list_build(int ac, char **av, void *ptr)
     {
       if (!((int)call_args[3] & MOIRA_KERBEROS))
         return(0);
-      if (contact_create((LDAP *)call_args[0], call_args[1], temp, kerberos_ou))
+
+      if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
+                        kerberos_ou))
         return(0);
+
     }
   else
     return(0);
 
   linklist = member_base;
+
   while (linklist)
     {
     if (!strcasecmp(temp, linklist->member))
       return(0);
+
     linklist = linklist->next;
     }
+
   linklist = calloc(1, sizeof(LK_ENTRY));
   linklist->op = 1;
   linklist->dn = NULL;
@@ -1834,53 +3336,57 @@ int member_list_build(int ac, char **av, void *ptr)
   strcpy(linklist->member, temp);
   linklist->next = member_base;
   member_base = linklist;
+
   return(0);
 }
 
 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
                   char *group_ou, char *group_membership, char *user_name,
-                  char *UserOu)
+                  char *UserOu, char *MoiraId)
 {
   char        distinguished_name[1024];
   char        *modvalues[2];
-  char        filter_exp[4096];
-  char        *attr_array[3];
   char        temp[256];
+  char        filter[128];
+  char        *attr_array[3];
   int         group_count;
   int         i;
   int         n;
   LDAPMod     *mods[20];
   LK_ENTRY    *group_base;
   ULONG       rc;
+  char        *s;
 
   if (!check_string(group_name))
-    return(1);
-  strcpy(temp, group_name);
-  sprintf(filter_exp, "(sAMAccountName=%s_zZx%c)", group_name, group_membership[0]);
-  attr_array[0] = "distinguishedName";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
-    {
-      com_err(whoami, 0, "LDAP server unable to get list %s info : %s",
-              group_name, ldap_err2string(rc));
-      goto cleanup;
-    }
+    return(AD_INVALID_NAME);
+
+  memset(filter, '\0', sizeof(filter));
+  group_base = NULL;
+  group_count = 0;
+
+  if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
+                        group_membership, MoiraId, 
+                        "distinguishedName", &group_base, 
+                        &group_count, filter))
+    return(rc);
+
   if (group_count != 1)
     {
-      com_err(whoami, 0, "LDAP server unable to find list %s in AD",
+      com_err(whoami, 0, "Unable to find list %s in AD",
               group_name);
       linklist_free(group_base);
       group_base = NULL;
       group_count = 0;
       goto cleanup;
     }
+
   strcpy(distinguished_name, group_base->value);
   linklist_free(group_base);
   group_base = NULL;
   group_count = 0;
 
   sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
+
   modvalues[0] = temp;
   modvalues[1] = NULL;
 
@@ -1888,27 +3394,79 @@ int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name,
   ADD_ATTR("member", modvalues, LDAP_MOD_DELETE);
   mods[n] = NULL;
   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
+  if (rc == LDAP_UNWILLING_TO_PERFORM)
+    rc = LDAP_SUCCESS;
+
   if (rc != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "LDAP server unable to modify list %s members : %s",
+      com_err(whoami, 0, "Unable to modify list %s members : %s",
               group_name, ldap_err2string(rc));
       goto cleanup;
     }
 
-cleanup:
+  if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) 
+    {
+      if (Exchange)
+       {
+         if(!strcmp(UserOu, contact_ou) && 
+            ((s = strstr(user_name, "@mit.edu")) != (char *) NULL))
+           {
+             memset(temp, '\0', sizeof(temp));
+             strcpy(temp, user_name);
+             s = strchr(temp, '@');
+             *s = '\0';
+             
+             sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp);
+         
+             if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL,
+                                      &group_base, &group_count, 
+                                      LDAP_SCOPE_SUBTREE) != 0))
+               return(rc);       
+             
+             if(group_count)
+               goto cleanup;
+             
+             linklist_free(group_base);
+             group_base = NULL;
+             group_count = 0;
+           }
+      
+         sprintf(filter, "(distinguishedName=%s)", temp);
+         attr_array[0] = "memberOf";
+         attr_array[1] = NULL;
+         
+         if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
+                                  &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE) != 0))
+           return(rc);
+         
+
+         if(!group_count) 
+           {
+             com_err(whoami, 0, "Removing unreferenced object %s", temp);
+         
+             if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) 
+               return(rc);
+           }
+       }
+    }
+
+ cleanup:
   return(rc);
 }
 
 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
-               char *group_ou, char *group_membership, char *user_name, char *UserOu)
+               char *group_ou, char *group_membership, char *user_name, 
+               char *UserOu, char *MoiraId)
 {
   char        distinguished_name[1024];
   char        *modvalues[2];
-  char        filter_exp[4096];
-  char        *attr_array[3];
   char        temp[256];
+  char        filter[128];
   int         group_count;
   int         n;
   int         i;
@@ -1916,32 +3474,28 @@ int member_add(LDAP *ldap_handle, char *dn_path, char *group_name,
   LK_ENTRY    *group_base;
   ULONG       rc;
 
+  if (!check_string(group_name))
+    return(AD_INVALID_NAME);
+
   rc = 0;
+  memset(filter, '\0', sizeof(filter));
   group_base = NULL;
   group_count = 0;
 
-  if (!check_string(group_name))
-    return(-1);
+  if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
+                        group_membership, MoiraId, 
+                        "distinguishedName", &group_base, 
+                        &group_count, filter))
+    return(rc);
 
-  strcpy(temp, group_name);
-  sprintf(filter_exp, "(sAMAccountName=%s_zZx%c)", group_name, group_membership[0]);
-  attr_array[0] = "distinguishedName";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
-    {
-      com_err(whoami, 0, "LDAP server unable to get list %s info : %s",
-              group_name, ldap_err2string(rc));
-      return(-1);
-    }
   if (group_count != 1)
     {
       linklist_free(group_base);
       group_base = NULL;
       group_count = 0;
-      com_err(whoami, 0, "LDAP server unable to find list %s in AD",
+      com_err(whoami, 0, "Unable to find list %s in AD",
               group_name);
-      return(-1);
+      return(AD_MULTIPLE_GROUPS_FOUND);
     }
 
   strcpy(distinguished_name, group_base->value);
@@ -1957,66 +3511,301 @@ int member_add(LDAP *ldap_handle, char *dn_path, char *group_name,
   ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
   mods[n] = NULL;
   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
+
   if (rc == LDAP_ALREADY_EXISTS)
     rc = LDAP_SUCCESS;
+
+  if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou)))
+    {
+      if (rc == LDAP_UNWILLING_TO_PERFORM)
+        rc = LDAP_SUCCESS;
+    }
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
   if (rc != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "LDAP server unable to modify list %s members in AD : %s",
-              group_name, ldap_err2string(rc));
+      com_err(whoami, 0, "Unable to add %s to list %s as a member : %s",
+              user_name, group_name, ldap_err2string(rc));
     }
-
+  
   return(rc);
 }
 
+int contact_remove_email(LDAP *ld, char *bind_path,
+                        LK_ENTRY **linklist_base, int linklist_current)
+{
+  LK_ENTRY  *gPtr;
+  int       rc;
+  char      *mail_v[] = {NULL, NULL};
+  LDAPMod   *mods[20];
+  int n;
+  int i;
+
+  mail_v[0] = NULL;
+
+  n = 0;
+  ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+  ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE);
+  ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE);
+  ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE);
+  mods[n] = NULL;
+
+  gPtr = (*linklist_base);
+  
+  while(gPtr) {
+    rc = ldap_modify_s(ld, gPtr->dn, mods);
+    
+    if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
+      {
+       com_err(whoami, 0, "Unable to modify contact %s in AD : %s",
+               gPtr->dn, ldap_err2string(rc));
+       return(rc);
+      }
+
+    gPtr = gPtr->next;
+  }
+
+  for (i = 0; i < n; i++)
+    free(mods[i]);
+  
+    return(rc);
+}
+
 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
 {
   LDAPMod *mods[20];
+  LK_ENTRY  *group_base;
+  int  group_count;
   char new_dn[256];
   char cn_user_name[256];
   char contact_name[256];
+  char mail_nickname[256];
+  char proxy_address_internal[256];
+  char proxy_address_external[256];
+  char target_address[256];
+  char internal_contact_name[256];
+  char filter[128];
+  char mail[256];
+  char mit_address_book[256];
+  char default_address_book[256];
+  char contact_address_book[256];
   char *email_v[] = {NULL, NULL};
   char *cn_v[] = {NULL, NULL};
   char *contact_v[] = {NULL, NULL};
+  char *mail_nickname_v[] = {NULL, NULL};
+  char *proxy_address_internal_v[] = {NULL, NULL};
+  char *proxy_address_external_v[] = {NULL, NULL};
+  char *target_address_v[] = {NULL, NULL};
+  char *mit_address_book_v[] = {NULL, NULL};
+  char *default_address_book_v[] = {NULL, NULL};
+  char *contact_address_book_v[] = {NULL, NULL};
+  char *hide_address_lists_v[] = {NULL, NULL};
+  char *attr_array[3];
+
   char *objectClass_v[] = {"top", "person", 
                            "organizationalPerson", 
                            "contact", NULL};
   char *name_v[] = {NULL, NULL};
   char *desc_v[] = {NULL, NULL};
+  char *s;
   int  n;
   int  rc;
   int  i;
 
   if (!check_string(user))
     {
-      com_err(whoami, 0, "invalid LDAP name %s", user);
-      return(-1);
+      com_err(whoami, 0, "Unable to process invalid LDAP name %s", user);
+      return(AD_INVALID_NAME);
     }
-  strcpy(contact_name, user);
+
+  strcpy(mail, user);
+  strcpy(contact_name, mail);
+  strcpy(internal_contact_name, mail);
+
+  if((s = strchr(internal_contact_name, '@')) != NULL) {
+    *s = '?';
+  }
+
   sprintf(cn_user_name,"CN=%s,%s,%s", contact_name, group_ou, bind_path);
+  sprintf(target_address, "SMTP:%s", contact_name);
+  sprintf(proxy_address_external, "SMTP:%s", contact_name);
+  sprintf(mail_nickname, "%s", internal_contact_name);
+  
   cn_v[0] = cn_user_name;
   contact_v[0] = contact_name;
   name_v[0] = user;
   desc_v[0] = "Auto account created by Moira";
-  email_v[0] = user;
-
+  email_v[0] = mail;
+  proxy_address_internal_v[0] = proxy_address_internal;
+  proxy_address_external_v[0] = proxy_address_external;
+  mail_nickname_v[0] = mail_nickname;
+  target_address_v[0] = target_address;
+  mit_address_book_v[0] = mit_address_book;
+  default_address_book_v[0] = default_address_book;
+  contact_address_book_v[0] = contact_address_book;
   strcpy(new_dn, cn_user_name);
   n = 0;
+
   ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
   ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
-  if (!strcmp(group_ou, contact_ou))
+
+  if (Exchange)
     {
-      ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
+      if (!strcmp(group_ou, contact_ou) && email_isvalid(mail))
+       {
+         group_count = 0;
+         group_base = NULL;
+         
+         sprintf(filter, "(&(objectClass=user)(cn=%s))", mail);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+
+         if ((rc = linklist_build(ld, bind_path, filter, attr_array,
+                                  &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE)) != 0) 
+           {
+             com_err(whoami, 0, "Unable to process contact %s : %s", 
+                     user, ldap_err2string(rc));
+             return(rc);
+           }
+      
+         if (group_count) 
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     user);
+             return(1);
+           }
+
+         linklist_free(group_base);
+         group_base = NULL;
+         group_count = 0;
+      
+         sprintf(filter, "(&(objectClass=group)(cn=%s))", mail);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+
+         if ((rc = linklist_build(ld, bind_path, filter, attr_array,
+                                  &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE)) != 0) 
+           {
+             com_err(whoami, 0, "Unable to process contact %s : %s", 
+                     user, ldap_err2string(rc));
+             return(rc);
+           }
+         
+         if (group_count) 
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     user);
+             return(1);
+           }
+  
+         linklist_free(group_base);
+         group_count = 0;
+         group_base = NULL;
+         
+         sprintf(filter, "(&(objectClass=user)(mail=%s))", mail);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+
+         if ((rc = linklist_build(ld, bind_path, filter, attr_array,
+                                  &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE)) != 0) 
+           {
+             com_err(whoami, 0, "Unable to process contact %s : %s", 
+                     user, ldap_err2string(rc));
+             return(rc);
+           }
+         
+         if (group_count) 
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     user);
+             return(1);
+           }
+
+         linklist_free(group_base);
+         group_base = NULL;
+         group_count = 0;
+
+         sprintf(filter, "(&(objectClass=group)(mail=%s))", mail);
+         attr_array[0] = "cn";
+         attr_array[1] = NULL;
+
+         if ((rc = linklist_build(ld, bind_path, filter, attr_array,
+                                  &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE)) != 0) 
+           {
+             com_err(whoami, 0, "Unable to process contact %s : %s", 
+                     user, ldap_err2string(rc));
+             return(rc);
+           }
+      
+         if (group_count) 
+           {
+             com_err(whoami, 0, "Object already exists with name %s",
+                     user);
+             return(1);
+           }
+         
+         linklist_free(group_base);
+         group_base = NULL;
+         group_count = 0;
+         
+         ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
+         ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
+         ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD);
+         ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD);
+         
+         hide_address_lists_v[0] = "TRUE";
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
+                  LDAP_MOD_ADD);
+       }
     }
+
   mods[n] = NULL;
 
   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
+  if (Exchange)
+    {
+
+      if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
+         !strcmp(group_ou, contact_ou) && email_isvalid(mail))
+       {
+         n = 0;
+         
+         ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
+         ADD_ATTR("proxyAddresses", proxy_address_external_v, 
+                  LDAP_MOD_REPLACE);
+         ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
+
+         hide_address_lists_v[0] = "TRUE";
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
+                  LDAP_MOD_REPLACE);
+    
+         mods[n] = NULL;
+         rc = ldap_modify_s(ld, new_dn, mods);
+      
+         if (rc) 
+           {
+             com_err(whoami, 0, "Unable to update contact %s", mail);
+           }
+      
+         for (i = 0; i < n; i++)
+           free(mods[i]);
+       }
+    }
+
   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
     {
       n = 0;
@@ -2027,286 +3816,511 @@ int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
       mods[n] = NULL;
       rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
+
       for (i = 0; i < n; i++)
         free(mods[i]);
     }
+
   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
     {
-      com_err(whoami, 0, "could not create contact %s : %s",
+      com_err(whoami, 0, "Unable to create contact %s : %s",
               user, ldap_err2string(rc));
-      return(-1);
+      return(rc);
     }
+
   return(0);
 }
 
 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
-                char *Uid, char *MitId)
+                char *Uid, char *MitId, char *MoiraId, int State,
+                char *WinHomeDir, char *WinProfileDir, char *first,
+               char *middle, char *last)
 {
   LDAPMod   *mods[20];
   LK_ENTRY  *group_base;
   int  group_count;
-  char distinguished_name[256];
+  char distinguished_name[512];
+  char displayName[256];
+  char *mitMoiraId_v[] = {NULL, NULL};
   char *uid_v[] = {NULL, NULL};
   char *mitid_v[] = {NULL, NULL};
   char *homedir_v[] = {NULL, NULL};
   char *winProfile_v[] = {NULL, NULL};
   char *drives_v[] = {NULL, NULL};
+  char *userAccountControl_v[] = {NULL, NULL};
+  char *alt_recipient_v[] = {NULL, NULL};
+  char *hide_address_lists_v[] = {NULL, NULL};
+  char *mail_v[] = {NULL, NULL};
+  char userAccountControlStr[80];
   int  n;
   int  rc;
   int  i;
-  char filter_exp[256];
+  int  OldUseSFU30;
+  u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
+    UF_PASSWD_CANT_CHANGE;
+  char filter[128];
   char *attr_array[3];
-  char **hp;
-  char path[256];
-  char winPath[256];
-  char winProfile[256];
+  char temp[256];
+  char mail[256];
+  char contact_mail[256];
+  char filter_exp[1024];
+  char search_path[512];
+  char TemplateDn[512];
+  char TemplateSamName[128];
+  char alt_recipient[256];
+  char acBERBuf[N_SD_BER_BYTES];
+  LDAPControl sControl = {"1.2.840.113556.1.4.801",
+                          { N_SD_BER_BYTES, acBERBuf },
+                          TRUE};
+  LDAPControl *apsServerControls[] = {&sControl, NULL};
+  LDAPMessage *psMsg;
+  LDAP_BERVAL   **ppsValues;
+  ULONG dwInfo;
+  char *argv[3];
+  char *homeMDB;
+  char *homeServerName;
+  char *save_argv[7];
+  char search_string[256];
+
+  dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+    DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+  BEREncodeSecurityBits(dwInfo, acBERBuf);
 
   if (!check_string(user_name))
     {
-      com_err(whoami, 0, "invalid LDAP user name %s", user_name);
-      return(-1);
+      com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
+             user_name);
+      return(AD_INVALID_NAME);
+    }
+  
+  memset(contact_mail, '\0', sizeof(contact_mail));
+  sprintf(contact_mail, "%s@mit.edu", user_name);
+  memset(mail, '\0', sizeof(mail));
+  sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
+  memset(alt_recipient, '\0', sizeof(alt_recipient));
+  sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
+         dn_path);
+  sprintf(search_string, "@%s", uppercase(ldap_domain));
+
+  if (Exchange)
+    {
+      if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
+       {
+         com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
+       }
     }
 
   group_count = 0;
   group_base = NULL;
-  sprintf(filter_exp, "(sAMAccountName=%s)", user_name);
-  attr_array[0] = "cn";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
+
+  memset(displayName, '\0', sizeof(displayName));
+
+  if (strlen(MoiraId) != 0)
     {
-      com_err(whoami, 0, "LDAP server couldn't process user %s : %s",
-              user_name, ldap_err2string(rc));
-      return(rc);
+      sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
+      attr_array[0] = "cn";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          return(rc);
+        }
+    }
+
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      group_base = NULL;
+      group_count = 0;
+      sprintf(filter, "(sAMAccountName=%s)", user_name);
+      attr_array[0] = "cn";
+      attr_array[1] = NULL;
+      sprintf(temp, "%s,%s", user_ou, dn_path);
+      if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          return(rc);
+        }
     }
 
   if (group_count != 1)
     {
-      com_err(whoami, 0, "LDAP server unable to find user %s in AD",
+      com_err(whoami, 0, "Unable to find user %s in AD",
               user_name);
       linklist_free(group_base);
-      return(LDAP_NO_SUCH_OBJECT);
+      return(AD_NO_USER_FOUND);
     }
+
   strcpy(distinguished_name, group_base->dn);
 
   linklist_free(group_base);
   group_count = 0;
-  n = 0;
-  if (strlen(Uid) != 0)
-    {
-      uid_v[0] = Uid;
-      ADD_ATTR("uid", uid_v, LDAP_MOD_REPLACE);
-      ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
-    }
-  if (strlen(MitId) != 0)
-    {
-      mitid_v[0] = MitId;
-      ADD_ATTR("employeeID", mitid_v, LDAP_MOD_REPLACE);
+
+  if ((strlen(MitId) != 0) && (MitId[0] == '9'))
+    rc = attribute_update(ldap_handle, distinguished_name, MitId, 
+                         "employeeID", user_name);
+  else
+    rc = attribute_update(ldap_handle, distinguished_name, "none", 
+                         "employeeID", user_name);
+
+  if(strlen(first)) {
+    strcat(displayName, first);
+  }
+
+  if(strlen(middle)) {
+    if(strlen(first)) 
+      strcat(displayName, " ");
+
+    strcat(displayName, middle);
+  }
+
+  if(strlen(last)) {
+    if(strlen(middle) || strlen(first))
+      strcat(displayName, " ");
+
+    strcat(displayName, last);
+  }
+
+  if(strlen(displayName)) 
+    rc = attribute_update(ldap_handle, distinguished_name, displayName, 
+                         "displayName", user_name);
+  else
+    rc = attribute_update(ldap_handle, distinguished_name, user_name,
+                         "displayName", user_name);
+  
+  if(strlen(first))
+    rc = attribute_update(ldap_handle, distinguished_name, first, 
+                         "givenName", user_name);
+  else
+    rc = attribute_update(ldap_handle, distinguished_name, "",
+                         "givenName", user_name);
+
+  if(strlen(middle) == 1) 
+    rc = attribute_update(ldap_handle, distinguished_name, middle,
+                         "initials", user_name);
+  else 
+    rc = attribute_update(ldap_handle, distinguished_name, "",
+                         "initials", user_name);
+  
+  if(strlen(last))
+    rc = attribute_update(ldap_handle, distinguished_name, last,
+                         "sn", user_name);
+  else 
+    rc = attribute_update(ldap_handle, distinguished_name, "",
+                         "sn", user_name);
+  
+  rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
+                       user_name);
+  rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
+                       "mitMoiraId", user_name);
+
+  n = 0;
+  uid_v[0] = Uid;
+
+  if (!UseSFU30)
+    {
+      ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
     }
-  if ((hp = hes_resolve(user_name, "filsys")) != NULL)
+  else
     {
-      memset(path, 0, sizeof(path));
-      memset(winPath, 0, sizeof(winPath));
-      sscanf(hp[0], "%*s %s", path);
-      if (strlen(path) && strnicmp(path, AFS, strlen(AFS)) == 0)
-        {
-          AfsToWinAfs(path, winPath);
-          homedir_v[0] = winPath;
-          ADD_ATTR("homeDirectory", homedir_v, LDAP_MOD_REPLACE);
-          strcpy(winProfile, winPath);
-          strcat(winProfile, "\\.winprofile");
-          winProfile_v[0] = winProfile;
-          ADD_ATTR("profilePath", winProfile_v, LDAP_MOD_REPLACE);
-          drives_v[0] = "H:";
-          ADD_ATTR("homeDrive", drives_v, LDAP_MOD_REPLACE);
-        }
+      ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
     }
-  mods[n] = NULL;
-  if (n != 0)
+
+  if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
     {
-      if ((rc = ldap_modify_s(ldap_handle, distinguished_name, mods)) != LDAP_SUCCESS)
-        {
-          com_err(whoami, 0, "Couldn't modify user data for %s : %s",
-                  user_name, ldap_err2string(rc));
-        }
-      for (i = 0; i < n; i++)
-        free(mods[i]);
+      userAccountControl |= UF_ACCOUNTDISABLE;
+
+      if (Exchange)
+       {
+         hide_address_lists_v[0] = "TRUE";
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
+                  LDAP_MOD_REPLACE);
+       }
     }
-  if (hp != NULL)
+  else
     {
-      i = 0;
-      while (hp[i])
+      if (Exchange)
+       {
+         hide_address_lists_v[0] = NULL;
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
+                  LDAP_MOD_REPLACE);
+       }
+    }
+
+  sprintf(userAccountControlStr, "%ld", userAccountControl);
+  userAccountControl_v[0] = userAccountControlStr;
+  ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
+
+  if (Exchange)
+    {
+      if (rc = moira_connect())
+       {
+         critical_alert(whoami, "AD incremental", 
+                        "Error contacting Moira server : %s",
+                        error_message(rc));
+         return;
+       }
+      argv[0] = user_name;
+
+      if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
+       {
+         if(!strcmp(save_argv[1], "EXCHANGE") || 
+            (strstr(save_argv[3], search_string) != NULL))
+           {
+             alt_recipient_v[0] = NULL;
+             ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
+
+             argv[0] = exchange_acl;
+             argv[1] = "USER";
+             argv[2] = user_name;
+             
+             rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
+             
+             if ((rc) && (rc != MR_EXISTS))
+               {
+                 com_err(whoami, 0, "Unable to add user %s to %s: %s",
+                         user_name, exchange_acl, error_message(rc));
+               }
+           }
+         else 
+           {
+             alt_recipient_v[0] = alt_recipient;
+             ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
+             
+             argv[0] = exchange_acl;
+             argv[1] = "USER";
+             argv[2] = user_name;
+             
+             rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
+             
+             if ((rc) && (rc != MR_NO_MATCH))
+               {  
+                 com_err(whoami, 0,
+                         "Unable to remove user %s from %s: %s, %d",
+                         user_name, exchange_acl, error_message(rc), rc);
+               }  
+           }
+       }
+      else
+       {
+         alt_recipient_v[0] = alt_recipient;
+         ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
+         
+         argv[0] = exchange_acl;
+         argv[1] = "USER";
+         argv[2] = user_name;
+         
+         rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
+         
+         if ((rc) && (rc != MR_NO_MATCH))
+           {  
+             com_err(whoami, 0,
+                     "Unable to remove user %s from %s: %s, %d",
+                     user_name, exchange_acl, error_message(rc), rc);
+           }  
+       }
+      
+      moira_disconnect();
+    }
+  else
+    {
+      mail_v[0] = contact_mail;
+      ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
+    }
+
+  n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
+                       WinProfileDir, homedir_v, winProfile_v,
+                       drives_v, mods, LDAP_MOD_REPLACE, n);
+
+  sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
+  sprintf(search_path, "%s,%s", security_template_ou, dn_path);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+  group_count = 0;
+  group_base = NULL;
+
+  if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array,
+                          &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE) != 0))
+    return(1);
+
+  if (group_count != 1)
+    {
+      com_err(whoami, 0, "Unable to process user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+
+  strcpy(TemplateDn, group_base->dn);
+  strcpy(TemplateSamName, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+
+  rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
+                        filter_exp, NULL, 0, apsServerControls, NULL,
+                        NULL, 0, &psMsg);
+
+  if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
+    {
+      com_err(whoami, 0, "Unable to find user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+
+  ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
+
+  if (ppsValues == NULL)
+    {
+      com_err(whoami, 0, "Unable to find user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+  
+  ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
+          LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+  
+  mods[n] = NULL;
+
+  if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
+                         mods)) != LDAP_SUCCESS)
+    {
+      OldUseSFU30 = UseSFU30;
+      SwitchSFU(mods, &UseSFU30, n);
+      if (OldUseSFU30 != UseSFU30)
+       rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
+      if (rc)
         {
-          free(hp[i]);
-          i++;
+         com_err(whoami, 0, "Unable to modify user data for %s : %s",
+                 user_name, ldap_err2string(rc));
         }
     }
+  
+  for (i = 0; i < n; i++)
+    free(mods[i]);
 
   return(rc);
 }
 
 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
-                char *user_name, char *Uid, char *MitId, int State)
+                char *user_name)
 {
   LDAPMod *mods[20];
   char new_dn[256];
   char old_dn[256];
   char upn[256];
-  char temp[128];
+  char mail[256];
+  char contact_mail[256];
+  char proxy_address[256];
+  char query_base_dn[256];
+  char temp[256];
   char *userPrincipalName_v[] = {NULL, NULL};
   char *altSecurityIdentities_v[] = {NULL, NULL};
   char *name_v[] = {NULL, NULL};
   char *samAccountName_v[] = {NULL, NULL};
-  char *uid_v[] = {NULL, NULL};
-  char *mitid_v[] = {NULL, NULL};
+  char *mail_v[] = {NULL, NULL};
+  char *mail_nickname_v[] = {NULL, NULL};
+  char *proxy_address_v[] = {NULL, NULL};
+  char *query_base_dn_v[] = {NULL, NULL};
   int  n;
   int  rc;
   int  i;
 
-  if ((State != US_REGISTERED) && (State != US_NO_PASSWD) && (State != US_ENROLL_NOT_ALLOWED))
-    return(-1);
-
   if (!check_string(before_user_name))
     {
-      com_err(whoami, 0, "invalid LDAP user name %s", before_user_name);
-      return(-1);
+      com_err(whoami, 0, 
+             "Unable to process invalid LDAP user name %s", before_user_name);
+      return(AD_INVALID_NAME);
     }
+
   if (!check_string(user_name))
     {
-      com_err(whoami, 0, "invalid LDAP user name %s", user_name);
-      return(-1);
+      com_err(whoami, 0, 
+             "Unable to process invalid LDAP user name %s", user_name);
+      return(AD_INVALID_NAME);
     }
 
   strcpy(user_name, user_name);
   sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
   sprintf(new_dn, "cn=%s", user_name);
+  sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
+  sprintf(contact_mail, "%s@mit.edu", user_name);
+  sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
+
   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
                            NULL, NULL)) != LDAP_SUCCESS)
     {
-      if (rc != LDAP_NO_SUCH_OBJECT)
-        com_err(whoami, 0, "Couldn't rename user from %s to %s : %s",
-                before_user_name, user_name, ldap_err2string(rc));
+      com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
+              before_user_name, user_name, ldap_err2string(rc));
       return(rc);
     }
 
+  if (Exchange)
+    {
+      sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
+             dn_path);
+
+      if(rc = ldap_delete_s(ldap_handle, temp))
+       {
+         com_err(whoami, 0, "Unable to delete user contact for %s",
+                 user_name);
+       }
+      
+      if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
+       {
+         com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
+       }
+    }
+
   name_v[0] = user_name;
   sprintf(upn, "%s@%s", user_name, ldap_domain);
   userPrincipalName_v[0] = upn;
   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
+  sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
   altSecurityIdentities_v[0] = temp;
   samAccountName_v[0] = user_name;
+  mail_v[0] = mail;
+  mail_nickname_v[0] = user_name;
+  proxy_address_v[0] = proxy_address; 
+  query_base_dn_v[0] = query_base_dn;
 
   n = 0;
   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
-  if (strlen(Uid) != 0)
-    {
-      uid_v[0] = Uid;
-      ADD_ATTR("uid", uid_v, LDAP_MOD_REPLACE);
-      ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
-    }
-  if (strlen(MitId) != 0)
-    {
-      mitid_v[0] = MitId;
-      ADD_ATTR("employeeID", mitid_v, LDAP_MOD_REPLACE);
-    }
-  mods[n] = NULL;
-  sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
-  if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
-    {
-      com_err(whoami, 0, "After renaming, couldn't modify user data for %s : %s",
-              user_name, ldap_err2string(rc));
-    }
-  for (i = 0; i < n; i++)
-    free(mods[i]);
-  return(rc);
-}
-
-int filesys_process(LDAP *ldap_handle, char *dn_path, char *fs_name, 
-                    char *fs_type, char *fs_pack, int operation)
-{
-  char  distinguished_name[256];
-  char  winPath[256];
-  char  winProfile[256];
-  char  filter_exp[256];
-  char  *attr_array[3];
-  char  *homedir_v[] = {NULL, NULL};
-  char  *winProfile_v[] = {NULL, NULL};
-  char  *drives_v[] = {NULL, NULL};
-  int   group_count;
-  int   n;
-  int   rc;
-  int   i;
-  LDAPMod   *mods[20];
-  LK_ENTRY  *group_base;
-
-  if (!check_string(fs_name))
-    {
-      com_err(whoami, 0, "invalid filesys name %s", fs_name);
-      return(-1);
-    }
-
-  if (strcmp(fs_type, "AFS"))
-    {
-      com_err(whoami, 0, "invalid filesys type %s", fs_type);
-      return(-1);
-    }
-
-  group_count = 0;
-  group_base = NULL;
-  sprintf(filter_exp, "(sAMAccountName=%s)", fs_name);
-  attr_array[0] = "cn";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
-    {
-      com_err(whoami, 0, "LDAP server couldn't process filesys %s : %s",
-              fs_name, ldap_err2string(rc));
-      return(rc);
-    }
-
-  if (group_count != 1)
-    {
-      linklist_free(group_base);
-      com_err(whoami, 0, "LDAP server unable to find user %s in AD",
-              fs_name);
-      return(LDAP_NO_SUCH_OBJECT);
-    }
-  strcpy(distinguished_name, group_base->dn);
-  linklist_free(group_base);
-  group_count = 0;
 
-  n = 0;
-  if (operation == LDAP_MOD_ADD)
+  if (Exchange)
     {
-      memset(winPath, 0, sizeof(winPath));
-      AfsToWinAfs(fs_pack, winPath);
-      homedir_v[0] = winPath;
-      drives_v[0] = "H:";
-      memset(winProfile, 0, sizeof(winProfile));
-      strcpy(winProfile, winPath);
-      strcat(winProfile, "\\.winprofile");
-      winProfile_v[0] = winProfile;
+      ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
+      ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
+      ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
+      ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
     }
   else
     {
-      homedir_v[0] = NULL;
-      drives_v[0] = NULL;
-      winProfile_v[0] = NULL;
+      mail_v[0] = contact_mail;
+      ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
     }
-  ADD_ATTR("profilePath", winProfile_v, operation);
-  ADD_ATTR("homeDrive", drives_v, operation);
-  ADD_ATTR("homeDirectory", homedir_v, operation);
+
   mods[n] = NULL;
+  
+  sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
 
-  rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
-  if (rc != LDAP_SUCCESS)
+  if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "Couldn't modify user data for filesys %s : %s",
-              fs_name, ldap_err2string(rc));
+      com_err(whoami, 0, 
+             "Unable to modify user data for %s after renaming : %s",
+              user_name, ldap_err2string(rc));
     }
+  
   for (i = 0; i < n; i++)
     free(mods[i]);
 
@@ -2315,12 +4329,19 @@ int filesys_process(LDAP *ldap_handle, char *dn_path, char *fs_name,
 
 int user_create(int ac, char **av, void *ptr)
 {
-  LK_ENTRY  *group_base;
   LDAPMod *mods[20];
   char new_dn[256];
   char user_name[256];
   char sam_name[256];
   char upn[256];
+  char mail[256];
+  char contact_mail[256];
+  char proxy_address[256];
+  char mail_nickname[256];
+  char query_base_dn[256];
+  char displayName[256];
+  char address_book[256];
+  char alt_recipient[256];
   char *cn_v[] = {NULL, NULL};
   char *objectClass_v[] = {"top", "person", 
                            "organizationalPerson", 
@@ -2328,59 +4349,168 @@ int user_create(int ac, char **av, void *ptr)
 
   char *samAccountName_v[] = {NULL, NULL};
   char *altSecurityIdentities_v[] = {NULL, NULL};
+  char *mitMoiraId_v[] = {NULL, NULL};
   char *name_v[] = {NULL, NULL};
   char *desc_v[] = {NULL, NULL};
   char *userPrincipalName_v[] = {NULL, NULL};
   char *userAccountControl_v[] = {NULL, NULL};
   char *uid_v[] = {NULL, NULL};
   char *mitid_v[] = {NULL, NULL};
+  char *homedir_v[] = {NULL, NULL};
+  char *winProfile_v[] = {NULL, NULL};
+  char *drives_v[] = {NULL, NULL};
+  char *mail_v[] = {NULL, NULL};
+  char *givenName_v[] = {NULL, NULL};
+  char *sn_v[] = {NULL, NULL};
+  char *initials_v[] = {NULL, NULL};
+  char *displayName_v[] = {NULL, NULL};
+  char *proxy_address_v[] = {NULL, NULL};
+  char *mail_nickname_v[] = {NULL, NULL};
+  char *query_base_dn_v[] = {NULL, NULL};
+  char *address_book_v[] = {NULL, NULL};
+  char *homeMDB_v[] = {NULL, NULL};
+  char *homeServerName_v[] = {NULL, NULL};
+  char *mdbUseDefaults_v[] = {NULL, NULL};
+  char *mailbox_guid_v[] = {NULL, NULL};
+  char *user_culture_v[] = {NULL, NULL};
+  char *user_account_control_v[] = {NULL, NULL};
+  char *msexch_version_v[] = {NULL, NULL};
+  char *alt_recipient_v[] = {NULL, NULL};
+  char *hide_address_lists_v[] = {NULL, NULL};
   char userAccountControlStr[80];
   char temp[128];
-  u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | UF_PASSWD_CANT_CHANGE;
+  char filter_exp[1024];
+  char search_path[512];
+  char *attr_array[3];
+  u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
+    UF_PASSWD_CANT_CHANGE; 
   int  n;
   int  rc;
   int  i;
-  int  group_count;
-  char filter_exp[256];
-  char *attr_array[3];
+  int  OldUseSFU30;
   char **call_args;
+  char WinHomeDir[1024];
+  char WinProfileDir[1024];
+  char *homeMDB;
+  char *homeServerName;
+  ULONG dwInfo;
+  char acBERBuf[N_SD_BER_BYTES];
+  LK_ENTRY  *group_base;
+  int    group_count;
+  char TemplateDn[512];
+  char TemplateSamName[128];
+  LDAP_BERVAL **ppsValues;
+  LDAPControl sControl = {"1.2.840.113556.1.4.801",
+                          { N_SD_BER_BYTES, acBERBuf },
+                          TRUE};
+  LDAPControl *apsServerControls[] = {&sControl, NULL};
+  LDAPMessage *psMsg;
+  char *argv[3];
+  char *save_argv[7];
+  char search_string[256];
 
   call_args = ptr;
 
-  if ((atoi(av[U_STATE]) != US_REGISTERED) && (atoi(av[U_STATE]) != US_NO_PASSWD) && 
-      (atoi(av[U_STATE]) != US_ENROLL_NOT_ALLOWED))
-    {
-      callback_rc = -1;
-      return(-1);
-    }
-  if (!strncmp(av[U_NAME], "#", 1))
-    {
-      callback_rc = -1;
-      return(-1);
-    }
+  dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+    DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+  BEREncodeSecurityBits(dwInfo, acBERBuf);
+
   if (!check_string(av[U_NAME]))
     {
-      callback_rc = -1;
-      com_err(whoami, 0, "invalid LDAP user name %s", av[U_NAME]);
-      return(-1);
+      callback_rc = AD_INVALID_NAME;
+      com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
+             av[U_NAME]);
+      return(AD_INVALID_NAME);
     }
 
+  memset(WinHomeDir, '\0', sizeof(WinHomeDir));
+  memset(WinProfileDir, '\0', sizeof(WinProfileDir));
+  memset(displayName, '\0', sizeof(displayName));
+  memset(query_base_dn, '\0', sizeof(query_base_dn));
+  strcpy(WinHomeDir, av[U_WINHOMEDIR]);
+  strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
   strcpy(user_name, av[U_NAME]);
   sprintf(upn, "%s@%s", user_name, ldap_domain);
   sprintf(sam_name, "%s", av[U_NAME]);
+
+  if(strlen(av[U_FIRST])) {
+    strcat(displayName, av[U_FIRST]);
+  }
+
+  if(strlen(av[U_MIDDLE])) {
+    if(strlen(av[U_FIRST]))
+       strcat(displayName, " "); 
+
+    strcat(displayName, av[U_MIDDLE]);
+  }
+
+  if(strlen(av[U_LAST])) {
+    if(strlen(av[U_FIRST]) || strlen(av[U_LAST]))
+      strcat(displayName, " ");
+
+    strcat(displayName, av[U_LAST]);
+  }
+
   samAccountName_v[0] = sam_name;
-  if (atoi(av[U_STATE]) == US_DELETED)
-    userAccountControl |= UF_ACCOUNTDISABLE;
+  if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
+      (atoi(av[U_STATE]) != US_REGISTERED))
+    {
+      userAccountControl |= UF_ACCOUNTDISABLE;
+
+      if (Exchange)
+       {
+         hide_address_lists_v[0] = "TRUE";
+         ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
+                  LDAP_MOD_ADD);
+       }
+    }
+
   sprintf(userAccountControlStr, "%ld", userAccountControl);
   userAccountControl_v[0] = userAccountControlStr;
   userPrincipalName_v[0] = upn;
-
   cn_v[0] = user_name;
   name_v[0] = user_name;
   desc_v[0] = "Auto account created by Moira";
+  mail_v[0] = mail;
+  givenName_v[0] = av[U_FIRST];
+  sn_v[0] = av[U_LAST];
+  displayName_v[0] = displayName;
+  mail_nickname_v[0] = user_name;
+  
   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
   altSecurityIdentities_v[0] = temp;    
   sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
+  sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
+  sprintf(contact_mail, "%s@mit.edu", user_name);
+  sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
+  query_base_dn_v[0] = query_base_dn;
+  sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
+         call_args[1]);
+  sprintf(search_string, "@%s", uppercase(ldap_domain));
+
+
+  if (Exchange)
+    {
+      if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
+                       contact_ou))
+       {
+         com_err(whoami, 0, "Unable to create user contact %s", 
+                 contact_mail);
+       }
+      
+      if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
+                     &homeServerName)) 
+       {
+         com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
+         return(1);
+       }
+      
+      com_err(whoami, 0, "homeMDB:%s", homeMDB);
+      com_err(whoami, 0, "homeServerName:%s", homeServerName);
+  
+      homeMDB_v[0] = homeMDB;
+      homeServerName_v[0] = homeServerName; 
+    }
 
   n = 0;
   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
@@ -2389,82 +4519,215 @@ int user_create(int ac, char **av, void *ptr)
   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
-  ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
-  ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
+
+  if (Exchange)
+    {
+      ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
+      ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
+      ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
+      mdbUseDefaults_v[0] = "TRUE";
+      ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
+      ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
+      
+      argv[0] = user_name;
+    
+      if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
+       {
+         if(!strcmp(save_argv[1], "EXCHANGE") || 
+            (strstr(save_argv[3], search_string) != NULL))
+           {
+             argv[0] = exchange_acl;
+             argv[1] = "USER";
+             argv[2] = user_name;
+             
+             rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
+             
+             if ((rc) && (rc != MR_EXISTS))
+               {
+                 com_err(whoami, 0, "Unable to add user %s to %s: %s",
+                         user_name, exchange_acl, error_message(rc));
+               }
+           } 
+         else 
+           {
+             alt_recipient_v[0] = alt_recipient;
+             ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
+           }
+       }
+      else
+       {
+         alt_recipient_v[0] = alt_recipient;
+         ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
+         
+         com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
+       }
+    }
+  else
+    {
+      mail_v[0] = contact_mail;
+      ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
+    }
+
+  if(strlen(av[U_FIRST])) {
+    ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
+  }
+
+  if(strlen(av[U_LAST])) {
+    ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
+  }
+
+  if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
+    ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
+  } else {
+    ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
+  }
+
+  if (strlen(av[U_MIDDLE]) == 1) {
+    initials_v[0] = av[U_MIDDLE];
+    ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
+  }
+
+  if (strlen(call_args[2]) != 0)    
+    {
+      mitMoiraId_v[0] = call_args[2];
+      ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
+    }
+  
+  ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD); 
+
   if (strlen(av[U_UID]) != 0)
     {
       uid_v[0] = av[U_UID];
       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
-      ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
+
+      if (!UseSFU30)
+        {
+          ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
+        }
+      else
+        {
+          ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
+        }
     }
-  if (strlen(av[U_MITID]) != 0)
+
+  if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
       mitid_v[0] = av[U_MITID];
   else
       mitid_v[0] = "none";
+
   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
+
+  n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, WinHomeDir, 
+                       WinProfileDir, homedir_v, winProfile_v,
+                       drives_v, mods, LDAP_MOD_ADD, n);
+
+  sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
+  sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+  group_count = 0;
+  group_base = NULL;
+
+  if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
+                          attr_array, &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE) != 0))
+    return(1);
+
+  if (group_count != 1)
+    {
+      com_err(whoami, 0, "Unable to process user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+
+  strcpy(TemplateDn, group_base->dn);
+  strcpy(TemplateSamName, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+
+  rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, LDAP_SCOPE_SUBTREE,
+                        filter_exp, NULL, 0, apsServerControls, NULL,
+                        NULL, 0, &psMsg);
+
+  if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
+    {
+      com_err(whoami, 0, "Unable to find user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+
+  ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
+                                 "ntSecurityDescriptor");
+  if (ppsValues == NULL)
+    {
+      com_err(whoami, 0, "Unable to find user security template: %s - "
+             "security not set", "UserTemplate.u");
+      return(1);
+    }
+  
+  ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
+     LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
+
   mods[n] = NULL;
 
   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
+
+  if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
+    {
+      OldUseSFU30 = UseSFU30;
+      SwitchSFU(mods, &UseSFU30, n);
+      if (OldUseSFU30 != UseSFU30)
+       rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
+    }
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
     {
-      com_err(whoami, 0, "could not create user %s : %s",
+      com_err(whoami, 0, "Unable to create user %s : %s",
               user_name, ldap_err2string(rc));
       callback_rc = rc;
       return(rc);
     }
-  if (rc == LDAP_ALREADY_EXISTS)
-    {
-      UserReactivate = 1;
-      rc = user_change_status((LDAP *)call_args[0], call_args[1], av[U_NAME], MEMBER_ACTIVATE);
-      return(0);
-    }
-  if (rc == LDAP_SUCCESS)
+
+  if ((rc == LDAP_SUCCESS) && (SetPassword))
     {
       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
         {
-          com_err(whoami, 0, "Couldn't set password for user %s : %ld",
-                  user_name, rc);
-        }
-    }
-  sprintf(filter_exp, "(sAMAccountName=%s)", av[U_NAME]);
-  attr_array[0] = "objectSid";
-  attr_array[1] = NULL;
-  group_count = 0;
-  group_base = NULL;
-  if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], filter_exp, attr_array, 
-                           &group_base, &group_count)) == LDAP_SUCCESS)
-    {
-      if (group_count == 1)
-        {
-          (*sid_ptr) = group_base;
-          (*sid_ptr)->member = strdup(av[L_NAME]);
-          (*sid_ptr)->type = (char *)GROUPS;
-          sid_ptr = &(*sid_ptr)->next;
-        }
-      else
-        {
-          if (group_base != NULL)
-            linklist_free(group_base);
+          ad_kdc_disconnect();
+          if (!ad_server_connect(default_server, ldap_domain))
+            {
+              com_err(whoami, 0, "Unable to set password for user %s : %s",
+                      user_name, 
+                     "cannot get changepw ticket from windows domain");
+            }
+          else
+            {
+              if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
+                {
+                  com_err(whoami, 0, "Unable to set password for user %s "
+                         ": %ld", user_name, rc);
+                }
+            }
         }
     }
-  else
-    {
-      if (group_base != NULL)
-        linklist_free(group_base);
-    }
+
   return(0);
 }
 
-int user_change_status(LDAP *ldap_handle, char *dn_path, char *user_name, int operation)
+int user_change_status(LDAP *ldap_handle, char *dn_path, 
+                       char *user_name, char *MoiraId,
+                       int operation)
 {
-  char      filter_exp[1024];
+  char      filter[128];
   char      *attr_array[3];
   char      temp[256];
   char      distinguished_name[1024];
   char      **modvalues;
+  char      *mitMoiraId_v[] = {NULL, NULL};
   LDAPMod   *mods[20];
   LK_ENTRY  *group_base;
   int       group_count;
@@ -2475,102 +4738,182 @@ int user_change_status(LDAP *ldap_handle, char *dn_path, char *user_name, int op
 
   if (!check_string(user_name))
     {
-      com_err(whoami, 0, "invalid LDAP user name %s", user_name);
-      return(-1);
+      com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
+             user_name);
+      return(AD_INVALID_NAME);
     }
 
   group_count = 0;
   group_base = NULL;
-  sprintf(filter_exp, "(sAMAccountName=%s)", user_name);
-  attr_array[0] = "UserAccountControl";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
+
+  if (strlen(MoiraId) != 0)
     {
-      com_err(whoami, 0, "LDAP server couldn't process user %s : %s",
-              user_name, ldap_err2string(rc));
-      return(rc);
+      sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
+      attr_array[0] = "UserAccountControl";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          return(rc);
+        }
     }
 
   if (group_count != 1)
     {
       linklist_free(group_base);
-      com_err(whoami, 0, "LDAP server unable to find user %s in AD",
+      group_count = 0;
+      group_base = NULL;
+      sprintf(filter, "(sAMAccountName=%s)", user_name);
+      attr_array[0] = "UserAccountControl";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          return(rc);
+        }
+    }
+  
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      com_err(whoami, 0, "Unable to find user %s in AD",
               user_name);
       return(LDAP_NO_SUCH_OBJECT);
     }
 
   strcpy(distinguished_name, group_base->dn);
   ulongValue = atoi((*group_base).value);
+
   if (operation == MEMBER_DEACTIVATE)
     ulongValue |= UF_ACCOUNTDISABLE;
   else    
     ulongValue &= ~UF_ACCOUNTDISABLE;
+
   sprintf(temp, "%ld", ulongValue);
+
   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
                                 temp, &modvalues, REPLACE)) == 1)
     goto cleanup;
+
   linklist_free(group_base);
   group_base = NULL;
   group_count = 0;
   n = 0;
   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
+
+  if (strlen(MoiraId) != 0)
+    {
+    mitMoiraId_v[0] = MoiraId;
+    ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
+    }
+
   mods[n] = NULL;
   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
+
   for (i = 0; i < n; i++)
     free(mods[i]);
+
   free_values(modvalues);
+
   if (rc != LDAP_SUCCESS)
     {
-      com_err(whoami, 0, "LDAP server could not change status of user %s : %s",
+      com_err(whoami, 0, "Unable to change status of user %s : %s",
               user_name, ldap_err2string(rc));
     }
-cleanup:
+  
+ cleanup:
   return(rc);
 }
 
-int user_delete(LDAP *ldap_handle, char *dn_path, char *u_name)
+int user_delete(LDAP *ldap_handle, char *dn_path, 
+                char *u_name, char *MoiraId)
 {
-  char      filter_exp[1024];
+  char      filter[128];
   char      *attr_array[3];
   char      distinguished_name[1024];
   char      user_name[512];
   LK_ENTRY  *group_base;
   int       group_count;
   int       rc;
+  char      temp[256];
 
   if (!check_string(u_name))
-    return(0);
+    return(AD_INVALID_NAME);
+
   strcpy(user_name, u_name);
   group_count = 0;
   group_base = NULL;
-  sprintf(filter_exp, "(sAMAccountName=%s)", user_name);
-  attr_array[0] = "name";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                           &group_base, &group_count)) != 0)
+
+  if (strlen(MoiraId) != 0)
     {
-      com_err(whoami, 0, "LDAP server couldn't process user %s : %s",
-              user_name, ldap_err2string(rc));
-      goto cleanup;
+      sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
+      attr_array[0] = "name";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          goto cleanup;
+        }
+    }
+  
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      group_count = 0;
+      group_base = NULL;
+      sprintf(filter, "(sAMAccountName=%s)", user_name);
+      attr_array[0] = "name";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  user_name, ldap_err2string(rc));
+          goto cleanup;
+        }
     }
 
   if (group_count != 1)
     {
-      com_err(whoami, 0, "LDAP server unable to find user %s in AD",
+      com_err(whoami, 0, "Unable to find user %s in AD",
               user_name);
       goto cleanup;
     }
-
+  
   strcpy(distinguished_name, group_base->dn);
+
   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
     {
-      com_err(whoami, 0, "LDAP server couldn't process user %s : %s",
+      com_err(whoami, 0, "Unable to process user %s : %s",
               user_name, ldap_err2string(rc));
     }
 
-cleanup:
+  /* Need to add code to delete mit.edu contact */
+  
+  if (Exchange)
+    {
+      sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
+
+      if(rc = ldap_delete_s(ldap_handle, temp))
+       {
+         com_err(whoami, 0, "Unable to delete user contact for %s",
+                 user_name);
+       }
+    }
+
+ cleanup:
   linklist_free(group_base);
+
   return(0);
 }
 
@@ -2582,16 +4925,22 @@ void linklist_free(LK_ENTRY *linklist_base)
     {
       if (linklist_base->dn != NULL)
         free(linklist_base->dn);
+
       if (linklist_base->attribute != NULL)
         free(linklist_base->attribute);
+
       if (linklist_base->value != NULL)
         free(linklist_base->value);
+
       if (linklist_base->member != NULL)
         free(linklist_base->member);
+
       if (linklist_base->type != NULL)
         free(linklist_base->type);
+
       if (linklist_base->list != NULL)
         free(linklist_base->list);
+
       linklist_previous = linklist_base;
       linklist_base = linklist_previous->next;
       free(linklist_previous);
@@ -2603,6 +4952,7 @@ void free_values(char **modvalues)
   int i;
 
   i = 0;
+
   if (modvalues != NULL)
     {
     while (modvalues[i] != NULL)
@@ -2615,64 +4965,6 @@ void free_values(char **modvalues)
   }
 }
 
-int sid_update(LDAP *ldap_handle, char *dn_path)
-{
-  LK_ENTRY      *ptr;
-  int           rc;
-  unsigned char temp[126];
-  char          *av[3];
-
-  ptr = sid_base;
-
-  while (ptr != NULL)
-    {
-      memset(temp, 0, sizeof(temp));
-      convert_b_to_a(temp, ptr->value, ptr->length);
-      if (!ptr->member)
-        continue;
-      av[0] = ptr->member;
-      av[1] = temp;
-      if (ptr->type == (char *)GROUPS)
-        {
-          ptr->type = NULL;
-          rc = mr_query("add_list_sid_by_name", 2, av, NULL, NULL);
-        }
-      else if (ptr->type == (char *)USERS)
-        {
-          ptr->type = NULL;
-          rc = mr_query("add_user_sid_by_login", 2, av, NULL, NULL);
-        }
-      ptr = ptr->next;
-    }
-  return(0);
-}
-
-void convert_b_to_a(char *string, UCHAR *binary, int length)
-{
-  int   i;
-  int   j;
-  UCHAR tmp;
-
-  j = 0;
-  for (i = 0; i < length; i++)
-    {
-      tmp = binary[i];
-      string[j] = tmp;
-      string[j] >>= 4;
-      string[j] &= 0x0f;
-      string[j] += 0x30;
-      if (string[j] > '9')
-        string[j] += 0x27;
-      ++j;
-      string[j] = tmp & 0x0f;
-      string[j] += 0x30;
-      if (string[j] > '9')
-        string[j] += 0x27;
-      j++;
-    }
-  string[j] = 0;
-}
-
 static int illegalchars[] = {
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
@@ -2699,12 +4991,36 @@ int check_string(char *s)
   for (; *s; s++)
     {
       character = *s;
+
+      if (isupper(character))
+        character = tolower(character);
+
+      if (illegalchars[(unsigned) character])
+        return 0;
+    }
+
+  return(1);
+}
+
+int check_container_name(char *s)
+{
+  char  character;
+
+  for (; *s; s++)
+    {
+      character = *s;
+
       if (isupper(character))
         character = tolower(character);
+
+      if (character == ' ')
+       continue;
+
       if (illegalchars[(unsigned) character])
         return 0;
     }
-  return 1;
+
+  return(1);
 }
 
 int mr_connect_cl(char *server, char *client, int version, int auth)
@@ -2714,6 +5030,7 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
   char  temp[128];
 
   status = mr_connect(server);
+
   if (status)
     {
       com_err(whoami, status, "while connecting to Moira");
@@ -2721,12 +5038,14 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
     }
 
   status = mr_motd(&motd);
+
   if (status)
     {
       mr_disconnect();
       com_err(whoami, status, "while checking server status");
       return status;
     }
+
   if (motd)
     {
       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
@@ -2736,6 +5055,7 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
     }
 
   status = mr_version(version);
+
   if (status)
     {
       if (status == MR_UNKNOWN_PROC)
@@ -2748,7 +5068,8 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
 
       if (status == MR_VERSION_HIGH)
         {
-          com_err(whoami, 0, "Warning: This client is running newer code than the server.");
+          com_err(whoami, 0, "Warning: This client is running newer code "
+                 "than the server.");
                   com_err(whoami, 0, "Some operations may not work.");
         }
       else if (status && status != MR_VERSION_LOW)
@@ -2761,7 +5082,7 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
 
   if (auth)
     {
-      status = mr_auth(client);
+      status = mr_krb5_auth(client);
       if (status)
         {
           com_err(whoami, status, "while authenticating to Moira.");
@@ -2769,26 +5090,2911 @@ int mr_connect_cl(char *server, char *client, int version, int auth)
           return status;
         }
     }
-
+  
   return MR_SUCCESS;
 }
 
 void AfsToWinAfs(char* path, char* winPath)
 {
-    char* pathPtr;
-    char* winPathPtr;
-    strcpy(winPath, WINAFS);
-    pathPtr = path + strlen(AFS);
-    winPathPtr = winPath + strlen(WINAFS);
+  char* pathPtr;
+  char* winPathPtr;
+  strcpy(winPath, WINAFS);
+  pathPtr = path + strlen(AFS);
+  winPathPtr = winPath + strlen(WINAFS);
+  
+  while (*pathPtr)
+    {
+      if (*pathPtr == '/')
+       *winPathPtr = '\\';
+      else
+       *winPathPtr = *pathPtr;
+      
+      pathPtr++;
+      winPathPtr++;
+    }
+}
+
+int GetAceInfo(int ac, char **av, void *ptr)
+{
+  char **call_args;
+  int   security_flag;
+
+  call_args = ptr;
+  
+  strcpy(call_args[0], av[L_ACE_TYPE]);
+  strcpy(call_args[1], av[L_ACE_NAME]);
+  security_flag = 0;
+  get_group_membership(call_args[2], call_args[3], &security_flag, av);
+  return(LDAP_SUCCESS);  
+}
+
+int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
+{
+  char filter[128];
+  char *attr_array[3];
+  int  group_count;
+  int  rc;
+  LK_ENTRY  *group_base;
+  
+  group_count = 0;
+  group_base = NULL;
+  
+  sprintf(filter, "(sAMAccountName=%s)", Name);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to process ACE name %s : %s",
+              Name, ldap_err2string(rc));
+      return(1);
+    }
+
+  linklist_free(group_base);
+  group_base = NULL;
+
+  if (group_count == 0)
+    return(0);
+  
+  return(1);
+}
+
+#define MAX_ACE 7
+
+int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
+              int UpdateGroup, int *ProcessGroup, char *maillist)
+{
+  char  *av[2];
+  char  GroupName[256];
+  char  *call_args[7];
+  int   rc;
+  char  *AceInfo[4];
+  char  AceType[32];
+  char  AceName[128];
+  char  AceMembership[2];
+  char  AceOu[256];
+  char  temp[128];
+  char  *save_argv[U_END];
 
-    while (*pathPtr)
+  if (!SetGroupAce)
     {
-        if (*pathPtr == '/')
-          *winPathPtr = '\\';
-        else
-          *winPathPtr = *pathPtr;
+      com_err(whoami, 0, "ProcessAce disabled, skipping");
+      return(0);
+    }
+
+  strcpy(GroupName, Name);
+  
+  if (strcasecmp(Type, "LIST"))
+    return(1);
+
+  while (1)
+    {
+      av[0] = GroupName;
+      AceInfo[0] = AceType;
+      AceInfo[1] = AceName;
+      AceInfo[2] = AceMembership;
+      AceInfo[3] = AceOu;
+      memset(AceType, '\0', sizeof(AceType));
+      memset(AceName, '\0', sizeof(AceName));
+      memset(AceMembership, '\0', sizeof(AceMembership));
+      memset(AceOu, '\0', sizeof(AceOu));
+      callback_rc = 0;
+    
+      if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
+        { 
+          com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
+                 GroupName, error_message(rc));
+          return(1);
+        }
+
+      if (callback_rc)
+        {
+          com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
+          return(1);
+        }
+
+      if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
+        return(0);
+
+      strcpy(temp, AceName);
+
+      if (!strcasecmp(AceType, "LIST"))
+        sprintf(temp, "%s%s", AceName, group_suffix);
+
+      if (!UpdateGroup)
+        {
+          if (checkADname(ldap_handle, dn_path, temp))
+            return(0);
+          (*ProcessGroup) = 1;
+        }
+
+      if (!strcasecmp(AceInfo[0], "LIST"))
+        {
+          if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
+                            AceMembership, 0, UpdateGroup, maillist))
+            return(1);
+        }
+      else if (!strcasecmp(AceInfo[0], "USER"))
+        {
+          av[0] = AceName;
+          call_args[0] = (char *)ldap_handle;
+          call_args[1] = dn_path;
+          call_args[2] = "";
+          call_args[3] = NULL;
+          callback_rc = 0;
+
+          if (rc = mr_query("get_user_account_by_login", 1, av, 
+                           save_query_info, save_argv))
+            {
+              com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
+                     AceName, Name);
+              return(1);
+            }
+
+         if (rc = user_create(U_END, save_argv, call_args)) 
+           {
+              com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
+                     AceName, Name);
+              return(1);
+           }
+         
+          if (callback_rc)
+            {
+              com_err(whoami, 0, "Unable to process user Ace %s for group %s",
+                     AceName, Name);
+              return(1);
+            }
+
+          return(0);
+        }
+      else
+        return(1);
+
+      if (!strcasecmp(AceType, "LIST"))
+        {
+          if (!strcasecmp(GroupName, AceName))
+            return(0);
+        }
+
+      strcpy(GroupName, AceName);
+    }
+  
+  return(1);
+}
+
+int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
+                   char *group_name, char *group_ou, char *group_membership, 
+                   int group_security_flag, int updateGroup, char *maillist)
+{
+  char  *av[3];
+  char  *call_args[8];
+  int   rc;
+  LK_ENTRY  *group_base;
+  int  group_count;
+  char filter[128];
+  char *attr_array[3];
+
+  av[0] = group_name;
+  call_args[0] = (char *)ldap_handle;
+  call_args[1] = dn_path;
+  call_args[2] = group_name;
+  call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
+  call_args[4] = (char *)updateGroup;
+  call_args[5] = MoiraId;
+  call_args[6] = "0";
+  call_args[7] = NULL;
+  callback_rc = 0;
+
+  group_count = 0;
+  group_base = NULL;
+
+  if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
+    {
+      moira_disconnect();
+      com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
+             error_message(rc));
+      return(rc);
+    }
+
+  if (callback_rc)
+    {
+      moira_disconnect();
+      com_err(whoami, 0, "Unable to create list %s", group_name);
+      return(callback_rc);
+    }
+
+  return(0);
+}
 
-        pathPtr++;
-        winPathPtr++;
+int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
+                   char *group_ou, char *group_membership, 
+                   int group_security_flag, char *MoiraId)
+{
+  char      *av[3];
+  char      *call_args[7];
+  char      *pUserOu;
+  LK_ENTRY  *ptr;
+  int       rc;
+  char      member[256];
+  char      *s;
+
+  com_err(whoami, 0, "Populating group %s", group_name);
+  av[0] = group_name;
+  call_args[0] = (char *)ldap_handle;
+  call_args[1] = dn_path;
+  call_args[2] = group_name;
+  call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
+  call_args[4] = NULL;
+  member_base = NULL;
+
+  if (rc = mr_query("get_end_members_of_list", 1, av,
+                    member_list_build, call_args))
+    {
+      com_err(whoami, 0, "Unable to populate list %s : %s", 
+              group_name, error_message(rc));
+      return(3);
     }
+
+  if (member_base != NULL)
+    {
+      ptr = member_base;
+
+      while (ptr != NULL)
+        {
+          if (!strcasecmp(ptr->type, "LIST"))
+            {
+              ptr = ptr->next;
+              continue;
+            }
+
+          pUserOu = user_ou;
+
+          if (!strcasecmp(ptr->type, "STRING"))
+            {
+              if (contact_create(ldap_handle, dn_path, ptr->member, 
+                                contact_ou))
+                return(3);
+
+              pUserOu = contact_ou;
+            }
+          else if (!strcasecmp(ptr->type, "KERBEROS"))
+            {
+              if (contact_create(ldap_handle, dn_path, ptr->member, 
+                                kerberos_ou))
+                return(3);
+
+              pUserOu = kerberos_ou;
+            }
+
+          rc = member_add(ldap_handle, dn_path, group_name,
+                          group_ou, group_membership, ptr->member, 
+                          pUserOu, MoiraId);
+          ptr = ptr->next;
+        }
+
+      linklist_free(member_base);
+      member_base = NULL;
+    }
+
+  return(0);
+}
+
+int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
+                  char *group_name, char *group_ou, char *group_membership, 
+                  int group_security_flag, int type, char *maillist)
+{
+  char      before_desc[512];
+  char      before_name[256];
+  char      before_group_ou[256];
+  char      before_group_membership[2];
+  char      distinguishedName[256];
+  char      ad_distinguishedName[256];
+  char      filter[128];
+  char      *attr_array[3];
+  int       before_security_flag;
+  int       group_count;
+  int       rc;
+  LK_ENTRY  *group_base;
+  LK_ENTRY  *ptr;
+  char      ou_both[512];
+  char      ou_security[512];
+  char      ou_distribution[512];
+  char      ou_neither[512];
+
+  memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
+  sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
+
+  memset(filter, '\0', sizeof(filter));
+  group_base = NULL;
+  group_count = 0;
+
+  if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
+                        "*", MoiraId, 
+                        "distinguishedName", &group_base, 
+                        &group_count, filter))
+    return(rc);
+
+  if (type == CHECK_GROUPS)
+    {
+      if (group_count == 1)
+        {
+          if (!strcasecmp(group_base->value, distinguishedName))
+            {
+              linklist_free(group_base);
+              return(0);
+            }
+        }
+
+      linklist_free(group_base);
+
+      if (group_count == 0)
+        return(AD_NO_GROUPS_FOUND);
+
+      if (group_count == 1)
+        return(AD_WRONG_GROUP_DN_FOUND);
+
+      return(AD_MULTIPLE_GROUPS_FOUND);
+    }
+
+  if (group_count == 0)
+    {
+      return(AD_NO_GROUPS_FOUND);
+    }
+
+  if (group_count > 1)
+    {
+      ptr = group_base;
+
+      while (ptr != NULL)
+        {
+          if (!strcasecmp(distinguishedName, ptr->value))
+            break;
+
+          ptr = ptr->next;
+        }
+
+      if (ptr == NULL)
+        {
+          com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
+                 MoiraId);
+          ptr = group_base;
+
+          while (ptr != NULL)
+            {
+              com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
+              ptr = ptr->next;
+            }
+
+          linklist_free(group_base);
+          return(AD_MULTIPLE_GROUPS_FOUND);
+        }
+
+      ptr = group_base;
+
+      while (ptr != NULL)
+        {
+          if (strcasecmp(distinguishedName, ptr->value))
+            rc = ldap_delete_s(ldap_handle, ptr->value);
+
+          ptr = ptr->next;
+        }
+
+      linklist_free(group_base);
+      memset(filter, '\0', sizeof(filter));
+      group_base = NULL;
+      group_count = 0;
+
+      if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
+                            "*", MoiraId, 
+                            "distinguishedName", &group_base, 
+                            &group_count, filter))
+        return(rc);
+
+      if (group_count == 0)
+        return(AD_NO_GROUPS_FOUND);
+
+      if (group_count > 1)
+        return(AD_MULTIPLE_GROUPS_FOUND);
+    }
+  
+  strcpy(ad_distinguishedName, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
+               MoiraId, ldap_err2string(rc));
+      return(rc);
+    }
+
+  sprintf(filter, "(sAMAccountName=%s)", group_base->value);
+  
+  if (!strcasecmp(ad_distinguishedName, distinguishedName))
+    {
+      linklist_free(group_base);
+      group_base = NULL;
+      group_count = 0;
+      return(0);
+    }
+
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+  memset(ou_both, '\0', sizeof(ou_both));
+  memset(ou_security, '\0', sizeof(ou_security));
+  memset(ou_distribution, '\0', sizeof(ou_distribution));
+  memset(ou_neither, '\0', sizeof(ou_neither));
+  memset(before_name, '\0', sizeof(before_name));
+  memset(before_desc, '\0', sizeof(before_desc));
+  memset(before_group_membership, '\0', sizeof(before_group_membership));
+  attr_array[0] = "name";
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
+              MoiraId, ldap_err2string(rc));
+      return(rc);
+    }
+
+  strcpy(before_name, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+  attr_array[0] = "description";
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, 
+              "Unable to get list description with MoiraId = %s: %s",
+              MoiraId, ldap_err2string(rc));
+      return(rc);
+    }
+
+  if (group_count != 0)
+    {
+      strcpy(before_desc, group_base->value);
+      linklist_free(group_base);
+      group_base = NULL;
+      group_count = 0;
+    }
+
+  change_to_lower_case(ad_distinguishedName);  
+  strcpy(ou_both, group_ou_both);
+  change_to_lower_case(ou_both);
+  strcpy(ou_security, group_ou_security);
+  change_to_lower_case(ou_security);
+  strcpy(ou_distribution, group_ou_distribution);
+  change_to_lower_case(ou_distribution);
+  strcpy(ou_neither, group_ou_neither);
+  change_to_lower_case(ou_neither);
+
+  if (strstr(ad_distinguishedName, ou_both))
+    {
+      strcpy(before_group_ou, group_ou_both);
+      before_group_membership[0] = 'B';
+      before_security_flag = 1;
+    }
+  else if (strstr(ad_distinguishedName, ou_security))
+    {
+      strcpy(before_group_ou, group_ou_security);
+      before_group_membership[0] = 'S';
+      before_security_flag = 1;
+    }
+  else if (strstr(ad_distinguishedName, ou_distribution))
+    {
+      strcpy(before_group_ou, group_ou_distribution);
+      before_group_membership[0] = 'D';
+      before_security_flag = 0;
+    }
+  else if (strstr(ad_distinguishedName, ou_neither))
+    {
+      strcpy(before_group_ou, group_ou_neither);
+      before_group_membership[0] = 'N';
+      before_security_flag = 0;
+    }
+  else
+    return(AD_NO_OU_FOUND);
+
+  rc = group_rename(ldap_handle, dn_path, before_name, 
+                   before_group_membership, 
+                    before_group_ou, before_security_flag, before_desc,
+                    group_name, group_membership, group_ou, 
+                   group_security_flag,
+                    before_desc, MoiraId, filter, maillist);
+
+  return(rc);
+}
+
+void change_to_lower_case(char *ptr)
+{
+  int i;
+
+  for (i = 0; i < (int)strlen(ptr); i++)
+    {
+      ptr[i] = tolower(ptr[i]);
+    }
+}
+
+int ad_get_group(LDAP *ldap_handle, char *dn_path, 
+                 char *group_name, char *group_membership, 
+                 char *MoiraId, char *attribute,
+                 LK_ENTRY **linklist_base, int *linklist_count,
+                 char *rFilter)
+{
+  LK_ENTRY  *pPtr;
+  char  filter[128];
+  char  *attr_array[3];
+  int   rc;
+
+  (*linklist_base) = NULL;
+  (*linklist_count) = 0;
+
+  if (strlen(rFilter) != 0)
+    {
+      strcpy(filter, rFilter);
+      attr_array[0] = attribute;
+      attr_array[1] = NULL;
+      
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               linklist_base, linklist_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
+                  MoiraId, ldap_err2string(rc));
+         return(rc);
+       }
+
+    if ((*linklist_count) == 1)
+      {
+        strcpy(rFilter, filter);
+        return(0);
+      }
+    }
+
+  linklist_free((*linklist_base));
+  (*linklist_base) = NULL;
+  (*linklist_count) = 0;
+
+  if (strlen(MoiraId) != 0)
+    {
+      sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
+      attr_array[0] = attribute;
+      attr_array[1] = NULL;
+
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               linklist_base, linklist_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
+                  MoiraId, ldap_err2string(rc));
+         return(rc);
+       }
+    }
+
+  if ((*linklist_count) > 1)
+    {
+      com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
+      pPtr = (*linklist_base);
+
+      while (pPtr)
+        {
+          com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
+                 MoiraId);
+          pPtr = pPtr->next;
+        }
+
+      linklist_free((*linklist_base));
+      (*linklist_base) = NULL;
+      (*linklist_count) = 0;
+    }
+
+  if ((*linklist_count) == 1)
+    {
+      if (!memcmp(&(*linklist_base)->value[3], group_name, strlen(group_name)))
+        {
+          strcpy(rFilter, filter);
+          return(0);
+        }
+    }
+
+  linklist_free((*linklist_base));
+  (*linklist_base) = NULL;
+  (*linklist_count) = 0;
+  sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
+  attr_array[0] = attribute;
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           linklist_base, linklist_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
+              MoiraId, ldap_err2string(rc));
+      return(rc);
+    }
+
+  if ((*linklist_count) == 1)
+    {
+      strcpy(rFilter, filter);
+      return(0);
+    }
+
+  return(0);
+}
+
+int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
+{
+  char filter[128];
+  char *attr_array[3];
+  char SamAccountName[64];
+  int  group_count;
+  int  rc;
+  LK_ENTRY  *group_base;
+  LK_ENTRY  *gPtr;
+
+  group_count = 0;
+  group_base = NULL;
+
+  if (strlen(MoiraId) != 0)
+    {
+      sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
+      attr_array[0] = "sAMAccountName";
+      attr_array[1] = NULL;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  UserName, ldap_err2string(rc));
+          return(rc);
+        }
+
+      if (group_count > 1)
+        {
+          com_err(whoami, 0, "multiple users exist with MoiraId = %s",
+                  MoiraId);
+          gPtr = group_base;
+
+          while (gPtr)
+            {
+              com_err(whoami, 0, "user %s exist with MoiraId = %s",
+                      gPtr->value, MoiraId);
+              gPtr = gPtr->next;
+            }
+        }
+    }
+
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      group_count = 0;
+      group_base = NULL;
+      sprintf(filter, "(sAMAccountName=%s)", UserName);
+      attr_array[0] = "sAMAccountName";
+      attr_array[1] = NULL;
+
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) != 0)
+        {
+          com_err(whoami, 0, "Unable to process user %s : %s",
+                  UserName, ldap_err2string(rc));
+          return(rc);
+        }
+    }
+
+  if (group_count != 1)
+    {
+      linklist_free(group_base);
+      return(AD_NO_USER_FOUND);
+    }
+
+  strcpy(SamAccountName, group_base->value);
+  linklist_free(group_base);
+  group_count = 0;
+  rc = 0;
+
+  if (strcmp(SamAccountName, UserName))
+    {
+      rc = user_rename(ldap_handle, dn_path, SamAccountName, 
+                       UserName);
+    }
+
+  return(0);
+}
+
+void container_get_dn(char *src, char *dest)
+{
+  char *sPtr;
+  char *array[20];
+  char name[256];
+  int  n;
+
+  memset(array, '\0', 20 * sizeof(array[0]));
+
+  if (strlen(src) == 0)
+    return;
+
+  strcpy(name, src);
+  sPtr = name;
+  n = 0;
+  array[n] = name;
+  ++n;
+
+  while (*sPtr)
+    {
+      if ((*sPtr) == '/')
+        {
+          (*sPtr) = '\0';
+          ++sPtr;
+          array[n] = sPtr;
+          ++n;
+        }
+      else
+        ++sPtr;
+    }
+
+  strcpy(dest, "OU=");
+
+  while (n != 0)
+    {
+      strcat(dest, array[n-1]);
+      --n;
+      if (n > 0)
+        {
+          strcat(dest, ",OU=");
+        }
+    }
+
+  return;
+}
+
+void container_get_name(char *src, char *dest)
+{
+  char *sPtr;
+  char *dPtr;
+
+  if (strlen(src) == 0)
+    return;
+
+  sPtr = src;
+  dPtr = src;
+
+  while (*sPtr)
+    {
+      if ((*sPtr) == '/')
+        {
+          dPtr = sPtr;
+          ++dPtr;
+        }
+      ++sPtr;
+    }
+
+  strcpy(dest, dPtr);
+  return;
+}
+
+void container_check(LDAP *ldap_handle, char *dn_path, char *name)
+{
+  char cName[256];
+  char *av[7];
+  int  i;
+  int  rc;
+
+  strcpy(cName, name);
+
+  for (i = 0; i < (int)strlen(cName); i++)
+    {
+      if (cName[i] == '/')
+        {
+          cName[i] = '\0';
+          av[CONTAINER_NAME] = cName;
+          av[CONTAINER_DESC] = "";
+          av[CONTAINER_LOCATION] = "";
+          av[CONTAINER_CONTACT] = "";
+          av[CONTAINER_TYPE] = "";
+          av[CONTAINER_ID] = "";
+          av[CONTAINER_ROWID] = "";
+          rc = container_create(ldap_handle, dn_path, 7, av);
+
+          if (rc == LDAP_SUCCESS)
+            {
+              com_err(whoami, 0, "container %s created without a mitMoiraId", 
+                     cName);
+            }
+
+          cName[i] = '/';
+        }
+    }
+}
+
+int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
+                    char **before, int afterc, char **after)
+{
+  char      dName[256];
+  char      cName[256];
+  char      new_cn[128];
+  char      new_dn_path[256];
+  char      temp[256];
+  char      distinguishedName[256];
+  char      *pPtr;
+  int       rc;
+  int       i;
+
+  memset(cName, '\0', sizeof(cName));
+  container_get_name(after[CONTAINER_NAME], cName);
+
+  if (!check_container_name(cName))
+    {
+      com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
+             cName);
+      return(AD_INVALID_NAME);
+    }
+
+  memset(distinguishedName, '\0', sizeof(distinguishedName));
+
+  if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
+                                          distinguishedName, beforec, before))
+    return(rc);
+
+  if (strlen(distinguishedName) == 0)
+    {
+      rc = container_create(ldap_handle, dn_path, afterc, after);
+      return(rc);
+    }
+
+  strcpy(temp, after[CONTAINER_NAME]);
+  pPtr = temp;
+
+  for (i = 0; i < (int)strlen(temp); i++)
+    {
+      if (temp[i] == '/')
+        {
+          pPtr = &temp[i];
+        }
+    }
+
+  (*pPtr) = '\0';
+
+  container_get_dn(temp, dName);
+
+  if (strlen(temp) != 0)
+    sprintf(new_dn_path, "%s,%s", dName, dn_path);
+  else
+    sprintf(new_dn_path, "%s", dn_path);
+
+  sprintf(new_cn, "OU=%s", cName);
+
+  container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
+
+  if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
+                          TRUE, NULL, NULL)) != LDAP_SUCCESS)
+    {
+      com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
+              before[CONTAINER_NAME], after[CONTAINER_NAME], 
+             ldap_err2string(rc));
+      return(rc);
+    }
+
+  memset(dName, '\0', sizeof(dName));
+  container_get_dn(after[CONTAINER_NAME], dName);
+  rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
+
+  return(rc);
+}
+
+int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
+{
+  char      distinguishedName[256];
+  int       rc;
+
+  memset(distinguishedName, '\0', sizeof(distinguishedName));
+
+  if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
+                                          distinguishedName, count, av))
+    return(rc);
+
+  if (strlen(distinguishedName) == 0)
+    return(0);
+
+  if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
+    {
+      if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
+        container_move_objects(ldap_handle, dn_path, distinguishedName);
+      else
+        com_err(whoami, 0, "Unable to delete container %s from AD : %s",
+                av[CONTAINER_NAME], ldap_err2string(rc));
+    }
+
+  return(rc);
+}
+
+int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
+{
+  char      *attr_array[3];
+  LK_ENTRY  *group_base;
+  int       group_count;
+  LDAPMod   *mods[20];
+  char      *objectClass_v[] = {"top", 
+                           "organizationalUnit", 
+                           NULL};
+
+  char *ou_v[] = {NULL, NULL};
+  char *name_v[] = {NULL, NULL};
+  char *moiraId_v[] = {NULL, NULL};
+  char *desc_v[] = {NULL, NULL};
+  char *managedBy_v[] = {NULL, NULL};
+  char dName[256];
+  char cName[256];
+  char managedByDN[256];
+  char filter[256];
+  char temp[256];
+  int  n;
+  int  i;
+  int  rc;
+
+  memset(filter, '\0', sizeof(filter));
+  memset(dName, '\0', sizeof(dName));
+  memset(cName, '\0', sizeof(cName));
+  memset(managedByDN, '\0', sizeof(managedByDN));
+  container_get_dn(av[CONTAINER_NAME], dName);
+  container_get_name(av[CONTAINER_NAME], cName);
+
+  if ((strlen(cName) == 0) || (strlen(dName) == 0))
+    {
+      com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
+             cName);
+      return(AD_INVALID_NAME);
+    }
+
+  if (!check_container_name(cName))
+    {
+      com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
+             cName);
+      return(AD_INVALID_NAME);
+    }
+
+  n = 0;
+  ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
+  name_v[0] = cName;
+  ADD_ATTR("name", name_v, LDAP_MOD_ADD);
+  ou_v[0] = cName;
+  ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
+
+  if (strlen(av[CONTAINER_ROWID]) != 0)
+    {
+      moiraId_v[0] = av[CONTAINER_ROWID];
+      ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
+    }
+
+  if (strlen(av[CONTAINER_DESC]) != 0)
+    {
+      desc_v[0] = av[CONTAINER_DESC];
+      ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
+    }
+
+  if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
+    {
+      if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
+       {
+         if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
+                             kerberos_ou))
+           {
+             sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
+                     kerberos_ou, dn_path);
+             managedBy_v[0] = managedByDN;
+             ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
+           }
+       }
+      else
+       {
+         if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
+           {
+             sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
+                     "(objectClass=user)))", av[CONTAINER_ID]);
+           }
+
+         if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
+           {
+             sprintf(filter, "(&(objectClass=group)(cn=%s))", 
+                     av[CONTAINER_ID]);
+           }
+
+         if (strlen(filter) != 0)
+           {
+             attr_array[0] = "distinguishedName";
+             attr_array[1] = NULL;
+             group_count = 0;
+             group_base = NULL;
+             if ((rc = linklist_build(ldap_handle, dn_path, filter, 
+                                      attr_array, 
+                                      &group_base, &group_count, 
+                                      LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
+               {
+                 if (group_count == 1)
+                   {
+                     strcpy(managedByDN, group_base->value);
+                     managedBy_v[0] = managedByDN;
+                     ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
+                   }
+                 linklist_free(group_base);
+                 group_base = NULL;
+                 group_count = 0;
+               }
+           }
+       }
+    }
+  
+  mods[n] = NULL;
+
+  sprintf(temp, "%s,%s", dName, dn_path);
+  rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
+  
+  for (i = 0; i < n; i++)
+    free(mods[i]);
+  
+  if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
+    {
+      com_err(whoami, 0, "Unable to create container %s : %s",
+              cName, ldap_err2string(rc));
+      return(rc);
+    }
+
+  if (rc == LDAP_ALREADY_EXISTS)
+    {
+      if (strlen(av[CONTAINER_ROWID]) != 0)
+        rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
+    }
+
+  return(rc);
+}
+
+int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
+                    char **before, int afterc, char **after)
+{
+  char distinguishedName[256];
+  int  rc;
+
+  memset(distinguishedName, '\0', sizeof(distinguishedName));
+
+  if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
+                                          distinguishedName, afterc, after))
+    return(rc);
+
+  if (strlen(distinguishedName) == 0)
+    {
+      rc = container_create(ldap_handle, dn_path, afterc, after);
+      return(rc);
+    }
+  
+  container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
+  rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
+                         after);
+
+  return(rc);
+}
+
+int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
+                                   char *distinguishedName, int count, 
+                                   char **av)
+{
+  char      *attr_array[3];
+  LK_ENTRY  *group_base;
+  int       group_count;
+  char      dName[256];
+  char      cName[256];
+  char      filter[512];
+  int       rc;
+
+  memset(filter, '\0', sizeof(filter));
+  memset(dName, '\0', sizeof(dName));
+  memset(cName, '\0', sizeof(cName));
+  container_get_dn(av[CONTAINER_NAME], dName);
+  container_get_name(av[CONTAINER_NAME], cName);
+
+  if (strlen(dName) == 0)
+    {
+      com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
+             av[CONTAINER_NAME]);
+      return(AD_INVALID_NAME);
+    }
+
+  if (!check_container_name(cName))
+    {
+      com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
+             cName);
+      return(AD_INVALID_NAME);
+    }
+  
+  sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
+         av[CONTAINER_ROWID]);
+  attr_array[0] = "distinguishedName";
+  attr_array[1] = NULL;
+  group_count = 0;
+  group_base = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
+    {
+      if (group_count == 1)
+        {
+          strcpy(distinguishedName, group_base->value);
+        }
+
+      linklist_free(group_base);
+      group_base = NULL;
+      group_count = 0;
+    }
+
+  if (strlen(distinguishedName) == 0)
+    {
+      sprintf(filter, "(&(objectClass=organizationalUnit)"
+             "(distinguishedName=%s,%s))", dName, dn_path);
+      attr_array[0] = "distinguishedName";
+      attr_array[1] = NULL;
+      group_count = 0;
+      group_base = NULL;
+
+      if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                               &group_base, &group_count, 
+                              LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
+        {
+          if (group_count == 1)
+            {
+              strcpy(distinguishedName, group_base->value);
+            }
+
+          linklist_free(group_base);
+          group_base = NULL;
+          group_count = 0;
+        }
+    }
+
+  return(0);
+}
+
+int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
+                       char *distinguishedName, int count, char **av)
+{
+  char      *attr_array[5];
+  LK_ENTRY  *group_base;
+  LK_ENTRY  *pPtr;
+  LDAPMod   *mods[20];
+  int       group_count;
+  char      filter[512];
+  char      *moiraId_v[] = {NULL, NULL};
+  char      *desc_v[] = {NULL, NULL};
+  char      *managedBy_v[] = {NULL, NULL};
+  char      managedByDN[256];
+  char      moiraId[64];
+  char      desc[256];
+  char      ad_path[512];
+  int       rc;
+  int       i;
+  int       n;
+
+
+  strcpy(ad_path, distinguishedName);
+
+  if (strlen(dName) != 0)
+    sprintf(ad_path, "%s,%s", dName, dn_path);
+
+  sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
+         ad_path);
+
+  if (strlen(av[CONTAINER_ID]) != 0)
+    sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
+           av[CONTAINER_ROWID]);
+
+  attr_array[0] = "mitMoiraId";
+  attr_array[1] = "description";
+  attr_array[2] = "managedBy";
+  attr_array[3] = NULL;
+  group_count = 0;
+  group_base = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                           &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
+    {
+      com_err(whoami, 0, "Unable to retreive container info for %s : %s",
+              av[CONTAINER_NAME], ldap_err2string(rc));
+      return(rc);
+    }
+
+  memset(managedByDN, '\0', sizeof(managedByDN));
+  memset(moiraId, '\0', sizeof(moiraId));
+  memset(desc, '\0', sizeof(desc));
+  pPtr = group_base;
+
+  while (pPtr)
+    {
+      if (!strcasecmp(pPtr->attribute, "description"))
+        strcpy(desc, pPtr->value);
+      else if (!strcasecmp(pPtr->attribute, "managedBy"))
+        strcpy(managedByDN, pPtr->value);
+      else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
+        strcpy(moiraId, pPtr->value);
+      pPtr = pPtr->next;
+    }
+
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+
+  n = 0;
+  if (strlen(av[CONTAINER_ROWID]) != 0)
+    {
+      moiraId_v[0] = av[CONTAINER_ROWID];
+      ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
+    }
+
+  if (strlen(av[CONTAINER_DESC]) != 0)
+    {
+      attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
+                      dName);
+    }
+  else
+    {
+      if (strlen(desc) != 0)
+        {
+          attribute_update(ldap_handle, ad_path, "", "description", dName);
+        }
+    }
+
+  if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
+    {
+      if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
+       {
+         if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
+                             kerberos_ou))
+           {
+             sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
+                     kerberos_ou, dn_path);
+             managedBy_v[0] = managedByDN;
+             ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
+           }
+         else
+           {
+             if (strlen(managedByDN) != 0)
+               {
+                 attribute_update(ldap_handle, ad_path, "", "managedBy", 
+                                  dName);
+               }
+           }
+       }
+      else
+       {
+         memset(filter, '\0', sizeof(filter));
+
+         if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
+           {
+             sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
+                     "(objectClass=user)))", av[CONTAINER_ID]);
+           }
+
+         if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
+           {
+             sprintf(filter, "(&(objectClass=group)(cn=%s))", 
+                     av[CONTAINER_ID]);
+           }
+
+         if (strlen(filter) != 0)
+           {
+             attr_array[0] = "distinguishedName";
+             attr_array[1] = NULL;
+             group_count = 0;
+             group_base = NULL;
+             if ((rc = linklist_build(ldap_handle, dn_path, filter, 
+                                      attr_array, &group_base, &group_count, 
+                                      LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
+               {
+                 if (group_count == 1)
+                   {
+                     strcpy(managedByDN, group_base->value);
+                     managedBy_v[0] = managedByDN;
+                     ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
+                   }
+                 else
+                   {
+                     if (strlen(managedByDN) != 0)
+                       {
+                         attribute_update(ldap_handle, ad_path, "", 
+                                          "managedBy", dName);
+                       }
+                   }
+
+                 linklist_free(group_base);
+                 group_base = NULL;
+                 group_count = 0;
+               }
+           }
+         else
+           {
+             if (strlen(managedByDN) != 0)
+               {
+                 attribute_update(ldap_handle, ad_path, "", "managedBy", 
+                                  dName);
+               }
+           }
+       }
+    }
+
+  mods[n] = NULL;
+
+  if (n == 0)
+    return(LDAP_SUCCESS);
+
+  rc = ldap_modify_s(ldap_handle, ad_path, mods);
+
+  for (i = 0; i < n; i++)
+    free(mods[i]);
+
+  if (rc != LDAP_SUCCESS)
+    {
+      com_err(whoami, 0, "Unable to modify container info for %s : %s",
+             av[CONTAINER_NAME], ldap_err2string(rc));
+      return(rc);
+    }
+  
+  return(rc);
+}
+
+int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
+{
+  char      *attr_array[3];
+  LK_ENTRY  *group_base;
+  LK_ENTRY  *pPtr;
+  int       group_count;
+  char      filter[512];
+  char      new_cn[128];
+  char      temp[256];
+  int       rc;
+  int       NumberOfEntries = 10;
+  int       i;
+  int       count;
+
+  rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
+
+  for (i = 0; i < 3; i++)
+    {
+      memset(filter, '\0', sizeof(filter));
+
+      if (i == 0)
+        {
+          strcpy(filter, "(!(|(objectClass=computer)"
+                "(objectClass=organizationalUnit)))");
+          attr_array[0] = "cn";
+          attr_array[1] = NULL;
+        }
+      else if (i == 1)
+        {
+          strcpy(filter, "(objectClass=computer)");
+          attr_array[0] = "cn";
+          attr_array[1] = NULL;
+        }
+      else
+        {
+          strcpy(filter, "(objectClass=organizationalUnit)");
+          attr_array[0] = "ou";
+          attr_array[1] = NULL;
+        }
+
+      while (1)
+        {
+          if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
+                                   &group_base, &group_count, 
+                                  LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
+            {
+              break;
+            }
+
+          if (group_count == 0)
+            break;
+
+          pPtr = group_base;
+
+          while(pPtr)
+            {
+              if (!strcasecmp(pPtr->attribute, "cn"))
+                {
+                  sprintf(new_cn, "cn=%s", pPtr->value);
+                  if (i == 0)
+                    sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
+                  if (i == 1)
+                    sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
+                  count = 1;
+
+                  while (1)
+                    {
+                      rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
+                                         TRUE, NULL, NULL);
+                      if (rc == LDAP_ALREADY_EXISTS)
+                        {
+                          sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
+                          ++count;
+                        }
+                      else
+                        break;
+                    }
+                }
+              else if (!strcasecmp(pPtr->attribute, "ou"))
+                {
+                  rc = ldap_delete_s(ldap_handle, pPtr->dn);
+                }
+
+              pPtr = pPtr->next;
+            }
+
+          linklist_free(group_base);
+          group_base = NULL;
+          group_count = 0;
+        }
+    }
+
+  return(0);
+}
+
+int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
+                  char *machine_ou, char *NewMachineName)
+{
+  LK_ENTRY  *group_base;
+  int  group_count;
+  int  i;
+  char filter[128];
+  char *attr_array[3];
+  char cn[256];
+  char dn[256];
+  char temp[256];
+  char *pPtr;
+  int   rc;
+
+  strcpy(NewMachineName, member);
+  rc = moira_connect();
+  rc = GetMachineName(NewMachineName);
+  moira_disconnect();
+
+  if (strlen(NewMachineName) == 0)
+    {
+      com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
+             member);
+      return(1);
+    }
+
+  pPtr = NULL;
+  pPtr = strchr(NewMachineName, '.');
+
+  if (pPtr != NULL)
+    (*pPtr) = '\0';
+
+  group_base = NULL;
+  group_count = 0;
+  sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
+  attr_array[0] = "cn";
+  attr_array[1] = NULL;
+  sprintf(temp, "%s", dn_path);
+
+  if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
+                          &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to process machine %s : %s",
+              member, ldap_err2string(rc));
+      return(1);
+    }
+
+  if (group_count != 1)
+    {
+      com_err(whoami, 0, 
+             "Unable to process machine %s : machine not found in AD",
+              NewMachineName);
+      return(1);
+    }
+
+  strcpy(dn, group_base->dn);
+  strcpy(cn, group_base->value);
+
+  for (i = 0; i < (int)strlen(dn); i++)
+    dn[i] = tolower(dn[i]);
+
+  for (i = 0; i < (int)strlen(cn); i++)
+    cn[i] = tolower(cn[i]);
+
+  linklist_free(group_base);
+  pPtr = NULL;
+  pPtr = strstr(dn, cn);
+
+  if (pPtr == NULL)
+    {
+      com_err(whoami, 0, "Unable to process machine %s",
+              member);
+      return(1);
+    }
+
+  pPtr += strlen(cn) + 1;
+  strcpy(machine_ou, pPtr);
+  pPtr = NULL;
+  pPtr = strstr(machine_ou, "dc=");
+
+  if (pPtr == NULL)
+    {
+      com_err(whoami, 0, "Unable to process machine %s",
+              member);
+      return(1);
+    }
+
+  --pPtr;
+  (*pPtr) = '\0';
+
+  return(0);
+}
+
+int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
+                      char *MoiraMachineName, char *DestinationOu)
+{
+  char        NewCn[128];
+  char        OldDn[512];
+  char        MachineName[128];
+  char        filter[128];
+  char        *attr_array[3];
+  char        NewOu[256];
+  char        *cPtr = NULL;
+  int         group_count;
+  long        rc;
+  LK_ENTRY    *group_base;
+
+  group_count = 0;
+  group_base = NULL;
+  
+  strcpy(MachineName, MoiraMachineName);
+  rc = GetMachineName(MachineName);
+
+  if (strlen(MachineName) == 0)
+    {
+      com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
+             MoiraMachineName);
+      return(1);
+    }
+  
+  cPtr = strchr(MachineName, '.');
+
+  if (cPtr != NULL)
+    (*cPtr) = '\0';
+
+  sprintf(filter, "(sAMAccountName=%s$)", MachineName);
+  attr_array[0] = "sAMAccountName";
+  attr_array[1] = NULL;
+
+  if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
+                          &group_base, 
+                          &group_count, LDAP_SCOPE_SUBTREE)) != 0)
+    {
+      com_err(whoami, 0, "Unable to process machine %s : %s",
+             MoiraMachineName, ldap_err2string(rc));
+      return(1);
+    }
+  
+  if (group_count == 1)
+    strcpy(OldDn, group_base->dn);
+
+  linklist_free(group_base);
+  group_base = NULL;
+
+  if (group_count != 1)
+    {
+      com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
+             MoiraMachineName);
+      return(1);
+    }
+
+  sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
+  cPtr = strchr(OldDn, ',');
+
+  if (cPtr != NULL)
+    {
+      ++cPtr;
+      if (!strcasecmp(cPtr, NewOu))
+       return(0);
+    }
+
+  sprintf(NewCn, "CN=%s", MachineName);
+  rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
+
+  return(rc);
+}
+
+int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
+{
+  char    Name[128];
+  char    *pPtr;
+  int     rc;
+  
+  memset(Name, '\0', sizeof(Name));
+  strcpy(Name, machine_name);
+  pPtr = NULL;
+  pPtr = strchr(Name, '.');
+
+  if (pPtr != NULL)
+    (*pPtr) = '\0';
+
+  strcat(Name, "$");
+  return(!(rc = checkADname(ldap_handle, dn_path, Name)));
+}
+
+int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
+                               char *machine_name, char *container_name)
+{
+  int     rc;
+  char    *av[2];
+  char    *call_args[2];
+  
+  av[0] = machine_name;
+  call_args[0] = (char *)container_name;
+  rc = mr_query("get_machine_to_container_map", 1, av, 
+               machine_GetMoiraContainer, call_args);
+  return(rc);
+}
+
+int machine_GetMoiraContainer(int ac, char **av, void *ptr)
+{
+  char **call_args;
+  
+  call_args = ptr;
+  strcpy(call_args[0], av[1]);
+  return(0);
+}
+
+int Moira_container_group_create(char **after)
+{
+  long rc;
+  char GroupName[64];
+  char *argv[20];
+  
+  memset(GroupName, '\0', sizeof(GroupName));
+  rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
+                             after[CONTAINER_ROWID]);
+  if (rc)
+    return rc;
+  
+  argv[L_NAME] = GroupName;
+  argv[L_ACTIVE] = "1";
+  argv[L_PUBLIC] = "0";
+  argv[L_HIDDEN] = "0";
+  argv[L_MAILLIST] = "0";
+  argv[L_GROUP] = "1";
+  argv[L_GID] = UNIQUE_GID;
+  argv[L_NFSGROUP] = "0";
+  argv[L_MAILMAN] = "0";
+  argv[L_MAILMAN_SERVER] = "[NONE]";
+  argv[L_DESC] = "auto created container group";
+  argv[L_ACE_TYPE] = "USER";
+  argv[L_MEMACE_TYPE] = "USER";
+  argv[L_ACE_NAME] = "sms";
+  argv[L_MEMACE_NAME] = "sms";
+
+  if (rc = mr_query("add_list", 15, argv, NULL, NULL))
+    {
+      com_err(whoami, 0, 
+             "Unable to create container group %s for container %s: %s",
+             GroupName, after[CONTAINER_NAME], error_message(rc));
+    }
+
+  Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
+  Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
+  
+  return(rc);
+}
+
+int Moira_container_group_update(char **before, char **after)
+{
+  long rc;
+  char BeforeGroupName[64];
+  char AfterGroupName[64];
+  char *argv[20];
+  
+  if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
+    return(0);
+
+  memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
+  Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
+  if (strlen(BeforeGroupName) == 0)
+    return(0);
+
+  memset(AfterGroupName, '\0', sizeof(AfterGroupName));
+  rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
+                             after[CONTAINER_ROWID]);
+  if (rc)
+    return rc;
+
+  if (strcasecmp(BeforeGroupName, AfterGroupName))
+    {
+      argv[L_NAME] = BeforeGroupName;
+      argv[L_NAME + 1] = AfterGroupName;
+      argv[L_ACTIVE + 1] = "1";
+      argv[L_PUBLIC + 1] = "0";
+      argv[L_HIDDEN + 1] = "0";
+      argv[L_MAILLIST + 1] = "0";
+      argv[L_GROUP + 1] = "1";
+      argv[L_GID + 1] = UNIQUE_GID;
+      argv[L_NFSGROUP + 1] = "0";
+      argv[L_MAILMAN + 1] = "0";
+      argv[L_MAILMAN_SERVER + 1] = "[NONE]";
+      argv[L_DESC + 1] = "auto created container group";
+      argv[L_ACE_TYPE + 1] = "USER";
+      argv[L_MEMACE_TYPE + 1] = "USER";
+      argv[L_ACE_NAME + 1] = "sms";
+      argv[L_MEMACE_NAME + 1] = "sms";
+      
+      if (rc = mr_query("update_list", 16, argv, NULL, NULL))
+       {
+         com_err(whoami, 0, 
+                 "Unable to rename container group from %s to %s: %s",
+                 BeforeGroupName, AfterGroupName, error_message(rc));
+       }
+    }
+  
+  return(rc);
+}
+
+int Moira_container_group_delete(char **before)
+{
+  long rc = 0;
+  char *argv[13];
+  char GroupName[64];
+  char ParentGroupName[64];
+  
+  memset(ParentGroupName, '\0', sizeof(ParentGroupName));
+  Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
+
+  memset(GroupName, '\0', sizeof(GroupName));
+
+  if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
+    strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
+  
+  if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
+    {
+      argv[0] = ParentGroupName;
+      argv[1] = "LIST";
+      argv[2] = GroupName;
+
+      if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
+       {
+         com_err(whoami, 0, 
+                 "Unable to delete container group %s from list: %s",
+                 GroupName, ParentGroupName, error_message(rc));
+       }
+    }
+  
+  if (strlen(GroupName) != 0)
+    {
+      argv[0] = GroupName;
+
+      if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
+       {
+         com_err(whoami, 0, "Unable to delete container group %s : %s",
+                 GroupName, error_message(rc));
+       }
+    }
+  
+  return(rc);
+}
+
+int Moira_groupname_create(char *GroupName, char *ContainerName,
+                          char *ContainerRowID)
+{
+  char *ptr;
+  char *ptr1;
+  char temp[64];
+  char newGroupName[64];
+  char tempGroupName[64];
+  char tempgname[64];
+  char *argv[1];
+  int  i;
+  long rc;
+
+  strcpy(temp, ContainerName);
+  
+  ptr1 = strrchr(temp, '/');
+
+  if (ptr1 != NULL)
+  {
+    *ptr1 = '\0';
+    ptr = ++ptr1;
+    ptr1 = strrchr(temp, '/');
+
+    if (ptr1 != NULL)
+    {
+        sprintf(tempgname, "%s-%s", ++ptr1, ptr);
+    }
+    else
+        strcpy(tempgname, ptr);
+  }
+  else
+    strcpy(tempgname, temp);
+
+  if (strlen(tempgname) > 25)
+    tempgname[25] ='\0';
+
+  sprintf(newGroupName, "cnt-%s", tempgname);
+
+  /* change everything to lower case */
+  ptr = newGroupName;
+
+  while (*ptr)
+    {
+      if (isupper(*ptr))
+       *ptr = tolower(*ptr);
+
+      if (*ptr == ' ')
+       *ptr = '-';
+
+      ptr++;
+    }
+
+  strcpy(tempGroupName, newGroupName);
+  i = (int)'0';
+
+  /* append 0-9 then a-z if a duplicate is found */
+  while(1)
+    {
+      argv[0] = newGroupName;
+
+      if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
+       {
+         if (rc == MR_NO_MATCH)
+           break;
+         com_err(whoami, 0, "Moira error while creating group name for "
+                 "container %s : %s", ContainerName, error_message(rc));
+         return rc;
+       }
+
+      sprintf(newGroupName, "%s-%c", tempGroupName, i);
+
+      if (i == (int)'z')
+       {
+         com_err(whoami, 0, "Unable to find a unique group name for "
+                 "container %s: too many duplicate container names",
+                 ContainerName);
+         return 1;
+       }
+
+      if (i == '9')
+       i = 'a';
+      else
+       i++;
+    }
+
+  strcpy(GroupName, newGroupName);
+  return(0);
+}
+
+int Moira_setContainerGroup(char *origContainerName, char *GroupName)
+{
+  long rc;
+  char *argv[3];
+  
+  argv[0] = origContainerName;
+  argv[1] = GroupName;
+  
+  if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
+    {
+      com_err(whoami, 0, 
+             "Unable to set container group %s in container %s: %s",
+             GroupName, origContainerName, error_message(rc));
+    }
+  
+  return(0);
+}
+
+int Moira_addGroupToParent(char *origContainerName, char *GroupName)
+ {
+   char ContainerName[64];
+   char ParentGroupName[64];
+   char *argv[3];
+   long rc;
+
+   strcpy(ContainerName, origContainerName);
+   
+   Moira_getGroupName(ContainerName, ParentGroupName, 1);
+
+   /* top-level container */
+   if (strlen(ParentGroupName) == 0)
+     return(0);
+   
+   argv[0] = ParentGroupName;
+   argv[1] = "LIST";
+   argv[2] = GroupName;
+
+   if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
+     {
+       com_err(whoami, 0, 
+              "Unable to add container group %s to parent group %s: %s",
+              GroupName, ParentGroupName, error_message(rc));
+     }
+   
+   return(0);
+ }
+
+int Moira_getContainerGroup(int ac, char **av, void *ptr)
+{
+  char **call_args;
+  
+  call_args = ptr;
+  strcpy(call_args[0], av[1]);
+
+  return(0);
+}
+
+int Moira_getGroupName(char *origContainerName, char *GroupName,
+                      int ParentFlag)
+{
+  char ContainerName[64];
+  char *argv[3];
+  char *call_args[3];
+  char *ptr;
+  long rc;
+
+  strcpy(ContainerName, origContainerName);
+
+  if (ParentFlag)
+    {
+      ptr = strrchr(ContainerName, '/');
+
+      if (ptr != NULL)
+       (*ptr) = '\0';
+      else
+       return(0);
+    }
+
+  argv[0] = ContainerName;
+  argv[1] = NULL;
+  call_args[0] = GroupName;
+  call_args[1] = NULL;
+
+  if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
+                     call_args)))
+    {
+      if (strlen(GroupName) != 0)
+       return(0);
+    }
+
+  if (rc)
+    com_err(whoami, 0, "Unable to get container group from container %s: %s",
+           ContainerName, error_message(rc));
+  else
+    com_err(whoami, 0, "Unable to get container group from container %s",
+           ContainerName);
+  
+  return(0);
+}
+
+int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
+                                         int DeleteMachine)
+{
+  char *argv[3];
+  long rc;
+  
+  if (strcmp(GroupName, "[none]") == 0)
+    return 0;
+
+  argv[0] = GroupName;
+  argv[1] = "MACHINE";
+  argv[2] = MachineName;
+
+  if (!DeleteMachine)
+    rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
+  else
+    rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
+
+  if (rc)
+    {
+      com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
+             MachineName, GroupName, error_message(rc));
+    }
+
+  return(0);
+}
+
+int GetMachineName(char *MachineName)
+{
+  char    *args[2];
+  char    NewMachineName[1024];
+  char    *szDot;
+  int     rc = 0;
+  int     i;
+  DWORD   dwLen = 0;
+  char    *call_args[2];
+  
+  // If the address happens to be in the top-level MIT domain, great!
+  strcpy(NewMachineName, MachineName);
+
+  for (i = 0; i < (int)strlen(NewMachineName); i++)
+    NewMachineName[i] = toupper(NewMachineName[i]);
+
+  szDot = strchr(NewMachineName,'.');
+
+  if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
+    {
+      return(0);
+    }
+  
+  // If not, see if it has a Moira alias in the top-level MIT domain.
+  memset(NewMachineName, '\0', sizeof(NewMachineName));
+  args[0] = "*";
+  args[1] = MachineName;
+  call_args[0] = NewMachineName;
+  call_args[1] = NULL;
+
+  if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
+    {
+      com_err(whoami, 0, "Unable to resolve machine name %s : %s",
+             MachineName, error_message(rc));
+      strcpy(MachineName, "");
+      return(0);
+    }
+  
+  if (strlen(NewMachineName) != 0)
+    strcpy(MachineName, NewMachineName);
+  else
+    strcpy(MachineName, "");
+
+  return(0);
+}
+
+int ProcessMachineName(int ac, char **av, void *ptr)
+{
+  char    **call_args;
+  char    MachineName[1024];
+  char    *szDot;
+  int     i;
+  
+  call_args = ptr;
+
+  if (strlen(call_args[0]) == 0)
+    {
+      strcpy(MachineName, av[0]);
+
+      for (i = 0; i < (int)strlen(MachineName); i++)
+       MachineName[i] = toupper(MachineName[i]);
+
+      szDot = strchr(MachineName,'.');
+
+        if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
+         {
+            strcpy(call_args[0], MachineName);
+         }
+    }
+
+  return(0);
+}
+
+void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
+{
+  int i;
+  
+  if (*UseSFU30)
+    {
+      for (i = 0; i < n; i++)
+        {
+         if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
+           mods[i]->mod_type = "uidNumber";
+        }
+
+      (*UseSFU30) = 0;
+    }
+  else
+    {
+      for (i = 0; i < n; i++)
+        {
+         if (!strcmp(mods[i]->mod_type, "uidNumber"))
+           mods[i]->mod_type = "msSFU30UidNumber";
+        }
+
+      (*UseSFU30) = 1;
+    }
+}
+
+int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
+                    char *DistinguishedName,
+                     char *WinHomeDir, char *WinProfileDir,
+                     char **homedir_v, char **winProfile_v,
+                     char **drives_v, LDAPMod **mods, 
+                     int OpType, int n)
+{
+  char **hp;
+  char cWeight[3];
+  char cPath[1024];
+  char path[1024];
+  char winPath[1024];
+  char winProfile[1024];
+  char homeDrive[8];
+  int  last_weight;
+  int  i;
+  int  rc;
+  LDAPMod *DelMods[20];
+  
+  memset(homeDrive, '\0', sizeof(homeDrive));
+  memset(path, '\0', sizeof(path));
+  memset(winPath, '\0', sizeof(winPath));
+  memset(winProfile, '\0', sizeof(winProfile));
+  hp = NULL;
+
+  if ((!strcasecmp(WinHomeDir, "[afs]")) || 
+      (!strcasecmp(WinProfileDir, "[afs]")))
+    {
+      if ((hp = hes_resolve(user_name, "filsys")) != NULL)
+        {
+         memset(cWeight, 0, sizeof(cWeight));
+         memset(cPath, 0, sizeof(cPath));
+         last_weight = 1000;
+         i = 0;
+
+         while (hp[i] != NULL)
+            {
+             if (sscanf(hp[i], "%*s %s", cPath))
+                {
+                 if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
+                    {
+                     if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
+                        {
+                         if (atoi(cWeight) < last_weight)
+                            {
+                             strcpy(path, cPath);
+                             last_weight = (int)atoi(cWeight);
+                            }
+                        }
+                     else 
+                       strcpy(path, cPath);
+                    }
+                }
+              ++i;
+            }
+
+         if (strlen(path))
+            {
+             if (!strnicmp(path, AFS, strlen(AFS)))
+                {
+                 AfsToWinAfs(path, winPath);
+                 strcpy(winProfile, winPath);
+                 strcat(winProfile, "\\.winprofile");
+                }
+            }
+        }
+      else
+       return(n);
+    }
+
+    if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
+       (!strcasecmp(WinProfileDir, "[dfs]")))
+    {
+      sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
+             user_name[0], user_name);
+
+      if (!strcasecmp(WinProfileDir, "[dfs]"))
+       {
+         strcpy(winProfile, path);
+         strcat(winProfile, "\\.winprofile");
+       }
+
+      if (!strcasecmp(WinHomeDir, "[dfs]"))
+       strcpy(winPath, path);
+    }
+    
+    if (hp != NULL)
+      {
+        i = 0;
+        while (hp[i])
+         {
+            free(hp[i]);
+            i++;
+         }
+      }
+    
+    if (!strcasecmp(WinHomeDir, "[local]"))
+      memset(winPath, '\0', sizeof(winPath));
+    else if (!strcasecmp(WinHomeDir, "[afs]") || 
+            !strcasecmp(WinHomeDir, "[dfs]"))
+      {
+        strcpy(homeDrive, "H:");
+      }
+    else
+      {
+        strcpy(winPath, WinHomeDir);
+        if (!strncmp(WinHomeDir, "\\\\", 2))
+         {
+            strcpy(homeDrive, "H:");
+         }        
+      }
+    
+    // nothing needs to be done if WinProfileDir is [afs].
+    if (!strcasecmp(WinProfileDir, "[local]"))
+      memset(winProfile, '\0', sizeof(winProfile));
+    else if (strcasecmp(WinProfileDir, "[afs]") && 
+            strcasecmp(WinProfileDir, "[dfs]"))
+      {
+        strcpy(winProfile, WinProfileDir);
+      }
+    
+    if (strlen(winProfile) != 0)
+      {
+        if (winProfile[strlen(winProfile) - 1] == '\\')
+         winProfile[strlen(winProfile) - 1] = '\0';
+      }
+
+    if (strlen(winPath) != 0)
+      {
+        if (winPath[strlen(winPath) - 1] == '\\')
+         winPath[strlen(winPath) - 1] = '\0';
+      }
+    
+    if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
+      strcat(winProfile, "\\");
+
+    if ((winPath[1] == ':') && (strlen(winPath) == 2))
+      strcat(winPath, "\\");
+    
+    if (strlen(winPath) == 0)
+      {
+        if (OpType == LDAP_MOD_REPLACE)
+         {
+            i = 0;
+            DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
+            DelMods[i] = NULL;
+            //unset homeDirectory attribute for user.
+            rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
+            free(DelMods[0]);
+         }
+      }
+    else
+      {
+        homedir_v[0] = strdup(winPath);
+        ADD_ATTR("homeDirectory", homedir_v, OpType);
+      }
+    
+    if (strlen(winProfile) == 0)
+      {
+        if (OpType == LDAP_MOD_REPLACE)
+         {
+            i = 0;
+            DEL_ATTR("profilePath", LDAP_MOD_DELETE);
+            DelMods[i] = NULL;
+            //unset profilePate attribute for user.
+            rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
+            free(DelMods[0]);
+         }
+      }
+    else
+      {
+        winProfile_v[0] = strdup(winProfile);
+        ADD_ATTR("profilePath", winProfile_v, OpType);
+      }
+    
+    if (strlen(homeDrive) == 0)
+      {
+        if (OpType == LDAP_MOD_REPLACE)
+         {
+            i = 0;
+            DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
+            DelMods[i] = NULL;
+            //unset homeDrive attribute for user
+            rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
+            free(DelMods[0]);
+         }
+      }
+    else
+      {
+        drives_v[0] = strdup(homeDrive);
+        ADD_ATTR("homeDrive", drives_v, OpType);
+      }
+
+    return(n);
+}
+
+int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
+                    char *attribute_value, char *attribute, char *user_name)
+{
+  char      *mod_v[] = {NULL, NULL};
+  LDAPMod   *DelMods[20];
+  LDAPMod   *mods[20];
+  int       n;
+  int       i;
+  int       rc;
+  
+  if (strlen(attribute_value) == 0)
+    {
+      i = 0;
+      DEL_ATTR(attribute, LDAP_MOD_DELETE);
+      DelMods[i] = NULL;
+      rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
+      free(DelMods[0]);
+    }
+  else
+    {
+      n = 0;
+      mod_v[0] = attribute_value;
+      ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
+      mods[n] = NULL;
+
+      if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
+                             mods)) != LDAP_SUCCESS)
+        {
+          free(mods[0]);
+          n = 0;
+          mod_v[0] = attribute_value;
+          ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
+          mods[n] = NULL;
+
+          if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
+                                 mods)) != LDAP_SUCCESS)
+            {
+              com_err(whoami, 0, "Unable to change the %s attribute for %s "
+                     "in the AD : %s",
+                      attribute, user_name, ldap_err2string(rc));
+            }
+        }
+
+      free(mods[0]);
+    }
+  
+  return(rc);
+}
+
+void StringTrim(char *StringToTrim)
+{
+  char *t, *s;
+  char *save;
+
+  save = strdup(StringToTrim);
+
+  s = save;
+
+  while (isspace(*s))
+    s++;
+
+  /* skip to end of string */
+  if (*s == '\0')
+    {
+      if (*save)
+       *save = '\0';
+      strcpy(StringToTrim, save);
+      return;
+    }
+  
+  for (t = s; *t; t++)
+    continue;
+
+  while (t > s)
+    {
+      --t;
+      if (!isspace(*t))
+       {
+         t++;
+         break;
+       }
+    }
+
+  if (*t)
+    *t = '\0';
+  
+  strcpy(StringToTrim, s);
+  return;
+}
+
+int ReadConfigFile(char *DomainName)
+{
+    int     Count;
+    int     i;
+    int     k;
+    char    temp[256];
+    char    temp1[256];
+    FILE    *fptr;
+
+    Count = 0;
+
+    sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
+
+    if ((fptr = fopen(temp, "r")) != NULL)
+      {
+        while (fgets(temp, sizeof(temp), fptr) != 0)
+         {
+            for (i = 0; i < (int)strlen(temp); i++)
+             temp[i] = toupper(temp[i]);
+
+            if (temp[strlen(temp) - 1] == '\n')
+             temp[strlen(temp) - 1] = '\0';
+
+            StringTrim(temp);
+
+            if (strlen(temp) == 0)
+             continue;
+
+            if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
+             {
+                if (strlen(temp) > (strlen(DOMAIN)))
+                 {
+                    strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
+                    StringTrim(ldap_domain);
+                 }
+             }
+            else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
+             {
+                if (strlen(temp) > (strlen(PRINCIPALNAME)))
+                 {
+                    strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
+                    StringTrim(PrincipalName);
+                 }
+             }
+            else if (!strncmp(temp, SERVER, strlen(SERVER)))
+             {
+                if (strlen(temp) > (strlen(SERVER)))
+                 {
+                    ServerList[Count] = calloc(1, 256);
+                    strcpy(ServerList[Count], &temp[strlen(SERVER)]);
+                    StringTrim(ServerList[Count]);
+                    ++Count;
+                 }
+             }
+            else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
+             {
+                if (strlen(temp) > (strlen(MSSFU)))
+                 {
+                    strcpy(temp1, &temp[strlen(MSSFU)]);
+                    StringTrim(temp1);
+                    if (!strcmp(temp1, SFUTYPE))
+                     UseSFU30 = 1;
+                 }
+             }
+           else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
+             {
+               if (strlen(temp) > (strlen(GROUP_SUFFIX)))
+                 {
+                   strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "NO")) 
+                     {
+                       UseGroupSuffix = 0;
+                       memset(group_suffix, '\0', sizeof(group_suffix));
+                     }
+                 }
+             }
+           else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
+             {
+               if (strlen(temp) > (strlen(GROUP_TYPE)))
+                 {
+                   strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "UNIVERSAL")) 
+                     UseGroupUniversal = 1;
+                 }
+             }
+           else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
+             {
+               if (strlen(temp) > (strlen(SET_GROUP_ACE)))
+                 {
+                   strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "NO"))
+                     SetGroupAce = 0;
+                 }
+             }
+           else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
+             {
+               if (strlen(temp) > (strlen(SET_PASSWORD)))
+                 {
+                   strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "NO"))
+                     SetPassword = 0;
+                 }
+             }
+           else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
+             {
+               if (strlen(temp) > (strlen(EXCHANGE)))
+                 {
+                   strcpy(temp1, &temp[strlen(EXCHANGE)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "YES"))
+                     Exchange = 1;
+                 }
+             }
+           else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
+                             strlen(PROCESS_MACHINE_CONTAINER)))
+             {
+               if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
+                 {
+                   strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
+                   StringTrim(temp1);
+                   if (!strcasecmp(temp1, "NO"))
+                     ProcessMachineContainer = 0;
+                 }
+             }
+            else
+             {
+                if (strlen(ldap_domain) != 0)
+                 {
+                    memset(ldap_domain, '\0', sizeof(ldap_domain));
+                    break;
+                 }
+
+                if (strlen(temp) != 0)
+                 strcpy(ldap_domain, temp);
+             }
+         }
+        fclose(fptr);
+      }
+    
+    if (strlen(ldap_domain) == 0)
+      {
+      strcpy(ldap_domain, DomainName);
+      }
+
+    if (Count == 0)
+        return(0);
+
+    for (i = 0; i < Count; i++)
+      {
+        if (ServerList[i] != 0)
+         {
+            strcat(ServerList[i], ".");
+            strcat(ServerList[i], ldap_domain);
+            for (k = 0; k < (int)strlen(ServerList[i]); k++)
+             ServerList[i][k] = toupper(ServerList[i][k]);
+         }
+      }
+    
+    return(0);
+}
+
+int ReadDomainList()
+{
+  int     Count;
+  int     i;
+  char    temp[128];
+  char    temp1[128];
+  FILE    *fptr;
+  unsigned char c[11];
+  unsigned char stuff[256];
+  int     rc;
+  int     ok;
+
+  Count = 0;
+  sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
+
+  if ((fptr = fopen(temp, "r")) != NULL)
+    {
+      while (fgets(temp, sizeof(temp), fptr) != 0)
+       {
+         for (i = 0; i < (int)strlen(temp); i++)
+           temp[i] = toupper(temp[i]);
+
+         if (temp[strlen(temp) - 1] == '\n')
+           temp[strlen(temp) - 1] = '\0';
+
+         StringTrim(temp);
+
+         if (strlen(temp) == 0)
+           continue;
+
+         if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
+           {
+             if (strlen(temp) > (strlen(DOMAIN)))
+               {
+                 strcpy(temp1, &temp[strlen(DOMAIN)]);
+                 StringTrim(temp1);
+                 strcpy(temp, temp1);
+               }
+           }
+         
+         strcpy(DomainNames[Count], temp);
+         StringTrim(DomainNames[Count]);
+         ++Count;
+       }
+
+      fclose(fptr);
+    }
+
+  if (Count == 0)
+    {
+      critical_alert(whoami, "incremental", "%s", "winad.incr cannot run due to a "
+                    "configuration error in winad.cfg");
+      return(1);
+    }
+  
+  return(0);
+}
+
+int email_isvalid(const char *address) {
+  int        count = 0;
+  const char *c, *domain;
+  static char *rfc822_specials = "()<>@,;:\\\"[]";
+
+  if(address[strlen(address) - 1] == '.') 
+    return 0;
+    
+  /* first we validate the name portion (name@domain) */
+  for (c = address;  *c;  c++) {
+    if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
+                      '\"')) {
+      while (*++c) {
+        if (*c == '\"') 
+         break;
+        if (*c == '\\' && (*++c == ' ')) 
+         continue;
+        if (*c <= ' ' || *c >= 127) 
+         return 0;
+      }
+
+      if (!*c++) 
+       return 0;
+      if (*c == '@') 
+       break;
+      if (*c != '.') 
+       return 0;
+      continue;
+    }
+
+    if (*c == '@') 
+      break;
+    if (*c <= ' ' || *c >= 127) 
+      return 0;
+    if (strchr(rfc822_specials, *c)) 
+      return 0;
+  }
+
+  if (c == address || *(c - 1) == '.') 
+    return 0;
+
+  /* next we validate the domain portion (name@domain) */
+  if (!*(domain = ++c)) return 0;
+  do {
+    if (*c == '.') {
+      if (c == domain || *(c - 1) == '.') 
+       return 0;
+      count++;
+    }
+    if (*c <= ' ' || *c >= 127) 
+      return 0;
+    if (strchr(rfc822_specials, *c)) 
+      return 0;
+  } while (*++c);
+
+  return (count >= 1);
+}
+
+int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
+            char **homeServerName) 
+{
+  LK_ENTRY *group_base;
+  LK_ENTRY *sub_group_base;
+  LK_ENTRY *gPtr;
+  LK_ENTRY *sub_gPtr;
+  int      group_count;
+  int      sub_group_count;
+  char     filter[1024];
+  char     sub_filter[1024];
+  char     search_path[1024];
+  char     range[1024];
+  char     *attr_array[3];
+  char     *s;
+  int      homeMDB_count = -1;
+  int      rc;
+  int      i;
+  int      mdbbl_count;
+  int      rangeStep = 1500;
+  int      rangeLow = 0;
+  int      rangeHigh = rangeLow + (rangeStep - 1);
+  int      isLast = 0;
+
+  /* Grumble..... microsoft not making it searchable from the root *grr* */
+
+  memset(filter, '\0', sizeof(filter));
+  memset(search_path, '\0', sizeof(search_path));
+  
+  sprintf(filter, "(objectClass=msExchMDB)");
+  sprintf(search_path, "CN=Configuration,%s", dn_path);
+  attr_array[0] = "distinguishedName";
+  attr_array[1] = NULL;
+  
+  group_base = NULL;
+  group_count = 0;
+  
+  if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
+                          &group_base, &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0) 
+    {
+      com_err(whoami, 0, "Unable to find msExchMDB %s",
+             ldap_err2string(rc));
+      return(rc);
+    }
+  
+  if (group_count) 
+    {
+      gPtr = group_base;
+      
+      while(gPtr) {
+       if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
+           ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL) ||
+           ((s = strstr(gPtr->dn, "Recovery")) != (char *) NULL))
+         {
+           gPtr = gPtr->next;
+           continue;
+         }
+
+       /* 
+        * Due to limits in active directory we need to use the LDAP
+        * range semantics to query and return all the values in 
+        * large lists, we will stop increasing the range when
+        * the result count is 0.
+         */
+
+       i = 0;  
+       mdbbl_count = 0;
+
+       for(;;) 
+         {
+           memset(sub_filter, '\0', sizeof(sub_filter));
+           memset(range, '\0', sizeof(range));
+           sprintf(sub_filter, "(objectClass=msExchMDB)");
+
+           if(isLast)
+             sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
+           else 
+             sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
+
+           attr_array[0] = range;
+           attr_array[1] = NULL;
+           
+           sub_group_base = NULL;
+           sub_group_count = 0;
+           
+           if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
+                                    attr_array, &sub_group_base, 
+                                    &sub_group_count, 
+                                    LDAP_SCOPE_SUBTREE)) != 0) 
+             {
+               com_err(whoami, 0, "Unable to find homeMDBBL %s",
+                       ldap_err2string(rc));
+               return(rc);
+             }
+
+           if(!sub_group_count)
+             {
+               if(isLast) 
+                 {
+                   isLast = 0;
+                   rangeLow = 0;
+                   rangeHigh = rangeLow + (rangeStep - 1);
+                   break;
+                 }
+               else
+                 isLast++;
+             }
+
+           mdbbl_count += sub_group_count;
+           rangeLow = rangeHigh + 1;
+           rangeHigh = rangeLow + (rangeStep - 1);
+         }
+
+       /* First time through, need to initialize or update the least used */
+       
+       com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
+               mdbbl_count);
+
+       if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
+         {
+           homeMDB_count = mdbbl_count; 
+           *homeMDB = strdup(gPtr->dn);
+         }
+
+       gPtr = gPtr->next;
+       linklist_free(sub_group_base);
+      }
+    }
+
+  linklist_free(group_base);
+  
+  /* 
+   * Ok found the server least allocated need to now query to get its
+   * msExchHomeServerName so we can set it as a user attribute
+   */
+  
+  attr_array[0] = "legacyExchangeDN";
+  attr_array[1] = NULL;        
+  
+  group_count = 0;
+  group_base = NULL;
+  
+  if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
+                          attr_array, &group_base, 
+                          &group_count, 
+                          LDAP_SCOPE_SUBTREE)) != 0) 
+    {
+      com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
+             ldap_err2string(rc));
+      return(rc);
+    }  
+  
+  if(group_count) 
+    {
+      *homeServerName = strdup(group_base->value);
+      if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
+       {
+         *s = '\0';
+       }
+    } 
+
+  linklist_free(group_base);
+  
+  return(rc);
+}
+      
+char *lowercase(char *s)
+{
+  char *p;
+
+  for (p = s; *p; p++)
+    {
+      if (isupper(*p))
+       *p = tolower(*p);
+    }
+  return s;
+}
+
+char *uppercase(char *s)
+{
+  char *p;
+
+  for (p = s; *p; p++)
+    {
+      if (islower(*p))
+       *p = toupper(*p);
+    }
+  return s;
+}
+
+int save_query_info(int argc, char **argv, void *hint)
+{
+  int i;
+  char **nargv = hint;
+
+  for(i = 0; i < argc; i++)
+    nargv[i] = strdup(argv[i]);
+
+  return MR_CONT;
 }
This page took 0.346459 seconds and 4 git commands to generate.