]> andersk Git - moira.git/commitdiff
From dtanner: updates to Active Directory incremental update program.
authorzacheiss <zacheiss>
Sat, 11 Nov 2000 11:05:22 +0000 (11:05 +0000)
committerzacheiss <zacheiss>
Sat, 11 Nov 2000 11:05:22 +0000 (11:05 +0000)
incremental/winad/Makefile.in
incremental/winad/kpasswd.h [new file with mode: 0644]
incremental/winad/krb5_utils.c [new file with mode: 0644]
incremental/winad/ldap_adgssapi_bind.c
incremental/winad/setpw.c [new file with mode: 0644]
incremental/winad/winad.c

index efd55e8f8cb3c5669366a10867804e199a6c5b30..51c2ffce72c27d05e0b874af1406a139dce4d68a 100644 (file)
@@ -22,7 +22,7 @@ SRCTOP=@top_srcdir@
 BUILDTOP=../..
 mrbindir=@mrbindir@
 
-WINAD_OBJS=winad.o ldap_adgssapi_bind.o
+WINAD_OBJS=winad.o ldap_adgssapi_bind.o krb5_utils.o setpw.o
 
 TARGET=winad.incr
 
diff --git a/incremental/winad/kpasswd.h b/incremental/winad/kpasswd.h
new file mode 100644 (file)
index 0000000..cfd5108
--- /dev/null
@@ -0,0 +1,52 @@
+/*--
+
+THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+PARTICULAR PURPOSE.
+
+Copyright (C) 1999  Microsoft Corporation.  All rights reserved.
+
+Module Name:
+
+    kpasswd.h
+
+Abstract:
+
+    Definitions for the Kerberos change password functions
+
+--*/
+
+/* changepw.h */
+krb5_error_code krb5_set_password
+       KRB5_PROTOTYPE((krb5_context, krb5_ccache, char *, char *, char *, int *));
+
+/*krb5_error_code 
+(krb5_context, const krb5_data *, struct sockaddr **, int *);
+*/
+
+/* password change constants */
+
+typedef struct _krb5_setpw {
+       krb5_magic      magic;
+       krb5_data       newpasswd;
+       krb5_principal  targprinc;
+} krb5_setpw;
+
+#ifndef KRB5_KPASSWD_SUCCESS
+#define KRB5_KPASSWD_SUCCESS           0
+#define KRB5_KPASSWD_MALFORMED         1
+#define KRB5_KPASSWD_HARDERROR         2
+#define KRB5_KPASSWD_AUTHERROR         3
+#define KRB5_KPASSWD_SOFTERROR         4
+#endif
+#define KRB5_KPASSWD_ACCESSDENIED      5
+#define KRB5_KPASSWD_BAD_VERSION       6
+#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7
+
+#define KRB5_KPASSWD_VERS_CHANGEPW     1
+#define KRB5_KPASSWD_VERS_SETPW                0xff80
+
+#ifndef DEFAULT_KPASSWD_PORT
+#define DEFAULT_KPASSWD_PORT   464
+#endif
diff --git a/incremental/winad/krb5_utils.c b/incremental/winad/krb5_utils.c
new file mode 100644 (file)
index 0000000..f8d0a77
--- /dev/null
@@ -0,0 +1,265 @@
+/*--
+    krb5_utils.c
+
+Abstract:
+
+    ASN.1 encoder for the
+    Kerberos Change Password Protocol (I-D) variant for Windows 2000
+
+--*/
+
+#include <krb5.h>
+#ifdef _WIN32
+#include "asn1_make.h"
+#endif
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#define NEED_SOCKETS
+#ifndef _WIN32
+#include <netdb.h>
+#include <sys/socket.h>
+#endif
+#include <stdio.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "kpasswd.h"
+
+#ifndef KRB5_USE_INET
+#ifdef HAVE_NETINET_IN_H
+#define KRB5_USE_INET 1
+#endif
+#endif
+
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+#ifndef _WIN32
+typedef krb5_octet asn1_octet;
+typedef krb5_error_code asn1_error_code;
+typedef struct code_buffer_rep {
+  char *base, *bound, *next;
+} asn1buf;
+typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40,
+                CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class;
+#endif
+
+static const char rcsid[] = "$Id$";
+
+asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, 
+                                  int *retlen);
+asn1_error_code asn1_encode_principal_name(asn1buf *buf, 
+                                           const krb5_principal val, 
+                                           int *retlen);
+asn1_error_code asn1_encode_octetstring(asn1buf *buf, const int len, 
+                                        const asn1_octet *val, int *retlen);
+
+/* From src/lib/krb5/asn.1/krb5_encode.c */
+
+/* setup() -- create and initialize bookkeeping variables
+     retval: stores error codes returned from subroutines
+     buf: the coding buffer
+     length: length of the most-recently produced encoding
+     sum: cumulative length of the entire encoding */
+#define krb5_setup()\
+  asn1_error_code retval;\
+  asn1buf *buf=NULL;\
+  int length, sum=0;\
+\
+  if(rep == NULL) return ASN1_MISSING_FIELD;\
+\
+  retval = asn1buf_create(&buf);\
+  if(retval) return retval
+
+
+/* krb5_addfield -- add a field, or component, to the encoding */
+#define krb5_addfield(value,tag,encoder)\
+{ retval = encoder(buf,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* krb5_addlenfield -- add a field whose length must be separately specified */
+#define krb5_addlenfield(len,value,tag,encoder)\
+{ retval = encoder(buf,len,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* form a sequence (by adding a sequence header to the current encoding) */
+#define krb5_makeseq()\
+  retval = asn1_make_sequence(buf,sum,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length
+
+/* produce the final output and clean up the workspace */
+#define krb5_cleanup()\
+  retval = asn12krb5_buf(buf,code);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  retval = asn1buf_destroy(&buf);\
+  if(retval){\
+    return retval; }\
+\
+  return(0)
+
+krb5_error_code encode_krb5_setpw(const krb5_setpw *rep,
+                                  krb5_data ** code)
+{
+  krb5_setup();
+
+  if (rep->targprinc != NULL)
+    {  /* target principal name is OPTIONAL */
+      krb5_addfield(rep->targprinc,2,asn1_encode_realm);
+      krb5_addfield(rep->targprinc,1,asn1_encode_principal_name);
+    }
+  krb5_addlenfield(rep->newpasswd.length, rep->newpasswd.data, 
+                   0, asn1_encode_octetstring);
+  krb5_makeseq();
+  krb5_cleanup();
+}
+
+krb5_error_code
+krb5_locate_dns_srv(krb5_context context, const krb5_data *realm,
+                    const char *service, const char *protocol,
+                    struct sockaddr **addr_pp, int *naddrs)
+{
+  int             len;
+  int             out;
+  int             j;
+  int             count;
+  unsigned char   reply[1024];
+  struct hostent  *hp;
+  unsigned char   *p;
+  char            host[128];
+  int             status;
+  int             priority;
+  int             weight;
+  u_short         port;
+  struct sockaddr *addr_p = NULL;
+  struct sockaddr_in *sin_p;
+    
+  out = 0;
+  addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr));
+  if (addr_p == NULL)
+         return(ENOMEM);
+  count = 1;
+
+#ifdef HAVE_SNPRINTF
+  snprintf(host, sizeof(host), "%s.%s.%*s.",
+                service, protocol, realm->length, realm->data);
+#else
+  sprintf(host, "%s.%s.%*s.",
+               service, protocol, realm->length, realm->data);
+#endif
+  len = res_search(host, C_IN, T_SRV, reply, sizeof(reply));
+  if (len >=0)
+    {
+         p = reply;
+           p += sizeof(HEADER);
+           status = dn_expand(reply, reply + len, p, host, sizeof(host));
+         if (status < 0)
+             goto out;
+           p += status;
+         p += 4;
+         while (p < reply + len)
+        {
+               int type, class, ttl, size;
+               status = dn_expand(reply, reply + len, p, host, sizeof(host));
+               if (status < 0)
+                       goto out;
+             p += status;
+               type = (p[0] << 8) | p[1];
+               p += 2;
+               class = (p[0] << 8) | p[1];
+               p += 2;
+             ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+               p += 4;
+               size = (p[0] << 8) | p[1];
+               p += 2;
+               if (type == T_SRV)
+            {
+                         status = dn_expand(reply, reply + len, p + 6, host, sizeof(host));
+                       if (status < 0)
+                         goto out;
+                         priority = (p[0] << 8) | p[1];
+                         weight = (p[2] << 8) | p[3];
+                         port = (p[4] << 8) | p[5];
+                       hp = (struct hostent *)gethostbyname(host);
+                       if (hp != 0)
+                {
+                             switch (hp->h_addrtype)
+                    {
+#ifdef KRB5_USE_INET
+                                 case AF_INET:
+                                         for (j=0; hp->h_addr_list[j]; j++)
+                          {
+                                             sin_p = (struct sockaddr_in *) &addr_p[out++];
+                                             memset ((char *)sin_p, 0, sizeof(struct sockaddr));
+                                             sin_p->sin_family = hp->h_addrtype;
+                                             sin_p->sin_port = htons(port);
+                                             memcpy((char *)&sin_p->sin_addr,
+                                                   (char *)hp->h_addr_list[j],
+                                                 sizeof(struct in_addr));
+                                           if (out+1 >= count)
+                              {
+                                                     count += 5;
+                                                       addr_p = (struct sockaddr *)
+                                                       realloc ((char *)addr_p,
+                                                             sizeof(struct sockaddr) * count);
+                                                       if (!addr_p)
+                                                         goto out;
+                                               }
+                                           }
+                                         break;
+#endif
+                               default:
+                                       break;
+                               }
+                           }
+                         p += size;
+                 }
+             }
+    }
+    
+out:
+  if (out == 0)
+    {
+     free(addr_p);
+     return(KRB5_REALM_CANT_RESOLVE);
+    }
+
+  *addr_pp = addr_p;
+  *naddrs = out;
+  return(0);
+}
+
+krb5_error_code 
+krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
+                    struct sockaddr **addr_pp, int *naddrs)
+{
+  krb5_error_code code;
+       code = krb5_locate_dns_srv(context, realm, "_kpasswd", "_udp",
+                                  addr_pp, naddrs);
+  if (code)
+    code = krb5_locate_dns_srv(context, realm, "_kpasswd", "_tcp",
+                               addr_pp, naddrs);
+
+  return(code);
+}
index db3869b63efecca23fac71f5180bb0534e0d64d8..3c3c97c1554d38e7e8029e8e3e3dac6f47d083a7 100755 (executable)
 #include <sys/types.h>
 #ifndef _WIN32
 #include <sys/uio.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
 #endif
 
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <lber.h>
 #include <krb5.h>
 #include "ldap-int.h"
 #include "gssldap-int.h"
 typedef gss_uint32  OM_uint32;
 #endif
 
+char ldap_domain_name[128];
+
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+#define LDAP_SERVICE   "_ldap"
+#define TCP_PROTOCOL   "_tcp"
+
+int locate_ldap_server(char *domain, char **server_name);
 int ldap_delete_tickets(LDAP *ld, char *service_name);
-static int negotiate_security_options(gssldap_client_state_t state, int layer);
+static int negotiate_security_options(gssldap_client_state_t state, 
+                                      int layer);
 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name);
-unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, 
-                                         gss_ctx_id_t context,
-                                         gsssasl_security_negotiation_t inmask, 
-                                         size_t masklength, 
-                                         gss_buffer_t wrapped_tok);
+unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
+                                          gsssasl_security_negotiation_t inmask,
+                                          size_t masklength, gss_buffer_t wrapped_tok);
+
 int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
-                                 gss_buffer_t wrapped_tok,
-                                 gsssasl_security_negotiation_t *outmask,
-                                 size_t *masklength);
+                                  gss_buffer_t wrapped_tok,
+                                  gsssasl_security_negotiation_t *outmask,
+                                  size_t *masklength);
 
 #ifdef GSSSASL_DEBUG
 static int debug_ = 1;
@@ -47,7 +60,7 @@ static int debug_ = 1;
 #define TRACE(x)
 #define LDAP_PERROR(ld, x)
 #define LOG_STATUS(msg, min, maj)
-#endif                         /* GSSSASL_DEBUG */
+#endif  /* GSSSASL_DEBUG */
 
 #ifdef HACK_SERVICE_NAME
 char *__service = NULL;
@@ -61,6 +74,129 @@ static gss_ctx_id_t security_context;
 static int security_layer = 0;
 static int security_token_size = 0;
 
+LDAP_CALLBACK int LDAP_C ldap_gssapi_read(LBER_SOCKET sock, void *data,
+                                          int len)
+{
+  OM_uint32   maj_stat;
+  OM_uint32   min_stat;
+  OM_uint32   rc;
+  OM_uint32   pdulen;
+  gss_buffer_desc recv_tok;
+  gss_buffer_desc wrapped_tok;
+
+  if (security_layer & 
+    (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION))
+    {
+      if (recv(sock, (char *)&pdulen, sizeof(pdulen), 0) != sizeof(pdulen))
+        return (0);
+      wrapped_tok.length = ntohl(pdulen);
+#ifdef GSSSASL_DEBUG
+      if (debug_)
+        {
+          fprintf(stderr, "Reading data of %d octets\n",
+                  wrapped_tok.length);
+        }
+#endif  /* GSSSASL_DEBUG */
+      if ((int)wrapped_tok.length > security_token_size)
+        return (0);
+      wrapped_tok.value = malloc(wrapped_tok.length);
+      if (wrapped_tok.value == NULL)
+        return (0);
+      if (recv(sock, wrapped_tok.value, wrapped_tok.length, 0)
+          != (int)wrapped_tok.length)
+        {
+          gss_release_buffer(&rc, &wrapped_tok);
+          return (0);
+        }
+      maj_stat = gss_unwrap(&min_stat,
+                            security_context,
+                            &wrapped_tok,
+                            &recv_tok,
+                            &rc,
+                            (gss_qop_t *) NULL);
+      if (maj_stat != GSS_S_COMPLETE)
+        {
+          gss_release_buffer(&rc, &wrapped_tok);
+          return maj_stat;
+        }
+#ifdef GSSSASL_DEBUG
+      if (debug_)
+        {
+          fprintf(stderr, "Got %d bytes of %s data\n",
+                  recv_tok.length, rc ? "private" : "signed");
+        }
+#endif  /* GSSSASL_DEBUG */
+      if ((int)recv_tok.length > len)
+        {
+          gss_release_buffer(&rc, &recv_tok);
+          gss_release_buffer(&rc, &wrapped_tok);
+          return GSS_S_FAILURE;
+        }
+      memcpy(data, recv_tok.value, recv_tok.length);
+      pdulen = recv_tok.length;
+      gss_release_buffer(&rc, &recv_tok);
+      gss_release_buffer(&rc, &wrapped_tok);
+
+      return pdulen;
+    } 
+  else
+    return read(sock, data, len);
+}
+
+LDAP_CALLBACK int LDAP_C ldap_gssapi_write(LBER_SOCKET sock, const void  *data,
+                                           int len)
+{
+  OM_uint32   maj_stat;
+  OM_uint32   min_stat;
+  OM_uint32   pdulen;
+  OM_uint32   rc;
+  gss_buffer_desc send_tok;
+  gss_buffer_desc wrapped_tok;
+  unsigned char   *ptr;
+
+  if (security_layer & 
+      (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION))
+    {
+      send_tok.length = len;
+      send_tok.value = (void *) data;
+#ifdef GSSSASL_DEBUG
+      if (debug_)
+        {
+          fprintf(stderr, "Sending %d bytes of data\n",
+                  len);
+        }
+#endif  /* GSSSASL_DEBUG */
+      maj_stat = gss_wrap(&min_stat,
+                          security_context,
+                          (security_layer & GSSSASL_PRIVACY_PROTECTION) ? 1 : 0,
+                          GSS_C_QOP_DEFAULT,
+                          &send_tok,
+                          &rc,
+                          &wrapped_tok);
+      if (maj_stat != GSS_S_COMPLETE)
+        return maj_stat;
+#ifdef GSSSASL_DEBUG
+      if (debug_)
+        {
+          fprintf(stderr, "Sent %d bytes of %s data\n",
+                  wrapped_tok.length, rc ? "private" : "signed");
+        }
+#endif  /* GSSSASL_DEBUG */
+      pdulen = htonl(wrapped_tok.length);
+      ptr = calloc(1, sizeof(pdulen) + wrapped_tok.length);
+      memcpy(ptr, &pdulen, sizeof(pdulen));
+      memcpy(&ptr[sizeof(pdulen)], wrapped_tok.value, wrapped_tok.length);
+      rc = send(sock, ptr, sizeof(pdulen) + wrapped_tok.length, 0);
+      free(ptr);
+      if (rc == (wrapped_tok.length + sizeof(pdulen)))
+        rc = len;
+      gss_release_buffer(&maj_stat, &wrapped_tok);
+      return rc;
+    } 
+  else
+    return send(sock, data, len, 0);
+}
+
 #ifdef GSSSASL_DEBUG
 /*
  * Dump the token to stderr
@@ -69,12 +205,14 @@ static void print_token(gss_buffer_t tok)
 {
   int i;
   unsigned char *p = tok->value;
-  
+
   for (i = 0; i < (int)tok->length; i++, p++)
     {
       fprintf(stderr, "%02x ", *p);
       if ((i % 16) == 15)
-       fprintf(stderr, "\n");
+        {
+          fprintf(stderr, "\n");
+        }
     }
   fprintf(stderr, "\n");
   fflush(stderr);
@@ -93,15 +231,22 @@ static void log_status_impl(const char *reason, OM_uint32 res, int type)
   msg_ctx = 0;
   while (1)
     {
-      maj_stat = gss_display_status(&min_stat, res, type, GSS_C_NULL_OID,
-                                   &msg_ctx, &msg);
+      maj_stat = gss_display_status(&min_stat,
+                                    res,
+                                    type,
+                                    GSS_C_NULL_OID,
+                                    &msg_ctx,
+                                    &msg);
 
       if (debug_)
-       fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n", (char *) msg.value,
-               reason);
+        {
+          fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n",
+                  (char *) msg.value,
+                  reason);
+        }
       (void) gss_release_buffer(&min_stat, &msg);
       if (!msg_ctx)
-       break;
+        break;
     }
   return;
 }
@@ -109,14 +254,14 @@ static void log_status_impl(const char *reason, OM_uint32 res, int type)
 /*
  * Cover function to handle a GSS-API error
  */
-static void log_status(const char *reason, OM_uint32 maj_stat, 
-                      OM_uint32 min_stat)
+static void log_status(const char *reason, OM_uint32 maj_stat,
+                       OM_uint32 min_stat)
 {
   log_status_impl(reason, maj_stat, GSS_C_GSS_CODE);
   log_status_impl(reason, min_stat, GSS_C_MECH_CODE);
   return;
 }
-#endif                         /* GSSSASL_DEBUG */
+#endif  /* GSSSASL_DEBUG */
 
 /*
  * Send a GSS-API token as part of a SASL BindRequest
@@ -130,9 +275,14 @@ static int send_token(gssldap_client_state_t state, gss_buffer_t send_tok)
   cred.bv_val = send_tok->value;
   cred.bv_len = send_tok->length;
 
-  if (ldap_sasl_bind(state->ld, state->binddn, GSSAPI_SASL_NAME, &cred,
-                    NULL, NULL, &state->msgid) != LDAP_SUCCESS)
-    {
+  if (ldap_sasl_bind(state->ld,
+                     state->binddn,
+                     GSSAPI_SASL_NAME,
+                     &cred,
+                     NULL,
+                     NULL,
+                     &state->msgid) != LDAP_SUCCESS)
+        {
       LDAP_PERROR(state->ld, "send_token");
       TRACE("<== send_token");
       return -1;
@@ -151,30 +301,36 @@ static int parse_bind_result(gssldap_client_state_t state)
 
   TRACE("==> parse_bind_result");
 
-  if (ldap_result(state->ld, state->msgid, LDAP_MSG_ALL, NULL, &res) <= 0) 
+  if (ldap_result(state->ld,
+                  state->msgid,
+                  LDAP_MSG_ALL,
+                  NULL,
+                  &res) <= 0) 
     {
       LDAP_PERROR(state->ld, "ldap_result");
       TRACE("<== parse_bind_result");
       return -1;
     }
-  for (msg = ldap_first_message(state->ld, res); msg != NULL;
-       msg = ldap_next_message(state->ld, msg)) 
+  for (msg = ldap_first_message(state->ld, res);
+  msg != NULL;
+  msg = ldap_next_message(state->ld, msg)) 
     {
       if (ldap_msgtype(msg) == LDAP_RES_BIND)
-       {
-         ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0);
-         break;
-       }
-    }
+        {
+          ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0);
+          break;
+        }
+     }
 
   ldap_msgfree(res);
   state->msgid = -1;
-  
+
   TRACE("<== parse_bind_result");
-  
+
   if (rc == LDAP_SUCCESS) 
-    return 0;
-  
+    {
+      return 0;
+    }
   state->rc = rc;
   return -1;
 }
@@ -201,44 +357,51 @@ static int recv_token(gssldap_client_state_t state, gss_buffer_t recv_tok)
   recv_tok->value = NULL;
   recv_tok->length = 0;
 
-  for (msg = ldap_first_message(state->ld, res); msg != NULL;
-       msg = ldap_next_message(state->ld, msg)) 
+  for (msg = ldap_first_message(state->ld, res);
+  msg != NULL;
+  msg = ldap_next_message(state->ld, msg)) 
     {
-      if (ldap_msgtype(msg) == LDAP_RES_BIND && servercred == NULL) 
-        {
-         rc = ldap_parse_sasl_bind_result(state->ld, msg, &servercred, 0);
-         if (rc == LDAP_SUCCESS && servercred != NULL) 
-            {
-             recv_tok->value = malloc(servercred->bv_len);
-             if (recv_tok->value != NULL) 
-                {
-                 memcpy(recv_tok->value, servercred->bv_val, 
-                        servercred->bv_len);
-                 recv_tok->length = servercred->bv_len;
-                }
-             break;
-            } 
-         else 
-            {
-             state->rc = rc;
-            }
-        }
-    }
+    if (ldap_msgtype(msg) == LDAP_RES_BIND && servercred == NULL) 
+      {
+        rc = ldap_parse_sasl_bind_result(state->ld,
+                                         msg,
+                                         &servercred,
+                                         0);
+        if (rc == LDAP_SUCCESS && servercred != NULL) 
+          {
+            recv_tok->value = malloc(servercred->bv_len);
+            if (recv_tok->value != NULL) 
+              {
+                memcpy(recv_tok->value, servercred->bv_val, servercred->bv_len);
+                recv_tok->length = servercred->bv_len;
+              }
+            break;
+          } 
+        else 
+          {
+            state->rc = rc;
+          }
+      }
+  }
 
   ldap_msgfree(res);
   state->msgid = -1;
   TRACE("<== recv_token");
   if (servercred != NULL) 
     {
-      nslberi_free(servercred);
+       nslberi_free(servercred);
       TRACE("<== recv_token");
       return 0;
-    }
+      }
   if (state->rc == LDAP_SUCCESS) 
-    state->rc = LDAP_OPERATIONS_ERROR;
+    {
+      state->rc = LDAP_OPERATIONS_ERROR;
+    } 
   else 
-    LDAP_PERROR(state->ld, "recv_token");
-  
+    {
+      LDAP_PERROR(state->ld, "recv_token");
+    }
+
   TRACE("<== recv_token");
   return -1;
 }
@@ -257,16 +420,16 @@ static int recv_token(gssldap_client_state_t state, gss_buffer_t recv_tok)
  * to GSS_Init_sec_context, repeating the actions in this paragraph.
  */
 static int client_establish_context(LDAP *ld, gssldap_client_state_t state, 
-                                   char *service_name)
+                                    char *service_name)
 {
   gss_buffer_desc send_tok;
   gss_buffer_desc recv_tok;
   gss_buffer_desc *token_ptr;
-  gss_name_t target_name;
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
-  gss_OID oid = GSS_C_NULL_OID;
-  OM_uint32 ret_flags;
+  gss_name_t      target_name;
+  OM_uint32       maj_stat;
+  OM_uint32       min_stat;
+  gss_OID         oid = GSS_C_NULL_OID;
+  OM_uint32       ret_flags;
 
   TRACE("==> client_establish_context");
 
@@ -274,8 +437,10 @@ static int client_establish_context(LDAP *ld, gssldap_client_state_t state,
   send_tok.value = service_name;
   send_tok.length = strlen(send_tok.value) + 1;
 
-  maj_stat = gss_import_name(&min_stat, &send_tok, 
-                            (gss_OID) gss_nt_service_name, &target_name);
+  maj_stat = gss_import_name(&min_stat,
+                             &send_tok,
+                             (gss_OID) gss_nt_service_name,
+                             &target_name);
   if (ldap_reset_principal(ld, service_name, target_name))
     {
       TRACE("<== client_establish_context");
@@ -284,68 +449,76 @@ static int client_establish_context(LDAP *ld, gssldap_client_state_t state,
 
   token_ptr = GSS_C_NO_BUFFER;
   state->context = GSS_C_NO_CONTEXT;
-  
+
   do 
     {
-      maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL,
-                                     &state->context, target_name, oid,
-                                     GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
-                                     0, NULL, token_ptr, NULL, &send_tok,
-                                      &ret_flags, NULL);
+      maj_stat = gss_init_sec_context(&min_stat,
+                                        GSS_C_NO_CREDENTIAL,
+                                        &state->context,
+                                        target_name,
+                                        oid,
+                                        GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+                                        0,
+                                        NULL,
+                                        token_ptr,
+                                        NULL,
+                                        &send_tok,
+                                        &ret_flags,
+                                        NULL);
 
       if (token_ptr != GSS_C_NO_BUFFER)
-       (void) gss_release_buffer(&min_stat, &recv_tok);
+        (void) gss_release_buffer(&min_stat, &recv_tok);
 
       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
-       {
-         LOG_STATUS("initializing context", maj_stat, min_stat);
-         (void) gss_release_name(&min_stat, &target_name);
-         TRACE("<== client_establish_context");
-         return -1;
-       }
+        {
+          LOG_STATUS("initializing context", maj_stat, min_stat);
+          (void) gss_release_name(&min_stat, &target_name);
+          TRACE("<== client_establish_context");
+          return -1;
+        }
 #ifdef GSSSASL_DEBUG
       if (debug_) 
-       {
-         fprintf(stderr, "Sending init_sec_context token (size=%d)...\n",
-                 send_tok.length);
-         fflush(stderr);
-         print_token(&send_tok);
-       }
+        {
+          fprintf(stderr, "Sending init_sec_context token (size=%d)...\n",
+          send_tok.length);
+          fflush(stderr);
+          print_token(&send_tok);
+        }
 #endif
       if (send_token(state, &send_tok) < 0)
-       {
-         TRACE("Send_token failed");
-         (void) gss_release_buffer(&min_stat, &send_tok);
-         (void) gss_release_name(&min_stat, &target_name);
-         TRACE("<== client_establish_context");
-         return -1;
-       }
+        {
+          TRACE("Send_token failed");
+          (void) gss_release_buffer(&min_stat, &send_tok);
+          (void) gss_release_name(&min_stat, &target_name);
+          TRACE("<== client_establish_context");
+          return -1;
+        }
       (void) gss_release_buffer(&min_stat, &send_tok);
       if (maj_stat == GSS_S_CONTINUE_NEEDED) 
-       {
-         TRACE("continue needed...");
-         if (recv_token(state, &recv_tok) < 0) 
-           {
-             TRACE("recv_token failed");
-             (void) gss_release_name(&min_stat, &target_name);
-             TRACE("<== client_establish_context");
-             return -1;
-           }
+        {
+          TRACE("continue needed...");
+          if (recv_token(state, &recv_tok) < 0) 
+            {
+              TRACE("recv_token failed");
+              (void) gss_release_name(&min_stat, &target_name);
+              TRACE("<== client_establish_context");
+              return -1;
+            }
 #ifdef GSSSASL_DEBUG
-         if (debug_)
-           {
-             fprintf(stderr, "Received token (size=%d)...\n",
-                     recv_tok.length);
-             fflush(stderr);
-             print_token(&recv_tok);
-           }
+          if (debug_)
+            {
+              fprintf(stderr, "Received token (size=%d)...\n",
+              recv_tok.length);
+              fflush(stderr);
+              print_token(&recv_tok);
+            }
 #endif
-         token_ptr = &recv_tok;
-       }
+          token_ptr = &recv_tok;
+        }
     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
 
   (void) gss_release_name(&min_stat, &target_name);
-  
+
   TRACE("<== client_establish_context");
   return 0;
 }
@@ -369,19 +542,20 @@ static int client_establish_context(LDAP *ld, gssldap_client_state_t state,
  * generated output_message.  The client can then consider the server
  * authenticated.
  */
-static int negotiate_security_options(gssldap_client_state_t state, int layer)
+static int negotiate_security_options(gssldap_client_state_t state, 
+                                      int layer)
 {
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
+  OM_uint32       maj_stat;
+  OM_uint32       min_stat;
   gss_buffer_desc recv_tok;
   gss_buffer_desc send_tok;
-  OM_uint32 rc;
-  size_t mask_length;
-  gsssasl_security_negotiation_t send_mask;
-  gsssasl_security_negotiation_t recv_mask;
-    
+  OM_uint32       rc;
+  size_t          mask_length;
+  gsssasl_security_negotiation_t  send_mask;
+  gsssasl_security_negotiation_t  recv_mask;
+
   TRACE("==> negotiate_security_options");
-    
+
   memset(&send_tok, '\0', sizeof(send_tok));
   memset(&recv_tok, '\0', sizeof(recv_tok));
   if ((rc = recv_token(state, &recv_tok)) < 0)
@@ -391,95 +565,101 @@ static int negotiate_security_options(gssldap_client_state_t state, int layer)
     }
 #ifdef GSSSASL_DEBUG
   if (debug_)
-        {
-         fprintf(stderr, "Received token (size=%d)...\n",
-                 recv_tok.length);
-         fflush(stderr);
-         print_token(&recv_tok);
-        }
-#endif                         /* GSSSASL_DEBUG */
-  
-    maj_stat = gsssasl_unpack_security_token(&min_stat, state->context,
-                                             &recv_tok, &recv_mask, 
-                                            &mask_length);
-
-    if (maj_stat != GSS_S_COMPLETE)
-      {
-        LOG_STATUS("unpacking security negotiation token", maj_stat, min_stat);
-        TRACE("<== negotiate_security_options (unpack failed)");
-        return -1;
+    {
+      fprintf(stderr, "Received token (size=%d)...\n",
+      recv_tok.length);
+      fflush(stderr);
+      print_token(&recv_tok);
       }
+#endif  /* GSSSASL_DEBUG */
+
+  maj_stat = gsssasl_unpack_security_token(&min_stat,
+                                           state->context,
+                                           &recv_tok,
+                                           &recv_mask,
+                                           &mask_length);
+
+  if (maj_stat != GSS_S_COMPLETE)
+    {
+      LOG_STATUS("unpacking security negotiation token",
+                 maj_stat,
+                 min_stat);
+      TRACE("<== negotiate_security_options (unpack failed)");
+      return -1;
+    }
 #ifdef GSSSASL_DEBUG
-    if (debug_) 
-      {
-        fprintf(stderr, "Received security token level %d size %d\n",
-               recv_mask->security_layer,
-               recv_mask->token_size);
+  if (debug_) 
+    {
+      fprintf(stderr, "Received security token level %d size %d\n",
+      recv_mask->security_layer,
+      recv_mask->token_size);
       }
 #endif
-    if ((~recv_mask->security_layer) & layer) 
-      {
-        free(recv_mask);
-        TRACE("<== negotiate_security_options (unsupported security layer)");
-        return -1;
-      }
-    mask_length = 
-      sizeof(recv_mask) + GSSAPI_LDAP_DN_PREFIX_LEN + strlen(state->binddn);
-    send_mask = NSLDAPI_MALLOC(mask_length);
-    if (send_mask == NULL) 
-      {
-        free(recv_mask);
-        TRACE("<== negotiate_security_options (malloc failed)");
-        return -1;
+  if ((~recv_mask->security_layer) & layer) 
+    {
+      free(recv_mask);
+      TRACE("<== negotiate_security_options (unsupported security layer)");
+      return -1;
       }
-    send_mask->security_layer = layer;
-    send_mask->token_size = recv_mask->token_size;
-    memcpy(send_mask->identity, GSSAPI_LDAP_DN_PREFIX, 
-          GSSAPI_LDAP_DN_PREFIX_LEN);
-    memcpy(send_mask->identity + GSSAPI_LDAP_DN_PREFIX_LEN, state->binddn,
-           mask_length - sizeof(recv_mask) - GSSAPI_LDAP_DN_PREFIX_LEN);
-
-    free(recv_mask);
-    
+  mask_length = sizeof(recv_mask) + 
+                       GSSAPI_LDAP_DN_PREFIX_LEN + strlen(state->binddn);
+  send_mask = NSLDAPI_MALLOC(mask_length);
+  if (send_mask == NULL) 
+    {
+      free(recv_mask);
+      TRACE("<== negotiate_security_options (malloc failed)");
+      return -1;
+    }
+  send_mask->security_layer = layer;
+  send_mask->token_size = recv_mask->token_size;
+  memcpy(send_mask->identity, GSSAPI_LDAP_DN_PREFIX, GSSAPI_LDAP_DN_PREFIX_LEN);
+  memcpy(send_mask->identity + GSSAPI_LDAP_DN_PREFIX_LEN,
+         state->binddn,
+         mask_length - sizeof(recv_mask) - GSSAPI_LDAP_DN_PREFIX_LEN);
+  free(recv_mask);
+
 #ifdef GSSSASL_DEBUG
-    if (debug_) 
-      {
-        fprintf(stderr, "Sending security token level %d size %d\n",
-               send_mask->security_layer,
-               send_mask->token_size);
-      }
+  if (debug_) 
+    {
+      fprintf(stderr, "Sending security token level %d size %d\n",
+      send_mask->security_layer,
+      send_mask->token_size);
+    }
 #endif
-    maj_stat = gsssasl_pack_security_token(&min_stat, state->context,
-                                           send_mask, mask_length, &send_tok);
-    if (maj_stat != GSS_S_COMPLETE)
-      {
-        LOG_STATUS("packing security negotiation token", maj_stat, min_stat);
-        NSLDAPI_FREE(send_mask);
-        TRACE("<== negotiate_security_options (pack failed)");
-        return -1;
-      }
-    if ((rc = send_token(state, &send_tok)) < 0)
-      {
-        NSLDAPI_FREE(send_mask);
-        TRACE("<== negotiate_security_options (send_token failed)");
-        return rc;
+  maj_stat = gsssasl_pack_security_token(&min_stat,
+                                         state->context,
+                                         send_mask,
+                                         mask_length,
+                                         &send_tok);
+  if (maj_stat != GSS_S_COMPLETE)
+    {
+      LOG_STATUS("packing security negotiation token", maj_stat, min_stat);
+      NSLDAPI_FREE(send_mask);
+      TRACE("<== negotiate_security_options (pack failed)");
+      return -1;
+    }
+  if ((rc = send_token(state, &send_tok)) < 0)
+    {
+      NSLDAPI_FREE(send_mask);
+      TRACE("<== negotiate_security_options (send_token failed)");
+      return rc;
+    }
+  rc = parse_bind_result(state);
+
+  if (rc == 0) 
+    {
+      security_context = state->context;
+      security_layer = layer;
+      security_token_size = send_mask->token_size;
       }
-    rc = parse_bind_result(state);
-    
-    if (rc == 0) 
-        {
-         security_context = state->context;
-         security_layer = layer;
-         security_token_size = send_mask->token_size;
-        }
 
-    NSLDAPI_FREE(send_mask);
-    if (send_tok.value != NULL)
-      gss_release_buffer(&rc, &send_tok);
-    if (recv_tok.value != NULL)
-      gss_release_buffer(&rc, &recv_tok);
-    TRACE("<== negotiate_security_options");
-    return rc;
+  NSLDAPI_FREE(send_mask);
+  if (send_tok.value != NULL)
+    gss_release_buffer(&rc, &send_tok);
+  if (recv_tok.value != NULL)
+    gss_release_buffer(&rc, &recv_tok);
+  TRACE("<== negotiate_security_options");
+  return rc;
 }
 
 #ifdef GSSSASL_DEBUG
@@ -493,7 +673,7 @@ LDAP_CALL ldap_gssapi_debug(int on)
   debug_ = on;
   return old;
 }
-#endif                         /* GSSSASL_DEBUG */
+#endif  /* GSSSASL_DEBUG */
 
 /*
  * Public function for doing a GSS-API SASL bind
@@ -502,112 +682,139 @@ LDAP_API(int)
 LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer)
 {
   gssldap_client_state_desc state;
-  char *service_name;
-  OM_uint32 min_stat;
-  int rc;
-  int i;
+  char        *service_name;
+  OM_uint32   min_stat;
+  int         rc;
+  int         i;
+  struct ldap_io_fns iofns;
 
   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
-    return -1;
-  
+    {
+      return -1;
+    }
+
   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
 
-  service_name = NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + 
-                               strlen(ld->ld_defhost));
+  service_name = 
+    NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + strlen(ld->ld_defhost));
   if (service_name == NULL) 
-    return -1;
-
+    {
+      return -1;
+    }
   strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@");
   strcat(service_name, ld->ld_defhost);
 
 #ifdef GSSSASL_DEBUG
-    if (debug_) 
-      {
-        fprintf(stderr, "LDAP service name: %s\n", service_name);
-        fflush(stderr);
-      }
+  if (debug_) 
+    {
+      fprintf(stderr, "LDAP service name: %s\n", service_name);
+      fflush(stderr);
+    }
 #endif
 
-    state.msgid = -1;
-    state.ld = ld;
-    state.binddn = who;
-    state.context = GSS_C_NO_CONTEXT;
-    state.rc = LDAP_OPERATIONS_ERROR;
+  state.msgid = -1;
+  state.ld = ld;
+  state.binddn = who;
+  state.context = GSS_C_NO_CONTEXT;
+  state.rc = LDAP_OPERATIONS_ERROR;
 
-    rc = client_establish_context(ld, &state, service_name);
-    if (rc == 0) 
+  rc = client_establish_context(ld, &state, service_name);
+  if (rc == 0) 
+    {
       rc = negotiate_security_options(&state, layer);
-    if (rc == 0) 
-      {
+    }
+  if (rc == 0) 
+    {
 #ifdef GSSSASL_DEBUG
-        gss_buffer_desc tname;
-        gss_buffer_desc sname;
-        gss_name_t targ_name;
-        gss_name_t src_name;
-        OM_uint32 context_flags;
-        OM_uint32 lifetime;
-        OM_uint32 maj_stat;
-        int is_open;
-        int is_local;
-        gss_OID mechanism;
-        gss_OID name_type;
-
-        maj_stat = gss_inquire_context(&min_stat, state.context, &src_name,
-                                      &targ_name, &lifetime, &mechanism,
-                                      &context_flags, &is_local, &is_open);
-        if (maj_stat != GSS_S_COMPLETE) 
-            {
-             LOG_STATUS("inquiring context", maj_stat, min_stat);
-             return LDAP_OPERATIONS_ERROR;
-            }
-        maj_stat = gss_display_name(&min_stat, src_name, &sname, &name_type);
-        if (maj_stat != GSS_S_COMPLETE) 
-         {
-            LOG_STATUS("displaying source name", maj_stat, min_stat);
-            return LDAP_OPERATIONS_ERROR;
-         }
-        maj_stat = gss_display_name(&min_stat, targ_name, &tname,
-                                    (gss_OID *) NULL);
-        if (maj_stat != GSS_S_COMPLETE) 
-         {
-            LOG_STATUS("displaying target name", maj_stat, min_stat);
-            return LDAP_OPERATIONS_ERROR;
-         }
-        if (debug_) 
-         {
-            fprintf(stderr, "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
-                    (int) sname.length, (char *) sname.value,
-                    (int) tname.length, (char *) tname.value, lifetime,
-                    context_flags,
-                    (is_local) ? "locally initiated" : "remotely initiated",
-                    (is_open) ? "open" : "closed");
-            fflush(stderr);
-         }
-        (void) gss_release_name(&min_stat, &src_name);
-        (void) gss_release_name(&min_stat, &targ_name);
-        (void) gss_release_buffer(&min_stat, &sname);
-        (void) gss_release_buffer(&min_stat, &tname);
+      gss_buffer_desc tname;
+      gss_buffer_desc sname;
+      gss_name_t      targ_name;
+      gss_name_t      src_name;
+      OM_uint32       context_flags;
+      OM_uint32       lifetime;
+      OM_uint32       maj_stat;
+      int             is_open;
+      int             is_local;
+      gss_OID         mechanism;
+      gss_OID         name_type;
+
+      maj_stat = gss_inquire_context(&min_stat,
+                                      state.context,
+                                      &src_name,
+                                      &targ_name,
+                                      &lifetime,
+                                      &mechanism,
+                                      &context_flags,
+                                      &is_local,
+                                      &is_open);
+      if (maj_stat != GSS_S_COMPLETE) 
+        {
+          LOG_STATUS("inquiring context", maj_stat, min_stat);
+          return LDAP_OPERATIONS_ERROR;
+        }
+      maj_stat = gss_display_name(&min_stat,
+                                  src_name,
+                                  &sname,
+                                  &name_type);
+      if (maj_stat != GSS_S_COMPLETE) 
+        {
+          LOG_STATUS("displaying source name", maj_stat, min_stat);
+          return LDAP_OPERATIONS_ERROR;
+        }
+      maj_stat = gss_display_name(&min_stat,
+                                  targ_name,
+                                  &tname,
+                                  (gss_OID *) NULL);
+      if (maj_stat != GSS_S_COMPLETE) 
+        {
+          LOG_STATUS("displaying target name", maj_stat, min_stat);
+          return LDAP_OPERATIONS_ERROR;
+        }
+      if (debug_) 
+        {
+          fprintf(stderr, 
+                  "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
+                  (int) sname.length, (char *) sname.value,
+                  (int) tname.length, (char *) tname.value, lifetime,
+                  context_flags,
+                  (is_local) ? "locally initiated" : "remotely initiated",
+                  (is_open) ? "open" : "closed");
+          fflush(stderr);
+        }
+      (void) gss_release_name(&min_stat, &src_name);
+      (void) gss_release_name(&min_stat, &targ_name);
+      (void) gss_release_buffer(&min_stat, &sname);
+      (void) gss_release_buffer(&min_stat, &tname);
 #endif
-        state.rc = LDAP_SUCCESS;
-      }
-    NSLDAPI_FREE(service_name);
-    LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL);
+      state.rc = LDAP_SUCCESS;
+    }
 
-    if (state.context != GSS_C_NO_CONTEXT)
-      gss_delete_sec_context(&min_stat, &state.context, GSS_C_NO_BUFFER);
-    return state.rc;
+  if (state.rc == LDAP_SUCCESS)
+    {
+      if (layer = GSSSASL_PRIVACY_PROTECTION)
+        {
+          memset(&iofns, 0, sizeof(iofns));
+          iofns.liof_read = ldap_gssapi_read;
+          iofns.liof_write = ldap_gssapi_write;
+          state.rc = ldap_set_option(ld, LDAP_OPT_IO_FN_PTRS, &iofns);
+        }
+    }
+
+  NSLDAPI_FREE(service_name);
+  LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL);
+
+  return state.rc;
 }
 
 /* Wrap and encode a security negotiation token */
-unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat,
-                                         gss_ctx_id_t context,
-                                         gsssasl_security_negotiation_t inmask,
-                                         size_t masklength, 
-                                         gss_buffer_t wrapped_tok)
+unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, 
+                             gss_ctx_id_t context,
+                             gsssasl_security_negotiation_t inmask,
+                             size_t masklength, gss_buffer_t wrapped_tok)
 {
-  OM_uint32 maj_stat;
-  OM_uint32 rc;
+  OM_uint32       maj_stat;
+  OM_uint32       rc;
   gss_buffer_desc send_tok;
 
   wrapped_tok->length = 0;
@@ -621,8 +828,13 @@ unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat,
   send_tok.length = masklength;
   send_tok.value = inmask;
 
-  maj_stat = gss_wrap(min_stat, context, 0, GSS_C_QOP_DEFAULT, &send_tok,
-                     (int *)&rc, wrapped_tok);
+  maj_stat = gss_wrap(min_stat,
+                      context,
+                      0,
+                      GSS_C_QOP_DEFAULT,
+                      &send_tok,
+                      (int *)&rc,
+                      wrapped_tok);
 
   inmask->token_size = ntohl(inmask->token_size);
 
@@ -630,36 +842,42 @@ unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat,
 }
 
 /* Unwrap and decode a security negotiation token. */
-int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
-                                 gss_buffer_t wrapped_tok,
-                                 gsssasl_security_negotiation_t *outmask,
-                                 size_t *masklength)
+int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, 
+                                  gss_buffer_t wrapped_tok,
+                                  gsssasl_security_negotiation_t *outmask, 
+                                  size_t *masklength)
 {
-  OM_uint32 maj_stat;
-  OM_uint32 rc;
+  OM_uint32       maj_stat;
+  OM_uint32       rc;
   gss_buffer_desc recv_tok;
 
   *masklength = 0;
   *outmask = NULL;
   memset(&recv_tok, '\0', sizeof(recv_tok));
 
-  maj_stat = gss_unwrap(min_stat, context, wrapped_tok, &recv_tok,
-                       (int *)&rc, (gss_qop_t *) NULL);
+  maj_stat = gss_unwrap(min_stat,
+                        context,
+                        wrapped_tok,
+                        &recv_tok,
+                        (int *)&rc,
+                        (gss_qop_t *) NULL);
   if (maj_stat != GSS_S_COMPLETE)
     return maj_stat;
 
+/*
 #ifdef _WIN32
   if (recv_tok.length < sizeof(gsssasl_security_negotiation_desc)) 
     {
       gss_release_buffer(&rc, &recv_tok);
       return GSS_S_FAILURE;
     }
-#endif /*WIN32*/
+#endif
+*/
 
-    /*
-     * we're lazy and don't copy the token. This could cause
-     * problems if libgssapi uses a different malloc!
-     */
+  /*
+   * we're lazy and don't copy the token. This could cause
+   * problems if libgssapi uses a different malloc!
+   */
   *masklength = recv_tok.length;
   *outmask = (gsssasl_security_negotiation_t) recv_tok.value;
   if (*outmask == NULL) 
@@ -672,100 +890,60 @@ int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
 
 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name)
 {
-  krb5_context context = NULL;
-  krb5_principal princ;
-  krb5_principal princ1;
-  krb5_principal temp_princ;
-  krb5_data *ptr = NULL;
-  char sname = NULL;
-  char *realm = NULL;
-  char *server = NULL;
-  char *host = NULL;
-  char *cptr = NULL;
-  char temp[1024];
-  int i;
-  int rc;
+  krb5_context    context = NULL;
+  krb5_principal  princ;
+  krb5_principal  princ1;
+  krb5_principal  temp_princ;
+  char            *realm;
+  char            *server_name = NULL;
+  int             i;
 
-  rc = -1;
   princ = (krb5_principal)(target_name);
-  
+
   if (krb5_init_context(&context))
-    return(rc);
-  sname = strdup(service_name);
-  if ((realm = strchr(sname, '@'))) 
-    {
-      *realm = '\0';
-      realm++;
-    }
-  
-  if ((cptr = strchr(sname, '/')))
-    *cptr = '\0';
-  
-  server = strdup(realm);
-  for (i = 0; i < (int)strlen(server); i++)
-    server[i] = tolower(server[i]);
-
-  if (princ->length != 0)
-    {
-      ptr = krb5_princ_component(context, princ, (princ->length - 1));
-      if (ptr != NULL)
-       {
-         if (ptr->length != 0)
-           {
-             host = strdup(ptr->data);
-             if ((cptr = strchr(host, '.'))) 
-               *cptr = '\0';
-           }
-       }
-    }
-  ptr = NULL;
+    return(-1);
+
+  realm = strdup(ldap_domain_name);
+  for (i = 0; i < (int)strlen(realm); i++)
+    realm[i] = toupper(realm[i]);
+  server_name = strdup(ld->ld_defhost);
+  for (i = 0; i < (int)strlen(server_name); i++)
+    server_name[i] = tolower(server_name[i]);
 
-  if (host != NULL)
-    sprintf(temp, "%s.%s", host, server);
-  else
-        sprintf(temp, "%s", server);
-  
   temp_princ = malloc(sizeof(*princ));
   memcpy(temp_princ, princ, sizeof(*princ));
 
-  krb5_build_principal(context, &princ1, strlen(realm), realm, sname, temp
-                      server, 0);
+  krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap"
+                       server_name, ldap_domain_name, 0);
 
   memcpy(princ, princ1, sizeof(*princ1));
   free(princ1);
   krb5_free_principal(context, temp_princ);
-  
-/*
- *   if (host != NULL)
- *       sprintf(temp, "%s/%s.%s", sname, host, server);
- *   else
- *       sprintf(temp, "%s/%s", sname, server);
- *   rc = 0;
- */
-  if (server != NULL)
-    free(server);
-  if (sname != NULL)
-    free(sname);
-  if (host != NULL)
-    free(host);
+
+  if (realm != NULL)
+    free(realm);
+  if (server_name != NULL)
+    free(server_name);
   if (context != NULL)
     krb5_free_context(context);
-  return 0;
+  return(0);
 }
 
 int ldap_delete_tickets(LDAP *ld, char *service_name)
 {
-  int i;
-  int rc;
-  krb5_context context = NULL;
-  krb5_ccache v5Cache = NULL;
-  krb5_creds creds;
-  krb5_cc_cursor v5Cursor;
+  int             i;
+  int             rc;
+  krb5_context    context = NULL;
+  krb5_ccache     v5Cache = NULL;
+  krb5_creds      creds;
+  krb5_cc_cursor  v5Cursor;
   krb5_error_code code;
-  char *sServerName;
+  char            *sServerName;
 
   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
-    return -1;
+    {
+      return -1;
+    }
 
   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
@@ -785,17 +963,21 @@ int ldap_delete_tickets(LDAP *ld, char *service_name)
   while (!(code = krb5_cc_next_cred(context, v5Cache, &v5Cursor, &creds))) 
     {
       if (krb5_unparse_name(context, creds.server, &sServerName))
-       {
-         krb5_free_cred_contents(context, &creds);
-         continue;
-       }
+        {
+          krb5_free_cred_contents(context, &creds);
+          continue;
+        }
       if (!memcmp(sServerName, service_name, strlen(service_name)))
-       krb5_cc_remove_cred(context, v5Cache, 0, &creds);
+        {
+          krb5_cc_remove_cred(context, v5Cache, 0, &creds);
+        }
       continue;
     }
-  
+
   if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))
-    krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
+    {
+      krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
+    }
   rc = 0;
 
 cleanup:
@@ -805,3 +987,59 @@ cleanup:
     krb5_free_context(context);
   return(rc);
 }
+
+int locate_ldap_server(char *domain, char **server_name)
+{
+  char  service[128];
+  char  host[128];
+  int   location_type;
+  int   length;
+  int   rc;
+  int   return_code;
+  int   entry_length;
+  int   server_count;
+  unsigned char   reply[1024];
+  unsigned char   *ptr;
+    
+  strcpy(ldap_domain_name, domain);
+  sprintf(service, "%s.%s.%s.", LDAP_SERVICE, TCP_PROTOCOL, domain);
+
+  return_code = -1;
+  server_count = 0;
+  memset(reply, '\0', sizeof(reply));
+  length = res_search(service, C_IN, T_SRV, reply, sizeof(reply));
+  if (length >= 0)
+    {
+      ptr = reply;
+      ptr += sizeof(HEADER);
+      if ((rc = dn_expand(reply, reply + length, ptr, host, 
+                          sizeof(host))) < 0)
+        return(-1);
+      ptr += (rc + 4);
+
+      while (ptr < reply + length)
+        {
+          if ((rc = dn_expand(reply, reply + length, ptr, host, 
+                              sizeof(host))) < 0)
+            break;
+          ptr += rc;
+          location_type = (ptr[0] << 8) | ptr[1];
+          ptr += 8;
+               entry_length = (ptr[0] << 8) | ptr[1];
+          ptr += 2;
+          if (location_type == T_SRV)
+            {
+              if ((rc = dn_expand(reply, reply + length, ptr + 6, host, 
+                                  sizeof(host))) < 0)
+                return -1;
+              
+              (*server_name) = strdup(host);
+              ++server_name;
+              return_code = 1;
+              server_count++;
+            }
+        ptr += entry_length;
+        }
+    }
+  return(return_code);
+}
diff --git a/incremental/winad/setpw.c b/incremental/winad/setpw.c
new file mode 100644 (file)
index 0000000..905e61a
--- /dev/null
@@ -0,0 +1,657 @@
+/*--
+
+THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+PARTICULAR PURPOSE.
+
+Copyright (C) 1999  Microsoft Corporation.  All rights reserved.
+
+Module Name:
+
+    ksetpw.c
+
+Abstract:
+
+    Set a user's password using the
+    Kerberos Change Password Protocol (I-D) variant for Windows 2000
+
+--*/
+/*
+ * lib/krb5/os/changepw.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may 
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#define NEED_SOCKETS
+#include <krb5.h>
+#include <krb.h>
+#ifdef _WIN32
+#include "k5-int.h"
+#include "adm_err.h"
+#include "krb5_err.h"
+#endif
+#include <auth_con.h>
+#include "kpasswd.h"
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/select.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/timeb.h>
+#include <errno.h>
+
+
+#define PW_LENGTH 25
+
+#ifndef krb5_is_krb_error
+#define krb5_is_krb_error(dat)\
+       ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\
+                                   (dat)->data[0] == 0x5e))
+#endif
+
+/* Win32 defines. */
+#if defined(_WIN32) && !defined(__CYGWIN32__)
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#endif /* _WIN32 && !__CYGWIN32__ */
+
+static const char rcsid[] = "$Id$";
+
+static int frequency[26][26] =
+{ {4, 20, 28, 52, 2, 11, 28, 4, 32, 4, 6, 62, 23, 167, 2, 14, 0, 83, 76, 
+127, 7, 25, 8, 1, 9, 1}, /* aa - az */
+   {13, 0, 0, 0, 55, 0, 0, 0, 8, 2, 0, 22, 0, 0, 11, 0, 0, 15, 4, 2, 13, 0, 
+0, 0, 15, 0}, /* ba - bz */
+   {32, 0, 7, 1, 69, 0, 0, 33, 17, 0, 10, 9, 1, 0, 50, 3, 0, 10, 0, 28, 11, 
+0, 0, 0, 3, 0}, /* ca - cz */
+   {40, 16, 9, 5, 65, 18, 3, 9, 56, 0, 1, 4, 15, 6, 16, 4, 0, 21, 18, 53, 
+19, 5, 15, 0, 3, 0}, /* da - dz */
+   {84, 20, 55, 125, 51, 40, 19, 16, 50, 1, 4, 55, 54, 146, 35, 37, 6, 191, 
+149, 65, 9, 26, 21, 12, 5, 0}, /* ea - ez */
+   {19, 3, 5, 1, 19, 21, 1, 3, 30, 2, 0, 11, 1, 0, 51, 0, 0, 26, 8, 47, 6, 
+3, 3, 0, 2, 0}, /* fa - fz */
+   {20, 4, 3, 2, 35, 1, 3, 15, 18, 0, 0, 5, 1, 4, 21, 1, 1, 20, 9, 21, 9, 
+0, 5, 0, 1, 0}, /* ga - gz */
+   {101, 1, 3, 0, 270, 5, 1, 6, 57, 0, 0, 0, 3, 2, 44, 1, 0, 3, 10, 18, 6, 
+0, 5, 0, 3, 0}, /* ha - hz */
+   {40, 7, 51, 23, 25, 9, 11, 3, 0, 0, 2, 38, 25, 202, 56, 12, 1, 46, 79, 
+117, 1, 22, 0, 4, 0, 3}, /* ia - iz */
+   {3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 
+0, 0}, /* ja - jz */
+   {1, 0, 0, 0, 11, 0, 0, 0, 13, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6, 2, 1, 0, 2, 
+0, 1, 0}, /* ka - kz */
+   {44, 2, 5, 12, 62, 7, 5, 2, 42, 1, 1, 53, 2, 2, 25, 1, 1, 2, 16, 23, 9, 
+0, 1, 0, 33, 0}, /* la - lz */
+   {52, 14, 1, 0, 64, 0, 0, 3, 37, 0, 0, 0, 7, 1, 17, 18, 1, 2, 12, 3, 8, 
+0, 1, 0, 2, 0}, /* ma - mz */
+   {42, 10, 47, 122, 63, 19, 106, 12, 30, 1, 6, 6, 9, 7, 54, 7, 1, 7, 44, 
+124, 6, 1, 15, 0, 12, 0}, /* na - nz */
+   {7, 12, 14, 17, 5, 95, 3, 5, 14, 0, 0, 19, 41, 134, 13, 23, 0, 91, 23, 
+42, 55, 16, 28, 0, 4, 1}, /* oa - oz */
+   {19, 1, 0, 0, 37, 0, 0, 4, 8, 0, 0, 15, 1, 0, 27, 9, 0, 33, 14, 7, 6, 0, 
+0, 0, 0, 0}, /* pa - pz */
+   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 
+0, 0, 0}, /* qa - qz */
+   {83, 8, 16, 23, 169, 4, 8, 8, 77, 1, 10, 5, 26, 16, 60, 4, 0, 24, 37, 
+55, 6, 11, 4, 0, 28, 0}, /* ra - rz */
+   {65, 9, 17, 9, 73, 13, 1, 47, 75, 3, 0, 7, 11, 12, 56, 17, 6, 9, 48, 
+116, 35, 1, 28, 0, 4, 0}, /* sa - sz */
+   {57, 22, 3, 1, 76, 5, 2, 330, 126, 1, 0, 14, 10, 6, 79, 7, 0, 49, 50, 
+56, 21, 2, 27, 0, 24, 0}, /* ta - tz */
+   {11, 5, 9, 6, 9, 1, 6, 0, 9, 0, 1, 19, 5, 31, 1, 15, 0, 47, 39, 31, 0, 
+3, 0, 0, 0, 0}, /* ua - uz */
+   {7, 0, 0, 0, 72, 0, 0, 0, 28, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 
+0, 3, 0}, /* va - vz */
+   {36, 1, 1, 0, 38, 0, 0, 33, 36, 0, 0, 4, 1, 8, 15, 0, 0, 0, 4, 2, 0, 0, 
+1, 0, 0, 0}, /* wa - wz */
+   {1, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0, 1, 5, 0, 0, 0, 3, 0, 0, 1, 0, 
+0, 0}, /* xa - xz */
+   {14, 5, 4, 2, 7, 12, 12, 6, 10, 0, 0, 3, 7, 5, 17, 3, 0, 4, 16, 30, 0, 
+0, 5, 0, 0, 0}, /* ya - yz */
+   {1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+0, 0}}; /* za - zz */
+
+/*
+ * This MUST be equal to the sum of the equivalent rows above.
+ */
+
+static int row_sums[26] =
+{796,  160,    284,    401,    1276,   262,    199,    539,    777,    
+  16,  39,     351,    243,    751,    662,    181,    17,     683,    
+  662, 968,    248,    115,    180,    17,     162,    5};
+
+/*
+ * Frequencies of starting characters
+ */
+
+static int start_freq [26] =
+{1299, 425,    725,    271,    375,    470,    93,     223,    1009,
+ 24,   20,     355,    379,    319,    823,    618,    21,     317,
+ 962,  1991,   271,    104,    516,    6,      16,     14};
+
+/*
+ * This MUST be equal to the sum of all elements in the above array.
+ */
+static int total_sum = 11646;
+
+long myrandom();
+void generate_password(char *password);
+int set_password(char *user, char *domain);
+krb5_error_code encode_krb5_setpw
+       PROTOTYPE((const krb5_setpw *rep, krb5_data ** code));
+krb5_error_code 
+krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
+                    struct sockaddr **addr_pp, int *naddrs);
+
+krb5_error_code krb5_mk_setpw_req(krb5_context context,  krb5_auth_context auth_context,
+                                  krb5_data *ap_req, krb5_principal targprinc,
+                                  char *passwd, krb5_data *packet)
+{
+  krb5_error_code  ret;
+  krb5_setpw       setpw;
+  krb5_data        cipherpw;
+  krb5_data        *encoded_setpw;
+  krb5_replay_data replay;
+  char             *ptr;
+  register int     count = 2;
+
+  memset (&setpw, 0, sizeof(krb5_setpw));
+  if (ret = krb5_auth_con_setflags(context, auth_context,
+                                   KRB5_AUTH_CONTEXT_DO_SEQUENCE))
+       return(ret);
+  setpw.targprinc = targprinc;
+  setpw.newpasswd.length = strlen(passwd);
+  setpw.newpasswd.data = passwd;
+  if ((ret = encode_krb5_setpw(&setpw, &encoded_setpw)))
+         return( ret );
+  if (ret = krb5_mk_priv(context, auth_context,
+                                          encoded_setpw, &cipherpw, &replay))
+       return(ret);
+  packet->length = 6 + ap_req->length + cipherpw.length;
+  packet->data = (char *) malloc(packet->length);
+  ptr = packet->data;
+  /* Length */
+  *ptr++ = (packet->length>>8) & 0xff;
+  *ptr++ = packet->length & 0xff;
+  /* version */
+  *ptr++ = (char)0xff;
+  *ptr++ = (char)0x80;
+  /* ap_req length, big-endian */
+  *ptr++ = (ap_req->length>>8) & 0xff;
+  *ptr++ = ap_req->length & 0xff;
+  /* ap-req data */
+  memcpy(ptr, ap_req->data, ap_req->length);
+  ptr += ap_req->length;
+  /* krb-priv of password */
+  memcpy(ptr, cipherpw.data, cipherpw.length);
+  return(0);
+}
+
+krb5_error_code krb5_rd_setpw_rep(krb5_context context, krb5_auth_context auth_context,
+                                  krb5_data *packet, int *result_code,
+                                  krb5_data *result_data)
+{
+  char             *ptr;
+  int              plen;
+  int              vno;
+  krb5_data        ap_rep;
+  krb5_error_code  ret;
+  krb5_data        cipherresult;
+  krb5_data        clearresult;
+  krb5_error       *krberror;
+  krb5_replay_data replay;
+  krb5_keyblock    *tmp;
+  krb5_ap_rep_enc_part *ap_rep_enc;
+
+  if (packet->length < 4)
+       return(KRB5KRB_AP_ERR_MODIFIED);
+  ptr = packet->data;
+  if (krb5_is_krb_error(packet))
+    {
+           ret = decode_krb5_error(packet, &krberror);
+           if (ret)
+             return(ret);
+           ret = krberror->error;
+           krb5_free_error(context, krberror);
+           return(ret);
+    }
+  /* verify length */
+  plen = (*ptr++ & 0xff);
+  plen = (plen<<8) | (*ptr++ & 0xff);
+  if (plen != packet->length)
+         return(KRB5KRB_AP_ERR_MODIFIED);
+  vno = (*ptr++ & 0xff);
+  vno = (vno<<8) | (*ptr++ & 0xff);
+  if (vno != KRB5_KPASSWD_VERS_SETPW && vno != KRB5_KPASSWD_VERS_CHANGEPW)
+         return(KRB5KDC_ERR_BAD_PVNO);
+  /* read, check ap-rep length */
+  ap_rep.length = (*ptr++ & 0xff);
+  ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
+  if (ptr + ap_rep.length >= packet->data + packet->length)
+         return(KRB5KRB_AP_ERR_MODIFIED);
+  if (ap_rep.length)
+    {
+           /* verify ap_rep */
+           ap_rep.data = ptr;
+           ptr += ap_rep.length;
+           if (ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc))
+             return(ret);
+           krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+           /* extract and decrypt the result */
+           cipherresult.data = ptr;
+           cipherresult.length = (packet->data + packet->length) - ptr;
+           /* XXX there's no api to do this right. The problem is that
+              if there's a remote subkey, it will be used.  This is
+              not what the spec requires */
+           tmp = auth_context->remote_subkey;
+           auth_context->remote_subkey = NULL;
+           ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+                                          &replay);
+           auth_context->remote_subkey = tmp;
+           if (ret)
+             return(ret);
+    }
+  else
+    {
+           cipherresult.data = ptr;
+           cipherresult.length = (packet->data + packet->length) - ptr;
+
+           if (ret = krb5_rd_error(context, &cipherresult, &krberror))
+             return(ret);
+
+           clearresult = krberror->e_data;
+    }
+  if (clearresult.length < 2)
+    {
+           ret = KRB5KRB_AP_ERR_MODIFIED;
+           goto cleanup;
+    }
+  ptr = clearresult.data;
+  *result_code = (*ptr++ & 0xff);
+  *result_code = (*result_code<<8) | (*ptr++ & 0xff);
+  if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
+           (*result_code > KRB5_KPASSWD_ACCESSDENIED))
+    {
+       ret = KRB5KRB_AP_ERR_MODIFIED;
+           goto cleanup;
+    }
+  /* all success replies should be authenticated/encrypted */
+  if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS))
+    {
+           ret = KRB5KRB_AP_ERR_MODIFIED;
+           goto cleanup;
+    }
+  result_data->length = (clearresult.data + clearresult.length) - ptr;
+  if (result_data->length)
+    {
+           result_data->data = (char *) malloc(result_data->length);
+           memcpy(result_data->data, ptr, result_data->length);
+    }
+  else
+         result_data->data = NULL;
+  ret = 0;
+cleanup:
+  if (ap_rep.length)
+         free(clearresult.data);
+  else
+         krb5_free_error(context, krberror);
+  return(ret);
+}
+
+krb5_error_code krb5_set_password(krb5_context context, krb5_ccache ccache,
+                                  char *newpw, char *user, char *domain,
+                                  int *result_code)
+{
+  krb5_auth_context auth_context;
+  krb5_data         ap_req;
+  krb5_data         chpw_req;
+  krb5_data         chpw_rep;
+  krb5_data         result_string;
+  krb5_address      local_kaddr;
+  krb5_address      remote_kaddr;
+  char              userrealm[256];
+  char              temp[256];
+  krb5_error_code   code;
+  krb5_creds        creds;
+  krb5_creds        *credsp;
+  struct sockaddr   *addr_p;
+  struct sockaddr   local_addr;
+  struct sockaddr   remote_addr;
+  struct sockaddr   tmp_addr;
+  SOCKET            s1;
+  SOCKET            s2;
+  int               i;
+  int               out;
+  int               addrlen;
+  int               cc;
+  int               local_result_code;
+  int               tmp_len;
+  int               error_count;
+  krb5_principal    targprinc;
+  struct timeval    TimeVal;
+  fd_set            readfds;
+
+  auth_context = NULL;
+  addr_p = NULL;
+  credsp = NULL;
+  memset(&local_addr, 0, sizeof(local_addr));
+  memset(&local_kaddr, 0, sizeof(local_kaddr));
+  memset(&result_string, 0, sizeof(result_string));
+  memset(&remote_kaddr, 0, sizeof(remote_kaddr));
+  memset(&chpw_req, 0, sizeof(krb5_data));
+  memset(&chpw_rep, 0, sizeof(krb5_data));
+  memset(&ap_req, 0, sizeof(krb5_data));
+  auth_context = NULL;
+  memset(&creds, 0, sizeof(creds));
+  memset(userrealm, '\0', sizeof(userrealm));
+  targprinc = NULL;
+  for (i = 0; i < (int)strlen(domain); i++)
+      userrealm[i] = toupper(domain[i]);
+
+  sprintf(temp, "%s@%s", user, userrealm);
+  krb5_parse_name(context, temp, &targprinc);
+
+  sprintf(temp, "%s@%s", "kadmin/changepw", userrealm);
+  if (code = krb5_parse_name(context, temp, &creds.server))
+    goto cleanup;
+
+  if (code = krb5_cc_get_principal(context, ccache, &creds.client))
+    goto cleanup;
+  if (code = krb5_get_credentials(context, 0, ccache, &creds, &credsp))
+    goto cleanup;
+  if (code = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
+                                                   NULL, credsp, &ap_req))
+    goto cleanup;
+ if (code = krb5_locate_kpasswd(context, &targprinc->realm, &addr_p, &out))
+         goto cleanup;
+  if (out == 0)
+    {     /* Couldn't resolve any KPASSWD names */
+      code = 1;
+      goto cleanup;
+    }
+
+  /* this is really obscure.  s1 is used for all communications.  it
+     is left unconnected in case the server is multihomed and routes
+     are asymmetric.  s2 is connected to resolve routes and get
+     addresses.  this is the *only* way to get proper addresses for
+     multihomed hosts if routing is asymmetric.  
+
+     A related problem in the server, but not the client, is that
+     many os's have no way to disconnect a connected udp socket, so
+     the s2 socket needs to be closed and recreated for each
+     request.  The s1 socket must not be closed, or else queued
+     requests will be lost.
+
+     A "naive" client implementation (one socket, no connect,
+     hostname resolution to get the local ip addr) will work and
+     interoperate if the client is single-homed. */
+
+  if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+    {
+      free(addr_p);
+           return(errno);
+    }
+  if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+    {
+      closesocket(s1);
+      free(addr_p);
+           return(errno);
+    }
+  error_count = 0;
+  for (i=0; i<out; i++)
+    {
+           if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR)
+        continue;
+
+           addrlen = sizeof(local_addr);
+       if (getsockname(s2, &local_addr, &addrlen) < 0)
+        continue;
+           if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
+        {
+               local_kaddr.addrtype = ADDRTYPE_INET;
+               local_kaddr.length =
+                 sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
+               local_kaddr.contents = 
+                 (char *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
+             }
+      else
+        {
+               krb5_address **addrs;
+               krb5_os_localaddr(context, &addrs);
+               local_kaddr.magic = addrs[0]->magic;
+               local_kaddr.addrtype = addrs[0]->addrtype;
+               local_kaddr.length = addrs[0]->length;
+               local_kaddr.contents = calloc(1, addrs[0]->length);
+               memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+           krb5_free_addresses(context, addrs);
+             }
+
+           addrlen = sizeof(remote_addr);
+           if (getpeername(s2, &remote_addr, &addrlen) < 0)
+       continue;
+           remote_kaddr.addrtype = ADDRTYPE_INET;
+           remote_kaddr.length =
+             sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
+           remote_kaddr.contents = 
+             (char *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
+           /* mk_priv requires that the local address be set.
+              getsockname is used for this.  rd_priv requires that the
+              remote address be set.  recvfrom is used for this.  If
+              rd_priv is given a local address, and the message has the
+              recipient addr in it, this will be checked.  However, there
+              is simply no way to know ahead of time what address the
+              message will be delivered *to*.  Therefore, it is important
+              that either no recipient address is in the messages when
+              mk_priv is called, or that no local address is passed to
+              rd_priv.  Both is a better idea, and I have done that.  In
+              summary, when mk_priv is called, *only* a local address is
+              specified.  when rd_priv is called, *only* a remote address
+              is specified.  Are we having fun yet?  */
+           if (code = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL))
+        goto cleanup;
+           if (code = krb5_mk_setpw_req(context, auth_context, &ap_req,
+                                                   targprinc, newpw, &chpw_req))
+        goto cleanup;
+           if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0,
+                                        (struct sockaddr *) &addr_p[i],
+                                        sizeof(addr_p[i]))) != chpw_req.length)
+        continue; /* try the next addr */
+#ifdef _WIN32
+      krb5_free_data_contents(context, &chpw_req);
+#else
+      free(chpw_req.data);
+#endif
+           chpw_rep.length = 1500;
+           chpw_rep.data = (char *) calloc(1, chpw_rep.length);
+       /* XXX need a timeout/retry loop here */
+           /* "recv" would be good enough here... except that Windows/NT
+              commits the atrocity of returning -1 to indicate failure,
+              but leaving errno set to 0.
+          
+              "recvfrom(...,NULL,NULL)" would seem to be a good enough
+              alternative, and it works on NT, but it doesn't work on
+              SunOS 4.1.4 or Irix 5.3.  Thus we must actually accept the
+              value and discard it. */
+           tmp_len = sizeof(tmp_addr);
+      TimeVal.tv_sec = 10;
+      TimeVal.tv_usec = 0;
+
+      FD_ZERO(&readfds);
+      FD_SET(s1, &readfds);
+      code = select(1, &readfds, NULL, NULL, &TimeVal);
+
+      if ((code == 0) || (code == SOCKET_ERROR))
+        {
+          if (error_count < 2)
+            {
+              closesocket(s1);
+              closesocket(s2);
+              if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+                goto cleanup;
+              if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+                goto cleanup;
+              ++error_count;
+              --i;
+              continue;
+            }
+          code = errno;
+          goto cleanup;
+        }
+           if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, 0, &tmp_addr, &tmp_len)) < 0)
+        {
+          code = errno;
+          goto cleanup;
+             }
+           chpw_rep.length = cc;
+           if (code = krb5_auth_con_setaddrs(context, auth_context, NULL,
+                                                                 &remote_kaddr))
+        {
+          goto cleanup;
+             }
+      local_result_code = 0;
+           code = krb5_rd_setpw_rep(context, auth_context, &chpw_rep,
+                                                &local_result_code, &result_string);
+
+           if (result_code)
+             *result_code = local_result_code;
+#ifdef _WIN32
+      krb5_free_data_contents(context, &chpw_req);
+#else
+      free(chpw_req.data);
+#endif
+      break;
+
+    }
+cleanup:
+  closesocket(s1);
+  closesocket(s2);
+  if (addr_p != NULL)
+    free(addr_p);
+  if (auth_context != NULL)
+    krb5_auth_con_free(context, auth_context);
+  if (ap_req.data != NULL)
+#ifdef _WIN32
+      krb5_free_data_contents(context, &ap_req);
+#else
+      free(ap_req.data);
+#endif
+  krb5_free_cred_contents(context, &creds);
+  if (credsp != NULL)
+    krb5_free_creds(context, credsp);
+  if (targprinc != NULL)
+    krb5_free_principal(context, targprinc);
+       return(code);
+}
+
+int set_password(char *user, char *domain)
+{
+  krb5_context    context;
+  krb5_ccache     ccache;
+  int             res_code;
+  krb5_error_code retval;
+       char            pw[PW_LENGTH+1];
+
+  if (retval = krb5_init_context(&context))
+    return retval;
+  if (retval = krb5_cc_default(context, &ccache))
+      return(retval);
+
+  memset(pw, '\0', sizeof(pw));
+  generate_password(pw);
+  retval = krb5_set_password(context, ccache, pw, user, domain, &res_code);
+
+       krb5_cc_close(context, ccache);
+       krb5_free_context(context);
+  return(retval);
+}
+
+void generate_password(char *password)
+{
+       int   i;
+  int   j;
+  int   row_position;
+  int   nchars;
+  int   position;
+       int   word;
+  int   line;
+       char  *pwp;
+
+       for (line = 22; line; --line)
+    {
+      for (word = 7; word; --word)
+        {
+          position = myrandom()%total_sum;
+          for(row_position = 0, j = 0; position >= row_position; row_position += start_freq[j], j++)
+            continue;
+          *(pwp = password) = j + 'a' - 1;
+          for (nchars = PW_LENGTH-1; nchars; --nchars)
+            {
+              i = *pwp - 'a';
+              pwp++;
+              position = myrandom()%row_sums[i];
+              for (row_position = 0, j = 0; position >= row_position; row_position += frequency[i][j], j++)
+                continue;
+              *pwp = j + 'a' - 1;
+            }
+          *(++pwp)='\0';
+          return;
+                   }
+      putchar('\n');
+    }
+}
+
+long myrandom()
+{
+  static int init = 0;
+  int pid;
+#ifdef _WIN32
+  struct _timeb timebuffer;
+#else
+  struct timeval tv;
+#endif
+
+  if (!init)
+    {
+      init = 1;
+      pid = getpid();
+#ifdef _WIN32
+      _ftime(&timebuffer);
+      srand(timebuffer.time ^ timebuffer.millitm ^ pid);
+#else
+      gettimeofday(&tv, (struct timezone *) NULL);
+      srandom(tv.tv_sec ^ tv.tv_usec ^ pid);
+#endif
+    }
+  return (rand());
+}
index 8d38931349cc5f5354123f5772a38654c09c1adf..261df804366be7ceca69767a4eb1dc87eee0eb5f 100755 (executable)
@@ -1,11 +1,36 @@
 /* $Header$
- * 
- * Do incremental updates of a Windows Active Directory
+/*test parameters for reactivating a user account - done
+ * users 9 9 aadam 1 sh account test A 1 3 2 aadam 1 csh new login b 1 2 3
  *
- * test parameters for reactivating a user account
- *  users 9 9 testaccount 1 sh account test A 3 2 3 testaccount 1 csh new login b 1 2 3
- */
-
+ * test parameters for deactivating a user account - done
+ * users 9 9 aadam 0 sh account test A 1 2 3 aadam 1 csh new login b 0 0 0
+ *
+ *test parameters for creating a user account - done
+ * users 9 9 aadam 1 sh account test A 0 0 0 aadam 1 csh new login b 1 2 3
+ *
+ * test parameters for deleting a group - done
+ * list 7 7 pismere-team 1 2 3 4 5 6 pismere-team 8 9 10 11 12 0
+ *
+ * test parameters for creating and populating a group - done
+ * list 7 7 pismere-team 2 2 3 4 5 0 pismere-team 1 9 10 11 12 13
+ *
+ * test parameters for renaming a group - done
+ * list 7 7 testgroup 1 2 3 4 5 6 pismere-team 1 9 10 11 12 13
+ *
+ * test parameters for creating and not populating a group - done
+ * list 0 7 pismere-team 1 9 10 11 12 13
+ *
+ * test parameters for add member to list - done 
+ * imembers 9 9 pismere-team USER dtanner 0 2 3 4 5 6 pismere-team USER dtanner 1 2 3 4 5 6
+ * note: the group the group will be created if it does not exist in the AD.
+ *
+ * test parameters for remove member from list - done
+ * imembers 9 0 pismere-team USER testaccount 1 2 3 4 5 6
+ *
+ * test parameters for changing account name - done
+ * users 9 9 aatestaccount 1 sh account test A 1 1 2 darkwing 1 csh new login b 1 2 3
+ *
+*/
 #include <mit-copyright.h>
 #ifdef _WIN32
 #include <windows.h>
 #include <malloc.h>
 #include <lmaccess.h>
 #endif
+
+#include <string.h>
 #include <ldap.h>
 #include <stdio.h>
 #include <moira.h>
 #include <moira_site.h>
+#include <mrclient.h>
 #include <krb5.h>
 #include <krb.h>
 #include <gsssasl.h>
 #include <gssldap.h>
+#include "kpasswd.h"
+
+#ifdef _WIN32
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#define krb5_xfree free
+#endif /* _WIN32 */
 
 #ifndef _WIN32
 #include <sys/utsname.h>
 
+#define UCHAR unsigned char
+
 #define UF_SCRIPT               0x0001
 #define UF_ACCOUNTDISABLE       0x0002
 #define UF_HOMEDIR_REQUIRED     0x0008
 #define UF_LOCKOUT              0x0010
 #define UF_PASSWD_NOTREQD       0x0020
 #define UF_PASSWD_CANT_CHANGE   0x0040
+#define UF_DONT_EXPIRE_PASSWD   0x10000
 
 #define UF_TEMP_DUPLICATE_ACCOUNT       0x0100
 #define UF_NORMAL_ACCOUNT               0x0200
@@ -64,14 +109,27 @@ typedef struct _SID {
 } SID;
 #endif/*!WIN32*/
 
+#define ADS_GROUP_TYPE_GLOBAL_GROUP         0x00000002
+#define        ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP   0x00000004
+#define        ADS_GROUP_TYPE_LOCAL_GROUP          0x00000004
+#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 SUBSTITUTE  1
 #define REPLACE     2
 
+#define USERS         0
+#define GROUPS        1
+
 #define MEMBER_ADD          1
 #define MEMBER_REMOVE       2
 #define MEMBER_CHANGE_NAME  3
 #define MEMBER_ACTIVATE     4
 #define MEMBER_DEACTIVATE   5
+#define MEMBER_CREATE       6
 
 #define GROUP_CREATE            1
 #define GROUP_DELETE            2
@@ -92,170 +150,220 @@ typedef struct lk_entry {
 } LK_ENTRY;
 
 #define LDAP_BERVAL struct berval
+#define MAX_SERVER_NAMES 32
+
+#define ADD_ATTR(t, v, o)              \
+  mods[n] = malloc(sizeof(LDAPMod));   \
+  mods[n]->mod_op = o; \
+  mods[n]->mod_type = t;               \
+  mods[n++]->mod_values = v
 
 LK_ENTRY *member_base = NULL;
-char group_ou[] = "OU=groups,OU=athena";
+LK_ENTRY *sid_base = NULL;
+LK_ENTRY **sid_ptr = NULL;
+char kerberos_ou[] = "OU=kerberos, OU=moira, OU=athena";
+char contact_ou[] = "OU=strings, OU=moira, OU=athena";
+char user_ou[] = "OU=users, OU=moira, OU=athena";
+char group_ou_distribution[] = "OU=distribution, OU=lists, OU=moira, OU=athena";
+char group_ou_security[] = "OU=security, OU=lists, OU=moira, OU=athena";
+char group_ou_neither[] = "OU=neither, OU=lists, OU=moira, OU=athena";
+char group_ou_both[] = "OU=both, OU=lists, OU=moira, OU=athena";
+char group_ou_root[] = "OU=lists, OU=moira, OU=athena";
 char *whoami;
-static int mr_connections = 0;
-
-int add_list_members(int ac, char **av, void *group);
-int add_user_lists(int ac, char **av, void *user);
-int member_update(LDAP *ldap_handle, char *dn_path, LDAPMessage *ldap_entry, 
-                 char *login_name, char *new_login_name, char *ldap_hostname,
-                 int operation, LK_ENTRY *group_base);
-int group_update(LDAP *ldap_handle, char *ldap_hostname, 
-                char *before_group_name, char *after_group_name,
-                int operation, LK_ENTRY *user_list);
-int check_user(int ac, char **av, void *ustate);
-int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
-                       int newValue_count, char *oldValue, char *newValue,
-                       LDAPMod ***newValueArray, char ****modvalues,
-                       int type);
-int convert_domain_to_dn(char *domain, char **bind_path);
-void delete_user(LDAP *ldap_handle, LDAPMessage *ldap_entry);
+char group_manager[64];
+char ldap_domain[256];
+char list_type[32];
+char GroupType[2];
+int  maillist_flag;
+int  group_flag;
+int  mr_connections = 0;
+
+extern int locate_ldap_server(char *domain, char *server_name[]);
+extern int set_password(char *user, char *domain);
+
+int user_create(int ac, char **av, void *ptr);
+int user_change_status(LDAP *ldap_handle, char *dn_path,
+                       char *u_name, int operation);
+int user_delete(LDAP *ldap_handle, char *dn_path, char *u_name);
+int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou);
+int get_group_info(int ac, char**av, void *ptr);
+int group_create(int ac, char **av, void *ptr);
+int group_delete(int ac, char **av, void *ptr);
+int group_ad_delete(LDAP *ldap_handle, char *dn_path, char *group_name);
+int group_list_build(int ac, char **av, void *ptr);
+int group_update_membership(LDAP *ldap_handle, char *dn_path, char *group_name);
+int member_list_build(int ac, char **av, void *ptr);
+int member_list_process(LDAP *ldap_handle, char *dn_path, char *group_name,
+                        char *group_ou, char *group_membership);
+int sid_update(LDAP *ldap_handle, char *dn_path);
+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);
+
 void do_list(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_user(LDAP *ldap_handle, LDAPMessage *ldap_entry, char *ldap_hostname, 
-            char *dn_path, char **before, int beforec, char **after, 
-            int afterc);
+             char *dn_path, 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 edit_group(int op, char *group, char *type, char *member,
-               LDAP *ldap_handle, char *dn_path, char *ldap_hostname);
-int linklist_create_entry(char *attribute, char *value, 
-                         LK_ENTRY **linklist_entry);
+               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);
+                   char **attr_array, LK_ENTRY **linklist_base, 
+                   int *linklist_count);
 void linklist_free(LK_ENTRY *linklist_base);
-void free_values(int newvalue_count, LDAPMod **newvalue_array, 
-                char ***modvalues);
+
+int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
+                        char *distinguished_name, LK_ENTRY **linklist_current);
+int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
+                     LK_ENTRY **linklist_base, int *linklist_count);
+int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
+                    char *Attribute, char *distinguished_name, 
+                    LK_ENTRY **linklist_current);
+
+int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
+                        char *oldValue, char *newValue,
+                        char ***modvalues, int type);
+void free_values(char **modvalues);
+
+int convert_domain_to_dn(char *domain, char **bind_path);
 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                           char *distinguished_name);
+                            char *distinguished_name);
 int moira_disconnect(void);
 int moira_connect(void);
 void print_to_screen(const char *fmt, ...);
-int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                       char *distinguished_name, LK_ENTRY **linklist_current);
-int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                    LK_ENTRY **linklist_base, int *linklist_count);
-int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                   char *Attribute, char *distinguished_name, 
-                   LK_ENTRY **linklist_current);
 
 int main(int argc, char **argv)
 {
-  unsigned long rc;
-  int beforec, afterc, Max_wait_time = 500, Max_size_limit = LDAP_NO_LIMIT;
-  char ldap_hostname[256], search_exp[1024];
-  char *dn_path, *table, **before, **after;
-  ULONG version = LDAP_VERSION3;
-  LDAP *ldap_handle;
-  LDAPMessage *ldap_entry;
+  unsigned long   rc;
+  int             beforec;
+  int             afterc;
+  int             Max_wait_time = 500;
+  int             Max_size_limit = LDAP_NO_LIMIT;
+  int             i;
+  char            *dn_path;
+  char            *table;
+  char            **before;
+  char            **after;
+  char            search_exp[1024];
+  char            *server_name[MAX_SERVER_NAMES];
+  ULONG           version = LDAP_VERSION3;
+  LDAP            *ldap_handle;
+  LDAPMessage     *ldap_entry;
   FILE            *fptr;
-  
+
   whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
-  /*
-   *   if (argc < 4)
-   *       exit(1);
-   *
-   *   beforec = atoi(argv[2]);
-   *   afterc = atoi(argv[3]);
-   *
-   *   if (argc < (4 + beforec + afterc))
-   *       exit(1);
-   *
-   *   table = argv[1];
-   *   before = &argv[4];
-   *  after = &argv[4 + beforec];
-   */
-  memset(ldap_hostname, '\0', sizeof(ldap_hostname));
+
+  if (argc < 4)
+    {
+      com_err(whoami, 0, "%s", "argc < 4");
+      exit(1);
+    }
+  beforec = atoi(argv[2]);
+  afterc = atoi(argv[3]);
+
+  if (argc < (4 + beforec + afterc))
+    {
+      com_err(whoami, 0, "%s", "argc < (4 + breforec + afterc)");
+      exit(1);
+    }
+
+  table = argv[1];
+  before = &argv[4];
+  after = &argv[4 + beforec];
+
+  memset(ldap_domain, '\0', sizeof(ldap_domain));
   if ((fptr = fopen("winad.cfg", "r")) != NULL)
     {
-      fread(ldap_hostname, sizeof(char), sizeof(ldap_hostname), fptr);
+      fread(ldap_domain, sizeof(char), sizeof(ldap_domain), fptr);
       fclose(fptr);
     }
-  if (strlen(ldap_hostname) == 0)
-    strcpy(ldap_hostname, "windows.mit.edu");
-  
+  if (strlen(ldap_domain) == 0)
+    strcpy(ldap_domain, "windows.mit.edu");
   initialize_sms_error_table();
   initialize_krb_error_table();
-  
+
   memset(search_exp, '\0', sizeof(search_exp));
   ldap_entry = NULL;
   dn_path = NULL;
-  convert_domain_to_dn(ldap_hostname, &dn_path);
+  convert_domain_to_dn(ldap_domain, &dn_path);
   if (dn_path == NULL)
-    exit(1);
-  
-  ldap_handle = ldap_open(ldap_hostname, LDAP_PORT);
-  if (ldap_handle == NULL)
-    exit(1);
+    {
+      com_err(whoami, 0, "%s", "cannot create AD path");
+      exit(1);
+    }
+  memset(server_name, '\0', sizeof(server_name[0]) * MAX_SERVER_NAMES);
+  if (locate_ldap_server(ldap_domain, server_name) == -1)
+    {
+      com_err(whoami, 0, "%s %s", "cannot locate any server in domain ",
+              ldap_domain);
+      exit(1);
+    }
+
+  for (i = 0; i < MAX_SERVER_NAMES; i++)
+    {
+      if (server_name[i] != NULL)
+        {
+          if ((ldap_handle = ldap_open(server_name[i], LDAP_PORT)) != NULL)
+            {
+              break;
+            }
+        }
+    }
+  if (i >= MAX_SERVER_NAMES)
+    {
+      com_err(whoami, 0, "%s %s", "cannot connect to any server in domain ",
+              ldap_domain);
+      exit(1);
+    }
+  for (i = 0; i < MAX_SERVER_NAMES; i++)
+    {
+      if (server_name[i] != NULL)
+        free(server_name[i]);
+    }
   rc = ldap_set_option(ldap_handle, LDAP_OPT_PROTOCOL_VERSION, &version);
   rc = ldap_set_option(ldap_handle, LDAP_OPT_TIMELIMIT, 
                       (void *)&Max_wait_time);
   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, 
                       (void *)&Max_size_limit);
   rc = ldap_set_option(ldap_handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
-  rc = ldap_adgssapi_bind(ldap_handle, dn_path, GSSSASL_NO_SECURITY_LAYER);
+  rc = ldap_adgssapi_bind(ldap_handle, dn_path, GSSSASL_PRIVACY_PROTECTION);
   if (rc != LDAP_SUCCESS) 
-    exit(1);
-  
-  /* used for testing
-   * do_list(ldap_handle, dn_path, ldap_hostname, before, beforec, after, 
-   *         afterc);
-   */
-  
-  rc = group_update(ldap_handle, ldap_hostname, "testaccountF", NULL, 
-                   GROUP_CREATE, NULL);
-  printf("first rc = %d\n", rc);
-  if (rc != 0)
-    exit(1);
-  rc = group_update(ldap_handle, ldap_hostname, "pismere-team", 
-                   "testaccountF", GROUP_MOVE_MEMBERS, NULL);
-  printf("second rc = %d\n", rc);
-  if (rc != 0)
-    exit(1);
-  rc = group_update(ldap_handle, ldap_hostname, "testaccountF", NULL, 
-                   GROUP_DELETE, NULL);
-  printf("third rc = %d\n", rc);
-  exit(1);
-  
+        exit(1);
+
   if (!strcmp(table, "users"))
-    {
-      sprintf(search_exp, "(sAMAccountName=%s)", before[U_NAME]);
-      if ((rc = ldap_search_s(ldap_handle, dn_path, LDAP_SCOPE_SUBTREE, 
-                             search_exp, NULL, 0, &ldap_entry)) 
-         == LDAP_SUCCESS)
-       do_user(ldap_handle, ldap_entry, ldap_hostname, dn_path, before, 
-               beforec, after, afterc);
-      rc = ldap_msgfree(ldap_entry);
-    }
+    do_user(ldap_handle, ldap_entry, ldap_domain, dn_path, before, beforec,
+            after, afterc);
   else if (!strcmp(table, "list"))
-    do_list(ldap_handle, dn_path, ldap_hostname, before, beforec, after, 
-           afterc);
+    do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+            afterc);
   else if (!strcmp(table, "imembers"))
-    do_member(ldap_handle, dn_path, ldap_hostname, before, beforec, after, 
-             afterc);
-  /*
-   *   else if (!strcmp(table, "filesys"))
-   *       do_filesys(before, beforec, after, afterc);
-   *   else if (!strcmp(table, "quota"))
-   *       do_quota(before, beforec, after, afterc);
-   */
+    do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
+              afterc);
+/*
+  else if (!strcmp(table, "filesys"))
+    do_filesys(before, beforec, after, afterc);
+  else if (!strcmp(table, "quota"))
+    do_quota(before, beforec, after, afterc);
+*/
   rc = ldap_unbind_s(ldap_handle);
   free(dn_path);
-  
   exit(0);
 }
 
-void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
-            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)
 {
-  int agid = 0, bgid = 0, ahide, bhide;
-  long rc, id;
-  char *av[2];
-  
+  int     agid;
+  int     bgid;
+  int     ahide;
+  int     bhide;
+  long    rc;
+  char    *av[3];
+  char    *call_args[6];
+
+  agid = bgid = 0;
   if (beforec > L_GID && atoi(before[L_ACTIVE]) && atoi(before[L_GROUP]))
     {
       bgid = atoi(before[L_GID]);
@@ -266,89 +374,134 @@ void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
       agid = atoi(after[L_GID]);
       ahide = atoi(after[L_HIDDEN]);
     }
-  
+
   if (agid == 0 && bgid == 0)
     return;
-  
+
+  if (rc = moira_connect())
+    {
+      critical_alert("AD incremental",
+                     "Error contacting Moira server: %s",
+                     error_message(rc));
+      return;
+    }
+
   if (agid && bgid)
     {
       if (strcmp(after[L_NAME], before[L_NAME]))
-       {
-         com_err(whoami, 0, "Changing group %s to %s",
-                 before[L_NAME], after[L_NAME]);
-         
-         if (!(rc = group_update(ldap_handle, ldap_hostname, 
-                                 after[L_NAME], NULL, GROUP_CREATE, NULL)))
-           {
-             if (!(rc = group_update(ldap_handle, ldap_hostname, 
-                                     before[L_NAME], after[L_NAME], 
-                                     GROUP_MOVE_MEMBERS, NULL)))
-               {
-                 rc = group_update(ldap_handle, ldap_hostname, 
-                                   before[L_NAME], NULL, GROUP_DELETE, 
-                                   NULL);
-               }
-           }
-         if (rc)
-           {
-             critical_alert("incremental", "Couldn't change group %s "
-                            "to %s", before[L_NAME], after[L_NAME]);
-           }
-       }
-      return;
+        {
+          com_err(whoami, 0, "Changing group %s to %s",
+                  before[L_NAME], 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] = NULL;
+          call_args[4] = NULL;
+          member_base = NULL;
+          sid_base = NULL;
+          sid_ptr = &sid_base;
+          if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
+            {
+              critical_alert("AD incremental", "Couldn't find group %s ",
+                             after[L_NAME]);
+            }
+          else
+            {
+              if (sid_base != NULL)
+                {
+                  sid_update(ldap_handle, dn_path);
+                  linklist_free(sid_base);
+                }
+              if (!(rc = mr_query("get_members_of_list", 1, av,
+                                  member_list_build, call_args)))
+                {
+                  rc = member_list_process(ldap_handle, dn_path,
+                                           after[L_NAME], call_args[3],
+                                           call_args[4]);
+                }
+              if (rc = group_ad_delete(ldap_handle, dn_path, before[L_NAME]))
+                {
+                  av[0] = before[L_NAME];
+                  if (rc = mr_query("get_list_info", 1, av, group_delete,
+                                    call_args))
+                    {
+                      critical_alert("AD incremental", "Couldn't delete group %s ",
+                                     before[L_NAME]);
+                    }
+                }
+            }
+          linklist_free(member_base);
+          if (call_args[3] != NULL)
+            free(call_args[3]);
+          if (call_args[4] != NULL)
+            free(call_args[4]);
+        }
+      goto cleanup;
     }
   if (bgid)
     {
       com_err(whoami, 0, "Deleting group %s", before[L_NAME]);
-      rc = group_update(ldap_handle, ldap_hostname, before[L_NAME], NULL, 
-                       GROUP_DELETE, NULL);
-      if (rc)
-       {
-         critical_alert("incremental",
-                        "Couldn't delete group %s (id %d)",
-                        before[L_NAME], -bgid);
-       }
-      return;
+      if (rc = group_ad_delete(ldap_handle, dn_path, before[L_NAME]))
+        {
+          av[0] = before[L_NAME];
+          call_args[0] = (char *)ldap_handle;
+          call_args[1] = dn_path;
+          if (!(rc = mr_query("get_list_info", 1, av, group_delete,
+                              call_args)))
+            {
+              critical_alert("AD incremental",
+                             "Couldn't delete group %s",
+                             before[L_NAME]);
+            }
+        }
+      goto cleanup;
     }
   if (agid)
     {
-      id = -agid;
       com_err(whoami, 0, "Creating group %s", after[L_NAME]);
-      rc = group_update(ldap_handle, ldap_hostname, after[L_NAME], NULL, 
-                       GROUP_CREATE, NULL);
-      if (rc)
-       {
-         critical_alert("incremental", "Couldn't create group %s (id %d)",
-                        after[L_NAME], id);
-         return;
-       }
-      
-      if (beforec < L_ACTIVE)
-       return;
-      
-      rc = moira_connect();
-      if (rc)
-       {
-         critical_alert("incremental",
-                        "Error contacting Moira server to resolve %s: %s",
-                        after[L_NAME], error_message(rc));
-         return;
-       }
+
       av[0] = after[L_NAME];
-      rc = mr_query("get_end_members_of_list", 1, av,
-                   add_list_members, after[L_NAME]);
+      call_args[0] = (char *)ldap_handle;
+      call_args[1] = dn_path;
+      call_args[2] = after[L_NAME];
+      call_args[3] = NULL;
+      call_args[4] = NULL;
+      sid_base = NULL;
+      sid_ptr = &sid_base;
+      rc = mr_query("get_list_info", 1, av, group_create, call_args);
+      if ((rc) && (rc != LDAP_ALREADY_EXISTS))
+        {
+          critical_alert("AD incremental", "Couldn't create group %s",
+                         after[L_NAME]);
+            goto cleanup;
+        }
+      if (sid_base != NULL)
+        {
+          sid_update(ldap_handle, dn_path);
+          linklist_free(sid_base);
+        }
+
+      if (beforec < L_ACTIVE)
+        goto cleanup;
+      if (!(rc = mr_query("get_members_of_list", 1, av, member_list_build,
+                          call_args)))
+        {
+          rc = member_list_process(ldap_handle, dn_path, after[L_NAME],
+                                   call_args[3], call_args[4]);
+        }
       if (rc)
-       {
-         critical_alert("incremental",
-                        "Couldn't retrieve full membership of list %s: %s",
-                        after[L_NAME], error_message(rc));
-       }
-      rc = group_update(ldap_handle, ldap_hostname, after[L_NAME], NULL, 
-                       GROUP_UPDATE_MEMBERS, member_base);
+        {
+          critical_alert("AD incremental",
+                         "Error contacting Moira server to resolve %s: %s",
+                         after[L_NAME], error_message(rc));
+        }
       linklist_free(member_base);
-      moira_disconnect();
-      return;
+      goto cleanup;
     }
+cleanup:
+  moira_disconnect();
 }
 
 #define LM_EXTRA_ACTIVE          (LM_END)
@@ -360,41 +513,126 @@ void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
 #define LM_EXTRA_END      (LM_END+6)
 
 void do_member(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)
 {
+  char  *call_args[6];
+  char  *av[2];
+  char  group_name[128];
+  char  user_name[128];
+  int   rc;
+
   if (afterc)
     {
       if (afterc < LM_EXTRA_END)
-       return;
+        return;
       else
-       {
-         if (!atoi(after[LM_EXTRA_ACTIVE]) || !atoi(after[LM_EXTRA_GROUP]))
-           return;
-       }
-      edit_group(1, after[LM_LIST], after[LM_TYPE], after[LM_MEMBER], 
-                ldap_handle, dn_path, ldap_hostname);
+        {
+          if (!atoi(after[LM_EXTRA_ACTIVE]) || !atoi(after[LM_EXTRA_GROUP]))
+            return;
+        }
+      strcpy(user_name, after[U_NAME]);
+      strcpy(group_name, after[LM_LIST]);
     }
   else if (beforec)
     {
       if (beforec < LM_EXTRA_END)
-       return;
+             return;
       else
-       {
-         if (!atoi(before[LM_EXTRA_ACTIVE]) || !atoi(before[LM_EXTRA_GROUP]))
-           return;
-       }
-      edit_group(0, before[LM_LIST], before[LM_TYPE], before[LM_MEMBER],
-                ldap_handle, dn_path, ldap_hostname);
+        {
+          if (!atoi(before[LM_EXTRA_ACTIVE]) || !atoi(before[LM_EXTRA_GROUP]))
+              return;
+        }
+      strcpy(user_name, before[U_NAME]);
+      strcpy(group_name, before[LM_LIST]);
     }
+
+
+  if (rc = moira_connect())
+    {
+      critical_alert("AD incremental", 
+                     "Moira error retrieving grouplist of user %s: %s",
+                     user_name, error_message(rc));
+      return;
+    }
+  av[0] = group_name;
+  call_args[0] = (char *)ldap_handle;
+  call_args[1] = dn_path;
+  call_args[2] = group_name;
+  call_args[3] = NULL;
+  call_args[4] = NULL;
+  member_base = NULL;
+  sid_base = NULL;
+  sid_ptr = &sid_base;
+  if (!(rc = mr_query("get_list_info", 1, av, group_create, call_args)))
+    {
+      if (sid_base != NULL)
+        {
+          sid_update(ldap_handle, dn_path);
+          linklist_free(sid_base);
+        }
+      if (!(rc = mr_query("get_members_of_list", 1, av, member_list_build,
+                          call_args)))
+        {
+          rc = member_list_process(ldap_handle, dn_path, group_name,
+                                   call_args[3], call_args[4]);
+        }
+      else
+        {
+          if (rc == MR_NO_MATCH)
+            {
+              if (call_args[3] != NULL)
+                free(call_args[3]);
+              if (call_args[4] != NULL)
+                free(call_args[4]);
+              call_args[3] = NULL;
+              call_args[4] = NULL;
+              sid_base = NULL;
+              sid_ptr = &sid_base;
+              rc = group_ad_delete(ldap_handle, dn_path, group_name);
+              if (!(rc = mr_query("get_list_info", 1, av, group_create, call_args)))
+                {
+                  if (sid_base != NULL)
+                    {
+                      sid_update(ldap_handle, dn_path);
+                      linklist_free(sid_base);
+                    }
+                }
+            }
+        }
+    }
+  if (rc)
+    {
+      if (afterc)
+        critical_alert("AD incremental", "Couldn't add %s to group %s ",
+                       user_name, group_name);
+      else
+        critical_alert("AD incremental", "Couldn't remove %s from group %s ",
+                       user_name, group_name);
+    }
+  linklist_free(member_base);
+  if (call_args[3] != NULL)
+    free(call_args[3]);
+  if (call_args[4] != NULL)
+    free(call_args[4]);
+  moira_disconnect();
 }
 
+
 void do_user(LDAP *ldap_handle, LDAPMessage *ldap_entry, char *ldap_hostname, 
-            char *dn_path, char **before, int beforec, char **after, 
-            int afterc)
+             char *dn_path, char **before, int beforec, char **after, 
+             int afterc)
 {
-  int astate = 0, bstate = 0, auid = 0, buid = 0, rc;
-  char *av[2];
-  
+  int       astate;
+  int       bstate;
+  int       auid;
+  int       buid;
+  int       rc;
+  char      *av[2];
+  LK_ENTRY  *list_base;
+  LK_ENTRY  *ptr;
+  char      *call_args[6];
+
+  auid = buid = astate = bstate = 0;
   if (afterc > U_STATE)
     astate = atoi(after[U_STATE]);
   if (beforec > U_STATE)
@@ -403,846 +641,257 @@ void do_user(LDAP *ldap_handle, LDAPMessage *ldap_entry, char *ldap_hostname,
     auid = atoi(after[U_UID]);
   if (beforec > U_UID)
     buid = atoi(before[U_UID]);
-  
+
   if (astate == 2)
     astate = 1;
   if (bstate == 2)
     bstate = 1;
-  
+
   if (astate != 1 && bstate != 1)              /* inactive user */
     return;
-  
-  if ((astate == bstate) && (auid == buid) && 
-      !strcmp(before[U_NAME], after[U_NAME]))
+
+  if (astate == bstate && auid == buid && !strcmp(before[U_NAME], after[U_NAME]))
     return;
-  
-  if (astate == bstate)
-    {
-      com_err(whoami, 0, "Changing user %s to %s", before[U_NAME], 
-             after[U_NAME]);
-      rc = member_update(ldap_handle, dn_path, ldap_entry, before[U_NAME], 
-                        after[U_NAME],  ldap_hostname, MEMBER_CHANGE_NAME, 
-                        NULL);
-      if (rc)
-       {
-         critical_alert("incremental",
-                        "Couldn't change user %s (id %d) to %s (id %d)",
-                        before[U_NAME], buid, after[U_NAME], auid);
-       }
-      return;
-    }
-  if (bstate == 1)
+  if (rc = moira_connect())
     {
-      com_err(whoami, 0, "Deleting user %s", before[U_NAME]);
-      rc = member_update(ldap_handle, dn_path, ldap_entry, before[U_NAME], 
-                        NULL, ldap_hostname, MEMBER_DEACTIVATE, NULL);
-      if (rc)
-       {
-         critical_alert("incremental", "Couldn't deactivate user %s (id %d)",
-                        before[U_NAME], buid);
-       }
-      return;
-    }
-  if (astate == 1)
-    {
-      com_err(whoami, 0, "%s user %s",
-             ((bstate != 0) ? "Reactivating" : "Creating"),
-             after[U_NAME]);
-      
-      rc = member_update(ldap_handle, dn_path, ldap_entry, after[U_NAME], 
-                        NULL, ldap_hostname, MEMBER_ACTIVATE, NULL);
-      if (rc)
-       {
-         critical_alert("incremental", "Couldn't activate user %s (id %d)",
-                        after[U_NAME], auid);
-         return;
-       }
-      if (bstate != 0)
-       {
-         /* Reactivating a user; get his group list */
-         rc = moira_connect();
-         if (rc)
-           {
-             critical_alert("incremental", "Error contacting Moira server "
-                            "to retrieve grouplist of user %s: %s",
-                            after[U_NAME], error_message(rc));
-             return;
-           }
-         av[0] = "ruser";
-         av[1] = after[U_NAME];
-         member_base = NULL;
-         rc = mr_query("get_lists_of_member", 2, av, add_user_lists, 
-                       after[U_NAME]);
-         if (rc && rc != MR_NO_MATCH)
-           {
-             critical_alert("incremental",
-                            "Couldn't retrieve membership of user %s: %s",
-                            after[U_NAME], error_message(rc));
-           }
-         else
-           {
-             rc = member_update(ldap_handle, dn_path, ldap_entry, 
-                                after[U_NAME], NULL,  ldap_hostname, 
-                                MEMBER_ADD, member_base);
-             linklist_free(member_base);
-           }
-         moira_disconnect();
-       }
+      critical_alert("AD incremental", 
+                     "Error connection to Moira: %s",
+                     error_message(rc));
       return;
     }
-}
 
-int group_update(LDAP *ldap_handle, char *ldap_hostname, char *group_name,
-                char *after_group_name, int operation, LK_ENTRY *user_list)
-{
-  char distinguished_name[1024], filter_exp[1024], temp[256];
-  char ***modvalues, *attr_array[3], *dn_path = NULL;
-  int newvalue_count, group_count, sPtr_count;
-  LDAPMod **newvalue_array;
-  LK_ENTRY *group_base;
-  LK_ENTRY **sPtr;
-  LK_ENTRY *pPtr;
-  ULONG rc = 0;
-  
-  convert_domain_to_dn(ldap_hostname, &dn_path);
-  
-  newvalue_array = NULL;
-  newvalue_count = 0;
-  modvalues = NULL;
-  group_base = NULL;
-  group_count = 0;
-  newvalue_count = 0;
-  newvalue_array = NULL;
-  modvalues = NULL;
-  if ((newvalue_array = calloc(1, (5+1) * sizeof(LDAPMod *))) == NULL)
+  if (astate == bstate)
     {
-      rc = 1;
+      com_err(whoami, 0, "Changing user %s to %s", before[U_NAME],
+              after[U_NAME]);
+      av[0] = after[U_NAME];
+      call_args[0] = (char *)ldap_handle;
+      call_args[1] = dn_path;
+      sid_base = NULL;
+      sid_ptr = &sid_base;
+      if (rc = mr_query("get_user_account_by_login", 1, av, user_create,
+                        call_args))
+        {
+          critical_alert("AD incremental",
+                         "Couldn't change user name for %s to %s",
+                         before[U_NAME], after[U_NAME]);
+          goto cleanup;
+        }
+      if (sid_base != NULL)
+        {
+          sid_update(ldap_handle, dn_path);
+          linklist_free(sid_base);
+        }
+      user_delete(ldap_handle, dn_path, before[U_NAME]);
+      av[0] = "ruser";
+      av[1] = after[U_NAME];
+      call_args[0] = after[U_NAME];
+      member_base = NULL;
+      if (rc = mr_query("get_lists_of_member", 2, av, group_list_build,
+                        call_args))
+        {
+          critical_alert("AD incremental",
+                         "Couldn't retrieve membership of user %s: %s",
+                         after[U_NAME], error_message(rc));
+          goto cleanup;
+        }
+      list_base = member_base;
+      ptr = list_base;
+      while (ptr)
+        {
+          rc = group_update_membership(ldap_handle, dn_path, ptr->list);
+          ptr = ptr->next;
+          }
+      linklist_free(list_base);
       goto cleanup;
     }
-  newvalue_array[0] = NULL;
-  newvalue_array[1] = NULL;
-  newvalue_array[2] = NULL;
-  newvalue_array[3] = NULL;
-  newvalue_array[4] = NULL;
-  if ((modvalues = calloc(1, (5+1) * sizeof(char **))) == NULL)
+  if (bstate == 1)
     {
-      rc = 1;
+      com_err(whoami, 0, "Deactivate/Delete user %s from the AD", before[U_NAME]);
+      if (rc = user_delete(ldap_handle, dn_path, before[U_NAME]))
+        {
+          critical_alert("AD incremental",
+                         "Couldn't deactivate/delete user %s (id %d) from the AD",
+                         before[U_NAME], buid);
+        }
       goto cleanup;
     }
-  modvalues[0] = NULL;
-  modvalues[1] = NULL;
-  modvalues[2] = NULL;
-  modvalues[3] = NULL;
-  modvalues[4] = NULL;
-  
-  if (operation == GROUP_DELETE)
-    {
-      sprintf(filter_exp, "(sAMAccountName=%s)", group_name);
-      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)
-       goto cleanup;
-      if (group_count == 1)
-       rc = ldap_delete_s(ldap_handle, group_base->value);
-      if (rc != LDAP_SUCCESS)
-       {
-         critical_alert("incremental",
-                        "Couldn't delete group %s: %s",
-                        group_name, ldap_err2string(rc));
-         goto cleanup;
-       }
-    }
-  else if (operation == GROUP_CREATE)
-    {
-      linklist_create_entry("cn", group_name, &group_base);
-      group_count = 1;
-      if ((rc = construct_newvalues(group_base, group_count, newvalue_count,
-                                   NULL, NULL, &newvalue_array, &modvalues, 
-                                   REPLACE)) == 1)
-       goto cleanup;
-      newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-      newvalue_array[newvalue_count]->mod_type = "cn";
-      newvalue_array[newvalue_count]->mod_values = modvalues[newvalue_count];
-      linklist_free(group_base);
-      group_base = NULL;
-      
-      ++newvalue_count;
-      linklist_create_entry("name", group_name, &group_base);
-      group_count = 1;
-      if ((rc = construct_newvalues(group_base, group_count, newvalue_count,
-                                   NULL, NULL, &newvalue_array, &modvalues, 
-                                   REPLACE)) == 1)
-       goto cleanup;
-      newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-      newvalue_array[newvalue_count]->mod_type = "name";
-      newvalue_array[newvalue_count]->mod_values = modvalues[newvalue_count];
-      linklist_free(group_base);
-      group_base = NULL;
-      
-      ++newvalue_count;
-      linklist_create_entry("objectClass","top", &group_base);
-      linklist_create_entry("objectClass", "group", &group_base->next);
-      group_count = 2;
-      if ((rc = construct_newvalues(group_base, group_count, newvalue_count,
-                                   NULL, NULL, &newvalue_array, &modvalues, 
-                                   REPLACE)) == 1)
-       goto cleanup;
-      newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-      newvalue_array[newvalue_count]->mod_type = "objectClass";
-      newvalue_array[newvalue_count]->mod_values = modvalues[newvalue_count];
-      linklist_free(group_base);
-      group_base = NULL;
-      
-      ++newvalue_count;
-      linklist_create_entry("sAMAccountName", group_name, &group_base);
-      group_count = 1;
-      if ((rc = construct_newvalues(group_base, group_count, newvalue_count,
-                                   NULL, NULL, &newvalue_array, &modvalues, 
-                                   REPLACE)) == 1)
-       goto cleanup;
-      newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-      newvalue_array[newvalue_count]->mod_type = "sAMAccountName";
-      newvalue_array[newvalue_count]->mod_values = modvalues[newvalue_count];
-      linklist_free(group_base);
-      group_base = NULL;
-      
-      sprintf(temp,"CN=%s,%s,%s", group_name, group_ou, dn_path);
-      rc = ldap_add_s(ldap_handle, temp, newvalue_array);
-      if (rc != LDAP_SUCCESS)
-       {
-         critical_alert("incremental",
-                        "Couldn't create group %s: %s",
-                        group_name, ldap_err2string(rc));
-         goto cleanup;
-       }
-    }
-  else if (operation == GROUP_UPDATE_MEMBERS)
-    {
-      sprintf(filter_exp, "(sAMAccountName=%s)", group_name);
-      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)
-       goto cleanup;
-      if (group_count != 1)
-       {
-         rc = 1;
-         goto cleanup;
-       }
-      strcpy(distinguished_name, group_base->value);
-      linklist_free(group_base);
-      
-      pPtr = member_base;
-      group_base = NULL;
-      group_count = 0;
-      sPtr = &group_base;
-      while (pPtr)
-       {
-         sprintf(filter_exp, "(sAMAccountName=%s)", pPtr->member);
-         attr_array[0] = "distinguishedName";
-         attr_array[1] = NULL;
-         if ((*sPtr) != NULL)
-           sPtr = &((*sPtr)->next);
-         sPtr_count = 0;
-         if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, 
-                                  attr_array, sPtr, &sPtr_count)) != 0)
-           goto cleanup;
-         if (sPtr_count != 0)
-           group_count += sPtr_count;
-         pPtr = pPtr->next;
-       }
-      if (group_count != 0)
-       {
-         if ((rc = construct_newvalues(group_base, group_count, 
-                                       newvalue_count, NULL, NULL,
-                                       &newvalue_array, &modvalues, 
-                                       REPLACE)) == 1)
-           goto cleanup;
-         linklist_free(group_base);
-         newvalue_array[newvalue_count]->mod_type = "member";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-         rc = ldap_modify_s(ldap_handle, distinguished_name, newvalue_array);
-         group_count = 0;
-         group_base = NULL;
-         if (rc != LDAP_SUCCESS)
-           {
-             critical_alert("incremental",
-                            "Couldn't add users to group %s: %s",
-                            group_name, ldap_err2string(rc));
-             goto cleanup;
-            }
-       }
-    }
-  else if (operation == GROUP_MOVE_MEMBERS)
+  if (astate == 1)
     {
-      sprintf(filter_exp, "(sAMAccountName=%s)", after_group_name);
-      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)
-       goto cleanup;
-      if (group_count != 1)
-       {
-         rc = 1;
-         goto cleanup;
-       }
-      strcpy(distinguished_name, group_base->value);
-      linklist_free(group_base);
-      
-      group_base = NULL;
-      group_count = 0;
-      sprintf(filter_exp, "(sAMAccountName=%s)", group_name);
-      attr_array[0] = "member";
-      attr_array[1] = NULL;
-      if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                              &group_base, &group_count)) != 0)
-       goto cleanup;
-      
-      if (group_count != 0)
-       {
-         if ((rc = construct_newvalues(group_base, group_count, 
-                                       newvalue_count, NULL, NULL,
-                                       &newvalue_array, &modvalues, 
-                                       REPLACE)) == 1)
-           goto cleanup;
-         linklist_free(group_base);
-         newvalue_array[newvalue_count]->mod_type = "member";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-         rc = ldap_modify_s(ldap_handle, distinguished_name, newvalue_array);
-         group_count = 0;
-         group_base = NULL;
-         if (rc != LDAP_SUCCESS)
-           {
-             critical_alert("incremental",
-                            "Couldn't add users to group %s: %s",
-                            group_name, ldap_err2string(rc));
-             goto cleanup;
-           }
-       }
-    }
-  
- cleanup:
-  free_values(newvalue_count, newvalue_array, modvalues);
-  linklist_free(group_base);
-  if (dn_path != NULL)
-    free(dn_path);
-  if (rc == 1)
-    critical_alert("incremental",
-                  "Couldn't process group %s: %s",
-                  group_name, "Cannot calloc - out of memory");
-  return(rc);
-}
+      com_err(whoami, 0, "%s user %s",
+              ((bstate != 0) ? "Reactivating" : "Creating"),
+              after[U_NAME]);
 
-int member_update(LDAP *ldap_handle, char *cn_path, LDAPMessage *ldap_entry, 
-                 char *login_name, char *new_login_name, char *ldap_hostname,
-                 int operation, LK_ENTRY *group_list)
-{
-  char distinguished_name[1024], filter_exp[1024], temp[64];
-  char ***modvalues;  /* each *mod has a char **modvalue */
-  char *attr_array[3], *dn_path = NULL;
-  int newvalue_count, memberOf_count, group_count, processGroup_count;
-  LDAPMod     **newvalue_array;
-  LK_ENTRY    *processGroup;
-  LK_ENTRY    *processGroup_base;
-  LK_ENTRY    *memberOf_base;
-  LK_ENTRY    *group_base;
-  LK_ENTRY    *gPtr;
-  LK_ENTRY    *sPtr;
-  LK_ENTRY    *pPtr;
-  ULONG       rc;
-  ULONG       ulongValue;
-  
-  memset(distinguished_name, '\0', sizeof(distinguished_name));
-  get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
-  if (strlen(distinguished_name) == 0)
-    return(1);
-  
-  convert_domain_to_dn(ldap_hostname, &dn_path);
-  
-  memberOf_base = NULL;
-  processGroup_base = NULL;
-  processGroup = NULL;
-  newvalue_array = NULL;
-  newvalue_count = 0;
-  modvalues = NULL;
-  group_count = 0;
-  group_base = NULL;
-  
-  if ((newvalue_array = calloc(1, (3+1) * sizeof(LDAPMod *))) == NULL)
-    {
-      rc = 1;
-      goto cleanup;
-    }
-  newvalue_array[0] = NULL;
-  newvalue_array[1] = NULL;
-  newvalue_array[2] = NULL;
-  newvalue_array[3] = NULL;
-  if ((modvalues = calloc(1, (3+1) * sizeof(char **))) == NULL)
-    {
-      rc = 1;
-      goto cleanup;
-    }
-  modvalues[0] = NULL;
-  modvalues[1] = NULL;
-  modvalues[2] = NULL;
-  modvalues[3] = NULL;
-  
-  if (operation == MEMBER_CHANGE_NAME)
-    {
-      sprintf(filter_exp, "(sAMAccountName=%s)", login_name);
-      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)
-       goto cleanup;
-      
-      if (group_count != 0)
-       {
-         if ((rc = construct_newvalues(group_base, group_count, 
-                                       newvalue_count, login_name, 
-                                       new_login_name, &newvalue_array, 
-                                       &modvalues, REPLACE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_REPLACE ;
-         newvalue_array[newvalue_count]->mod_type = "sAMAccountName";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         linklist_free(group_base);
-         group_count = 0;
-         group_base = NULL;
-         ++newvalue_count;
-       }
-      
-      sprintf(filter_exp, "(sAMAccountName=%s)", login_name);
-      attr_array[0] = "UserPrincipalName";
-      attr_array[1] = NULL;
-      if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                              &group_base, &group_count)) != 0)
-       goto cleanup;
-      if (group_count != 0)
-       {
-         if ((rc = construct_newvalues(group_base, group_count, 
-                                       newvalue_count, login_name, 
-                                       new_login_name, &newvalue_array, 
-                                       &modvalues, SUBSTITUTE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_REPLACE ;
-         newvalue_array[newvalue_count]->mod_type = "UserPrincipalName";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         linklist_free(group_base);
-         group_count = 0;
-         group_base = NULL;
-         ++newvalue_count;
-       }
-      
-      sprintf(filter_exp, "(sAMAccountName=%s)", login_name);
-      attr_array[0] = "AltSecurityIdentities";
-      attr_array[1] = NULL;
-      if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                              &group_base, &group_count)) != 0)
-       goto cleanup;
-      if (group_count != 0)
-       {
-         if ((rc = construct_newvalues(group_base, group_count, 
-                                       newvalue_count, login_name, 
-                                       new_login_name, &newvalue_array, 
-                                       &modvalues, SUBSTITUTE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_REPLACE ;
-         newvalue_array[newvalue_count]->mod_type = "AltSecurityIdentities";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         linklist_free(group_base);
-         group_count = 0;
-         group_base = NULL;
-         ++newvalue_count;
-       }
-      
-      if (newvalue_count != 0)
-       rc = ldap_modify_s(ldap_handle, distinguished_name, newvalue_array);
-      if (rc != LDAP_SUCCESS)
-       {
-         critical_alert("incremental",
-                        "Couldn't process user %s: %s",
-                        login_name, ldap_err2string(rc));
-       }
-      goto cleanup;
-    }
-  if ((operation == MEMBER_ACTIVATE) ||
-      (operation == MEMBER_DEACTIVATE))
-    {    
-      sprintf(filter_exp, "(sAMAccountName=%s)", login_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)
-       goto cleanup;
-      
-      if (group_count != 0)
-       {
-         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, 
-                                       newvalue_count, (*group_base).value, 
-                                       temp, &newvalue_array, &modvalues, 
-                                       REPLACE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_REPLACE ;
-         newvalue_array[newvalue_count]->mod_type = "UserAccountControl";
-         newvalue_array[newvalue_count]->mod_values = 
-           modvalues[newvalue_count];
-         ++newvalue_count;
-         rc = ldap_modify_s(ldap_handle, distinguished_name, newvalue_array);
-         if (rc != LDAP_SUCCESS)
-           {
-             critical_alert("incremental",
-                            "Couldn't process user %s: %s",
-                            login_name, ldap_err2string(rc));
-           }
-       }
-      goto cleanup;
-    }
-  
-  sprintf(filter_exp, "(objectClass=group)");
-  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)
-    goto cleanup;
-  
-  sPtr = group_list;
-  while (sPtr != NULL)
-    {
-      gPtr = group_base;
-      while (gPtr != NULL)
-       {
-         if (!strcmp(sPtr->list, gPtr->value))
-           {
-             if (sPtr->dn != NULL)
-               free(sPtr->dn);
-             sPtr->dn = calloc(1, strlen(gPtr->dn) + 1);
-             memset(sPtr->dn, '\0', strlen(gPtr->dn) + 1);
-             strcpy(sPtr->dn, gPtr->dn);
-             if (sPtr->attribute != NULL)
-               free(sPtr->attribute);
-             sPtr->attribute = calloc(1, strlen(gPtr->attribute) + 1);
-             memset(sPtr->attribute, '\0', strlen(gPtr->attribute) + 1);
-             strcpy(sPtr->attribute, gPtr->attribute);
-             if (sPtr->value != NULL)
-               free(sPtr->value);
-             sPtr->value = calloc(1, strlen(gPtr->value) + 1);
-             memset(sPtr->value, '\0', strlen(gPtr->value) + 1);
-             strcpy(sPtr->value, gPtr->value);
-             break;
-           }
-         gPtr = gPtr->next;
-       }
-      sPtr = sPtr->next;
-    }
-  
-  memberOf_count = 0;
-  memberOf_base = NULL;
-  sprintf(filter_exp, "(sAMAccountName=%s)", login_name);
-  attr_array[0] = "memberOf";
-  attr_array[1] = NULL;
-  if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
-                          &memberOf_base, &memberOf_count)) != 0)
-    goto cleanup;
-  
-  processGroup_count = 0;
-  processGroup_base = NULL;
-  sPtr = group_list;
-  while (sPtr)
-    {
-      if (sPtr->dn == NULL)
-       {
-         sPtr = sPtr->next;
-         continue;
-       }
-      gPtr = memberOf_base;
-      while (gPtr)
-       {
-         if (!strcmp(gPtr->value, sPtr->dn))
-           break;
-         gPtr = gPtr->next;
-       }
-      if (sPtr->dn != NULL)
-       {
-         if (((gPtr == NULL) && (operation == MEMBER_ADD)) ||
-             ((gPtr != NULL) && (operation == MEMBER_REMOVE)))
-           {
-             gPtr = calloc(1, sizeof(LK_ENTRY));
-             memset(gPtr, '\0', sizeof(LK_ENTRY));
-             gPtr->attribute = calloc(1, strlen("member") + 1);
-             memset(gPtr->attribute, '\0', strlen("member") + 1);
-             strcpy(gPtr->attribute, "member");
-             gPtr->dn = calloc(1, strlen(sPtr->dn) + 1);
-             memset(gPtr->dn, '\0', strlen(sPtr->dn) + 1);
-             strcpy(gPtr->dn, sPtr->dn);
-             gPtr->value = calloc(1, strlen(distinguished_name) + 1);
-             memset(gPtr->value, '\0', strlen(distinguished_name) + 1);
-             strcpy(gPtr->value, distinguished_name);
-             if (processGroup_base != NULL)
-               gPtr->next = processGroup_base;
-             processGroup_base = gPtr;
-             gPtr = NULL;
-             ++processGroup_count;
-           }
-       }
-      sPtr = sPtr->next;
-    }
-  
-  linklist_free(group_base);
-  linklist_free(processGroup);
-  group_base = NULL;
-  processGroup = NULL;
-  sPtr = processGroup_base;
-  while (sPtr)
-    {
-      newvalue_count = 0;
-      newvalue_array = NULL;
-      modvalues = NULL;
-      processGroup = NULL;
-      if ((newvalue_array = calloc(1, (1+1) * sizeof(LDAPMod *))) == NULL)
-       {
-         rc = 1;
-         goto cleanup;
-       }
-      newvalue_array[0] = NULL;
-      newvalue_array[1] = NULL;
-      if ((modvalues = calloc(1, (1+1) * sizeof(char **))) == NULL)
-       {
-         rc = 1;
-         goto cleanup;
-       }
-      modvalues[0] = NULL;
-      modvalues[1] = NULL;
-      
-      if (operation == MEMBER_REMOVE)
-       {
-         processGroup_count = 0;
-         processGroup = NULL;
-         sprintf(filter_exp, "(distinguishedName=%s)", sPtr->dn);
-         attr_array[0] = "member";
-         attr_array[1] = NULL;
-         if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, 
-                                  attr_array,  &processGroup, 
-                                  &processGroup_count)) != 0)
-           goto cleanup;
-         gPtr = processGroup;
-         pPtr = NULL;
-         while (gPtr)
-           {
-             if (!strcmp(gPtr->value, sPtr->value))
-               {
-                 if (pPtr != NULL)
-                   pPtr->next = gPtr->next;
-                 else
-                   processGroup = gPtr->next;
-                 gPtr->next = NULL;
-                 linklist_free(gPtr);
-                 --processGroup_count;
-                 break;
-               }
-             pPtr = gPtr;
-             gPtr = gPtr->next;
-           }
-         if ((rc = construct_newvalues(processGroup, processGroup_count, 
-                                       newvalue_count, NULL, NULL,
-                                       &newvalue_array, &modvalues, 
-                                       REPLACE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_REPLACE ;
-         pPtr = processGroup;
-       }
-      else
-       {
-         processGroup = calloc(1, sizeof(LK_ENTRY));
-         memset(processGroup, '\0', sizeof(LK_ENTRY));
-         memcpy(processGroup, sPtr, sizeof(LK_ENTRY));
-         processGroup->next = NULL;
-         processGroup_count = 1;
-         if ((rc = construct_newvalues(processGroup, processGroup_count, 
-                                       newvalue_count, NULL, NULL,
-                                       &newvalue_array, &modvalues, 
-                                       REPLACE)) == 1)
-           goto cleanup;
-         newvalue_array[newvalue_count]->mod_op = LDAP_MOD_ADD;
-         pPtr = sPtr;
-       }
-      newvalue_array[newvalue_count]->mod_type = "member";
-      newvalue_array[newvalue_count]->mod_values = modvalues[newvalue_count];
-      rc = ldap_modify_s(ldap_handle, sPtr->dn, newvalue_array);
-      if (operation == MEMBER_REMOVE)
-       linklist_free(processGroup);
+      av[0] = after[U_NAME];
+      call_args[0] = (char *)ldap_handle;
+      call_args[1] = dn_path;
+      sid_base = NULL;
+      sid_ptr = &sid_base;
+      if (rc = mr_query("get_user_account_by_login", 1, av, user_create,
+                        call_args))
+        {
+          critical_alert("AD incremental", "Couldn't activate user %s (id %d)",
+                         after[U_NAME], auid);
+          goto cleanup;
+        }
+      if (sid_base != NULL)
+        {
+          sid_update(ldap_handle, dn_path);
+          linklist_free(sid_base);
+        }
+
+/*
+      av[0] = "ruser";
+      av[1] = after[U_NAME];
+      call_args[0] = after[U_NAME];
+      member_base = NULL;
+      if (rc = mr_query("get_lists_of_member", 2, av, group_list_build,
+                        call_args))
+        {
+          critical_alert("AD incremental",
+                         "Couldn't retrieve group membership of user %s",
+                         after[U_NAME]);
+        }
       else
-       free(processGroup);
-      processGroup = NULL;
-      newvalue_count = 1;
-      free_values(newvalue_count, newvalue_array, modvalues);
-      newvalue_array = NULL;
-      modvalues = NULL;
-      if (rc != LDAP_SUCCESS)
-       {
-         critical_alert("incremental",
-                        "Couldn't process user %s: %s",
-                        login_name, ldap_err2string(rc));
-         goto cleanup;
-       }
-      sPtr = sPtr->next;
-    }
-  
- cleanup:
-  free_values(newvalue_count, newvalue_array, modvalues);
-  linklist_free(memberOf_base);
-  linklist_free(group_base);
-  linklist_free(processGroup_base);
-  free(dn_path);
-  if (rc == 1)
-    critical_alert("incremental",
-                  "Couldn't process user %s: %s",
-                  login_name, "Cannot calloc - out of memory");
-  return(rc);
+        {
+          list_base = member_base;
+          ptr = list_base;
+          while (ptr)
+            {
+              rc = group_update_membership(ldap_handle, dn_path, ptr->list);
+              ptr = ptr->next;
+            }
+          linklist_free(list_base);
+        }
+*/
+    }
+cleanup:
+  moira_disconnect();
 }
 
 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
-                       int newvalue_count, char *oldValue, char *newValue,
-                       LDAPMod ***newValueArray, char ****modvalues,
-                       int type)
+                        char *oldValue, char *newValue,
+                        char ***modvalues, int type)
 {
-  LK_ENTRY *linklist_ptr;
-  int i;
-  char *cPtr;
-  
-  if (((*newValueArray)[newvalue_count] = 
-       calloc(1, sizeof(LDAPMod))) == NULL)
-    return(1);
-
-  if (((*modvalues)[newvalue_count] = 
-       calloc(1, (modvalue_count + 1) * sizeof(char *))) == NULL)
-    return(1);
+  LK_ENTRY    *linklist_ptr;
+  int         i;
+  char        *cPtr;
 
+  if (((*modvalues) = calloc(1, (modvalue_count + 1) * sizeof(char *)))
+      == NULL)
+    {
+      return(1);
+    }
   for (i = 0; i < (modvalue_count + 1); i++)
-    (*modvalues)[newvalue_count][i] = NULL;
+    (*modvalues)[i] = NULL;
   if (modvalue_count != 0)
     {
       linklist_ptr = linklist_base;
       for (i = 0; i < modvalue_count; i++)
-       {
-         if ((oldValue != NULL) && (newValue != NULL))
-           {
-             if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue)) 
-                 != (char *)NULL)
-               {
-                 if (type == REPLACE)
-                   {
-                     if (((*modvalues)[newvalue_count][i] = 
-                          calloc(1, strlen(newValue) + 1)) == NULL)
-                       return(1);
-                     memset((*modvalues)[newvalue_count][i], '\0', 
-                            strlen(newValue) + 1);
-                     strcpy((*modvalues)[newvalue_count][i], newValue);
-                   }
-                 else
-                   {
-                     if (((*modvalues)[newvalue_count][i] = 
-                          calloc(1, (int)(cPtr - linklist_ptr->value) + 
-                                 (linklist_ptr->length - strlen(oldValue)) + 
-                                 strlen(newValue) + 1)) == NULL)
-                       return(1);
-                     memset((*modvalues)[newvalue_count][i], '\0', 
-                            (int)(cPtr - linklist_ptr->value) + 
-                            (linklist_ptr->length - strlen(oldValue)) + 
-                            strlen(newValue) + 1);
-                     memcpy((*modvalues)[newvalue_count][i], 
-                            linklist_ptr->value, 
-                            (int)(cPtr - linklist_ptr->value));
-                     strcat((*modvalues)[newvalue_count][i], newValue);
-                     strcat((*modvalues)[newvalue_count][i], 
-                            &linklist_ptr->value[(int)(cPtr - linklist_ptr->value) + strlen(oldValue)]);
-                   }
-               }
-             else
-               {
-                 (*modvalues)[newvalue_count][i] = 
-                   calloc(1, linklist_ptr->length + 1);
-                 memset((*modvalues)[newvalue_count][i], 
-                        '\0', linklist_ptr->length + 1);
-                 memcpy((*modvalues)[newvalue_count][i], 
-                        linklist_ptr->value, linklist_ptr->length);
-               }
-           }
-         else
-           {
-             (*modvalues)[newvalue_count][i] = 
-               calloc(1, linklist_ptr->length + 1);
-             memset((*modvalues)[newvalue_count][i], '\0', 
-                    linklist_ptr->length + 1);
-             memcpy((*modvalues)[newvalue_count][i], linklist_ptr->value, 
-                    linklist_ptr->length);
-           }
-         linklist_ptr = linklist_ptr->next;
-       }
-      (*modvalues)[newvalue_count][i] = NULL;
+        {
+          if ((oldValue != NULL) && (newValue != NULL))
+            {
+              if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue))
+                 != (char *)NULL)
+                {
+                  if (type == REPLACE)
+                    {
+                      if (((*modvalues)[i] = calloc(1, strlen(newValue) + 1))
+                          == NULL)
+                        return(1);
+                      memset((*modvalues)[i], '\0', strlen(newValue) + 1);
+                      strcpy((*modvalues)[i], newValue);
+                    }
+                  else
+                    {
+                      if (((*modvalues)[i] = calloc(1, 
+                                        (int)(cPtr - linklist_ptr->value) + 
+                                        (linklist_ptr->length - strlen(oldValue)) + 
+                                        strlen(newValue) + 1)) == NULL)
+                        return(1);
+                      memset((*modvalues)[i], '\0', 
+                             (int)(cPtr - linklist_ptr->value) + 
+                             (linklist_ptr->length - strlen(oldValue)) + 
+                             strlen(newValue) + 1);
+                      memcpy((*modvalues)[i], linklist_ptr->value, 
+                             (int)(cPtr - linklist_ptr->value));
+                      strcat((*modvalues)[i], newValue);
+                      strcat((*modvalues)[i], 
+     &linklist_ptr->value[(int)(cPtr - linklist_ptr->value) + strlen(oldValue)]);
+                    }
+                }
+              else
+                {
+                  (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
+                  memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
+                  memcpy((*modvalues)[i], linklist_ptr->value,
+                         linklist_ptr->length);
+                }
+            }
+        else
+            {
+              (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
+              memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
+              memcpy((*modvalues)[i], linklist_ptr->value,
+                     linklist_ptr->length);
+            }
+          linklist_ptr = linklist_ptr->next;
+        }
+      (*modvalues)[i] = NULL;
     }
   return(0);
 }
 
+
 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
-                  char **attr_array, LK_ENTRY **linklist_base,
-                  int *linklist_count)
+                   char **attr_array, LK_ENTRY **linklist_base,
+                   int *linklist_count)
 {
-  ULONG rc = 0;
+  ULONG       rc;
   LDAPMessage *ldap_entry;
-  
+
+  rc = 0;
   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)) 
+                          search_exp, attr_array, 0, &ldap_entry))
       != LDAP_SUCCESS)
     return(0);
-  rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, 
-                       linklist_count);
-  
+  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)
+                     LK_ENTRY **linklist_base, int *linklist_count)
 {
-  char distinguished_name[1024];
-  LK_ENTRY *linklist_ptr;
-  int rc;
-  
-  memset(distinguished_name, '\0', sizeof(distinguished_name));
-  get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
-  
+  char        distinguished_name[1024];
+  LK_ENTRY    *linklist_ptr;
+  int         rc;
+
   if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL)
     return(0);
-  
-  if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name, 
-                               linklist_base)) != 0)
+
+  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)
     return(rc);
-  
+
   while ((ldap_entry = ldap_next_entry(ldap_handle, ldap_entry)) != NULL)
     {
-      if ((rc = retrieve_attributes(ldap_handle, ldap_entry, 
-                                   distinguished_name, linklist_base)) != 0)
-       return(rc);
+      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)
+        return(rc);
     }
-  
+
   linklist_ptr = (*linklist_base);
   (*linklist_count) = 0;
   while (linklist_ptr != NULL)
@@ -1254,62 +903,62 @@ int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry,
 }
 
 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                       char *distinguished_name, LK_ENTRY **linklist_current)
+                        char *distinguished_name, LK_ENTRY **linklist_current)
 {
-  char *Attribute;
-  BerElement *ptr;
-  
+  char        *Attribute;
+  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);
+      retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name,
+                      linklist_current);
       ldap_memfree(Attribute);
-      while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, ptr)) 
-            != NULL)
-       {
-         retrieve_values(ldap_handle, ldap_entry, Attribute, 
-                         distinguished_name, linklist_current);
-         ldap_memfree(Attribute);
-       }
+      while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, 
+                                              ptr)) != NULL)
+        {
+          retrieve_values(ldap_handle, ldap_entry, Attribute,
+                          distinguished_name, linklist_current);
+          ldap_memfree(Attribute);
+        }
     }
+  ldap_ber_free(ptr, 0);
   return(0);
 }
 
-int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                   char *Attribute, char *distinguished_name,
-                   LK_ENTRY **linklist_current)
+int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
+                    char *Attribute, char *distinguished_name,
+                    LK_ENTRY **linklist_current)
 {
-  char **str_value;
-  char temp[256];
-  void **Ptr;
-  int use_bervalue;
-  LK_ENTRY *linklist_previous;
+  char        **str_value;
+  char        temp[256];
+  void        **Ptr;
+  int         use_bervalue;
+  LK_ENTRY    *linklist_previous;
   LDAP_BERVAL **ber_value;
-  DWORD ber_length;
+  DWORD       ber_length;
 #ifdef LDAP_DEBUG
-  SID *sid;
-  GUID *guid;
-  int i;
-  int intValue;
-  DWORD *subauth;
-  SID_IDENTIFIER_AUTHORITY *sid_auth;
-  unsigned char *subauth_count;
-#endif /*LDAP_DEBUG*/
+  SID         *sid;
+  GUID        *guid;
+  int         i;
+  int         intValue;
+  DWORD       *subauth;
+  SID_IDENTIFIER_AUTHORITY    *sid_auth;
+  unsigned char   *subauth_count;
+#endif /*LDAP_BEGUG*/
 
   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);
@@ -1319,307 +968,171 @@ int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
   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)
-           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);
-             (*linklist_current)->length = ber_length;
-           }
-         else
-           {
-             if (((*linklist_current)->value = calloc(1, 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)
-           return(1);
-         memset((*linklist_current)->dn, '\0', 
-                strlen(distinguished_name) + 1);
-         strcpy((*linklist_current)->dn, distinguished_name);
-         
+        {
+          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)
+            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);
+              (*linklist_current)->length = ber_length;
+            }
+          else
+            {
+              if (((*linklist_current)->value = calloc(1, 
+                                                  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)
+            return(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", 
-                     guid->Data1, guid->Data2, guid->Data3, 
-                     guid->Data4[0], guid->Data4[1], guid->Data4[2], 
-                     guid->Data4[3], guid->Data4[4], guid->Data4[5], 
-                     guid->Data4[6], guid->Data4[7]);
-             print_to_screen("     %20s : {%s}\n", Attribute, temp);
-           }
-         else if (!strcmp(Attribute, "objectSid"))
-           {
-             sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val);
+          if (!strcmp(Attribute, "objectGUID"))
+            {
+              guid = (GUID *)((*linklist_current)->value);
+              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], 
+                      guid->Data4[6], guid->Data4[7]);
+              print_to_screen("     %20s : {%s}\n", Attribute, temp);
+            }
+          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");
-             sid_auth = &sid->IdentifierAuthority;
-             if (sid_auth->Value[0])
-               print_to_screen("            SECURITY_NULL_SID_AUTHORITY\n");
-             else if (sid_auth->Value[1])
-               print_to_screen("            SECURITY_WORLD_SID_AUTHORITY\n");
-             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");
-             else if (sid_auth->Value[5])
-               print_to_screen("            SECURITY_NT_AUTHORITY\n");
-             else
-               print_to_screen("            UNKNOWN SID AUTHORITY\n");
-             subauth_count = GetSidSubAuthorityCount(sid);
-             print_to_screen("        SidSubAuthorityCount = %d\n", 
-                             *subauth_count);
-             print_to_screen("        SidSubAuthority:\n");
-             for (i = 0; i < *subauth_count; i++)
-               {
-                 if ((subauth = GetSidSubAuthority(sid, i)) != NULL)
-                   print_to_screen("            %u\n", *subauth);
-               }
+              print_to_screen("        Revision = %d\n", sid->Revision);
+              print_to_screen("        SID Identifier Authority:\n");
+              sid_auth = &sid->IdentifierAuthority;
+              if (sid_auth->Value[0])
+                print_to_screen("            SECURITY_NULL_SID_AUTHORITY\n");
+              else if (sid_auth->Value[1])
+                print_to_screen("            SECURITY_WORLD_SID_AUTHORITY\n");
+              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");
+              else if (sid_auth->Value[5])
+                print_to_screen("            SECURITY_NT_AUTHORITY\n");
+              else
+                print_to_screen("            UNKNOWN SID AUTHORITY\n");
+              subauth_count = GetSidSubAuthorityCount(sid);
+              print_to_screen("        SidSubAuthorityCount = %d\n", 
+                              *subauth_count);
+              print_to_screen("        SidSubAuthority:\n");
+              for (i = 0; i < *subauth_count; i++)
+                {
+                  if ((subauth = GetSidSubAuthority(sid, i)) != NULL)
+                    print_to_screen("            %u\n", *subauth);
+                }
 #endif
-           }
-         else if ((!memcmp(Attribute, "userAccountControl", 
-                           strlen("userAccountControl"))) ||
-                  (!memcmp(Attribute, "sAMAccountType", 
-                           strlen("sAmAccountType"))))
-           {
-             intValue = atoi(*Ptr);
-             print_to_screen("     %20s : %ld\n",Attribute, intValue);
-             if (!memcmp(Attribute, "userAccountControl", 
-                         strlen("userAccountControl")))
-               {
-                 if (intValue & UF_ACCOUNTDISABLE)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Account disabled");
-                 else
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Account active");
-                 if (intValue & UF_HOMEDIR_REQUIRED)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Home directory required");
-                 if (intValue & UF_LOCKOUT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Account locked out");
-                 if (intValue & UF_PASSWD_NOTREQD)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "No password required");
-                 if (intValue & UF_PASSWD_CANT_CHANGE)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Cannot change password");
-                 if (intValue & UF_TEMP_DUPLICATE_ACCOUNT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Temp duplicate account");
-                 if (intValue & UF_NORMAL_ACCOUNT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Normal account");
-                 if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Interdomain trust account");
-                 if (intValue & UF_WORKSTATION_TRUST_ACCOUNT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Workstation trust account");
-                 if (intValue & UF_SERVER_TRUST_ACCOUNT)
-                   print_to_screen("     %20s :    %s\n", "", 
-                                   "Server trust account");
-               }
-           }
-         else
-           {
-             print_to_screen("     %20s : %s\n",Attribute, *Ptr);
-           }
+            }
+          else if ((!memcmp(Attribute, "userAccountControl", 
+                            strlen("userAccountControl"))) ||
+                   (!memcmp(Attribute, "sAMAccountType", 
+                            strlen("sAmAccountType"))))
+            {
+              intValue = atoi(*Ptr);
+              print_to_screen("     %20s : %ld\n",Attribute, intValue);
+              if (!memcmp(Attribute, "userAccountControl", 
+                          strlen("userAccountControl")))
+                {
+                  if (intValue & UF_ACCOUNTDISABLE)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Account disabled");
+                  else
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Account active");
+                  if (intValue & UF_HOMEDIR_REQUIRED)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Home directory required");
+                  if (intValue & UF_LOCKOUT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Account locked out");
+                  if (intValue & UF_PASSWD_NOTREQD)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "No password required");
+                  if (intValue & UF_PASSWD_CANT_CHANGE)
+                    print_to_screen("     %20s :    %s\n",
+                                    "", "Cannot change password");
+                  if (intValue & UF_TEMP_DUPLICATE_ACCOUNT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Temp duplicate account");
+                  if (intValue & UF_NORMAL_ACCOUNT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Normal account");
+                  if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Interdomain trust account");
+                  if (intValue & UF_WORKSTATION_TRUST_ACCOUNT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Workstation trust account");
+                  if (intValue & UF_SERVER_TRUST_ACCOUNT)
+                    print_to_screen("     %20s :    %s\n", 
+                                    "", "Server trust account");
+                }
+            }
+          else
+            {
+              print_to_screen("     %20s : %s\n",Attribute, *Ptr);
+            }
 #endif /*LDAP_DEBUG*/
-       }
+        }
       if (str_value != NULL)
-       ldap_value_free(str_value);
+        ldap_value_free(str_value);
       if (ber_value != NULL)
-       ldap_value_free_len(ber_value);
+        ldap_value_free_len(ber_value);
     }
   (*linklist_current) = linklist_previous;
   return(0);
 }
 
-int add_user_lists(int ac, char **av, void *user)
-{
-  if (atoi(av[L_ACTIVE]) && atoi(av[L_GROUP])) /* active group ? */
-    edit_group(1, av[L_NAME], "USER", user, NULL, NULL, NULL);
-  return 0;
-}
-
-void edit_group(int op, char *group, char *type, char *member,
-               LDAP *ldap_handle, char *dn_path, char *ldap_hostname)
-{
-  ULONG rc;
-  char *p = 0;
-  char search_exp[128];
-  static char local_realm[REALM_SZ+1] = "";
-  LK_ENTRY *linklist;
-  LDAPMessage *ldap_entry; 
-  
-  /* The following KERBEROS rc allows for the use of entities
-   * user@foreign_cell.
-   */
-  if (!local_realm[0])
-    krb_get_lrealm(local_realm, 1);
-  if (!strcmp(type, "KERBEROS"))
-    {
-      p = (char *)strchr(member, '@');
-      if (p && !strcasecmp(p+1, local_realm))
-       *p = 0;
-    }
-  else if (strcmp(type, "USER"))
-    return;                                    /* invalid type */
-  
-  /* Cannot risk doing another query during a callback */
-  /* We could do this simply for type USER, but eventually this may also
-   * dynamically add KERBEROS types to the prdb, and we will need to do
-   * a query to look up the uid of the null-instance user 
-   */
-  if (mr_connections)
-    {
-      linklist = calloc(1, sizeof(LK_ENTRY));
-      if (!linklist)
-       {
-         critical_alert("incremental", "Out of memory");
-         exit(1);
-       }
-      memset(linklist, '\0', sizeof(LK_ENTRY));
-      linklist->op = op;
-      linklist->dn = NULL;
-      linklist->list = calloc(1, strlen(group) + 1);
-      memset(linklist->list, '\0', strlen(group) + 1);
-      strcpy(linklist->list, group);
-      linklist->type = calloc(1, strlen(type) + 1);
-      memset(linklist->type, '\0', strlen(type) + 1);
-      strcpy(linklist->type, type);
-      linklist->member = calloc(1, strlen(member) + 1);
-      memset(linklist->member, '\0', strlen(member) + 1);
-      strcpy(linklist->member, member);
-      linklist->next = member_base;
-      member_base = linklist;
-      return;
-    }
-  
-  com_err(whoami, 0, "%s %s %s group %s", (op ? "Adding" : "Removing"), 
-         member, (op ? "to" : "from"), group);
-  sprintf(search_exp, "(sAMAccountName=%s)", member);
-  if ((rc = ldap_search_s(ldap_handle, dn_path, LDAP_SCOPE_SUBTREE, 
-                         search_exp, NULL, 0, &ldap_entry)) != LDAP_SUCCESS)
-    {
-      critical_alert("incremental", "Couldn't %s %s %s %s",
-                    op ? "add" : "remove", member,
-                    op ? "to" : "from", group);
-      rc = ldap_msgfree(ldap_entry);
-      return;
-    }
-  linklist = calloc(1, sizeof(LK_ENTRY));
-  if (!linklist)
-    {
-      critical_alert("incremental", "Out of memory");
-      exit(1);
-    }
-  memset(linklist, '\0', sizeof(LK_ENTRY));
-  linklist->op = op;
-  linklist->dn = NULL;
-  linklist->list = calloc(1, strlen(group) + 1);
-  memset(linklist->list, '\0', strlen(group) + 1);
-  strcpy(linklist->list, group);
-  linklist->type = calloc(1, strlen(type) + 1);
-  memset(linklist->type, '\0', strlen(type) + 1);
-  strcpy(linklist->type, type);
-  linklist->member = calloc(1, strlen(member) + 1);
-  memset(linklist->member, '\0', strlen(member) + 1);
-  strcpy(linklist->member, member);
-  linklist->next = NULL;
-  
-  rc = member_update(ldap_handle, dn_path, ldap_entry, member, NULL, 
-                    ldap_hostname, op ? MEMBER_ADD : MEMBER_REMOVE, linklist);
-  if (rc)
-    {
-      critical_alert("incremental", "Couldn't %s %s %s %s: %s",
-                    op ? "add" : "remove", member,
-                    op ? "to" : "from", group);
-    }
-  
-  linklist_free(linklist);
-  rc = ldap_msgfree(ldap_entry);
-  /*
-   *  rc = pr_try(op ? pr_AddToGroup : pr_RemoveUserFromGroup, member, buf);
-   *  if (rc)
-   *  {
-   *  if (op==1 && rc == PRIDEXIST)
-   *  return;
-   *  if (rc == PRNOENT)
-   *  {
-   *  if (op == 0)
-   *  return;
-   * if (!strcmp(type, "KERBEROS"))
-   *   return;
-   *  rc = moira_connect();
-   *  if (!rc)
-   *  {
-   *  rc = mr_query("get_user_by_login", 1, &member,
-   *  (void *)check_user, (char *) &ustate);
-   *  }
-   *  if (rc)
-   *  {
-   *  critical_alert("incremental", "Error contacting Moira server "
-   *  "to lookup user %s: %s", member,
-   *  error_message(rc));
-   *  }
-   *  mr_disconnect();
-   *  mr_connections--;
-   *  if (!rc && ustate!=1 && ustate!=2)
-   *  return;
-   *  rc = PRNOENT;
-   *  }
-   *  critical_alert("incremental", "Couldn't %s %s %s %s: %s",
-   *  op ? "add" : "remove", member,
-   *  op ? "to" : "from", buf,
-   *  error_message(rc));
-   *  }
-   */
-}
-
 int moira_connect(void)
 {
-  long rc;
-  char HostName[64];
-  
+  long    rc;
+  char    HostName[64];
+
   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("afs.incr");
+        rc = mr_auth("winad.incr");
+*/
       return rc;
     }
   return 0;
@@ -1627,114 +1140,44 @@ int moira_connect(void)
 
 int moira_disconnect(void)
 {
-  if (!--mr_connections)
-    mr_disconnect();
-  return 0;
-}
-
-int add_list_members(int ac, char **av, void *group)
-{
-  edit_group(1, group, av[0], av[1], NULL, NULL, NULL);
-  return 0;
-}
 
-int check_user(int ac, char **av, void *ustate)
-{
-  *(int *)ustate = atoi(av[U_STATE]);
-  return 0;
-}
-
-void free_values(int newvalue_count, LDAPMod **newvalue_array, 
-                char ***modvalues)
-{
-  int i, j;
-  
-  if (newvalue_array != NULL)
-    {
-      i = 0;
-      while (newvalue_array[i] != NULL)
-       {
-         free(newvalue_array[i]);
-         newvalue_array[i]= NULL;
-         ++i;
-       }
-      free(newvalue_array);
-      newvalue_array = NULL;
-    }
-  if (modvalues != NULL)
-    {
-      i = 0;
-      while (modvalues[i] != NULL)
-       {
-         j = 0;
-         while (modvalues[i][j] != NULL)
-           {
-             free(modvalues[i][j]);
-             modvalues[i][j] = NULL;
-             ++j;
-           }
-         free(modvalues[i]);
-         modvalues[i] = NULL;
-         ++i;
-       }
-      free(modvalues);
-      modvalues = NULL;
-    }
-}
-
-void linklist_free(LK_ENTRY *linklist_base)
-{
-  LK_ENTRY *linklist_previous;
-  
-  while (linklist_base != NULL)
+  if (!--mr_connections)
     {
-      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);
+      mr_disconnect();
     }
+  return 0;
 }
 
 int convert_domain_to_dn(char *domain, char **dnp)
 {
-  char *fp, *dp;
-  char dn[1024];
-  int dnlen = 1;
-  
+  char    *fp;
+  char    *dp;
+  char    dn[1024];
+  int     dnlen = 1;
+    
   memset(dn, 0, sizeof(dn));
   strcpy(dn, "dc=");
   dp = dn+3;
   for (fp = domain; *fp; fp++)
     {
       if (*fp == '.') 
-       {
-         strcpy(dp, ",dc=");
-         dp += 4;
-       }
+        {
+          strcpy(dp, ",dc=");
+          dp += 4;
+        }
       else
-       *dp++ = *fp;
+        *dp++ = *fp;
     }
-  
+
   *dnp = (char *)strdup(dn);
   return 0;
 }
 
 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
-                           char *distinguished_name)
+                            char *distinguished_name)
 {
-  char *CName;
-  
+  char    *CName;
+
   CName = ldap_get_dn(ldap_handle, ldap_entry);
   if (CName == NULL)
     return;
@@ -1743,7 +1186,7 @@ void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry,
 }
 
 int linklist_create_entry(char *attribute, char *value, 
-                         LK_ENTRY **linklist_entry)
+                          LK_ENTRY **linklist_entry)
 {
   (*linklist_entry) = calloc(1, sizeof(LK_ENTRY));
   if (!(*linklist_entry))
@@ -1765,9 +1208,1012 @@ int linklist_create_entry(char *attribute, char *value,
 void print_to_screen(const char *fmt, ...)
 {
   va_list pvar;
-  
+
   va_start(pvar, fmt);
   vfprintf(stderr, fmt, pvar);
   fflush(stderr);
   va_end(pvar);
 }
+
+int get_group_membership(char *group_membership, char *group_ou, 
+                         int *security_flag, char **av)
+{
+  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);
+    }
+  else if ((!maillist_flag) && (group_flag))
+    {
+      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);
+    }
+  else if ((maillist_flag) && (!group_flag))
+    {
+      if (group_membership != NULL)
+        group_membership[0] = 'D';
+      if (group_ou != NULL)
+        strcpy(group_ou, group_ou_distribution);
+    }
+  else
+    {
+      if (group_membership != NULL)
+        group_membership[0] = 'N';
+      if (group_ou != NULL)
+        strcpy(group_ou, group_ou_neither);
+    }
+  return(0);
+}
+
+int get_group_info(int ac, char**av, void *ptr)
+{
+  char **call_args;
+
+  call_args = ptr;
+
+  if (!atoi(av[L_ACTIVE]))
+    return(0);
+  if (ptr == NULL)
+    get_group_membership(GroupType, NULL, NULL, av);
+  else
+    get_group_membership(call_args[4], call_args[3], NULL, av);
+
+  return(0);
+}
+
+int group_create(int ac, char **av, void *ptr)
+{
+  LDAPMod *mods[20];
+  char new_dn[256];
+  char group_ou[256];
+  char new_group_name[256];
+  char sam_group_name[256];
+  char cn_group_name[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 *name_v[] = {NULL, NULL};
+  char *desc_v[] = {NULL, NULL};
+  char *info_v[] = {NULL, NULL};
+  char *groupTypeControl_v[] = {NULL, NULL};
+  char groupTypeControlStr[80];
+  char group_membership[1];
+  int  i;
+  int  security_flag;
+  u_int groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
+  int  n;
+  int  rc;
+  int  sid_count;
+  char filter_exp[256];
+  char *attr_array[3];
+  char **call_args;
+
+  call_args = ptr;
+
+  if (!atoi(av[L_ACTIVE]))
+    return(0);
+  if (!check_string(av[L_NAME]))
+    return(0);
+  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);
+  call_args[3] = strdup(group_ou);
+  call_args[4] = strdup(group_membership);
+
+  if (security_flag)
+    groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
+  sprintf(groupTypeControlStr, "%ld", groupTypeControl);
+  groupTypeControl_v[0] = groupTypeControlStr;
+
+  strcpy(new_group_name, av[L_NAME]);
+  strcpy(sam_group_name, av[L_NAME]);
+  strcpy(cn_group_name, av[L_NAME]);
+  sprintf(&sam_group_name[strlen(sam_group_name)], 
+          "_zZx%c", group_membership[0]);
+
+  samAccountName_v[0] = sam_group_name;
+  name_v[0] = new_group_name;
+  cn_v[0] = cn_group_name;
+
+  sprintf(new_dn, "cn=%s,%s,%s", cn_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 (!strcmp(av[L_ACE_TYPE], "LIST"))
+    {
+      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;
+
+  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))
+    return(rc);
+  sprintf(filter_exp, "(sAMAccountName=%s)", sam_group_name);
+  attr_array[0] = "objectSid";
+  attr_array[1] = NULL;
+  sid_count = 0;
+  if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], filter_exp, attr_array, 
+                               sid_ptr, &sid_count)) == LDAP_SUCCESS)
+    {
+      if (sid_count == 1)
+        {
+          (*sid_ptr)->member = strdup(av[L_NAME]);
+          (*sid_ptr)->type = (char *)GROUPS;
+          sid_ptr = &(*sid_ptr)->next;
+        }
+    }
+  return(LDAP_SUCCESS);
+}
+
+int group_delete(int ac, char **av, void *ptr)
+{
+  LK_ENTRY  *group_base;
+  char      **call_args;
+  char      *attr_array[3];
+  char      filter_exp[1024];
+  char      group_membership[1];
+  char      group_ou[256];
+  char      sam_group_name[256];
+  int       security_flag;
+  int       group_count;
+  int       rc;
+
+  call_args = ptr;
+
+  if (!check_string(av[L_NAME]))
+    return(0);
+  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);
+
+  group_count = 0;
+  group_base = NULL;
+  attr_array[0] = "distinguishedName";
+  attr_array[1] = NULL;
+  strcpy(sam_group_name, av[L_NAME]);
+  sprintf(&sam_group_name[strlen(sam_group_name)], "_zZx%c", 
+          group_membership[0]);
+  sprintf(filter_exp, "(sAMAccountName=%s)", sam_group_name);
+  if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], filter_exp, 
+                           attr_array, &group_base, &group_count)) != 0)
+    goto cleanup;
+  if (group_count == 1)
+    rc = ldap_delete_s((LDAP *)call_args[0], group_base->value);
+  if (rc != LDAP_SUCCESS)
+    {
+      critical_alert("AD incremental",
+                     "Couldn't delete group %s: %s",
+                     av[L_NAME], ldap_err2string(rc));
+    }
+cleanup:
+  linklist_free(group_base);
+  return(rc);
+}
+
+int group_ad_delete(LDAP *ldap_handle, char *dn_path, char *group_name)
+{
+  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;
+
+  if (!check_string(group_name))
+    return(0);
+
+  rc = 1;
+  group_count = 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*)", sam_group_name);
+  if (linklist_build(ldap_handle, temp, filter_exp, attr_array, 
+                           &group_base, &group_count) != 0)
+    goto cleanup;
+  if (group_count == 1)
+    {
+      rc = ldap_delete_s(ldap_handle, group_base->value);
+      if (rc != LDAP_SUCCESS)
+        {
+          critical_alert("AD incremental",
+                         "Couldn't delete group %s",
+                         group_name);
+        }
+    }
+cleanup:
+  linklist_free(group_base);
+  return(rc);
+}
+
+int group_list_build(int ac, char **av, void *ptr)
+{
+  LK_ENTRY    *linklist;
+  char        **call_args;
+
+  call_args = ptr;
+
+  if (!atoi(av[L_ACTIVE]))
+    return(0);
+  if (!check_string(av[L_NAME]))
+    return(0);
+  linklist = calloc(1, sizeof(LK_ENTRY));
+  if (!linklist)
+    {
+      critical_alert("AD incremental", "Out of memory");
+      exit(1);
+    }
+  memset(linklist, '\0', sizeof(LK_ENTRY));
+  linklist->op = 1;
+  linklist->dn = NULL;
+  linklist->list = calloc(1, strlen(av[L_NAME]) + 1);
+  strcpy(linklist->list, av[L_NAME]);
+  linklist->type = calloc(1, strlen("USER") + 1);
+  strcpy(linklist->type, "USER");
+  linklist->member = calloc(1, strlen(call_args[0]) + 1);
+  strcpy(linklist->member, call_args[0]);
+  linklist->next = member_base;
+  member_base = linklist;
+  return(0);
+}
+
+int member_list_build(int ac, char **av, void *ptr)
+{
+  LK_ENTRY  *linklist;
+  char      temp[128];
+  char      **call_args;
+
+  call_args = ptr;
+
+  strcpy(temp, av[ACE_NAME]);
+  if (!check_string(temp))
+    return(0);
+  if (!strcmp(av[ACE_TYPE], "STRING"))
+    {
+    contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou);
+    }
+  else if (!strcmp(av[ACE_TYPE], "LIST"))
+    {
+      strcpy(temp, av[ACE_NAME]);
+    }
+  else if (strcmp(av[ACE_TYPE], "USER"))
+    {
+    contact_create((LDAP *)call_args[0], call_args[1], temp, kerberos_ou);
+    }
+  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;
+  linklist->list = calloc(1, strlen(call_args[2]) + 1);
+  strcpy(linklist->list, call_args[2]);
+  linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1);
+  strcpy(linklist->type, av[ACE_TYPE]);
+  linklist->member = calloc(1, strlen(temp) + 1);
+  strcpy(linklist->member, temp);
+  linklist->next = member_base;
+  member_base = linklist;
+  return(0);
+}
+
+#define USER_COUNT  5
+
+int member_list_process(LDAP *ldap_handle, char *dn_path, char *group_name, 
+                        char *group_ou, char *group_membership)
+{
+  char        distinguished_name[1024];
+  char        **modvalues;
+  char        filter_exp[4096];
+  char        *attr_array[3];
+  char        temp[256];
+  char        group_member[256];
+  char        *args[2];
+  int         group_count;
+  int         new_list_count;
+  int         i;
+  int         j;
+  int         k;
+  int         n;
+  int         filter_count;
+  LDAPMod     *mods[20];
+  LK_ENTRY    *group_base;
+  LK_ENTRY    *new_list;
+  LK_ENTRY    *sPtr;
+  LK_ENTRY    *pPtr;
+  ULONG       rc;
+
+  rc = 0;
+  group_base = NULL;
+  group_count = 0;
+  modvalues = NULL;
+
+  pPtr = member_base;
+  while (pPtr)
+    {
+    ++group_count;
+    pPtr = pPtr->next;
+    }
+  j = group_count/USER_COUNT;
+  ++j;
+
+  if (!check_string(group_name))
+    return(0);
+  strcpy(temp, group_name);
+  sprintf(filter_exp, "(sAMAccountName=%s_zZx%c)", temp, 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)
+    {
+      critical_alert("AD incremental",
+                      "LDAP server unable to get group %s info: %d",
+                      group_name, rc);
+      rc = 1;
+      goto cleanup;
+    }
+  if (group_count != 1)
+    {
+      critical_alert("AD incremental",
+                      "LDAP server unable to find group %s in AD.",
+                      group_name);
+      rc = 1;
+      goto cleanup;
+    }
+  strcpy(distinguished_name, group_base->value);
+  linklist_free(group_base);
+  group_base = NULL;
+  group_count = 0;
+
+  pPtr = member_base;
+  for (i = 0; i < j; i++)
+    {
+      if (pPtr == NULL)
+        break;
+      memset(filter_exp, 0, sizeof(filter_exp));
+      strcpy(filter_exp, "(|");
+      filter_count = 0;
+      for (k = 0; k < USER_COUNT; k++)
+        {
+          strcpy(group_member, pPtr->member);
+          if (!check_string(group_member))
+            {
+              pPtr = pPtr->next;
+              if (pPtr == NULL)
+                break;
+              continue;
+            }
+          if (!strcmp(pPtr->type, "LIST"))
+            {
+              args[0] = pPtr->member;
+              rc = mr_query("get_list_info", 1, args, get_group_info, NULL);
+              sprintf(temp, "(sAMAccountName=%s_zZx%c)", group_member, 
+                      GroupType[0]);
+            }
+          else if (!strcmp(pPtr->type, "USER"))
+            {
+              sprintf(temp, "(sAMAccountName=%s)", group_member);
+            }
+          else if (!strcmp(pPtr->type, "STRING"))
+            {
+              sprintf(temp, "(cn=%s,%s,%s)", group_member, contact_ou, dn_path);
+            }
+          else
+            {
+              sprintf(temp, "(cn=%s,%s,%s)", group_member, kerberos_ou, dn_path);
+            }
+          strcat(filter_exp, temp);
+          ++filter_count;
+          pPtr = pPtr->next;
+          if (pPtr == NULL)
+            break;
+        }
+      if (filter_count == 0)
+        continue;
+      strcat(filter_exp, ")");
+      attr_array[0] = "distinguishedName";
+      attr_array[1] = NULL;
+      new_list = NULL;
+      new_list_count = 0;
+      if ((rc = linklist_build(ldap_handle, dn_path, filter_exp, attr_array, 
+                               &new_list, &new_list_count)) != 0)
+        {
+          critical_alert("AD incremental",
+                         "LDAP server unable to get group %s members from AD: %d",
+                         group_name, rc);
+          rc = 1;
+          goto cleanup;
+        }
+      group_count += new_list_count;
+      if (group_base == NULL)
+        group_base = new_list;
+      else
+        {
+          sPtr = group_base;
+          while (sPtr)
+            {
+              if (sPtr->next != NULL)
+                {
+                  sPtr = sPtr->next;
+                  continue;
+                }
+              sPtr->next = new_list;
+              break;
+            }
+        }
+    }
+
+  modvalues = NULL;
+  if (group_count != 0)
+    {
+      if ((rc = construct_newvalues(group_base, group_count, NULL, NULL,
+                                    &modvalues, REPLACE)) == 1)
+          goto cleanup;
+      n = 0;
+      ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
+      mods[n] = NULL;
+      if ((rc = ldap_modify_s(ldap_handle, distinguished_name, mods)) 
+          != LDAP_SUCCESS)
+        {
+          mods[0]->mod_op = LDAP_MOD_REPLACE;
+          rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
+        }
+      if (rc == LDAP_ALREADY_EXISTS)
+        rc = LDAP_SUCCESS;
+      for (i = 0; i < n; i++)
+        free(mods[i]);
+      linklist_free(group_base);
+      group_count = 0;
+      group_base = NULL;
+    }
+
+cleanup:
+  free_values(modvalues);
+  linklist_free(group_base);
+  return(rc);
+}
+
+int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
+{
+  LDAPMod *mods[20];
+  char new_dn[256];
+  char cn_user_name[256];
+  char contact_name[256];
+  char *cn_v[] = {NULL, NULL};
+  char *contact_v[] = {NULL, NULL};
+  char *objectClass_v[] = {"top", "person", 
+                           "organizationalPerson", 
+                           "contact", NULL};
+  char *name_v[] = {NULL, NULL};
+  char *desc_v[] = {NULL, NULL};
+  int  n;
+  int  rc;
+  int  i;
+
+  if (!check_string(user))
+    return(0);
+  strcpy(contact_name, user);
+  sprintf(cn_user_name,"CN=%s,%s,%s", contact_name, group_ou, bind_path);
+  cn_v[0] = cn_user_name;
+  contact_v[0] = contact_name;
+  name_v[0] = user;
+  desc_v[0] = "Auto account created by Moira";
+
+  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);
+  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))
+    return(rc);
+  return(LDAP_SUCCESS);
+}
+
+int user_create(int ac, char **av, void *ptr)
+{
+  LDAPMod *mods[20];
+  char new_dn[256];
+  char user_name[256];
+  char *cn_v[] = {NULL, NULL};
+  char *objectClass_v[] = {"top", "person", 
+                           "organizationalPerson", 
+                           "user", NULL};
+
+  char *samAccountName_v[] = {NULL, NULL};
+  char *altSecurityIdentities_v[] = {NULL, NULL};
+  char *name_v[] = {NULL, NULL};
+  char *desc_v[] = {NULL, NULL};
+  char upn[256];
+  char *userPrincipalName_v[] = {NULL, NULL};
+  char *userAccountControl_v[] = {NULL, NULL};
+  char userAccountControlStr[80];
+  char temp[128];
+  u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | UF_PASSWD_CANT_CHANGE;
+  int  n;
+  int  rc;
+  int  i;
+  int  sid_count;
+  char filter_exp[256];
+  char *attr_array[3];
+  char **call_args;
+
+  call_args = ptr;
+
+  if (!check_string(av[U_NAME]))
+    return(0);
+  if ((atoi(av[U_STATE]) != US_REGISTERED) && (atoi(av[U_STATE]) != US_NO_PASSWD) && 
+      (atoi(av[U_STATE]) != US_ENROLL_NOT_ALLOWED))
+  if (!strncmp(av[U_NAME], "#", 1))
+    return(0);
+  strcpy(user_name, av[U_NAME]);
+  sprintf(upn, "%s@%s", user_name, ldap_domain);
+  samAccountName_v[0] = user_name;
+  if (atoi(av[U_STATE]) == US_DELETED)
+    userAccountControl |= UF_ACCOUNTDISABLE;
+  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";
+  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]);
+
+  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("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);
+  mods[n] = NULL;
+
+  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))
+    return(rc);
+  if (rc == LDAP_SUCCESS)
+    {
+      if ((rc = set_password(user_name, ldap_domain)) != 0)
+        {
+          critical_alert("AD incremental", "Couldn't set password for user %s",
+                         user_name);
+          return(rc);
+        }
+    }
+  sprintf(filter_exp, "(sAMAccountName=%s)", user_name);
+  attr_array[0] = "objectSid";
+  attr_array[1] = NULL;
+  sid_count = 0;
+  if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], filter_exp, attr_array, 
+                               sid_ptr, &sid_count)) == LDAP_SUCCESS)
+    {
+      if (sid_count == 1)
+        {
+          (*sid_ptr)->member = strdup(av[U_NAME]);
+          (*sid_ptr)->type = (char *)USERS;
+          sid_ptr = &(*sid_ptr)->next;
+        }
+    }
+  return(LDAP_SUCCESS);
+  return(LDAP_SUCCESS);
+}
+
+int group_update_membership(LDAP *ldap_handle, char *dn_path, char *group_name)
+{
+  char      group_ou[512];
+  char      group_membership[3];
+  char      *call_args[6];
+  char      *av[2];
+  int       rc;
+
+  member_base = NULL;
+  memset(group_ou, 0, sizeof(group_ou));
+  memset(group_membership, 0, sizeof(group_membership));
+  av[0] = group_name;
+  call_args[0] = (char *)ldap_handle;
+  call_args[1] = dn_path;
+  call_args[2] = group_name;
+  call_args[3] = group_ou;
+  call_args[4] = group_membership;
+  if (rc = mr_query("get_list_info", 1, av, get_group_info, call_args))
+    {
+      critical_alert("AD incremental",
+                       "Moira error retrieving information from list %s: %s",
+                       group_name, error_message(rc));
+      return(rc);
+    }
+
+  if (rc = mr_query("get_members_of_list", 1, av, member_list_build, 
+                    call_args))
+    {
+      critical_alert("AD incremental",
+                     "Moira error retrieving list members from list %s: %s",
+                     group_name, error_message(rc));
+      goto cleanup;
+    }
+  if (rc = member_list_process(ldap_handle, dn_path, group_name, call_args[3], 
+                               call_args[4]))
+    {
+      if ((rc != 0) && (rc != 1))
+        {
+          critical_alert("AD incremental",
+                         "LDAP error updating AD membership list for list %s: %d",
+                         group_name, rc);
+        }
+      goto cleanup;
+    }
+cleanup:
+  linklist_free(member_base);
+  return(rc);
+}
+
+int user_change_status(LDAP *ldap_handle, char *dn_path, char *u_name,
+                       int operation)
+{
+  char      filter_exp[1024];
+  char      *attr_array[3];
+  char      temp[256];
+  char      distinguished_name[1024];
+  char      user_name[512];
+  char      **modvalues;
+  LDAPMod   *mods[20];
+  LK_ENTRY  *group_base;
+  int       group_count;
+  int       rc;
+  int       i;
+  int       n;
+  ULONG     ulongValue;
+
+  if (!check_string(u_name))
+    return(0);
+  strcpy(user_name, u_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)
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %s",
+                      user_name, "no memory");
+      goto cleanup;
+    }
+
+  if (group_count == 0)
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %s",
+                      user_name, "user not found in AD");
+      goto cleanup;
+    }
+
+  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);
+  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)
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %d",
+                     user_name, rc);
+    }
+cleanup:
+  linklist_free(group_base);
+  return(rc);
+}
+
+int user_delete(LDAP *ldap_handle, char *dn_path, char *u_name)
+{
+  char      filter_exp[1024];
+  char      *attr_array[3];
+  char      distinguished_name[1024];
+  char      user_name[512];
+  LK_ENTRY  *group_base;
+  int       group_count;
+  int       rc;
+
+  if (!check_string(u_name))
+    return(0);
+  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)
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %s",
+                      user_name, "no memory");
+      goto cleanup;
+    }
+
+  if (group_count == 0)
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %s",
+                      user_name, "user not found in AD");
+      goto cleanup;
+    }
+
+  strcpy(distinguished_name, group_base->dn);
+  if (rc = ldap_delete_s(ldap_handle, distinguished_name))
+    {
+      critical_alert("AD incremental",
+                     "LDAP server couldn't process user %s: %s",
+                      user_name, "cannot delete user from AD");
+    }
+
+cleanup:
+  linklist_free(group_base);
+  return(rc);
+}
+
+void linklist_free(LK_ENTRY *linklist_base)
+{
+  LK_ENTRY *linklist_previous;
+
+  while (linklist_base != NULL)
+    {
+      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);
+    }
+}
+
+void free_values(char **modvalues)
+{
+  int i;
+
+  i = 0;
+  if (modvalues != NULL)
+    {
+    while (modvalues[i] != NULL)
+      {
+        free(modvalues[i]);
+        modvalues[i] = NULL;
+        ++i;
+      }
+    free(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);
+      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 - ^_ */
+  1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
+  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, 0, /* P - _ */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+int check_string(char *s)
+{
+  for (; *s; s++)
+    {
+      if (isupper(*s))
+        *s = tolower(*s);
+      if (illegalchars[(unsigned) *s])
+        return 0;
+    }
+  return 1;
+}
+
+int mr_connect_cl(char *server, char *client, int version, int auth)
+{
+  int status;
+  char *motd;
+
+  status = mr_connect(server);
+  if (status)
+    {
+      com_err(whoami, status, "while connecting to Moira");
+      return MRCL_FAIL;
+    }
+
+  status = mr_motd(&motd);
+  if (status)
+    {
+      mr_disconnect();
+      com_err(whoami, status, "while checking server status");
+      return MRCL_FAIL;
+    }
+  if (motd)
+    {
+      fprintf(stderr, "The Moira server is currently unavailable:\n%s\n",
+                   motd);
+      mr_disconnect();
+      return MRCL_FAIL;
+    }
+
+  status = mr_version(version);
+  if (status)
+    {
+      if (status == MR_UNKNOWN_PROC)
+             {
+               if (version > 2)
+                 status = MR_VERSION_HIGH;
+               else
+                 status = MR_SUCCESS;
+             }
+
+      if (status == MR_VERSION_HIGH)
+             {
+               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)
+             {
+               com_err(whoami, status, "while setting query version number.");
+               mr_disconnect();
+               return MRCL_FAIL;
+             }
+    }
+
+  if (auth)
+    {
+      status = mr_auth(client);
+      if (status)
+             {
+               com_err(whoami, status, "while authenticating to Moira.");
+               mr_disconnect();
+               return MRCL_AUTH_ERROR;
+             }
+    }
+
+  return MRCL_SUCCESS;
+}
+
This page took 0.343701 seconds and 5 git commands to generate.