]> andersk Git - moira.git/blob - incremental/ldap/winad.c
More error message tweaking.
[moira.git] / incremental / ldap / winad.c
1 /* $Header$
2 /* ldap.incr arguments example
3  *
4  * arguments when moira creates the account - ignored by ldap.incr since the 
5  * account is unusable. users 0 11 #45198 45198 /bin/cmd cmd Last First Middle
6  * 0 950000001 2000 121049
7  *
8  * login, unix_uid, shell, winconsoleshell, last, 
9  * first, middle, status, mitid, type, moiraid
10  *
11  * arguments for creating or updating a user account 
12  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
13  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
14  * First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
15  * users 11 11 #45206 45206 /bin/cmd cmd Last First Middle 0 950000001 STAFF
16  * 121058  PathToHomeDir PathToProfileDir newuser 45206 /bin/cmd cmd Last
17  * First Middle 2 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
18  *
19  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
20  * mitid, type, moiraid
21  *
22  * arguments for deactivating/deleting a user account
23  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
24  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
25  * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
26  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
27  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
28  * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
29  * 
30  * login, unix_uid, shell, winconsoleshell, last, first, middle, status,
31  * mitid, type, moiraid
32  *
33  * arguments for reactivating a user account
34  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
35  * 121058 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
36  * 121058
37  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
38  * 121058 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF 12105
39  *
40  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
41  * mitid, type, moiraid
42  *
43  * arguments for changing user name
44  * users 11 11 oldusername 45206 /bin/cmd cmd Last First Middle 1 950000001 
45  * STAFF 121058 PathToHomeDir PathToProfileDir newusername 45206 /bin/cmd cmd 
46  * Last First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
47  *
48  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
49  * mitid, type, moiraid
50  *
51  * arguments for expunging a user
52  * users 11 0 username 45198 /bin/cmd cmd Last First Middle 0 950000001 2000
53  * 121049
54  *
55  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
56  * mitid, type, moiraid
57  *
58  * arguments for creating a "special" group/list
59  * list 0 11 listname 1 1 0 0 0 -1 NONE 0 description 92616
60  *
61  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
62  * acl_id, description, moiraid
63  * 
64  * arguments for creating a "mail" group/list
65  * list 0 11 listname 1 1 0 1 0 -1 NONE 0 description 92616
66  *
67  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
68  * acl_id, description, moiraid
69  *
70  * arguments for creating a "group" group/list
71  * list 0 11 listname 1 1 0 0 1 -1 NONE 0 description 92616
72  * 
73  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
74  * acl_id, description, moiraid
75  *
76  * arguments for creating a "group/mail" group/list
77  * list 0 11 listname 1 1 0 1 1 -1 NONE 0 description 92616
78  *
79  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
80  * acl_id, description, moiraid
81  *
82  * arguments to add a USER member to group/list
83  * imembers 0 12 listname USER userName 1 1 0 0 0 -1 1 92616 121047
84  *
85  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
86  * gid, userStatus, moiraListId, moiraUserId
87  *
88  * arguments to add a STRING or KERBEROS member to group/list
89  * imembers 0 10 listname STRING stringName 1 1 0 0 0 -1 92616
90  * imembers 0 10 listlistnameName KERBEROS kerberosName 1 1 0 0 0 -1 92616
91  *
92  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
93  * gid, moiraListId
94  *
95  * NOTE: group members of type LIST are ignored.
96  *
97  * arguments to remove a USER member to group/list
98  * imembers 12 0 listname USER userName 1 1 0 0 0 -1 1 92616 121047
99  * 
100  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
101  * gid, userStatus, moiraListId, moiraUserId
102  *
103  * arguments to remove a STRING or KERBEROS member to group/list
104  * imembers 10 0 listname STRING stringName 1 1 0 0 0 -1 92616
105  * imembers 10 0 listname KERBEROS kerberosName 1 1 0 0 0 -1 92616
106  *
107  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
108  * gid, moiraListId
109  *
110  * NOTE: group members of type LIST are ignored.
111  *
112  * arguments for renaming a group/list
113  * list 11 11 oldlistname 1 1 0 0 0 -1 NONE 0 description 92616 newlistname 1
114  * 1 0 0 0 -1 description 0 92616
115  * 
116  * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
117  * acl_id, description, moiraListId
118  *
119  * arguments for deleting a group/list
120  * list 11 0 listname 1 1 0 0 0 -1 NONE 0 description 92616
121  *
122  * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
123  * acl_id, description, moiraListId
124  *
125  * arguments for adding a file system
126  * filesys 0 12 username AFS ATHENA.MIT.EDU 
127  * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
128  * wheel 1 HOMEDIR 101727
129  *
130  * arguments for deleting a file system
131  * filesys 12 0 username AFS ATHENA.MIT.EDU 
132  * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
133  * wheel 1 HOMEDIR 101727
134  *
135  * arguments when moira creates a container (OU).
136  * containers 0 8 machines/test/bottom description location contact USER
137  * 105316 2222 [none]
138  *
139  * arguments when moira deletes a container (OU).
140  * containers 8 0 machines/test/bottom description location contact USER 
141  * 105316 2222 groupname
142  *
143  * arguments when moira modifies a container information (OU).
144  * containers 8 8 machines/test/bottom description location contact USER 
145  * 105316 2222 groupname machines/test/bottom description1 location contact 
146  * USER 105316 2222 groupname
147  *
148  * arguments when moira adds a machine from an OU
149  * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
150  * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
151  *
152  * arguments when moira removes a machine from an OU
153  * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
154  * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
155  *
156 */
157
158 #include <mit-copyright.h>
159
160 #ifdef _WIN32
161 #include <winsock2.h>
162 #include <windows.h>
163 #include <stdlib.h>
164 #include <malloc.h>
165 #include <lmaccess.h>
166 #endif
167
168 #include <hesiod.h>
169 #include <string.h>
170 #include <ldap.h>
171 #include <stdio.h>
172 #include <moira.h>
173 #include <moira_site.h>
174 #include <mrclient.h>
175 #include <krb5.h>
176 #include <gsssasl.h>
177 #include <gssldap.h> 
178 #include "kpasswd.h"
179
180 #ifdef _WIN32
181 #ifndef ECONNABORTED
182 #define ECONNABORTED WSAECONNABORTED
183 #endif
184 #ifndef ECONNREFUSED
185 #define ECONNREFUSED WSAECONNREFUSED
186 #endif
187 #ifndef EHOSTUNREACH
188 #define EHOSTUNREACH WSAEHOSTUNREACH
189 #endif
190 #define krb5_xfree free
191 #define F_OK 0
192 #define sleep(A) Sleep(A * 1000);
193 #endif /* _WIN32 */
194
195 #ifndef _WIN32
196 #include <sys/types.h>
197 #include <netinet/in.h>
198 #include <arpa/nameser.h>
199 #include <resolv.h>
200 #include <sys/utsname.h>
201 #include <unistd.h>
202
203 #define CFG_PATH "/moira/ldap/"
204 #define WINADCFG "ldap.cfg"
205 #define strnicmp(A,B,C) strncasecmp(A,B,C)
206 #define UCHAR unsigned char
207
208 #define UF_SCRIPT               0x0001
209 #define UF_ACCOUNTDISABLE       0x0002
210 #define UF_HOMEDIR_REQUIRED     0x0008
211 #define UF_LOCKOUT              0x0010
212 #define UF_PASSWD_NOTREQD       0x0020
213 #define UF_PASSWD_CANT_CHANGE   0x0040
214 #define UF_DONT_EXPIRE_PASSWD   0x10000
215
216 #define UF_TEMP_DUPLICATE_ACCOUNT       0x0100
217 #define UF_NORMAL_ACCOUNT               0x0200
218 #define UF_INTERDOMAIN_TRUST_ACCOUNT    0x0800
219 #define UF_WORKSTATION_TRUST_ACCOUNT    0x1000
220 #define UF_SERVER_TRUST_ACCOUNT         0x2000
221
222 #define OWNER_SECURITY_INFORMATION       (0x00000001L)
223 #define GROUP_SECURITY_INFORMATION       (0x00000002L)
224 #define DACL_SECURITY_INFORMATION        (0x00000004L)
225 #define SACL_SECURITY_INFORMATION        (0x00000008L)
226
227 #ifndef BYTE
228 #define BYTE unsigned char
229 #endif
230 typedef unsigned int DWORD;
231 typedef unsigned long ULONG;
232
233 typedef struct _GUID
234 {
235   unsigned long Data1;
236   unsigned short Data2;
237   unsigned short Data3;
238   unsigned char Data4[8];
239 } GUID;
240
241 typedef struct _SID_IDENTIFIER_AUTHORITY { 
242   BYTE Value[6]; 
243 } SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; 
244
245 typedef struct _SID {
246   BYTE  Revision;
247   BYTE  SubAuthorityCount;
248   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
249   DWORD SubAuthority[512];
250 } SID;
251 #endif/*!WIN32*/
252
253 #ifndef WINADCFG
254 #define WINADCFG "ldap.cfg"
255 #endif
256
257 #ifndef CFG_PATH
258 #define CFG_PATH ""
259 #endif 
260
261 #define AFS "/afs/"
262 #define WINAFS "\\\\afs\\all\\"
263
264 #define ADS_GROUP_TYPE_GLOBAL_GROUP         0x00000002
265 #define ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP   0x00000004
266 #define ADS_GROUP_TYPE_LOCAL_GROUP          0x00000004
267 #define ADS_GROUP_TYPE_UNIVERSAL_GROUP      0x00000008
268 #define ADS_GROUP_TYPE_SECURITY_ENABLED     0x80000000
269
270 #define QUERY_VERSION   -1
271 #define PRIMARY_REALM   "ATHENA.MIT.EDU"
272 #define PRIMARY_DOMAIN  "win.mit.edu"
273 #define PRODUCTION_PRINCIPAL "sms"
274 #define TEST_PRINCIPAL       "smstest"
275
276 #define SUBSTITUTE  1
277 #define REPLACE     2
278
279 #define USERS         0
280 #define GROUPS        1
281
282 #define MEMBER_ADD          1
283 #define MEMBER_REMOVE       2
284 #define MEMBER_CHANGE_NAME  3
285 #define MEMBER_ACTIVATE     4
286 #define MEMBER_DEACTIVATE   5
287 #define MEMBER_CREATE       6
288
289 #define MOIRA_ALL       0x0
290 #define MOIRA_USERS     0x1
291 #define MOIRA_KERBEROS  0x2
292 #define MOIRA_STRINGS   0x4
293 #define MOIRA_LISTS     0x8
294 #define MOIRA_MACHINE   0x16
295
296 #define CHECK_GROUPS    1
297 #define CLEANUP_GROUPS  2
298
299 #define AD_NO_GROUPS_FOUND        -1
300 #define AD_WRONG_GROUP_DN_FOUND   -2
301 #define AD_MULTIPLE_GROUPS_FOUND  -3
302 #define AD_INVALID_NAME           -4
303 #define AD_LDAP_FAILURE           -5
304 #define AD_INVALID_FILESYS        -6
305 #define AD_NO_ATTRIBUTE_FOUND     -7
306 #define AD_NO_OU_FOUND            -8
307 #define AD_NO_USER_FOUND          -9
308
309 /* container arguments */
310 #define CONTAINER_NAME       0
311 #define CONTAINER_DESC       1
312 #define CONTAINER_LOCATION   2
313 #define CONTAINER_CONTACT    3
314 #define CONTAINER_TYPE       4
315 #define CONTAINER_ID         5
316 #define CONTAINER_ROWID      6
317 #define CONTAINER_GROUP_NAME 7
318
319 /*mcntmap arguments*/
320 #define OU_MACHINE_NAME        0
321 #define OU_CONTAINER_NAME      1
322 #define OU_MACHINE_ID          2
323 #define OU_CONTAINER_ID        3
324 #define OU_CONTAINER_GROUP     4
325
326 typedef struct lk_entry {
327   int     op;
328   int     length;
329   int     ber_value;
330   char    *dn;
331   char    *attribute;
332   char    *value;
333   char    *member;
334   char    *type;
335   char    *list;
336   struct  lk_entry *next;
337 } LK_ENTRY;
338
339 #define STOP_FILE "/moira/ldap/noldap"
340 #define file_exists(file) (access((file), F_OK) == 0)
341
342 #define N_SD_BER_BYTES   5
343 #define LDAP_BERVAL struct berval
344 #define MAX_SERVER_NAMES 32
345
346 #define HIDDEN_GROUP                "HiddenGroup.g"
347 #define HIDDEN_GROUP_WITH_ADMIN     "HiddenGroupWithAdmin.g"
348 #define NOT_HIDDEN_GROUP            "NotHiddenGroup.g"
349 #define NOT_HIDDEN_GROUP_WITH_ADMIN "NotHiddenGroupWithAdmin.g"
350
351 #define ADDRESS_LIST_PREFIX "CN=MIT Directory,CN=All Address Lists,\
352 CN=Address Lists Container,CN=Massachusetts Institute of Technology,\
353 CN=Microsoft Exchange,CN=Services,CN=Configuration,"
354
355 #define ADD_ATTR(t, v, o)               \
356   mods[n] = malloc(sizeof(LDAPMod));    \
357   mods[n]->mod_op = o;                  \
358   mods[n]->mod_type = t;                \
359   mods[n++]->mod_values = v
360
361 #define DEL_ATTR(t, o)                  \
362   DelMods[i] = malloc(sizeof(LDAPMod)); \
363   DelMods[i]->mod_op = o;               \
364   DelMods[i]->mod_type = t;             \
365   DelMods[i++]->mod_values = NULL
366
367 #define DOMAIN_SUFFIX   "MIT.EDU"
368 #define DOMAIN  "DOMAIN:"
369 #define PRINCIPALNAME  "PRINCIPAL:"
370 #define SERVER  "SERVER:"
371 #define MSSFU   "SFU:"
372 #define SFUTYPE "30"
373 #define GROUP_SUFFIX "GROUP_SUFFIX:"
374 #define GROUP_TYPE   "GROUP_TYPE:"
375 #define SET_GROUP_ACE    "SET_GROUP_ACE:"
376 #define SET_PASSWORD "SET_PASSWORD:"
377 #define EXCHANGE "EXCHANGE:"
378 #define REALM "REALM:"
379 #define ACTIVE_DIRECTORY "ACTIVE_DIRECTORY:"
380 #define PORT "PORT:"
381 #define PROCESS_MACHINE_CONTAINER "PROCESS_MACHINE_CONTAINER:"
382 #define GROUP_POPULATE_MEMBERS "GROUP_POPULATE_MEMBERS:"
383 #define MAX_DOMAINS 10
384 char DomainNames[MAX_DOMAINS][128];
385
386 LK_ENTRY *member_base = NULL;
387
388 char   PrincipalName[128];
389 static char tbl_buf[1024];
390 char  kerberos_ou[] = "OU=kerberos,OU=moira";
391 char  contact_ou[] = "OU=strings,OU=moira";
392 char  user_ou[] = "OU=users,OU=moira";
393 char  group_ou_distribution[1024];
394 char  group_ou_root[1024];
395 char  group_ou_security[1024];
396 char  group_ou_neither[1024];
397 char  group_ou_both[1024]; 
398 char  orphans_machines_ou[] = "OU=Machines,OU=Orphans";
399 char  orphans_other_ou[] = "OU=Other,OU=Orphans";
400 char  security_template_ou[] = "OU=security_templates";
401 char *whoami;
402 char ldap_domain[256];
403 char ldap_realm[256];
404 char ldap_port[256];
405 char *ServerList[MAX_SERVER_NAMES];
406 char default_server[256];
407 static char tbl_buf[1024];
408 char group_suffix[256];
409 char exchange_acl[256];
410 int  mr_connections = 0;
411 int  callback_rc;
412 int  UseSFU30 = 0;
413 int  UseGroupSuffix = 1;
414 int  UseGroupUniversal = 0;
415 int  SetGroupAce = 1;
416 int  SetPassword = 1;
417 int  Exchange = 0;
418 int  ProcessMachineContainer = 1;
419 int  ActiveDirectory = 1;
420 int  UpdateDomainList;
421 int  fsgCount;
422 int  GroupPopulateDelete = 0;
423
424 extern int set_password(char *user, char *password, char *domain);
425
426 int ad_get_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
427                  char *group_membership, char *MoiraId, char *attribute,
428                  LK_ENTRY **linklist_base, int *linklist_count,
429                  char *rFilter);
430 void AfsToWinAfs(char* path, char* winPath);
431 int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, 
432                char *Win2kPassword, char *Win2kUser, char *default_server,
433                int connect_to_kdc, char **ServerList, char *ldap_realm,
434                char *ldap_port);
435 void ad_kdc_disconnect();
436 int ad_server_connect(char *connectedServer, char *domain);
437 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
438                      char *attribute_value, char *attribute, char *user_name);
439 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer);
440 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name);
441 int check_winad(void);
442 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, 
443                char *MoiraId);
444 /* containers */
445 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
446                        char *distinguishedName, int count, char **av);
447 void container_check(LDAP *ldap_handle, char *dn_path, char *name);
448 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av);
449 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av);
450 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
451                                     char *distinguishedName, int count, 
452                                     char **av);
453 void container_get_dn(char *src, char *dest);
454 void container_get_name(char *src, char *dest);
455 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName);
456 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
457                      char **before, int afterc, char **after);
458 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
459                      char **before, int afterc, char **after);
460
461 int GetAceInfo(int ac, char **av, void *ptr);
462 int get_group_membership(char *group_membership, char *group_ou, 
463                          int *security_flag, char **av);
464 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
465                    char *machine_ou, char *pPtr);
466 int Moira_container_group_create(char **after);
467 int Moira_container_group_delete(char **before);
468 int Moira_groupname_create(char *GroupName, char *ContainerName,
469                            char *ContainerRowID);
470 int Moira_container_group_update(char **before, char **after);
471 int Moira_process_machine_container_group(char *MachineName, char* groupName,
472                                           int DeleteMachine);
473 int Moira_addGroupToParent(char *origContainerName, char *GroupName);
474 int Moira_getContainerGroup(int ac, char **av, void *ptr);
475 int Moira_getGroupName(char *origContainerName, char *GroupName,
476                        int ParentFlag);
477 int Moira_setContainerGroup(char *ContainerName, char *GroupName);
478 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *group_name, char *Type,
479                int UpdateGroup, int *ProcessGroup, char *maillist);
480 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
481                   char *group_name, char *group_ou, char *group_membership, 
482                   int group_security_flag, int type, char *maillist);
483 int process_lists(int ac, char **av, void *ptr);
484 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
485                          char *TargetGroupName, int HiddenGroup, 
486                          char *AceType, char *AceName);
487 int ProcessMachineName(int ac, char **av, void *ptr);
488 int ReadConfigFile(char *DomainName);
489 int ReadDomainList();
490 void StringTrim(char *StringToTrim);
491 char *escape_string(char *s);
492 int save_query_info(int argc, char **argv, void *hint);
493 int save_fsgroup_info(int argc, char **argv, void *hint);
494 int user_create(int ac, char **av, void *ptr);
495 int user_change_status(LDAP *ldap_handle, char *dn_path, 
496                        char *user_name, char *MoiraId, int operation);
497 int user_delete(LDAP *ldap_handle, char *dn_path, 
498                 char *u_name, char *MoiraId);
499 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
500                 char *user_name);
501 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
502                 char *uid, char *MitId, char *MoiraId, int State,
503                 char *WinHomeDir, char *WinProfileDir, char *first,
504                 char *middle, char *last, char *shell, char *class);
505 void change_to_lower_case(char *ptr);
506 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou);
507 int contact_remove_email(LDAP *ld, char *bind_path,
508                          LK_ENTRY **linklist_entry, int linklist_current);
509 int group_create(int ac, char **av, void *ptr);
510 int group_delete(LDAP *ldap_handle, char *dn_path, 
511                  char *group_name, char *group_membership, char *MoiraId);
512 int group_rename(LDAP *ldap_handle, char *dn_path, 
513                  char *before_group_name, char *before_group_membership, 
514                  char *before_group_ou, int before_security_flag, 
515                  char *before_desc, char *after_group_name, 
516                  char *after_group_membership, char *after_group_ou, 
517                  int after_security_flag, char *after_desc,
518                  char *MoiraId, char *filter, char *maillist);
519 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name);
520 int machine_GetMoiraContainer(int ac, char **av, void *ptr);
521 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
522                                 char *machine_name, char *container_name);
523 int machine_move_to_ou(LDAP *ldap_handle, char *dn_path, 
524                        char *MoiraMachineName, char *DestinationOu);
525 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
526                    char *group_name, char *group_ou, char *group_membership, 
527                    int group_security_flag, int updateGroup, char *maillist);
528 int member_list_build(int ac, char **av, void *ptr);
529 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
530                char *group_ou, char *group_membership, 
531                char *user_name, char *pUserOu, char *MoiraId);
532 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
533                   char *group_ou, char *group_membership, char *user_name,
534                   char *pUserOu, char *MoiraId);
535 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
536                    char *group_ou, char *group_membership, 
537                    int group_security_flag, char *MoiraId);
538 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
539                      char *DistinguishedName,
540                      char *WinHomeDir, char *WinProfileDir,
541                      char **homedir_v, char **winProfile_v,
542                      char **drives_v, LDAPMod **mods, 
543                      int OpType, int n);
544 int sid_update(LDAP *ldap_handle, char *dn_path);
545 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n);
546 int check_string(char *s);
547 int check_container_name(char* s);
548
549 int mr_connect_cl(char *server, char *client, int version, int auth);
550 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
551                   char **before, int beforec, char **after, int afterc);
552 void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
553                 char **before, int beforec, char **after, int afterc);
554 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
555              char **before, int beforec, char **after, int afterc);
556 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
557              char **before, int beforec, char **after, int afterc);
558 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
559                char **before, int beforec, char **after, int afterc);
560 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
561                 char **before, int beforec, char **after, int afterc);
562 int linklist_create_entry(char *attribute, char *value,
563                           LK_ENTRY **linklist_entry);
564 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
565                    char **attr_array, LK_ENTRY **linklist_base, 
566                    int *linklist_count, unsigned long ScopeType);
567 void linklist_free(LK_ENTRY *linklist_base);
568
569 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
570                         char *distinguished_name, LK_ENTRY **linklist_current);
571 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
572                      LK_ENTRY **linklist_base, int *linklist_count);
573 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
574                     char *Attribute, char *distinguished_name, 
575                     LK_ENTRY **linklist_current);
576
577 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
578                         char *oldValue, char *newValue,
579                         char ***modvalues, int type);
580 void free_values(char **modvalues);
581
582 int convert_domain_to_dn(char *domain, char **bind_path);
583 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
584                             char *distinguished_name);
585 int moira_disconnect(void);
586 int moira_connect(void);
587 void print_to_screen(const char *fmt, ...);
588 int GetMachineName(char *MachineName);
589 int tickets_get_k5();
590 int destroy_cache(void);
591 int dest_tkt(void);
592
593 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB,
594                  char **homeServerName);
595
596 int main(int argc, char **argv)
597 {
598   unsigned long   rc;
599   int             beforec;
600   int             afterc;
601   int             i;
602   int             j;
603   int             k;
604   int             OldUseSFU30;
605   char            *table;
606   char            **before;
607   char            **after;
608   LDAP            *ldap_handle;
609   char            dn_path[256];
610   char            *orig_argv[64];
611   
612   whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
613   
614   if (argc < 4)
615     {
616       com_err(whoami, 0, "Unable to process %s", "argc < 4");
617       exit(1);
618     }
619   
620   if (argc < (4 + atoi(argv[2]) + atoi(argv[3])))
621     {
622       com_err(whoami, 0, "Unable to process %s", 
623               "argc < (4 + beforec + afterc)");
624       exit(1);
625     }
626
627   if (!strcmp(argv[1], "filesys"))
628     exit(0);
629
630   for (i = 1; i < argc; i++)
631     {
632       strcat(tbl_buf, argv[i]);
633       strcat(tbl_buf, " ");
634     }
635
636   com_err(whoami, 0, "%s", tbl_buf);
637
638   if (check_winad())
639     {
640       com_err(whoami, 0, "%s failed", "check_winad()");
641       exit(1);
642     }
643
644   initialize_sms_error_table();
645   initialize_krb_error_table();
646
647   UpdateDomainList = 0;
648   memset(DomainNames, '\0', sizeof(DomainNames[0]) * MAX_DOMAINS);
649
650   if (ReadDomainList())
651     {
652       com_err(whoami, 0, "%s failed", "ReadDomainList()");
653       exit(1);
654     }
655
656   for (i = 0; i < argc; i++)
657      orig_argv[i] = NULL;
658
659   for (k = 0; k < MAX_DOMAINS; k++)
660     {
661       if (strlen(DomainNames[k]) == 0)
662         continue;
663       for (i = 0; i < argc; i++)
664         {
665           if (orig_argv[i] != NULL)
666             free(orig_argv[i]);
667           orig_argv[i] = strdup(argv[i]);
668         }
669
670       memset(PrincipalName, '\0', sizeof(PrincipalName));
671       memset(ldap_domain, '\0', sizeof(ldap_domain));
672       memset(ServerList, '\0', sizeof(ServerList[0]) * MAX_SERVER_NAMES);
673       memset(default_server, '\0', sizeof(default_server));
674       memset(dn_path, '\0', sizeof(dn_path));
675       memset(group_suffix, '\0', sizeof(group_suffix));
676       memset(exchange_acl, '\0', sizeof(exchange_acl));
677
678       UseSFU30 = 0;
679       UseGroupSuffix = 1;
680       UseGroupUniversal = 0;
681       SetGroupAce = 1;
682       SetPassword = 1;
683       Exchange = 0;
684       ProcessMachineContainer = 1;
685       ActiveDirectory = 1;
686
687       sprintf(group_suffix, "%s", "_group");
688       sprintf(exchange_acl, "%s", "exchange-acl");
689
690       beforec = atoi(orig_argv[2]);
691       afterc = atoi(orig_argv[3]);
692       table = orig_argv[1];
693       before = &orig_argv[4];
694       after = &orig_argv[4 + beforec];
695
696       if (afterc == 0)
697         after = NULL;
698
699       if (beforec == 0)
700         before = NULL;
701
702       if (ReadConfigFile(DomainNames[k]))
703         continue;
704
705       if(ActiveDirectory)
706         {
707           sprintf(group_ou_distribution, "OU=mail,OU=lists,OU=moira");
708           sprintf(group_ou_root, "OU=lists,OU=moira");
709           sprintf(group_ou_security, "OU=group,OU=lists,OU=moira");
710           sprintf(group_ou_neither, "OU=special,OU=lists,OU=moira");
711           sprintf(group_ou_both, "OU=mail,OU=group,OU=lists,OU=moira");
712         }
713       else
714         {
715           sprintf(group_ou_distribution, "OU=lists,OU=moira");
716           sprintf(group_ou_root, "OU=lists,OU=moira");
717           sprintf(group_ou_security, "OU=lists,OU=moira");
718           sprintf(group_ou_neither, "OU=lists,OU=moira");
719           sprintf(group_ou_both, "OU=lists,OU=moira");
720         }
721
722       OldUseSFU30 = UseSFU30;
723
724       for (i = 0; i < 5; i++)
725         {
726           ldap_handle = (LDAP *)NULL;
727           if (!(rc = ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", 
728                                 default_server, SetPassword, ServerList, 
729                                 ldap_realm, ldap_port)))
730             {
731               com_err(whoami, 0, "connected to domain %s", DomainNames[k]);
732               break;
733             }
734         }
735
736       if ((rc) || (ldap_handle == NULL))
737         {
738           critical_alert("incremental",
739                          "ldap.incr cannot connect to any server in "
740                          "domain %s", DomainNames[k]);
741           continue;
742         }
743
744       for (i = 0; i < (int)strlen(table); i++)
745         table[i] = tolower(table[i]);
746
747       if (!strcmp(table, "users"))
748         do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after,
749                 afterc);
750       else if (!strcmp(table, "list"))
751         do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
752                 afterc);
753       else if (!strcmp(table, "imembers"))
754         do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
755                   afterc);
756       else if (!strcmp(table, "containers"))
757         do_container(ldap_handle, dn_path, ldap_domain, before, beforec, after,
758                      afterc);
759       else if (!strcmp(table, "mcntmap"))
760         do_mcntmap(ldap_handle, dn_path, ldap_domain, before, beforec, after,
761                    afterc);
762
763       if(SetPassword) 
764         ad_kdc_disconnect();
765
766       for (i = 0; i < MAX_SERVER_NAMES; i++)
767         {
768           if (ServerList[i] != NULL)
769             {
770               free(ServerList[i]);
771               ServerList[i] = NULL;
772             }
773         }
774       
775       rc = ldap_unbind_s(ldap_handle);
776     }
777   
778   exit(0);
779 }
780
781 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
782                 char **before, int beforec, char **after, int afterc)
783 {
784   char    MoiraContainerName[128];
785   char    ADContainerName[128];
786   char    MachineName[1024];
787   char    OriginalMachineName[1024];
788   long    rc;
789   int     DeleteMachine;
790   char    MoiraContainerGroup[64];
791
792   if (!ProcessMachineContainer)
793     {
794       com_err(whoami, 0, "Process machines and containers disabled, skipping");
795       return;
796     }
797   
798   DeleteMachine = 0;
799   memset(ADContainerName, '\0', sizeof(ADContainerName));
800   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
801   
802   if ((beforec == 0) && (afterc == 0))
803     return;
804   
805   if (rc = moira_connect())
806     {
807       critical_alert("Ldap incremental",
808                      "Error contacting Moira server : %s",
809                      error_message(rc));
810       return;
811     }
812   
813   if ((beforec != 0) && (afterc == 0)) /*remove a machine*/
814     {
815       strcpy(OriginalMachineName, before[OU_MACHINE_NAME]);
816       strcpy(MachineName, before[OU_MACHINE_NAME]);
817       strcpy(MoiraContainerGroup, before[OU_CONTAINER_GROUP]);
818       DeleteMachine = 1;
819       com_err(whoami, 0, "removing machine %s from %s", 
820               OriginalMachineName, before[OU_CONTAINER_NAME]);
821     }
822   else if ((beforec == 0) && (afterc != 0)) /*add a machine*/
823     {
824       strcpy(OriginalMachineName, after[OU_MACHINE_NAME]);
825       strcpy(MachineName, after[OU_MACHINE_NAME]);
826       strcpy(MoiraContainerGroup, after[OU_CONTAINER_GROUP]);
827       com_err(whoami, 0, "adding machine %s to container %s", 
828               OriginalMachineName, after[OU_CONTAINER_NAME]);
829     }
830   else
831     {
832       moira_disconnect();
833       return;
834     }
835   
836   rc = GetMachineName(MachineName);
837
838   if (strlen(MachineName) == 0)
839     {
840       moira_disconnect();
841       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
842               OriginalMachineName);
843       return;
844     }
845
846   Moira_process_machine_container_group(MachineName, MoiraContainerGroup,
847                                         DeleteMachine);
848
849   if (machine_check(ldap_handle, dn_path, MachineName))
850     {
851       com_err(whoami, 0, "Unable to find machine %s (alias %s) in directory.", 
852               OriginalMachineName, MachineName);
853       moira_disconnect();
854       return;
855     }
856
857   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
858   machine_get_moira_container(ldap_handle, dn_path, MachineName, 
859                               MoiraContainerName);
860
861   if (strlen(MoiraContainerName) == 0)
862     {
863       com_err(whoami, 0, "Unable to fine machine %s (alias %s) container "
864               "in Moira - moving to orphans OU.",
865               OriginalMachineName, MachineName);
866       machine_move_to_ou(ldap_handle, dn_path, MachineName, 
867                          orphans_machines_ou);
868       moira_disconnect();
869       return;
870     }
871
872   container_get_dn(MoiraContainerName, ADContainerName);
873
874   if (MoiraContainerName[strlen(MoiraContainerName) - 1] != '/')
875     strcat(MoiraContainerName, "/");
876
877   container_check(ldap_handle, dn_path, MoiraContainerName);
878   machine_move_to_ou(ldap_handle, dn_path, MachineName, ADContainerName);
879   moira_disconnect();
880   return;
881 }
882
883 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
884                   char **before, int beforec, char **after, int afterc)
885 {
886   long rc;
887
888   if (!ProcessMachineContainer)
889     {
890       com_err(whoami, 0, "Process machines and containers disabled, skipping");
891       return;
892     }
893
894   if ((beforec == 0) && (afterc == 0))
895     return;
896
897   if (rc = moira_connect())
898     {
899       critical_alert("Ldap incremental", "Error contacting Moira server : %s",
900                      error_message(rc));
901       return;
902     }
903
904   if ((beforec != 0) && (afterc == 0)) /*delete a new container*/
905     {
906       com_err(whoami, 0, "deleting container %s", before[CONTAINER_NAME]);
907       container_delete(ldap_handle, dn_path, beforec, before);
908       Moira_container_group_delete(before);
909       moira_disconnect();
910       return;
911     }
912
913   if ((beforec == 0) && (afterc != 0)) /*create a container*/
914     {
915       com_err(whoami, 0, "creating container %s", after[CONTAINER_NAME]);
916       container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
917       container_create(ldap_handle, dn_path, afterc, after);
918       Moira_container_group_create(after);
919       moira_disconnect();
920       return;
921     }
922
923   if (strcasecmp(before[CONTAINER_NAME], after[CONTAINER_NAME]))
924     {
925       com_err(whoami, 0, "renaming container %s to %s", 
926               before[CONTAINER_NAME], after[CONTAINER_NAME]);
927       container_rename(ldap_handle, dn_path, beforec, before, afterc, after);
928       Moira_container_group_update(before, after);
929       moira_disconnect();
930       return;
931     }
932
933   com_err(whoami, 0, "updating container %s information", 
934           after[CONTAINER_NAME]);
935   container_update(ldap_handle, dn_path, beforec, before, afterc, after);
936   Moira_container_group_update(before, after);
937   moira_disconnect();
938   return;
939 }
940
941 #define L_LIST_DESC 9
942 #define L_LIST_ID   10
943
944 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
945              char **before, int beforec, char **after, int afterc)
946 {
947   int   updateGroup;
948   int   ProcessGroup;
949   long  rc;
950   char  group_membership[6];
951   char  list_id[32];
952   int   security_flag;
953   char  filter[128];
954   char  group_ou[256];
955   char  before_list_id[32];
956   char  before_group_membership[1];
957   int   before_security_flag;
958   char  before_group_ou[256];
959   LK_ENTRY *ptr = NULL;
960
961   if (beforec == 0 && afterc == 0)
962     return;
963
964   memset(list_id, '\0', sizeof(list_id));
965   memset(before_list_id, '\0', sizeof(before_list_id));
966   memset(before_group_ou, '\0', sizeof(before_group_ou));
967   memset(before_group_membership, '\0', sizeof(before_group_membership));
968   memset(group_ou, '\0', sizeof(group_ou));
969   memset(group_membership, '\0', sizeof(group_membership));
970   updateGroup = 0;
971
972   if (beforec > L_GID)
973     {
974       if (beforec < L_LIST_ID)
975         return;
976       if (beforec > L_LIST_DESC)
977         {
978           strcpy(before_list_id, before[L_LIST_ID]);
979         }
980       before_security_flag = 0;
981       get_group_membership(before_group_membership, before_group_ou, 
982                            &before_security_flag, before);
983     }
984
985   if (afterc > L_GID)
986     {
987       if (afterc < L_LIST_ID)
988         return;
989       if (afterc > L_LIST_DESC)
990         {
991           strcpy(list_id, after[L_LIST_ID]);
992         }
993       security_flag = 0;
994       get_group_membership(group_membership, group_ou, &security_flag, after);
995     }
996   
997   if ((beforec == 0) && (afterc == 0)) /*this case should never happen*/
998     return;
999
1000   updateGroup = 0;
1001   
1002   if (beforec)
1003     {
1004       updateGroup = 1;
1005
1006       if ((rc = process_group(ldap_handle, dn_path, before_list_id, 
1007                               before[L_NAME], before_group_ou, 
1008                               before_group_membership, 
1009                               before_security_flag, CHECK_GROUPS,
1010                               before[L_MAILLIST])))
1011         {
1012           if (rc == AD_NO_GROUPS_FOUND)
1013             updateGroup = 0;
1014           else
1015             {
1016               if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
1017                   (rc == AD_MULTIPLE_GROUPS_FOUND))
1018                 {
1019                   rc = process_group(ldap_handle, dn_path, before_list_id, 
1020                                      before[L_NAME], before_group_ou, 
1021                                      before_group_membership, 
1022                                      before_security_flag, CLEANUP_GROUPS,
1023                                      before[L_MAILLIST]);
1024                 }
1025               if ((rc != AD_NO_GROUPS_FOUND) && (rc != 0))
1026                 {
1027                   com_err(whoami, 0, "Unable to process list %s",
1028                           before[L_NAME]);
1029                   return;
1030                 }
1031               if (rc == AD_NO_GROUPS_FOUND)
1032                 updateGroup = 0;
1033             }
1034         }
1035     }
1036
1037   if ((beforec != 0) && (afterc != 0))
1038     {
1039       if (((strcmp(after[L_NAME], before[L_NAME])) || 
1040            ((!strcmp(after[L_NAME], before[L_NAME])) && 
1041             (strcmp(before_group_ou, group_ou)))) &&
1042           (updateGroup == 1))
1043         {
1044           com_err(whoami, 0, "Changing list name from %s to %s",
1045                   before[L_NAME], after[L_NAME]);
1046
1047           if ((strlen(before_group_ou) == 0) || 
1048               (strlen(before_group_membership) == 0) ||
1049               (strlen(group_ou) == 0) || (strlen(group_membership) == 0))
1050             {
1051               com_err(whoami, 0, "%s", "Unable to find the group OU's");
1052               return;
1053             }
1054
1055           memset(filter, '\0', sizeof(filter));
1056
1057           if ((rc = group_rename(ldap_handle, dn_path, 
1058                                  before[L_NAME], before_group_membership, 
1059                                  before_group_ou, before_security_flag, 
1060                                  before[L_LIST_DESC], after[L_NAME], 
1061                                  group_membership, group_ou, security_flag, 
1062                                  after[L_LIST_DESC],
1063                                  list_id, filter, after[L_MAILLIST])))
1064             {
1065               if (rc != AD_NO_GROUPS_FOUND)
1066                 {
1067                   com_err(whoami, 0, 
1068                           "Unable to change list name from %s to %s",
1069                           before[L_NAME], after[L_NAME]);
1070                   return;
1071                 }
1072               updateGroup = 0;
1073             }
1074           beforec = 0;
1075         }
1076       else
1077         beforec = 0;
1078     }
1079   
1080   if (beforec)
1081     {
1082       if ((strlen(before_group_ou) == 0) || 
1083           (strlen(before_group_membership) == 0))
1084         {
1085           com_err(whoami, 0, 
1086                   "Unable to find the group OU for group %s", before[L_NAME]);
1087           return;
1088         }
1089
1090       com_err(whoami, 0, "Deleting group %s", before[L_NAME]);
1091       rc = group_delete(ldap_handle, dn_path, before[L_NAME], 
1092                         before_group_membership, before_list_id);
1093       return;
1094     }
1095
1096   if (afterc)
1097     {
1098       if (!updateGroup)
1099         {
1100           com_err(whoami, 0, "Creating group %s", after[L_NAME]);
1101
1102           if (rc = process_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1103                                   group_ou, group_membership, 
1104                                   security_flag, CHECK_GROUPS,
1105                                  after[L_MAILLIST]))
1106             {
1107               if (rc != AD_NO_GROUPS_FOUND)
1108                 {
1109                   if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
1110                       (rc == AD_MULTIPLE_GROUPS_FOUND))
1111                     {
1112                       rc = process_group(ldap_handle, dn_path, list_id, 
1113                                          after[L_NAME], 
1114                                          group_ou, group_membership, 
1115                                          security_flag, CLEANUP_GROUPS,
1116                                          after[L_MAILLIST]);
1117                     }
1118
1119                   if (rc)
1120                     {
1121                       com_err(whoami, 0, 
1122                               "Unable to create list %s", after[L_NAME]);
1123                       return;
1124                     }
1125                 }
1126             }
1127         }
1128       else
1129         com_err(whoami, 0, "Updating group %s information", after[L_NAME]);
1130
1131       if (rc = moira_connect())
1132         {
1133           critical_alert("Ldap incremental",
1134                          "Error contacting Moira server : %s",
1135                          error_message(rc));
1136           return;
1137         }
1138
1139       ProcessGroup = 0;
1140
1141       if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 0, 
1142                      &ProcessGroup, after[L_MAILLIST]))
1143         return;
1144
1145       if (ProcessGroup)
1146         {
1147           if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 1, 
1148                          &ProcessGroup, after[L_MAILLIST]))
1149             return;
1150         }
1151
1152       if (make_new_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1153                          group_ou, group_membership, security_flag, 
1154                          updateGroup, after[L_MAILLIST]))
1155         {
1156           moira_disconnect();
1157           return;
1158         }
1159     
1160       if (atoi(after[L_ACTIVE]))
1161         {
1162           populate_group(ldap_handle, dn_path, after[L_NAME], group_ou, 
1163                          group_membership, security_flag, list_id);
1164         }
1165
1166       moira_disconnect();
1167     }
1168   return;
1169 }
1170
1171 #define LM_EXTRA_ACTIVE   (LM_END)
1172 #define LM_EXTRA_PUBLIC   (LM_END+1)
1173 #define LM_EXTRA_HIDDEN   (LM_END+2)
1174 #define LM_EXTRA_MAILLIST (LM_END+3)
1175 #define LM_EXTRA_GROUP    (LM_END+4)
1176 #define LM_EXTRA_GID      (LM_END+5)
1177 #define LMN_LIST_ID       (LM_END+6)
1178 #define LM_LIST_ID        (LM_END+7)
1179 #define LM_USER_ID        (LM_END+8)
1180 #define LM_EXTRA_END      (LM_END+9)
1181
1182 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
1183                char **before, int beforec, char **after, int afterc)
1184 {
1185   LK_ENTRY *group_base;
1186   int group_count;
1187   char  filter[128];
1188   char *attr_array[3];
1189   char  group_name[128];
1190   char  user_name[128];
1191   char  user_type[128];
1192   char  moira_list_id[32];
1193   char  moira_user_id[32];
1194   char  group_membership[1];
1195   char  group_ou[256];
1196   char  machine_ou[256];
1197   char  member[256];
1198   char  *args[16];
1199   char  **ptr;
1200   char  *av[7];
1201   char  *call_args[7];
1202   char  *pUserOu;
1203   char  *s;
1204   char  NewMachineName[1024];
1205   int   security_flag;
1206   int   rc;
1207   int   ProcessGroup;
1208   char  *save_argv[U_END];
1209
1210   pUserOu = NULL;
1211   ptr = NULL;
1212   memset(moira_list_id, '\0', sizeof(moira_list_id));
1213   memset(moira_user_id, '\0', sizeof(moira_user_id));
1214
1215   if (afterc)
1216     {
1217       if (afterc < LM_EXTRA_GID)
1218         return;
1219
1220       if (!atoi(after[LM_EXTRA_ACTIVE]))
1221         {
1222           com_err(whoami, 0, 
1223                   "Unable to add %s to group %s : group not active", 
1224                   after[2], after[0]);
1225           return;
1226         }
1227
1228       ptr = after;
1229
1230       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1231         return;
1232
1233       strcpy(user_name, after[LM_MEMBER]);
1234       strcpy(group_name, after[LM_LIST]);
1235       strcpy(user_type, after[LM_TYPE]);
1236
1237       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1238         {
1239           if (afterc > LM_EXTRA_GROUP)
1240             {
1241               strcpy(moira_list_id, after[LMN_LIST_ID]);
1242               strcpy(moira_user_id, after[LM_LIST_ID]);
1243             }
1244         }
1245       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1246         {
1247           if (afterc > LMN_LIST_ID)
1248             {
1249               strcpy(moira_list_id, after[LM_LIST_ID]);
1250               strcpy(moira_user_id, after[LM_USER_ID]);
1251             }
1252         }
1253       else
1254         {
1255           if (afterc > LM_EXTRA_GID)
1256             strcpy(moira_list_id, after[LMN_LIST_ID]);
1257         }
1258     }
1259   else if (beforec)
1260     {
1261       if (beforec < LM_EXTRA_GID)
1262         return;
1263       if (!atoi(before[LM_EXTRA_ACTIVE]))
1264         {
1265           com_err(whoami, 0, 
1266                   "Unable to remove %s from group %s : group not active", 
1267                   before[2], before[0]);
1268           return;
1269         }
1270
1271       ptr = before;
1272
1273       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1274         return;
1275
1276       strcpy(user_name, before[LM_MEMBER]);
1277       strcpy(group_name, before[LM_LIST]);
1278       strcpy(user_type, before[LM_TYPE]);
1279
1280       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1281         {
1282           if (beforec > LM_EXTRA_GROUP)
1283             {
1284               strcpy(moira_list_id, before[LMN_LIST_ID]);
1285               strcpy(moira_user_id, before[LM_LIST_ID]);
1286             }
1287         }
1288       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1289         {
1290           if (beforec > LMN_LIST_ID)
1291             {
1292               strcpy(moira_list_id, before[LM_LIST_ID]);
1293               strcpy(moira_user_id, before[LM_USER_ID]);
1294             }
1295         }
1296       else
1297         {
1298           if (beforec > LM_EXTRA_GID)
1299             strcpy(moira_list_id, before[LMN_LIST_ID]);
1300         }
1301     }
1302
1303   if (ptr == NULL)
1304     {
1305       com_err(whoami, 0, 
1306               "Unable to process group : beforec = %d, afterc = %d", 
1307               beforec, afterc);
1308       return;
1309     }
1310
1311   args[L_NAME] = ptr[LM_LIST];
1312   args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE];
1313   args[L_PUBLIC] = ptr[LM_EXTRA_PUBLIC];
1314   args[L_HIDDEN] = ptr[LM_EXTRA_HIDDEN];
1315   args[L_MAILLIST] = ptr[LM_EXTRA_MAILLIST];
1316   args[L_GROUP] = ptr[LM_EXTRA_GROUP];
1317   args[L_GID] = ptr[LM_EXTRA_GID];
1318
1319   security_flag = 0;
1320   memset(group_ou, '\0', sizeof(group_ou));
1321   get_group_membership(group_membership, group_ou, &security_flag, args);
1322
1323   if (strlen(group_ou) == 0)
1324     {
1325       com_err(whoami, 0, "Unable to find the group OU for group %s", 
1326               group_name);
1327       return;
1328     }
1329
1330   if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, 
1331                          group_ou, group_membership, security_flag, 
1332                          CHECK_GROUPS, args[L_MAILLIST]))
1333     {
1334       if (rc != AD_NO_GROUPS_FOUND)
1335         {
1336           if (rc = process_group(ldap_handle, dn_path, moira_list_id, 
1337                                  group_name, group_ou, group_membership, 
1338                                  security_flag, CLEANUP_GROUPS,
1339                                  args[L_MAILLIST]))
1340             {
1341               if (rc != AD_NO_GROUPS_FOUND)
1342                 {
1343                   if (afterc)
1344                     com_err(whoami, 0, "Unable to add %s to group %s - " 
1345                             "unable to process group", user_name, group_name);
1346                   else
1347                     com_err(whoami, 0, "Unable to remove %s from group %s - "
1348                             "unable to process group", user_name, group_name);
1349                   return;
1350                 }
1351             }
1352         }
1353     }
1354
1355   if (rc == AD_NO_GROUPS_FOUND)
1356     {
1357       if (rc = moira_connect())
1358         {
1359           critical_alert("Ldap incremental",
1360                          "Error contacting Moira server : %s",
1361                          error_message(rc));
1362           return;
1363         }
1364       
1365       com_err(whoami, 0, "creating group %s", group_name);
1366       ProcessGroup = 0;
1367
1368       if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 0, 
1369                      &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1370         return;
1371
1372       if (ProcessGroup)
1373         {
1374           if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 1, 
1375                          &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1376             return;
1377         }
1378
1379       if (make_new_group(ldap_handle, dn_path, moira_list_id, ptr[LM_LIST], 
1380                          group_ou, group_membership, security_flag, 0,
1381                          ptr[LM_EXTRA_MAILLIST]))
1382         {
1383           moira_disconnect();
1384           return;
1385         }
1386     
1387       if (atoi(ptr[LM_EXTRA_ACTIVE]))
1388         {
1389           populate_group(ldap_handle, dn_path, ptr[LM_LIST], group_ou, 
1390                          group_membership, security_flag, moira_list_id);
1391         }
1392
1393       moira_disconnect();
1394     }
1395
1396   rc = 0;
1397
1398   if (beforec)
1399     {
1400       com_err(whoami, 0, "removing user %s from list %s", user_name, 
1401               group_name);
1402       pUserOu = user_ou;
1403  
1404       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1405         {
1406           if (!ProcessMachineContainer)
1407             {
1408               com_err(whoami, 0, "Process machines and containers disabled, "
1409                       "skipping");
1410               return;
1411             }
1412
1413           memset(machine_ou, '\0', sizeof(machine_ou));
1414           memset(NewMachineName, '\0', sizeof(NewMachineName));
1415           if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], 
1416                              machine_ou, NewMachineName))
1417             return;
1418           if (ptr[LM_MEMBER] != NULL)     
1419             free(ptr[LM_MEMBER]);
1420           ptr[LM_MEMBER] = strdup(NewMachineName);
1421           pUserOu = machine_ou;
1422         }
1423
1424       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1425         {
1426           strcpy(member, ptr[LM_MEMBER]);
1427
1428           if (Exchange) 
1429             {
1430               if((s = strchr(member, '@')) == (char *) NULL)
1431                 { 
1432                   strcat(member, "@mit.edu");
1433                   
1434                   if (ptr[LM_MEMBER] != NULL)
1435                     free(ptr[LM_MEMBER]);
1436                   ptr[LM_MEMBER] = strdup(member);
1437                 }
1438           
1439               if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1440                 {
1441                   s = strrchr(member, '.');
1442                   *s = '\0';
1443                   strcat(s, ".mit.edu");
1444                   
1445                   if (ptr[LM_MEMBER] != NULL)
1446                     free(ptr[LM_MEMBER]);
1447                   ptr[LM_MEMBER] = strdup(member);
1448                 }
1449             }
1450
1451           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1452                              contact_ou))
1453                 return;
1454
1455           pUserOu = contact_ou;
1456         }
1457       else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1458         {
1459           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1460                              kerberos_ou))
1461             return;
1462
1463           pUserOu = kerberos_ou;
1464         }
1465
1466       if (rc = moira_connect()) {
1467         critical_alert("Ldap incremental",
1468                        "Error contacting Moira server : %s",
1469                        error_message(rc));              
1470         return;
1471       }
1472       
1473       if (rc = populate_group(ldap_handle, dn_path, group_name,
1474                               group_ou, group_membership, 
1475                               security_flag, moira_list_id))
1476         com_err(whoami, 0, "Unable to remove %s from group %s", user_name, 
1477                 group_name);
1478       
1479       moira_disconnect();
1480       
1481       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1482         {
1483           if (rc = moira_connect())
1484             {
1485               critical_alert("Ldap incremental",
1486                              "Error contacting Moira server : %s",
1487                              error_message(rc));
1488               return;
1489             }
1490           
1491           if (rc = populate_group(ldap_handle, dn_path, group_name,
1492                                   group_ou, group_membership, security_flag,
1493                                   moira_list_id))
1494             com_err(whoami, 0, "Unable to remove %s from group %s",
1495                     user_name, group_name);
1496
1497           moira_disconnect();
1498         }
1499       return;
1500     }
1501   
1502   com_err(whoami, 0, "Adding %s to list %s", user_name, group_name);
1503   pUserOu = user_ou;
1504   
1505   if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1506     {
1507       memset(machine_ou, '\0', sizeof(machine_ou));
1508       memset(NewMachineName, '\0', sizeof(NewMachineName));
1509
1510       if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], machine_ou, 
1511                          NewMachineName))
1512         return;
1513
1514       if (ptr[LM_MEMBER] != NULL)
1515         free(ptr[LM_MEMBER]);
1516
1517       ptr[LM_MEMBER] = strdup(NewMachineName);
1518       pUserOu = machine_ou;
1519     }
1520   else if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1521     {
1522       strcpy(member, ptr[LM_MEMBER]);
1523
1524       if (Exchange) 
1525         {
1526           if((s = strchr(member, '@')) == (char *) NULL)
1527             { 
1528               strcat(member, "@mit.edu");
1529               
1530               if (ptr[LM_MEMBER] != NULL)
1531                 free(ptr[LM_MEMBER]);
1532               ptr[LM_MEMBER] = strdup(member);
1533             }
1534           
1535           if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1536             {
1537               s = strrchr(member, '.');
1538               *s = '\0';
1539               strcat(s, ".mit.edu");
1540               
1541               if (ptr[LM_MEMBER] != NULL)
1542                 free(ptr[LM_MEMBER]);
1543               ptr[LM_MEMBER] = strdup(member);
1544             }
1545         }
1546       
1547       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1548                          contact_ou))
1549         return;
1550
1551       pUserOu = contact_ou;
1552     }
1553   else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1554     {
1555       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1556                          kerberos_ou))
1557         return;
1558
1559       pUserOu = kerberos_ou;
1560     }
1561   else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1562     {
1563       if ((rc = check_user(ldap_handle, dn_path, ptr[LM_MEMBER], 
1564                            moira_user_id)) == AD_NO_USER_FOUND)
1565         {
1566           if (rc = moira_connect())
1567             {
1568               critical_alert("Ldap incremental", 
1569                              "Error connection to Moira : %s",
1570                              error_message(rc));
1571               return;
1572             }
1573
1574           com_err(whoami, 0, "creating user %s", ptr[LM_MEMBER]);
1575           av[0] = ptr[LM_MEMBER];
1576           call_args[0] = (char *)ldap_handle;
1577           call_args[1] = dn_path;
1578           call_args[2] = moira_user_id;
1579           call_args[3] = NULL;
1580           
1581           callback_rc = 0;
1582
1583           if (Exchange)
1584             {
1585               group_count = 0;
1586               group_base = NULL;
1587           
1588               sprintf(filter, "(&(objectClass=group)(cn=%s))", ptr[LM_MEMBER]);
1589               attr_array[0] = "cn";
1590               attr_array[1] = NULL;
1591               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
1592                                        attr_array, &group_base, &group_count,
1593                                        LDAP_SCOPE_SUBTREE)) != 0)
1594                 {
1595                   com_err(whoami, 0, "Unable to process user %s : %s",
1596                           ptr[LM_MEMBER], ldap_err2string(rc));
1597                   return;
1598                 }
1599               
1600               if (group_count)
1601                 {
1602                   com_err(whoami, 0, "Object already exists with name %s",
1603                           ptr[LM_MEMBER]);
1604                   return;
1605                 }
1606           
1607               linklist_free(group_base);
1608               group_count = 0;
1609               group_base = NULL;
1610             }
1611
1612           if (rc = mr_query("get_user_account_by_login", 1, av, 
1613                             save_query_info, save_argv))
1614             {
1615               moira_disconnect();
1616               com_err(whoami, 0, "Unable to create user %s : %s",
1617                       ptr[LM_MEMBER], error_message(rc));
1618               return;
1619             }
1620         
1621           if (rc = user_create(U_END, save_argv, call_args)) 
1622             {
1623               moira_disconnect();
1624               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1625               return;
1626             }
1627
1628           if (callback_rc)
1629             {
1630               moira_disconnect();
1631               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1632               return;
1633             }
1634         }
1635       else
1636         {
1637           if (rc != 0)
1638             return;
1639         }
1640       pUserOu = user_ou;
1641     }
1642
1643   if (rc = moira_connect()) {
1644     critical_alert("Ldap incremental",
1645                    "Error contacting Moira server : %s",
1646                    error_message(rc));              
1647     return;
1648   }
1649
1650   if (rc = populate_group(ldap_handle, dn_path, group_name,
1651                           group_ou, group_membership, security_flag,
1652                           moira_list_id))
1653     com_err(whoami, 0, "Unable to add %s to group %s", user_name, 
1654             group_name);
1655   
1656   moira_disconnect();
1657
1658   if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1659     {
1660       if (rc = moira_connect())
1661         {
1662           critical_alert("Ldap incremental",
1663                          "Error contacting Moira server : %s",
1664                          error_message(rc));
1665           return;
1666         }
1667       
1668       if (rc = populate_group(ldap_handle, dn_path, group_name,
1669                               group_ou, group_membership, security_flag,
1670                               moira_list_id))
1671         com_err(whoami, 0, "Unable to add %s to group %s",
1672                 user_name, group_name);
1673       
1674       moira_disconnect();
1675     }
1676
1677   return;
1678 }
1679
1680
1681 #define U_USER_ID    10
1682 #define U_HOMEDIR    11
1683 #define U_PROFILEDIR 12
1684
1685 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
1686              char **before, int beforec, char **after, 
1687              int afterc)
1688 {
1689   LK_ENTRY *group_base;
1690   int   group_count;
1691   char  filter[128];
1692   char  *attr_array[3];
1693   int   rc;
1694   char  *av[7];
1695   char  after_user_id[32];
1696   char  before_user_id[32];
1697   char  *call_args[7];
1698   char  *save_argv[U_END];
1699
1700   if ((beforec == 0) && (afterc == 0))
1701     return;
1702
1703   memset(after_user_id, '\0', sizeof(after_user_id));
1704   memset(before_user_id, '\0', sizeof(before_user_id));
1705
1706   if (beforec > U_USER_ID)
1707     strcpy(before_user_id, before[U_USER_ID]);
1708
1709   if (afterc > U_USER_ID)
1710     strcpy(after_user_id, after[U_USER_ID]);
1711
1712   if ((beforec == 0) && (afterc == 0)) /*this case should never happen */
1713     return;
1714
1715   if ((beforec == 0) && (afterc != 0)) 
1716     {
1717       /*this case only happens when the account*/
1718       /*account is first created but not usable*/
1719
1720       com_err(whoami, 0, "Unable to process user %s because the user account "
1721               "is not yet usable", after[U_NAME]);
1722       return;
1723     }
1724
1725   /*this case only happens when the account is expunged */
1726
1727   if ((beforec != 0) && (afterc == 0)) 
1728     {                                 
1729       if (atoi(before[U_STATE]) == 0)
1730         {
1731           com_err(whoami, 0, "expunging user %s from directory", 
1732                   before[U_NAME]);
1733           user_delete(ldap_handle, dn_path, before[U_NAME], before_user_id);
1734         }
1735       else
1736         {
1737           com_err(whoami, 0, "Unable to process because user %s has been "
1738                   "previously expungeded", before[U_NAME]);
1739         }
1740       return;
1741     }
1742
1743   /*process anything that gets here*/
1744
1745   if ((rc = check_user(ldap_handle, dn_path, before[U_NAME], 
1746                        before_user_id)) == AD_NO_USER_FOUND)
1747     {
1748       if (!check_string(after[U_NAME]))
1749         return;
1750
1751       if (rc = moira_connect())
1752         {
1753           critical_alert("Ldap incremental", 
1754                          "Error connection to Moira : %s",
1755                          error_message(rc));
1756           return;
1757         }
1758
1759       com_err(whoami, 0, "creating user %s", after[U_NAME]);
1760       
1761       av[0] = after[U_NAME];
1762       call_args[0] = (char *)ldap_handle;
1763       call_args[1] = dn_path;
1764       call_args[2] = after_user_id;
1765       call_args[3] = NULL;
1766       callback_rc = 0;
1767
1768       if (Exchange) 
1769         {
1770           group_count = 0;
1771           group_base = NULL;
1772           
1773           sprintf(filter, "(&(objectClass=group)(cn=%s))", after[U_NAME]);
1774           attr_array[0] = "cn";
1775           attr_array[1] = NULL;
1776           
1777           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
1778                                    &group_base, &group_count,
1779                                    LDAP_SCOPE_SUBTREE)) != 0)
1780             {
1781               com_err(whoami, 0, "Unable to process user %s : %s",
1782                       after[U_NAME], ldap_err2string(rc));
1783               return;
1784             }
1785           
1786           if (group_count >= 1)
1787             {
1788               com_err(whoami, 0, "Object already exists with name %s",
1789                       after[U_NAME]);
1790               return;
1791             }
1792       
1793           linklist_free(group_base);
1794           group_count = 0;
1795           group_base = NULL;
1796         }
1797
1798       if (rc = mr_query("get_user_account_by_login", 1, av,
1799                         save_query_info, save_argv))
1800         {
1801           moira_disconnect();
1802           com_err(whoami, 0, "Unable to create user %s : %s",
1803                   after[U_NAME], error_message(rc));
1804           return;
1805         }
1806
1807       if (rc = user_create(U_END, save_argv, call_args)) 
1808         {
1809           com_err(whoami, 0, "Unable to create user %s : %s",
1810                   after[U_NAME], error_message(rc));
1811           return;
1812         }
1813       
1814       if (callback_rc)
1815         {
1816           moira_disconnect();
1817           com_err(whoami, 0, "Unable to create user %s", after[U_NAME]);
1818           return;
1819         }
1820
1821       return;
1822     }
1823   else
1824     {
1825       if (rc != 0)
1826         return;
1827     }
1828
1829   if (strcmp(before[U_NAME], after[U_NAME]))
1830     {
1831       if ((check_string(before[U_NAME])) && (check_string(after[U_NAME])))
1832         {
1833           com_err(whoami, 0, "changing user %s to %s", 
1834                   before[U_NAME], after[U_NAME]);
1835
1836           if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], 
1837                                 after[U_NAME])) != LDAP_SUCCESS)
1838             {
1839               return;
1840             }
1841         }
1842     }
1843
1844   com_err(whoami, 0, "updating user %s information", after[U_NAME]);
1845   rc = user_update(ldap_handle, dn_path, after[U_NAME],
1846                    after[U_UID], after[U_MITID], 
1847                    after_user_id, atoi(after[U_STATE]),
1848                    after[U_HOMEDIR], after[U_PROFILEDIR],
1849                    after[U_FIRST], after[U_MIDDLE], after[U_LAST], 
1850                    after[U_SHELL], after[U_CLASS]);
1851
1852   return;
1853 }
1854
1855 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
1856                         char *oldValue, char *newValue,
1857                         char ***modvalues, int type)
1858 {
1859   LK_ENTRY    *linklist_ptr;
1860   int         i;
1861   char        *cPtr;
1862   
1863   if (((*modvalues) = calloc(1, 
1864                              (modvalue_count + 1) * sizeof(char *))) == NULL)
1865     {
1866       return(1);
1867     }
1868
1869   for (i = 0; i < (modvalue_count + 1); i++)
1870     (*modvalues)[i] = NULL;
1871
1872   if (modvalue_count != 0)
1873     {
1874       linklist_ptr = linklist_base;
1875       for (i = 0; i < modvalue_count; i++)
1876         {
1877           if ((oldValue != NULL) && (newValue != NULL))
1878             {
1879               if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue))
1880                   != (char *)NULL)
1881                 {
1882                   if (type == REPLACE)
1883                     {
1884                       if (((*modvalues)[i] = calloc(1, strlen(newValue) + 1))
1885                           == NULL)
1886                         return(1);
1887                       memset((*modvalues)[i], '\0', strlen(newValue) + 1);
1888                       strcpy((*modvalues)[i], newValue);
1889                     }
1890                   else
1891                     {
1892                       if (((*modvalues)[i] = calloc(1, 
1893                                         (int)(cPtr - linklist_ptr->value) + 
1894                                                (linklist_ptr->length - 
1895                                                strlen(oldValue)) + 
1896                                                strlen(newValue) + 1)) == NULL)
1897                         return(1);
1898                       memset((*modvalues)[i], '\0', 
1899                              (int)(cPtr - linklist_ptr->value) + 
1900                              (linklist_ptr->length - strlen(oldValue)) + 
1901                              strlen(newValue) + 1);
1902                       memcpy((*modvalues)[i], linklist_ptr->value, 
1903                              (int)(cPtr - linklist_ptr->value));
1904                       strcat((*modvalues)[i], newValue);
1905                       strcat((*modvalues)[i], 
1906                              &linklist_ptr->value[(int)(cPtr - 
1907                                      linklist_ptr->value) + strlen(oldValue)]);
1908                     }
1909                 }
1910               else
1911                 {
1912                   (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1913                   memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1914                   memcpy((*modvalues)[i], linklist_ptr->value,
1915                          linklist_ptr->length);
1916                 }
1917             }
1918         else
1919             {
1920               (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1921               memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1922               memcpy((*modvalues)[i], linklist_ptr->value,
1923                      linklist_ptr->length);
1924             }
1925           linklist_ptr = linklist_ptr->next;
1926         }
1927       (*modvalues)[i] = NULL;
1928     }
1929   return(0);
1930 }
1931
1932
1933 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
1934                    char **attr_array, LK_ENTRY **linklist_base,
1935                    int *linklist_count, unsigned long ScopeType)
1936 {
1937   ULONG       rc;
1938   LDAPMessage *ldap_entry;
1939
1940   rc = 0;
1941   ldap_entry = NULL;
1942   (*linklist_base) = NULL;
1943   (*linklist_count) = 0;
1944
1945   if ((rc = ldap_search_s(ldap_handle, dn_path, ScopeType, 
1946                           search_exp, attr_array, 0, 
1947                           &ldap_entry)) != LDAP_SUCCESS)
1948       {
1949         if (rc != LDAP_SIZELIMIT_EXCEEDED)
1950           return(0);
1951       }
1952
1953   rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, 
1954                         linklist_count);
1955
1956   ldap_msgfree(ldap_entry);
1957   return(rc);
1958 }
1959
1960 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
1961                      LK_ENTRY **linklist_base, int *linklist_count)
1962 {
1963   char        distinguished_name[1024];
1964   LK_ENTRY    *linklist_ptr;
1965   int         rc;
1966
1967   if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL)
1968     return(0);
1969   
1970   memset(distinguished_name, '\0', sizeof(distinguished_name));
1971   get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1972
1973   if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name,
1974                                 linklist_base)) != 0)
1975     return(rc);
1976
1977   while ((ldap_entry = ldap_next_entry(ldap_handle, ldap_entry)) != NULL)
1978     {
1979       memset(distinguished_name, '\0', sizeof(distinguished_name));
1980       get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1981       
1982       if ((rc = retrieve_attributes(ldap_handle, ldap_entry, 
1983                                     distinguished_name, linklist_base)) != 0)
1984         return(rc);
1985     }
1986
1987   linklist_ptr = (*linklist_base);
1988   (*linklist_count) = 0;
1989
1990   while (linklist_ptr != NULL)
1991     {
1992       ++(*linklist_count);
1993       linklist_ptr = linklist_ptr->next;
1994     }
1995
1996   return(0);
1997 }
1998
1999 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
2000                         char *distinguished_name, LK_ENTRY **linklist_current)
2001 {
2002   char        *Attribute;
2003   BerElement  *ptr;
2004
2005   ptr = NULL;
2006
2007   if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, 
2008                                         &ptr)) != NULL)
2009     {
2010       retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name,
2011                       linklist_current);
2012       ldap_memfree(Attribute);
2013       while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, 
2014                                               ptr)) != NULL)
2015         {
2016           retrieve_values(ldap_handle, ldap_entry, Attribute,
2017                           distinguished_name, linklist_current);
2018           ldap_memfree(Attribute);
2019         }
2020     }
2021
2022   ldap_ber_free(ptr, 0);
2023
2024   return(0);
2025 }
2026
2027 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
2028                     char *Attribute, char *distinguished_name,
2029                     LK_ENTRY **linklist_current)
2030 {
2031   char        **str_value;
2032   char        temp[256];
2033   void        **Ptr;
2034   int         use_bervalue;
2035   LK_ENTRY    *linklist_previous;
2036   LDAP_BERVAL **ber_value;
2037   DWORD       ber_length;
2038
2039 #ifdef LDAP_DEBUG
2040   SID         *sid;
2041   GUID        *guid;
2042   int         i;
2043   int         intValue;
2044   DWORD       *subauth;
2045   SID_IDENTIFIER_AUTHORITY    *sid_auth;
2046   unsigned char   *subauth_count;
2047 #endif /*LDAP_BEGUG*/
2048
2049   use_bervalue = 0;
2050   memset(temp, '\0', sizeof(temp));
2051
2052   if ((!strcmp(Attribute, "objectSid")) ||
2053       (!strcmp(Attribute, "objectGUID")))
2054     use_bervalue = 1;
2055   
2056   if (use_bervalue)
2057     {
2058       ber_value = ldap_get_values_len(ldap_handle, ldap_entry, Attribute);
2059       Ptr = (void **)ber_value;
2060       str_value = NULL;
2061     }
2062   else
2063     {
2064       str_value = ldap_get_values(ldap_handle, ldap_entry, Attribute);
2065       Ptr = (void **)str_value;
2066       ber_value = NULL;
2067     }
2068
2069   if (Ptr != NULL)
2070     {
2071       for (; *Ptr; Ptr++) 
2072         {
2073           if ((linklist_previous = calloc(1, sizeof(LK_ENTRY))) == NULL)
2074             return(1);
2075
2076           memset(linklist_previous, '\0', sizeof(LK_ENTRY));
2077           linklist_previous->next = (*linklist_current);
2078           (*linklist_current) = linklist_previous;
2079           
2080           if (((*linklist_current)->attribute = calloc(1, 
2081                                               strlen(Attribute) + 1)) == NULL)
2082             return(1);
2083
2084           memset((*linklist_current)->attribute, '\0', strlen(Attribute) + 1);
2085           strcpy((*linklist_current)->attribute, Attribute);
2086
2087           if (use_bervalue)
2088             {
2089               ber_length = (*(LDAP_BERVAL **)Ptr)->bv_len;
2090
2091               if (((*linklist_current)->value = calloc(1, ber_length)) == NULL)
2092                 return(1);
2093
2094               memset((*linklist_current)->value, '\0', ber_length);
2095               memcpy((*linklist_current)->value, 
2096                      (*(LDAP_BERVAL **)Ptr)->bv_val, ber_length);
2097               (*linklist_current)->length = ber_length;
2098             }
2099           else
2100             {
2101               if (((*linklist_current)->value = calloc(1, 
2102                                                     strlen(*Ptr) + 1)) == NULL)
2103                 return(1);
2104
2105               memset((*linklist_current)->value, '\0', strlen(*Ptr) + 1);
2106               (*linklist_current)->length = strlen(*Ptr);
2107               strcpy((*linklist_current)->value, *Ptr);
2108             }
2109
2110           (*linklist_current)->ber_value = use_bervalue;
2111
2112           if (((*linklist_current)->dn = calloc(1, 
2113                                       strlen(distinguished_name) + 1)) == NULL)
2114             return(1);
2115
2116           memset((*linklist_current)->dn, '\0', 
2117                  strlen(distinguished_name) + 1);
2118           strcpy((*linklist_current)->dn, distinguished_name);
2119
2120 #ifdef LDAP_DEBUG
2121           if (!strcmp(Attribute, "objectGUID"))
2122             {
2123               guid = (GUID *)((*linklist_current)->value);
2124               sprintf(temp, 
2125                       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
2126                       guid->Data1, guid->Data2, guid->Data3, 
2127                       guid->Data4[0], guid->Data4[1], guid->Data4[2], 
2128                       guid->Data4[3], guid->Data4[4], guid->Data4[5], 
2129                       guid->Data4[6], guid->Data4[7]);
2130               print_to_screen("     %20s : {%s}\n", Attribute, temp);
2131             }
2132           else if (!strcmp(Attribute, "objectSid"))
2133             {
2134               sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val);
2135
2136 #ifdef _WIN32
2137               print_to_screen("        Revision = %d\n", sid->Revision);
2138               print_to_screen("        SID Identifier Authority:\n");
2139               sid_auth = &sid->IdentifierAuthority;
2140               if (sid_auth->Value[0])
2141                 print_to_screen("            SECURITY_NULL_SID_AUTHORITY\n");
2142               else if (sid_auth->Value[1])
2143                 print_to_screen("            SECURITY_WORLD_SID_AUTHORITY\n");
2144               else if (sid_auth->Value[2])
2145                 print_to_screen("            SECURITY_LOCAL_SID_AUTHORITY\n");
2146               else if (sid_auth->Value[3])
2147                 print_to_screen("           SECURITY_CREATOR_SID_AUTHORITY\n");
2148               else if (sid_auth->Value[5])
2149                 print_to_screen("            SECURITY_NT_AUTHORITY\n");
2150               else
2151                 print_to_screen("            UNKNOWN SID AUTHORITY\n");
2152               subauth_count = GetSidSubAuthorityCount(sid);
2153               print_to_screen("        SidSubAuthorityCount = %d\n", 
2154                               *subauth_count);
2155               print_to_screen("        SidSubAuthority:\n");
2156               for (i = 0; i < *subauth_count; i++)
2157                 {
2158                   if ((subauth = GetSidSubAuthority(sid, i)) != NULL)
2159                     print_to_screen("            %u\n", *subauth);
2160                 }
2161 #endif
2162             }
2163           else if ((!memcmp(Attribute, "userAccountControl", 
2164                             strlen("userAccountControl"))) ||
2165                    (!memcmp(Attribute, "sAMAccountType", 
2166                             strlen("sAmAccountType"))))
2167             {
2168               intValue = atoi(*Ptr);
2169               print_to_screen("     %20s : %ld\n",Attribute, intValue);
2170
2171               if (!memcmp(Attribute, "userAccountControl", 
2172                           strlen("userAccountControl")))
2173                 {
2174                   if (intValue & UF_ACCOUNTDISABLE)
2175                     print_to_screen("     %20s :    %s\n", 
2176                                     "", "Account disabled");
2177                   else
2178                     print_to_screen("     %20s :    %s\n", 
2179                                     "", "Account active");
2180                   if (intValue & UF_HOMEDIR_REQUIRED)
2181                     print_to_screen("     %20s :    %s\n", 
2182                                     "", "Home directory required");
2183                   if (intValue & UF_LOCKOUT)
2184                     print_to_screen("     %20s :    %s\n", 
2185                                     "", "Account locked out");
2186                   if (intValue & UF_PASSWD_NOTREQD)
2187                     print_to_screen("     %20s :    %s\n", 
2188                                     "", "No password required");
2189                   if (intValue & UF_PASSWD_CANT_CHANGE)
2190                     print_to_screen("     %20s :    %s\n",
2191                                     "", "Cannot change password");
2192                   if (intValue & UF_TEMP_DUPLICATE_ACCOUNT)
2193                     print_to_screen("     %20s :    %s\n", 
2194                                     "", "Temp duplicate account");
2195                   if (intValue & UF_NORMAL_ACCOUNT)
2196                     print_to_screen("     %20s :    %s\n", 
2197                                     "", "Normal account");
2198                   if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT)
2199                     print_to_screen("     %20s :    %s\n", 
2200                                     "", "Interdomain trust account");
2201                   if (intValue & UF_WORKSTATION_TRUST_ACCOUNT)
2202                     print_to_screen("     %20s :    %s\n", 
2203                                     "", "Workstation trust account");
2204                   if (intValue & UF_SERVER_TRUST_ACCOUNT)
2205                     print_to_screen("     %20s :    %s\n", 
2206                                     "", "Server trust account");
2207                 }
2208             }
2209           else
2210             {
2211               print_to_screen("     %20s : %s\n",Attribute, *Ptr);
2212             }
2213 #endif /*LDAP_DEBUG*/
2214         }
2215
2216       if (str_value != NULL)
2217         ldap_value_free(str_value);
2218
2219       if (ber_value != NULL)
2220         ldap_value_free_len(ber_value);
2221     }
2222
2223   (*linklist_current) = linklist_previous;
2224
2225   return(0);
2226 }
2227
2228 int moira_connect(void)
2229 {
2230   long    rc;
2231   char    HostName[64];
2232
2233   if (!mr_connections++)
2234     {
2235
2236 #ifdef _WIN32
2237       memset(HostName, '\0', sizeof(HostName));
2238       strcpy(HostName, "ttsp");
2239       rc = mr_connect_cl(HostName, "ldap.incr", QUERY_VERSION, 1);
2240 #else
2241       struct utsname uts;
2242       uname(&uts);
2243       rc = mr_connect_cl(uts.nodename, "ldap.incr", QUERY_VERSION, 1);
2244 #endif /*WIN32*/
2245
2246       return rc;
2247     }
2248
2249   return 0;
2250 }
2251
2252 int check_winad(void)
2253 {
2254   int i;
2255   
2256   for (i = 0; file_exists(STOP_FILE); i++)
2257     {
2258       if (i > 30)
2259         {
2260           critical_alert("Ldap incremental",
2261                          "Ldap incremental failed (%s exists): %s",
2262                          STOP_FILE, tbl_buf);
2263           return(1);
2264         }
2265
2266       sleep(60);
2267     }
2268
2269   return(0);
2270 }
2271
2272 int moira_disconnect(void)
2273 {
2274
2275   if (!--mr_connections)
2276     {
2277       mr_disconnect();
2278     }
2279
2280   return 0;
2281 }
2282
2283 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
2284                             char *distinguished_name)
2285 {
2286   char    *CName;
2287   
2288   CName = ldap_get_dn(ldap_handle, ldap_entry);
2289
2290   if (CName == NULL)
2291     return;
2292
2293   strcpy(distinguished_name, CName);
2294   ldap_memfree(CName);
2295 }
2296
2297 int linklist_create_entry(char *attribute, char *value, 
2298                           LK_ENTRY **linklist_entry)
2299 {
2300   (*linklist_entry) = calloc(1, sizeof(LK_ENTRY));
2301
2302   if (!(*linklist_entry))
2303     {
2304       return(1);
2305     }
2306
2307   memset((*linklist_entry), '\0', sizeof(LK_ENTRY));
2308   (*linklist_entry)->attribute = calloc(1, strlen(attribute) + 1);
2309   memset((*linklist_entry)->attribute, '\0', strlen(attribute) + 1);
2310   strcpy((*linklist_entry)->attribute, attribute);
2311   (*linklist_entry)->value = calloc(1, strlen(value) + 1);
2312   memset((*linklist_entry)->value, '\0', strlen(value) + 1);
2313   strcpy((*linklist_entry)->value, value);
2314   (*linklist_entry)->length = strlen(value);
2315   (*linklist_entry)->next = NULL;
2316
2317   return(0);
2318 }
2319
2320 void print_to_screen(const char *fmt, ...)
2321 {
2322   va_list pvar;
2323
2324   va_start(pvar, fmt);
2325   vfprintf(stderr, fmt, pvar);
2326   fflush(stderr);
2327   va_end(pvar);
2328 }
2329
2330 int get_group_membership(char *group_membership, char *group_ou, 
2331                          int *security_flag, char **av)
2332 {
2333   int  maillist_flag;
2334   int  group_flag;
2335   
2336   maillist_flag = atoi(av[L_MAILLIST]);
2337   group_flag = atoi(av[L_GROUP]);
2338
2339   if (security_flag != NULL)
2340     (*security_flag) = 0;
2341   
2342   if ((maillist_flag) && (group_flag))
2343     {
2344       if (group_membership != NULL)
2345         group_membership[0] = 'B';
2346
2347       if (security_flag != NULL)
2348         (*security_flag) = 1;
2349
2350       if (group_ou != NULL)
2351         strcpy(group_ou, group_ou_both);
2352     }
2353   else if ((!maillist_flag) && (group_flag))
2354     {
2355       if (group_membership != NULL)
2356         group_membership[0] = 'S';
2357
2358       if (security_flag != NULL)
2359         (*security_flag) = 1;
2360
2361       if (group_ou != NULL)
2362         strcpy(group_ou, group_ou_security);
2363     }
2364   else if ((maillist_flag) && (!group_flag))
2365     {
2366       if (group_membership != NULL)
2367         group_membership[0] = 'D';
2368
2369       if (group_ou != NULL)
2370         strcpy(group_ou, group_ou_distribution);
2371     }
2372   else
2373     {
2374       if (group_membership != NULL)
2375         group_membership[0] = 'N';
2376
2377       if (group_ou != NULL)
2378         strcpy(group_ou, group_ou_neither);
2379     }
2380
2381   return(0);
2382 }
2383
2384 int group_rename(LDAP *ldap_handle, char *dn_path, 
2385                  char *before_group_name, char *before_group_membership, 
2386                  char *before_group_ou, int before_security_flag, 
2387                  char *before_desc, char *after_group_name, 
2388                  char *after_group_membership, char *after_group_ou, 
2389                  int after_security_flag, char *after_desc,
2390                  char *MoiraId, char *filter, char *maillist)
2391 {
2392   LDAPMod   *mods[20];
2393   char      old_dn[512];
2394   char      new_dn[512];
2395   char      new_dn_path[512];
2396   char      sam_name[256];
2397   char      mail[256];
2398   char      mail_nickname[256];
2399   char      proxy_address[256];
2400   char      address_book[256];
2401   char      *attr_array[3];
2402   char      *mitMoiraId_v[] = {NULL, NULL};
2403   char      *name_v[] = {NULL, NULL};
2404   char      *samAccountName_v[] = {NULL, NULL};
2405   char      *groupTypeControl_v[] = {NULL, NULL};
2406   char      *mail_v[] = {NULL, NULL};
2407   char      *proxy_address_v[] = {NULL, NULL};
2408   char      *mail_nickname_v[] = {NULL, NULL};
2409   char      *report_to_originator_v[] = {NULL, NULL};
2410   char      *address_book_v[] = {NULL, NULL};
2411   char      *legacy_exchange_dn_v[] = {NULL, NULL};
2412   char      *null_v[] = {NULL, NULL};
2413   u_int     groupTypeControl;
2414   char      groupTypeControlStr[80];
2415   char      contact_mail[256];
2416   int       n;
2417   int       i;
2418   int       rc;
2419   LK_ENTRY  *group_base;
2420   int       group_count;
2421   int       MailDisabled = 0;
2422
2423   if(UseGroupUniversal)
2424     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2425   else
2426     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2427      
2428   if (!check_string(before_group_name))
2429     {
2430       com_err(whoami, 0, 
2431               "Unable to process invalid LDAP list name %s", 
2432               before_group_name);
2433       return(AD_INVALID_NAME);
2434     }
2435
2436   if (!check_string(after_group_name))
2437     {
2438       com_err(whoami, 0, 
2439               "Unable to process invalid LDAP list name %s", after_group_name);
2440       return(AD_INVALID_NAME);
2441     }
2442
2443   if (Exchange) 
2444     {
2445       if(atoi(maillist)) 
2446         {
2447           group_count = 0;
2448           group_base = NULL;
2449           
2450           sprintf(filter, "(&(objectClass=user)(cn=%s))", after_group_name);
2451           attr_array[0] = "cn";
2452           attr_array[1] = NULL;
2453
2454           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
2455                                    &group_base, &group_count,
2456                                    LDAP_SCOPE_SUBTREE)) != 0)
2457           {
2458             com_err(whoami, 0, "Unable to process group %s : %s",
2459                     after_group_name, ldap_err2string(rc));
2460             return(rc);
2461           }
2462           
2463           if (group_count)
2464             {
2465               com_err(whoami, 0, "Object already exists with name %s",
2466                       after_group_name);
2467               MailDisabled++;
2468             }
2469         
2470           linklist_free(group_base);
2471           group_base = NULL;
2472           group_count = 0;
2473         }
2474     }
2475
2476   group_count = 0;
2477   group_base = NULL;
2478
2479   if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, 
2480                         before_group_membership, 
2481                         MoiraId, "samAccountName", &group_base, 
2482                         &group_count, filter))
2483     return(rc);
2484
2485   if (group_count == 0)
2486     {
2487       return(AD_NO_GROUPS_FOUND);
2488     }
2489
2490   if (group_count != 1)
2491     {
2492       com_err(whoami, 0, "Unable to process multiple groups with "
2493               "MoiraId = %s exist in the directory", MoiraId);
2494       return(AD_MULTIPLE_GROUPS_FOUND);
2495     }
2496
2497   strcpy(old_dn, group_base->dn);
2498
2499   linklist_free(group_base);
2500   group_base = NULL;
2501   group_count = 0;
2502   attr_array[0] = "sAMAccountName";
2503   attr_array[1] = NULL;
2504
2505   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
2506                            &group_base, &group_count, 
2507                            LDAP_SCOPE_SUBTREE)) != 0)
2508     {
2509       com_err(whoami, 0, "Unable to get list %s dn : %s",
2510               after_group_name, ldap_err2string(rc));
2511       return(rc);
2512     }
2513
2514   if (group_count != 1)
2515     {
2516       com_err(whoami, 0,
2517               "Unable to get sAMAccountName for group %s", 
2518               before_group_name);
2519       return(AD_LDAP_FAILURE);
2520     }
2521   
2522   strcpy(sam_name, group_base->value);
2523   linklist_free(group_base);
2524   group_base = NULL;
2525   group_count = 0;
2526   
2527   sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path);
2528   sprintf(new_dn, "cn=%s", after_group_name);
2529   sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain));
2530   sprintf(contact_mail, "%s@mit.edu", after_group_name); 
2531   sprintf(proxy_address, "SMTP:%s@%s", after_group_name, 
2532           lowercase(ldap_domain));
2533   sprintf(mail_nickname, "%s", after_group_name);
2534
2535   com_err(whoami, 0, "Old %s New %s,%s", old_dn, new_dn, new_dn_path);
2536
2537   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path,
2538                               TRUE, NULL, NULL)) != LDAP_SUCCESS)
2539     {
2540       com_err(whoami, 0, "Unable to rename list from %s to %s : %s",
2541               before_group_name, after_group_name, ldap_err2string(rc));
2542       return(rc);
2543     }
2544   
2545   name_v[0] = after_group_name;
2546
2547   if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], 
2548                group_suffix, strlen(group_suffix)))
2549     {
2550       sprintf(sam_name, "%s%s", after_group_name, group_suffix);
2551     }
2552   else
2553     {
2554       com_err(whoami, 0, 
2555               "Unable to rename list from %s to %s : sAMAccountName not found",
2556               before_group_name, after_group_name);
2557       return(rc);
2558     }
2559
2560   samAccountName_v[0] = sam_name;
2561
2562   if (after_security_flag)
2563     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2564
2565   sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2566   groupTypeControl_v[0] = groupTypeControlStr;
2567   mitMoiraId_v[0] = MoiraId;
2568
2569   sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
2570   rc = attribute_update(ldap_handle, new_dn, after_desc, "description", 
2571                         after_group_name);
2572   n = 0;
2573   ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE);
2574   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
2575   ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2576   ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE);
2577
2578   if (Exchange)
2579     {
2580       if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) 
2581         {
2582           mail_nickname_v[0] = mail_nickname;
2583           proxy_address_v[0] = proxy_address;
2584           mail_v[0] = mail;
2585           report_to_originator_v[0] = "TRUE";
2586
2587           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2588           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2589           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2590           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2591                    LDAP_MOD_REPLACE);
2592         } 
2593       else 
2594         {
2595           mail_nickname_v[0] = NULL;
2596           proxy_address_v[0] = NULL;
2597           mail_v[0] = NULL;
2598           legacy_exchange_dn_v[0] = NULL;
2599           address_book_v[0] = NULL;
2600           report_to_originator_v[0] = NULL;
2601
2602           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2603           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2604           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2605           ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE);
2606           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2607           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2608                    LDAP_MOD_REPLACE);
2609         }
2610     }
2611   else
2612     {
2613       if(atoi(maillist) && email_isvalid(contact_mail)) 
2614         {
2615           mail_v[0] = contact_mail;
2616           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2617
2618           if(!ActiveDirectory)
2619             {
2620               null_v[0] = "/dev/null";
2621               ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2622             }
2623         }
2624     }
2625
2626   mods[n] = NULL;
2627
2628   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
2629     {
2630       com_err(whoami, 0, 
2631               "Unable to modify list data for %s after renaming: %s",
2632               after_group_name, ldap_err2string(rc));
2633     }
2634
2635   for (i = 0; i < n; i++)
2636     free(mods[i]);
2637
2638   return(rc);
2639 }
2640
2641 int group_create(int ac, char **av, void *ptr)
2642 {
2643   LDAPMod *mods[20];
2644   char new_dn[256];
2645   char group_ou[256];
2646   char new_group_name[256];
2647   char sam_group_name[256];
2648   char cn_group_name[256];
2649   char mail[256];
2650   char contact_mail[256];
2651   char mail_nickname[256];
2652   char proxy_address[256];
2653   char address_book[256];
2654   char *cn_v[] = {NULL, NULL};
2655   char *objectClass_v[] = {"top", "group", NULL};
2656   char *objectClass_ldap_v[] = {"top", "microsoftComTop", "securityPrincipal",
2657                                 "group", "mailRecipient", NULL};
2658   char info[256];
2659   char *samAccountName_v[] = {NULL, NULL};
2660   char *altSecurityIdentities_v[] = {NULL, NULL};
2661   char *member_v[] = {NULL, NULL};
2662   char *name_v[] = {NULL, NULL};
2663   char *desc_v[] = {NULL, NULL};
2664   char *info_v[] = {NULL, NULL};
2665   char *mitMoiraId_v[] = {NULL, NULL};
2666   char *mitMoiraPublic_v[] = {NULL, NULL};
2667   char *mitMoiraHidden_v[] = {NULL, NULL};
2668   char *groupTypeControl_v[] = {NULL, NULL};
2669   char *mail_v[] = {NULL, NULL};
2670   char *proxy_address_v[] = {NULL, NULL};
2671   char *mail_nickname_v[] = {NULL, NULL};
2672   char *report_to_originator_v[] = {NULL, NULL};
2673   char *address_book_v[] = {NULL, NULL};
2674   char *legacy_exchange_dn_v[] = {NULL, NULL};
2675   char *gidNumber_v[] = {NULL, NULL};
2676   char *null_v[] = {NULL, NULL};
2677   char groupTypeControlStr[80];
2678   char group_membership[1];
2679   int  i;
2680   int  security_flag;
2681   u_int groupTypeControl;
2682   int  n;
2683   int  rc;
2684   int  updateGroup;
2685   int  MailDisabled = 0;
2686   char **call_args;
2687   LK_ENTRY *group_base;
2688   int  group_count;
2689   char filter[1024];
2690   char *attr_array[3];
2691   
2692   call_args = ptr;
2693
2694   if(UseGroupUniversal)
2695     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2696   else 
2697     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2698
2699   if (!check_string(av[L_NAME]))
2700     {
2701       com_err(whoami, 0, "Unable to process invalid LDAP list name %s", 
2702               av[L_NAME]);
2703       return(AD_INVALID_NAME);
2704     }
2705
2706   updateGroup = (int)call_args[4];
2707   memset(group_ou, 0, sizeof(group_ou));
2708   memset(group_membership, 0, sizeof(group_membership));
2709   security_flag = 0;
2710
2711   get_group_membership(group_membership, group_ou, &security_flag, av);
2712
2713   strcpy(new_group_name, av[L_NAME]);
2714   sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
2715   sprintf(contact_mail, "%s@mit.edu", av[L_NAME]);
2716   sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain));
2717   sprintf(mail_nickname, "%s", av[L_NAME]);
2718
2719   if (security_flag)
2720     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2721   
2722   sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix);
2723
2724   if (!updateGroup)
2725     {
2726       sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2727       groupTypeControl_v[0] = groupTypeControlStr;
2728
2729       strcpy(cn_group_name, av[L_NAME]);
2730       
2731       samAccountName_v[0] = sam_group_name;
2732       name_v[0] = new_group_name;
2733       cn_v[0] = new_group_name;
2734
2735       n = 0;
2736       ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
2737
2738       if(ActiveDirectory)
2739         {
2740           ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
2741         } 
2742       else
2743         {
2744           mitMoiraPublic_v[0] = av[L_PUBLIC];
2745           mitMoiraHidden_v[0] = av[L_HIDDEN];
2746           ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
2747           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_ADD);
2748           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_ADD);
2749           
2750           if(atoi(av[L_GROUP])) 
2751             {
2752               gidNumber_v[0] = av[L_GID];
2753               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_ADD);
2754             }
2755         }
2756
2757       ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
2758       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
2759       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
2760
2761       if (Exchange)
2762         {
2763           if(atoi(av[L_MAILLIST])) 
2764             {
2765               group_count = 0;
2766               group_base = NULL;
2767               
2768               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2769               attr_array[0] = "cn";
2770               attr_array[1] = NULL;
2771               
2772               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2773                                        filter, attr_array, &group_base, 
2774                                        &group_count,
2775                                        LDAP_SCOPE_SUBTREE)) != 0)
2776                 {
2777                   com_err(whoami, 0, "Unable to process group %s : %s",
2778                           av[L_NAME], ldap_err2string(rc));
2779                   return(rc);
2780                 }
2781               
2782               if (group_count)
2783                 {
2784                   com_err(whoami, 0, "Object already exists with name %s",
2785                           av[L_NAME]);
2786                   MailDisabled++;
2787                 }
2788         
2789               linklist_free(group_base);
2790               group_base = NULL;
2791               group_count = 0;
2792             }
2793           
2794           if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2795             {
2796               mail_nickname_v[0] = mail_nickname;
2797               report_to_originator_v[0] = "TRUE";
2798
2799               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
2800               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2801                        LDAP_MOD_ADD);
2802             }
2803         }
2804       else
2805         {
2806           if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2807             {
2808               mail_v[0] = contact_mail;
2809               ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
2810
2811               if(!ActiveDirectory)
2812                 {
2813                   null_v[0] = "/dev/null";
2814                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_ADD);
2815                 }
2816             }
2817         }
2818       
2819       if (strlen(av[L_DESC]) != 0)
2820         {
2821           desc_v[0] = av[L_DESC];
2822           ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
2823         }
2824       
2825       ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
2826
2827       if (strlen(av[L_ACE_NAME]) != 0)
2828         {
2829           sprintf(info, "The Administrator of this list is: %s", 
2830                   av[L_ACE_NAME]);
2831           info_v[0] = info;
2832           ADD_ATTR("info", info_v, LDAP_MOD_ADD);
2833         }
2834
2835       if (strlen(call_args[5]) != 0)
2836         {
2837           mitMoiraId_v[0] = call_args[5];
2838           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD);
2839         }
2840           
2841       mods[n] = NULL;
2842       
2843       rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
2844       
2845       for (i = 0; i < n; i++)
2846         free(mods[i]);
2847
2848       if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
2849         {
2850           com_err(whoami, 0, "Unable to create list %s in directory : %s",
2851                   av[L_NAME], ldap_err2string(rc));
2852           callback_rc = rc;
2853           return(rc);
2854         }
2855     }
2856
2857   if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup))
2858     {
2859       rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], 
2860                             "description", av[L_NAME]);
2861       sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]);
2862
2863       rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", 
2864                                 av[L_NAME]);
2865
2866       n = 0;
2867
2868       if (strlen(call_args[5]) != 0)
2869         {
2870           mitMoiraId_v[0] = call_args[5];
2871           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2872         }
2873
2874       if (!(atoi(av[L_ACTIVE])))
2875         {
2876           member_v[0] = NULL;
2877           ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
2878         }
2879    
2880       if (!ActiveDirectory) 
2881         {
2882           mitMoiraPublic_v[0] = av[L_PUBLIC];
2883           mitMoiraHidden_v[0] = av[L_HIDDEN];
2884           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_REPLACE);
2885           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_REPLACE);
2886
2887           if(atoi(av[L_GROUP])) 
2888             {
2889               gidNumber_v[0] = av[L_GID];
2890               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2891             }
2892           else
2893             {
2894               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2895             }
2896         }
2897
2898       if (Exchange)
2899         {
2900           if(atoi(av[L_MAILLIST])) 
2901             {
2902               group_count = 0;
2903               group_base = NULL;
2904               
2905               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2906               attr_array[0] = "cn";
2907               attr_array[1] = NULL;
2908               
2909               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2910                                        filter, attr_array, &group_base, 
2911                                        &group_count,
2912                                        LDAP_SCOPE_SUBTREE)) != 0)
2913                 {
2914                   com_err(whoami, 0, "Unable to process group %s : %s",
2915                           av[L_NAME], ldap_err2string(rc));
2916                   return(rc);
2917                 }
2918               
2919               if (group_count)
2920                 {
2921                   com_err(whoami, 0, "Object already exists with name %s",
2922                           av[L_NAME]);
2923                   MailDisabled++;
2924                 }
2925               
2926               linklist_free(group_base);
2927               group_base = NULL;
2928               group_count = 0;
2929             }
2930
2931           if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2932             {
2933               mail_nickname_v[0] = mail_nickname;
2934               report_to_originator_v[0] = "TRUE";
2935
2936               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2937               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2938                        LDAP_MOD_REPLACE);
2939             }
2940           else 
2941             {
2942               mail_v[0] = NULL;
2943               mail_nickname_v[0] = NULL;
2944               proxy_address_v[0] = NULL;
2945               legacy_exchange_dn_v[0] = NULL;
2946               address_book_v[0] = NULL;
2947               report_to_originator_v[0] = NULL;
2948
2949               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2950               ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2951               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2952               ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, 
2953                        LDAP_MOD_REPLACE);
2954               ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2955               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2956                        LDAP_MOD_REPLACE);
2957             }
2958         }
2959       else
2960         {
2961           if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2962             {
2963               mail_v[0] = contact_mail;
2964               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2965
2966               if(!ActiveDirectory)
2967                 {
2968                   null_v[0] = "/dev/null";
2969                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2970                 }
2971             }
2972           else
2973             {
2974               mail_v[0] = NULL;
2975               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2976
2977               if(!ActiveDirectory)
2978                 {
2979                   null_v[0] = NULL;
2980                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2981                 }
2982             }
2983         }
2984    
2985       mods[n] = NULL;
2986       rc = LDAP_SUCCESS;
2987
2988       if (n != 0)
2989         {
2990           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
2991
2992           for (i = 0; i < n; i++)
2993               free(mods[i]);
2994
2995           if (rc != LDAP_SUCCESS)
2996             {
2997               com_err(whoami, 0, "Unable to update list %s in directory : %s",
2998                       av[L_NAME], ldap_err2string(rc));
2999               callback_rc = rc;
3000               return(rc);
3001             }
3002         }
3003     }
3004
3005   ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], 
3006                        atoi(av[L_HIDDEN]),  av[L_ACE_TYPE], av[L_ACE_NAME]);
3007
3008   return(LDAP_SUCCESS);
3009 }
3010
3011 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
3012                          char *TargetGroupName, int HiddenGroup, 
3013                          char *AceType, char *AceName)
3014 {
3015   char          filter_exp[1024];
3016   char          *attr_array[5];
3017   char          search_path[512];
3018   char          root_ou[128];
3019   char          TemplateDn[512];
3020   char          TemplateSamName[128];
3021   char          TargetDn[512];
3022   char          TargetSamName[128];
3023   char          AceSamAccountName[128];
3024   char          AceDn[256];
3025   unsigned char AceSid[128];
3026   unsigned char UserTemplateSid[128];
3027   char          acBERBuf[N_SD_BER_BYTES];
3028   char          GroupSecurityTemplate[256];
3029   char          hide_addres_lists[256];
3030   char          address_book[256];
3031   char          *hide_address_lists_v[] = {NULL, NULL};
3032   char          *address_book_v[] = {NULL, NULL};
3033   char          *owner_v[] = {NULL, NULL};
3034   int           AceSidCount;
3035   int           UserTemplateSidCount;
3036   int           group_count;
3037   int           n;
3038   int           i;
3039   int           rc;
3040   int           nVal;
3041   ULONG         dwInfo;
3042   int           array_count = 0;
3043   LDAPMod       *mods[20];
3044   LK_ENTRY      *group_base;
3045   LDAP_BERVAL   **ppsValues;
3046   LDAPControl sControl = {"1.2.840.113556.1.4.801",
3047                           { N_SD_BER_BYTES, acBERBuf },
3048                           TRUE
3049                          };
3050   LDAPControl *apsServerControls[] = {&sControl, NULL};
3051   LDAPMessage *psMsg;
3052
3053   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
3054     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
3055   BEREncodeSecurityBits(dwInfo, acBERBuf);
3056
3057   sprintf(search_path, "%s,%s", group_ou_root, dn_path);
3058   sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix);
3059   attr_array[0] = "sAMAccountName";
3060   attr_array[1] = NULL;
3061   group_count = 0;
3062   group_base = NULL;
3063
3064   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3065                            &group_base, &group_count, 
3066                            LDAP_SCOPE_SUBTREE) != 0))
3067     return(1);
3068
3069   if (group_count != 1)
3070     {
3071       linklist_free(group_base);
3072       return(1);
3073     }
3074
3075   strcpy(TargetDn, group_base->dn);
3076   strcpy(TargetSamName, group_base->value);
3077   linklist_free(group_base);
3078   group_base = NULL;
3079   group_count = 0;
3080
3081   UserTemplateSidCount = 0;
3082   memset(UserTemplateSid, '\0', sizeof(UserTemplateSid));
3083   memset(AceSamAccountName, '\0', sizeof(AceSamAccountName));
3084   memset(AceSid, '\0', sizeof(AceSid));
3085   AceSidCount = 0;
3086   group_base = NULL;
3087   group_count = 0;
3088
3089   if (strlen(AceName) != 0)
3090     {
3091       if (!strcmp(AceType, "LIST"))
3092         {
3093           sprintf(AceSamAccountName, "%s%s", AceName, group_suffix);
3094           strcpy(root_ou, group_ou_root);
3095         }
3096       else if (!strcmp(AceType, "USER"))
3097         {
3098           sprintf(AceSamAccountName, "%s", AceName);
3099           strcpy(root_ou, user_ou);
3100         }
3101
3102       if (ActiveDirectory)
3103         {
3104           if (strlen(AceSamAccountName) != 0)
3105             {
3106               sprintf(search_path, "%s", dn_path);
3107               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3108               attr_array[0] = "objectSid";
3109               attr_array[1] = NULL;
3110               group_count = 0;
3111               group_base = NULL;
3112               
3113               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3114                                        attr_array, &group_base, &group_count, 
3115                                        LDAP_SCOPE_SUBTREE) != 0))
3116                 return(1);
3117               if (group_count == 1)
3118                 {
3119                   strcpy(AceDn, group_base->dn);
3120                   AceSidCount = group_base->length;
3121                   memcpy(AceSid, group_base->value, AceSidCount);
3122                 }
3123               linklist_free(group_base);
3124               group_base = NULL;
3125               group_count = 0;
3126             }
3127         }
3128       else
3129         {
3130           if (strlen(AceSamAccountName) != 0)
3131             {
3132               sprintf(search_path, "%s", dn_path);
3133               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3134               attr_array[0] = "samAccountName";
3135               attr_array[1] = NULL;
3136               group_count = 0;
3137               group_base = NULL;
3138               
3139               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3140                                        attr_array, &group_base, &group_count, 
3141                                        LDAP_SCOPE_SUBTREE) != 0))
3142                 return(1);
3143               if (group_count == 1)
3144                 {
3145                   strcpy(AceDn, group_base->dn);
3146                 }
3147               linklist_free(group_base);
3148               group_base = NULL;
3149               group_count = 0;
3150             }
3151         }
3152     }
3153
3154   if (!ActiveDirectory) 
3155     {
3156       if (strlen(AceDn) != 0) 
3157         {
3158           owner_v[0] = strdup(AceDn);
3159           n = 0;
3160           ADD_ATTR("owner", owner_v, LDAP_MOD_REPLACE);
3161
3162           mods[n] = NULL;
3163
3164           rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3165           
3166           for (i = 0; i < n; i++)
3167             free(mods[i]);
3168
3169           if (rc != LDAP_SUCCESS)
3170             com_err(whoami, 0, "Unable to set owner for group %s : %s",
3171               TargetGroupName, ldap_err2string(rc));
3172         }
3173
3174       return(rc);
3175     }
3176   
3177   if (AceSidCount == 0)
3178     {
3179       com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not "
3180               "have a directory SID.", TargetGroupName, AceName, AceType);
3181       com_err(whoami, 0, "   Non-admin security group template will be used.");
3182     }
3183   else
3184     {
3185       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3186       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
3187       attr_array[0] = "objectSid";
3188       attr_array[1] = NULL;
3189
3190       group_count = 0;
3191       group_base = NULL;
3192
3193       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3194                                attr_array, &group_base, &group_count, 
3195                                LDAP_SCOPE_SUBTREE) != 0))
3196         return(1);
3197
3198       if ((rc != 0) || (group_count != 1))
3199         {
3200           com_err(whoami, 0, "Unable to process user security template: %s", 
3201                   "UserTemplate");
3202           AceSidCount = 0;
3203         }
3204       else
3205         {
3206           UserTemplateSidCount = group_base->length;
3207           memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount);
3208         }
3209       linklist_free(group_base);
3210       group_base = NULL;
3211       group_count = 0;
3212     }
3213
3214   if (HiddenGroup)
3215     {
3216       if (AceSidCount == 0)
3217         {
3218           strcpy(GroupSecurityTemplate, HIDDEN_GROUP);
3219           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP);
3220         }
3221       else
3222         {
3223           strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN);
3224           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN);
3225         }
3226     }
3227   else
3228     {
3229       if (AceSidCount == 0)
3230         {
3231           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP);
3232           sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP);
3233         }
3234       else
3235         {
3236           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN);
3237           sprintf(filter_exp, "(sAMAccountName=%s)", 
3238                   NOT_HIDDEN_GROUP_WITH_ADMIN);
3239         }
3240     }
3241
3242   sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3243   attr_array[0] = "sAMAccountName";
3244   attr_array[1] = NULL;
3245   group_count = 0;
3246   group_base = NULL;
3247
3248   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3249                            &group_base, &group_count, 
3250                            LDAP_SCOPE_SUBTREE) != 0))
3251     return(1);
3252
3253   if (group_count != 1)
3254     {
3255       linklist_free(group_base);
3256       com_err(whoami, 0, "Unable to process group security template: %s - "
3257               "security not set", GroupSecurityTemplate);
3258       return(1);
3259     }
3260
3261   strcpy(TemplateDn, group_base->dn);
3262   strcpy(TemplateSamName, group_base->value);
3263   linklist_free(group_base);
3264   group_base = NULL;
3265   group_count = 0;
3266   
3267   sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName);
3268   rc = ldap_search_ext_s(ldap_handle,
3269                          TemplateDn,
3270                          LDAP_SCOPE_SUBTREE,
3271                          filter_exp,
3272                          NULL,
3273                          0,
3274                          apsServerControls,
3275                          NULL,
3276                          NULL,
3277                          0,
3278                          &psMsg);
3279
3280   if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
3281     {
3282       com_err(whoami, 0, "Unable to find group security template: %s - "
3283               "security not set", GroupSecurityTemplate);
3284       return(1);
3285     }
3286
3287   ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
3288
3289   if (ppsValues == NULL)
3290     {
3291       com_err(whoami, 0, "Unable to find group security descriptor for group "
3292               "%s - security not set", GroupSecurityTemplate);
3293       return(1);
3294     }
3295   
3296   if (AceSidCount != 0)
3297     {
3298       for (nVal = 0; ppsValues[nVal] != NULL; nVal++)
3299         {
3300           for (i = 0; 
3301                i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++)
3302             {
3303               if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, 
3304                           UserTemplateSidCount))
3305                 {
3306                   memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount);
3307                   break;
3308                 }
3309             }
3310         }
3311     }
3312
3313   n = 0;
3314   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, 
3315            LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
3316
3317   if (Exchange)
3318     {
3319       if(HiddenGroup) 
3320         {
3321           hide_address_lists_v[0] = "TRUE";
3322           address_book_v[0] = NULL;
3323           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3324                    LDAP_MOD_REPLACE);
3325           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
3326         } else {
3327           hide_address_lists_v[0] = NULL;
3328           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3329                    LDAP_MOD_REPLACE);
3330         }
3331     }
3332
3333   mods[n] = NULL;
3334
3335   rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3336
3337   for (i = 0; i < n; i++)
3338     free(mods[i]);
3339
3340   ldap_value_free_len(ppsValues);
3341   ldap_msgfree(psMsg);
3342
3343   if (rc != LDAP_SUCCESS)
3344     {
3345       com_err(whoami, 0, "Unable to set security settings for group %s : %s",
3346               TargetGroupName, ldap_err2string(rc));
3347
3348       if (AceSidCount != 0)
3349         {
3350           com_err(whoami, 0, 
3351                   "Trying to set security for group %s without admin.",
3352                   TargetGroupName);
3353
3354           if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, 
3355                                         HiddenGroup, "", ""))
3356             {
3357               com_err(whoami, 0, "Unable to set security for group %s.",
3358                       TargetGroupName);
3359               return(rc);
3360             }
3361         }
3362       return(rc);
3363     }
3364
3365   return(rc);
3366 }
3367
3368 int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, 
3369                  char *group_membership, char *MoiraId)
3370 {
3371   LK_ENTRY  *group_base;
3372   char      temp[512];
3373   char      filter[128];
3374   int       group_count;
3375   int       rc;
3376
3377   if (!check_string(group_name))
3378     {
3379       com_err(whoami, 0, 
3380               "Unable to process invalid LDAP list name %s", group_name);
3381       return(AD_INVALID_NAME);
3382     }
3383
3384   memset(filter, '\0', sizeof(filter));
3385   group_count = 0;
3386   group_base = NULL;
3387   sprintf(temp, "%s,%s", group_ou_root, dn_path);
3388
3389   if (rc = ad_get_group(ldap_handle, temp, group_name, 
3390                         group_membership, MoiraId, 
3391                         "samAccountName", &group_base, 
3392                         &group_count, filter))
3393     return(rc);
3394
3395   if (group_count == 1)
3396     {
3397       if ((rc = ldap_delete_s(ldap_handle, group_base->dn)) != LDAP_SUCCESS)
3398         {
3399           linklist_free(group_base);
3400           com_err(whoami, 0, "Unable to delete list %s from directory : %s",
3401                   group_name, ldap_err2string(rc));
3402           return(rc);
3403         }
3404       linklist_free(group_base);
3405     }
3406   else
3407     {
3408       linklist_free(group_base);
3409       com_err(whoami, 0, "Unable to find list %s in directory.", group_name);
3410       return(AD_NO_GROUPS_FOUND);
3411     }
3412   
3413   return(0);
3414 }
3415
3416 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer)
3417 {
3418     *pBuffer++ = 0x30;
3419     *pBuffer++ = 0x03;
3420     *pBuffer++ = 0x02;
3421     *pBuffer++ = 0x00;
3422     return(N_SD_BER_BYTES);
3423 }
3424
3425 int process_lists(int ac, char **av, void *ptr)
3426 {
3427   int   rc;
3428   int   security_flag;
3429   char  group_ou[256];
3430   char  group_membership[2];
3431   char  **call_args;
3432
3433   call_args = ptr;
3434
3435   security_flag = 0;
3436   memset(group_ou, '\0', sizeof(group_ou));
3437   memset(group_membership, '\0', sizeof(group_membership));
3438   get_group_membership(group_membership, group_ou, &security_flag, av);
3439   rc = populate_group((LDAP *)call_args[0], (char *)call_args[1], 
3440                       av[L_NAME], group_ou, group_membership, 
3441                       security_flag, "");
3442
3443   return(0);
3444 }
3445
3446 int member_list_build(int ac, char **av, void *ptr)
3447 {
3448   LK_ENTRY  *linklist;
3449   char      temp[1024];
3450   char      **call_args;
3451   char      *s;
3452   call_args = ptr;
3453
3454   strcpy(temp, av[ACE_NAME]);
3455   StringTrim(temp);
3456   
3457   if (!check_string(temp))
3458     return(0);
3459
3460   if (!strcmp(av[ACE_TYPE], "USER"))
3461     {
3462       if (!((int)call_args[3] & MOIRA_USERS))
3463         return(0);
3464     }
3465   else if (!strcmp(av[ACE_TYPE], "STRING"))
3466     {
3467       if (Exchange)
3468         {
3469           if((s = strchr(temp, '@')) == (char *) NULL) 
3470             {
3471               strcat(temp, "@mit.edu");
3472             }
3473           
3474           if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6))
3475             {
3476               s = strrchr(temp, '.');
3477               *s = '\0';
3478               strcat(s, ".mit.edu");
3479             }
3480         }
3481
3482       if (!((int)call_args[3] & MOIRA_STRINGS))
3483         return(0);
3484         
3485       if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou))
3486         return(0);
3487     }
3488   else if (!strcmp(av[ACE_TYPE], "LIST"))
3489     {
3490       if (!((int)call_args[3] & MOIRA_LISTS))
3491         return(0);
3492     }
3493   else if (!strcmp(av[ACE_TYPE], "KERBEROS"))
3494     {
3495       if (!((int)call_args[3] & MOIRA_KERBEROS))
3496         return(0);
3497
3498       if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
3499                          kerberos_ou))
3500         return(0);
3501
3502     }
3503   else if (!strcmp(av[ACE_TYPE], "MACHINE"))
3504     {
3505       if (!((int)call_args[3] & MOIRA_MACHINE))
3506         return(0);
3507     }
3508   else
3509     return(0);
3510
3511   linklist = member_base;
3512
3513   while (linklist)
3514     {
3515     if (!strcasecmp(temp, linklist->member) &&
3516         !strcasecmp(av[ACE_TYPE], linklist->type))
3517       return(0);
3518
3519     linklist = linklist->next;
3520     }
3521
3522   linklist = calloc(1, sizeof(LK_ENTRY));
3523   linklist->op = 1;
3524   linklist->dn = NULL;
3525   linklist->list = calloc(1, strlen(call_args[2]) + 1);
3526   strcpy(linklist->list, call_args[2]);
3527   linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1);
3528   strcpy(linklist->type, av[ACE_TYPE]);
3529   linklist->member = calloc(1, strlen(temp) + 1);
3530   strcpy(linklist->member, temp);
3531   linklist->next = member_base;
3532   member_base = linklist;
3533
3534   return(0);
3535 }
3536
3537 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
3538                   char *group_ou, char *group_membership, char *user_name,
3539                   char *UserOu, char *MoiraId)
3540 {
3541   char        distinguished_name[1024];
3542   char        *modvalues[2];
3543   char        temp[256];
3544   char        filter[128];
3545   char        *attr_array[3];
3546   int         group_count;
3547   int         i;
3548   int         n;
3549   LDAPMod     *mods[20];
3550   LK_ENTRY    *group_base;
3551   ULONG       rc;
3552   char        *s;
3553
3554   if (!check_string(group_name))
3555     return(AD_INVALID_NAME);
3556
3557   memset(filter, '\0', sizeof(filter));
3558   group_base = NULL;
3559   group_count = 0;
3560
3561   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3562                         group_membership, MoiraId, 
3563                         "samAccountName", &group_base, 
3564                         &group_count, filter))
3565     return(rc);
3566
3567   if (group_count != 1)
3568     {
3569       com_err(whoami, 0, "Unable to find list %s in directory",
3570               group_name);
3571       linklist_free(group_base);
3572       group_base = NULL;
3573       group_count = 0;
3574       goto cleanup;
3575     }
3576
3577   strcpy(distinguished_name, group_base->dn);
3578   linklist_free(group_base);
3579   group_base = NULL;
3580   group_count = 0;
3581
3582   if(ActiveDirectory)
3583     {
3584       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3585     }
3586   else
3587     {
3588       if(!strcmp(UserOu, user_ou))
3589         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3590       else
3591         sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3592     }
3593
3594   modvalues[0] = temp;
3595   modvalues[1] = NULL;
3596
3597   n = 0;
3598   ADD_ATTR("member", modvalues, LDAP_MOD_DELETE);
3599   mods[n] = NULL;
3600   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3601
3602   for (i = 0; i < n; i++)
3603     free(mods[i]);
3604
3605   if (rc == LDAP_UNWILLING_TO_PERFORM)
3606     rc = LDAP_SUCCESS;
3607
3608   if (rc != LDAP_SUCCESS)
3609     {
3610       com_err(whoami, 0, "Unable to modify list %s members : %s",
3611               group_name, ldap_err2string(rc));
3612       goto cleanup;
3613     }
3614
3615   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) 
3616     {
3617       if (Exchange)
3618         {
3619           if(!strcmp(UserOu, contact_ou) && 
3620              ((s = strstr(user_name, "@mit.edu")) != (char *) NULL))
3621             {
3622               memset(temp, '\0', sizeof(temp));
3623               strcpy(temp, user_name);
3624               s = strchr(temp, '@');
3625               *s = '\0';
3626               
3627               sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp);
3628           
3629               if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL,
3630                                        &group_base, &group_count, 
3631                                        LDAP_SCOPE_SUBTREE) != 0))
3632                 return(rc);       
3633               
3634               if(group_count)
3635                 goto cleanup;
3636               
3637               linklist_free(group_base);
3638               group_base = NULL;
3639               group_count = 0;
3640             }
3641           
3642           sprintf(filter, "(distinguishedName=%s)", temp);
3643           attr_array[0] = "memberOf";
3644           attr_array[1] = NULL;
3645           
3646           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
3647                                    &group_base, &group_count, 
3648                                    LDAP_SCOPE_SUBTREE) != 0))
3649             return(rc);
3650           
3651
3652           if(!group_count) 
3653             {
3654               com_err(whoami, 0, "Removing unreferenced object %s", temp);
3655           
3656               if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) 
3657                 return(rc);
3658             }
3659         }
3660     }
3661
3662  cleanup:
3663   return(rc);
3664 }
3665
3666 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
3667                char *group_ou, char *group_membership, char *user_name, 
3668                char *UserOu, char *MoiraId)
3669 {
3670   char        distinguished_name[1024];
3671   char        *modvalues[2];
3672   char        temp[256];
3673   char        filter[128];
3674   int         group_count;
3675   int         n;
3676   int         i;
3677   LDAPMod     *mods[20];
3678   LK_ENTRY    *group_base;
3679   ULONG       rc;
3680
3681   if (!check_string(group_name))
3682     return(AD_INVALID_NAME);
3683
3684   rc = 0;
3685   memset(filter, '\0', sizeof(filter));
3686   group_base = NULL;
3687   group_count = 0;
3688
3689   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3690                         group_membership, MoiraId, 
3691                         "samAccountName", &group_base, 
3692                         &group_count, filter))
3693     return(rc);
3694
3695   if (group_count != 1)
3696     {
3697       linklist_free(group_base);
3698       group_base = NULL;
3699       group_count = 0;
3700       com_err(whoami, 0, "Unable to find list %s %d in directory",
3701               group_name, group_count);
3702       return(AD_MULTIPLE_GROUPS_FOUND);
3703     }
3704
3705   strcpy(distinguished_name, group_base->dn);
3706   linklist_free(group_base);
3707   group_base = NULL;
3708   group_count = 0;
3709
3710   if(ActiveDirectory)
3711     {
3712       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3713     }
3714   else 
3715     {
3716       if(!strcmp(UserOu, user_ou))
3717         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3718       else
3719         sprintf(temp, "cn=%s,%s,%s", user_name, UserOu, dn_path);
3720     }
3721
3722   modvalues[0] = temp;
3723   modvalues[1] = NULL;
3724
3725   n = 0;
3726   ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
3727   mods[n] = NULL;
3728   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3729
3730   if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
3731     rc = LDAP_SUCCESS;
3732
3733   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou)))
3734     {
3735       if (rc == LDAP_UNWILLING_TO_PERFORM)
3736         rc = LDAP_SUCCESS;
3737     }
3738
3739   for (i = 0; i < n; i++)
3740     free(mods[i]);
3741
3742   if (rc != LDAP_SUCCESS)
3743     {
3744       com_err(whoami, 0, "Unable to add %s to list %s as a member : %s",
3745               user_name, group_name, ldap_err2string(rc));
3746     }
3747
3748   return(rc);
3749 }
3750
3751 int contact_remove_email(LDAP *ld, char *bind_path,
3752                          LK_ENTRY **linklist_base, int linklist_current)
3753 {
3754   LK_ENTRY  *gPtr;
3755   int       rc;
3756   char      *mail_v[] = {NULL, NULL};
3757   LDAPMod   *mods[20];
3758   int n;
3759   int i;
3760
3761   mail_v[0] = NULL;
3762
3763   n = 0;
3764   ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
3765   ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE);
3766   ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE);
3767   ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE);
3768   mods[n] = NULL;
3769
3770   gPtr = (*linklist_base);
3771   
3772   while(gPtr) {
3773     rc = ldap_modify_s(ld, gPtr->dn, mods);
3774     
3775     if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3776       {
3777         com_err(whoami, 0, "Unable to modify contact %s in directory : %s",
3778                 gPtr->dn, ldap_err2string(rc));
3779         return(rc);
3780       }
3781
3782     gPtr = gPtr->next;
3783   }
3784
3785   for (i = 0; i < n; i++)
3786     free(mods[i]);
3787   
3788     return(rc);
3789 }
3790
3791 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
3792 {
3793   LDAPMod *mods[20];
3794   LK_ENTRY  *group_base;
3795   int  group_count;
3796   char new_dn[256];
3797   char cn_user_name[256];
3798   char contact_name[256];
3799   char mail_nickname[256];
3800   char proxy_address_internal[256];
3801   char proxy_address_external[256];
3802   char target_address[256];
3803   char internal_contact_name[256];
3804   char filter[128];
3805   char mail[256];
3806   char principal[256];
3807   char mit_address_book[256];
3808   char default_address_book[256];
3809   char contact_address_book[256];
3810   char uid[256];
3811   char *email_v[] = {NULL, NULL};
3812   char *cn_v[] = {NULL, NULL};
3813   char *contact_v[] = {NULL, NULL};
3814   char *uid_v[] = {NULL, NULL};
3815   char *mail_nickname_v[] = {NULL, NULL};
3816   char *proxy_address_internal_v[] = {NULL, NULL};
3817   char *proxy_address_external_v[] = {NULL, NULL};
3818   char *target_address_v[] = {NULL, NULL};
3819   char *mit_address_book_v[] = {NULL, NULL};
3820   char *default_address_book_v[] = {NULL, NULL};
3821   char *contact_address_book_v[] = {NULL, NULL};
3822   char *hide_address_lists_v[] = {NULL, NULL};
3823   char *attr_array[3];
3824   char *objectClass_v[] = {"top", "person", 
3825                            "organizationalPerson", 
3826                            "contact", NULL};
3827   char *objectClass_ldap_v[] = {"top", "person", "microsoftComTop", 
3828                                 "inetOrgPerson", "organizationalPerson",
3829                                 "contact", "mailRecipient", "eduPerson",
3830                                 NULL};
3831   char *name_v[] = {NULL, NULL};
3832   char *desc_v[] = {NULL, NULL};
3833   char *s;
3834   int  n;
3835   int  rc;
3836   int  i;
3837   char temp[256];
3838   char *c;
3839   char *mail_routing_v[] = {NULL, NULL};
3840   char *principal_v[] = {NULL, NULL};
3841
3842   if (!check_string(user))
3843     {
3844       com_err(whoami, 0, "Unable to process invalid LDAP name %s", user);
3845       return(AD_INVALID_NAME);
3846     }
3847
3848   strcpy(mail, user);
3849   strcpy(contact_name, mail);
3850   strcpy(internal_contact_name, mail);
3851   
3852   if((s = strchr(internal_contact_name, '@')) != NULL) {
3853     *s = '?';
3854   }
3855
3856   sprintf(cn_user_name,"CN=%s,%s,%s", escape_string(contact_name), group_ou, 
3857           bind_path);
3858
3859   sprintf(target_address, "SMTP:%s", contact_name);
3860   sprintf(proxy_address_external, "SMTP:%s", contact_name);
3861   sprintf(mail_nickname, "%s", internal_contact_name);
3862  
3863   cn_v[0] = cn_user_name;
3864   contact_v[0] = contact_name;
3865   uid_v[0] = uid;
3866   name_v[0] = user;
3867   desc_v[0] = "Auto account created by Moira";
3868   email_v[0] = mail;
3869   proxy_address_internal_v[0] = proxy_address_internal;
3870   proxy_address_external_v[0] = proxy_address_external;
3871   mail_nickname_v[0] = mail_nickname;
3872   target_address_v[0] = target_address;
3873   mit_address_book_v[0] = mit_address_book;
3874   default_address_book_v[0] = default_address_book;
3875   contact_address_book_v[0] = contact_address_book;
3876   strcpy(new_dn, cn_user_name);
3877   n = 0;
3878
3879   ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
3880
3881   if(!ActiveDirectory)
3882     {
3883       if(!strcmp(group_ou, contact_ou))
3884         sprintf(uid, "%s%s", contact_name, "_strings");
3885       
3886       if(!strcmp(group_ou, kerberos_ou))
3887         sprintf(uid, "%s%s", contact_name, "_kerberos");
3888
3889       uid_v[0] = uid;
3890
3891       ADD_ATTR("sn", contact_v, LDAP_MOD_ADD);
3892       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
3893     }
3894
3895   if(ActiveDirectory)
3896     {
3897       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
3898     }
3899   else
3900     {
3901       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
3902     }
3903
3904   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
3905   ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
3906   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
3907
3908   if (Exchange)
3909     {
3910       if (!strcmp(group_ou, contact_ou) && email_isvalid(mail))
3911         {
3912           group_count = 0;
3913           group_base = NULL;
3914           
3915           sprintf(filter, "(&(objectClass=user)(cn=%s))", mail);
3916           attr_array[0] = "cn";
3917           attr_array[1] = NULL;
3918
3919           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3920                                    &group_base, &group_count, 
3921                                    LDAP_SCOPE_SUBTREE)) != 0) 
3922             {
3923               com_err(whoami, 0, "Unable to process contact %s : %s", 
3924                       user, ldap_err2string(rc));
3925               return(rc);
3926             }
3927       
3928           if (group_count) 
3929             {
3930               com_err(whoami, 0, "Object already exists with name %s",
3931                       user);
3932               return(1);
3933             }
3934
3935           linklist_free(group_base);
3936           group_base = NULL;
3937           group_count = 0;
3938       
3939           sprintf(filter, "(&(objectClass=group)(cn=%s))", mail);
3940           attr_array[0] = "cn";
3941           attr_array[1] = NULL;
3942
3943           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3944                                    &group_base, &group_count, 
3945                                    LDAP_SCOPE_SUBTREE)) != 0) 
3946             {
3947               com_err(whoami, 0, "Unable to process contact %s : %s", 
3948                       user, ldap_err2string(rc));
3949               return(rc);
3950             }
3951           
3952           if (group_count) 
3953             {
3954               com_err(whoami, 0, "Object already exists with name %s",
3955                       user);
3956               return(1);
3957             }
3958   
3959           linklist_free(group_base);
3960           group_count = 0;
3961           group_base = NULL;
3962           
3963           sprintf(filter, "(&(objectClass=user)(mail=%s))", mail);
3964           attr_array[0] = "cn";
3965           attr_array[1] = NULL;
3966
3967           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3968                                    &group_base, &group_count, 
3969                                    LDAP_SCOPE_SUBTREE)) != 0) 
3970             {
3971               com_err(whoami, 0, "Unable to process contact %s : %s", 
3972                       user, ldap_err2string(rc));
3973               return(rc);
3974             }
3975           
3976           if (group_count) 
3977             {
3978               com_err(whoami, 0, "Object already exists with name %s",
3979                       user);
3980               return(1);
3981             }
3982
3983           linklist_free(group_base);
3984           group_base = NULL;
3985           group_count = 0;
3986
3987           sprintf(filter, "(&(objectClass=group)(mail=%s))", mail);
3988           attr_array[0] = "cn";
3989           attr_array[1] = NULL;
3990
3991           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3992                                    &group_base, &group_count, 
3993                                    LDAP_SCOPE_SUBTREE)) != 0) 
3994             {
3995               com_err(whoami, 0, "Unable to process contact %s : %s", 
3996                       user, ldap_err2string(rc));
3997               return(rc);
3998             }
3999       
4000           if (group_count) 
4001             {
4002               com_err(whoami, 0, "Object already exists with name %s",
4003                       user);
4004               return(1);
4005             }
4006           
4007           linklist_free(group_base);
4008           group_base = NULL;
4009           group_count = 0;
4010           
4011           ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
4012           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
4013           ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD);
4014           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD);
4015           
4016           hide_address_lists_v[0] = "TRUE";
4017           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4018                    LDAP_MOD_ADD);
4019         }
4020     }
4021
4022   if(!ActiveDirectory) 
4023     {
4024       if((c = strchr(mail, '@')) == NULL)
4025           sprintf(temp, "%s@mit.edu", mail);
4026       else
4027           sprintf(temp, "%s", mail);
4028
4029       mail_routing_v[0] = temp;
4030       email_v[0] = temp;
4031       principal_v[0] = principal;
4032
4033       if(!strcmp(group_ou, contact_ou))
4034         {
4035           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4036           ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD);
4037         }
4038     }
4039
4040   mods[n] = NULL;
4041
4042   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4043
4044   for (i = 0; i < n; i++)
4045     free(mods[i]);
4046   
4047   if (Exchange)
4048     {
4049       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
4050           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
4051         {
4052           n = 0;
4053           
4054           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
4055           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
4056           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
4057                    LDAP_MOD_REPLACE);
4058           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
4059
4060           hide_address_lists_v[0] = "TRUE";
4061           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4062                    LDAP_MOD_REPLACE);
4063     
4064           mods[n] = NULL;
4065           rc = ldap_modify_s(ld, new_dn, mods);
4066       
4067           if (rc) 
4068             {
4069               com_err(whoami, 0, "Unable to update contact %s", mail);
4070             }
4071       
4072           for (i = 0; i < n; i++)
4073             free(mods[i]);
4074         }
4075     }
4076
4077   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4078     {
4079       com_err(whoami, 0, "Unable to create contact %s : %s",
4080               user, ldap_err2string(rc));
4081       return(rc);
4082     }
4083
4084   return(0);
4085 }
4086
4087 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
4088                 char *Uid, char *MitId, char *MoiraId, int State,
4089                 char *WinHomeDir, char *WinProfileDir, char *first,
4090                 char *middle, char *last, char *shell, char *class)
4091 {
4092   LDAPMod   *mods[20];
4093   LK_ENTRY  *group_base;
4094   int  group_count;
4095   char distinguished_name[512];
4096   char displayName[256];
4097   char *mitMoiraId_v[] = {NULL, NULL};
4098   char *mitMoiraClass_v[] = {NULL, NULL};
4099   char *mitMoiraStatus_v[] = {NULL, NULL};
4100   char *uid_v[] = {NULL, NULL};
4101   char *mitid_v[] = {NULL, NULL};
4102   char *homedir_v[] = {NULL, NULL};
4103   char *winProfile_v[] = {NULL, NULL};
4104   char *drives_v[] = {NULL, NULL};
4105   char *userAccountControl_v[] = {NULL, NULL};
4106   char *alt_recipient_v[] = {NULL, NULL};
4107   char *hide_address_lists_v[] = {NULL, NULL};
4108   char *mail_v[] = {NULL, NULL};
4109   char *gid_v[] = {NULL, NULL};
4110   char *loginshell_v[] = {NULL, NULL};
4111   char *principal_v[] = {NULL, NULL};
4112   char userAccountControlStr[80];
4113   int  n;
4114   int  rc;
4115   int  i;
4116   int  OldUseSFU30;
4117   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4118     UF_PASSWD_CANT_CHANGE;
4119   char filter[128];
4120   char *attr_array[3];
4121   char temp[1024];
4122   char mail[256];
4123   char contact_mail[256];
4124   char filter_exp[1024];
4125   char search_path[512];
4126   char TemplateDn[512];
4127   char TemplateSamName[128];
4128   char alt_recipient[256];
4129   char principal[256];
4130   char status[256];
4131   char acBERBuf[N_SD_BER_BYTES];
4132   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4133                           { N_SD_BER_BYTES, acBERBuf },
4134                           TRUE};
4135   LDAPControl *apsServerControls[] = {&sControl, NULL};
4136   LDAPMessage *psMsg;
4137   LDAP_BERVAL   **ppsValues;
4138   ULONG dwInfo;
4139   char *argv[3];
4140   char *homeMDB;
4141   char *homeServerName;
4142   char *save_argv[7];
4143   char search_string[256];
4144   char *p, *q;
4145   char *mail_routing_v[] = {NULL, NULL};
4146   char *c;
4147
4148   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4149     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4150   BEREncodeSecurityBits(dwInfo, acBERBuf);
4151
4152   if (!check_string(user_name))
4153     {
4154       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4155               user_name);
4156       return(AD_INVALID_NAME);
4157     }
4158   
4159   memset(contact_mail, '\0', sizeof(contact_mail));
4160   sprintf(contact_mail, "%s@mit.edu", user_name);
4161   memset(mail, '\0', sizeof(mail));
4162   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4163   memset(alt_recipient, '\0', sizeof(alt_recipient));
4164   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4165           dn_path);
4166   sprintf(search_string, "@%s", uppercase(ldap_domain));
4167
4168   if (Exchange)
4169     {
4170       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4171         {
4172           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4173         }
4174     }
4175
4176   group_count = 0;
4177   group_base = NULL;
4178
4179   memset(displayName, '\0', sizeof(displayName));
4180
4181   if (strlen(MoiraId) != 0)
4182     {
4183       if(ActiveDirectory)
4184         {
4185           sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4186         }
4187       else
4188         {
4189           sprintf(filter, 
4190                   "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId);
4191         }
4192
4193       attr_array[0] = "cn";
4194       attr_array[1] = NULL;
4195       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4196                                &group_base, &group_count, 
4197                                LDAP_SCOPE_SUBTREE)) != 0)
4198         {
4199           com_err(whoami, 0, "Unable to process user %s : %s",
4200                   user_name, ldap_err2string(rc));
4201           return(rc);
4202         }
4203     }
4204
4205   if (group_count != 1)
4206     {
4207       linklist_free(group_base);
4208       group_base = NULL;
4209       group_count = 0;
4210       sprintf(filter, "(sAMAccountName=%s)", user_name);
4211       attr_array[0] = "cn";
4212       attr_array[1] = NULL;
4213       sprintf(temp, "%s,%s", user_ou, dn_path);
4214       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
4215                                &group_base, &group_count, 
4216                                LDAP_SCOPE_SUBTREE)) != 0)
4217         {
4218           com_err(whoami, 0, "Unable to process user %s : %s",
4219                   user_name, ldap_err2string(rc));
4220           return(rc);
4221         }
4222     }
4223
4224   if (group_count != 1)
4225     {
4226       com_err(whoami, 0, "Unable to find user %s in directory",
4227               user_name);
4228       linklist_free(group_base);
4229       return(AD_NO_USER_FOUND);
4230     }
4231
4232   strcpy(distinguished_name, group_base->dn);
4233
4234   linklist_free(group_base);
4235   group_count = 0;
4236
4237   if(!ActiveDirectory) 
4238     {
4239       if (rc = moira_connect())
4240         {
4241           critical_alert("Ldap incremental", 
4242                          "Error contacting Moira server : %s",
4243                          error_message(rc));
4244           return;
4245         }
4246   
4247       argv[0] = user_name;
4248       
4249       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4250         {
4251           n = 0;
4252           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
4253           mods[n] = NULL;
4254           rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4255           
4256           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
4257             rc = LDAP_SUCCESS;
4258
4259           if(rc)
4260             com_err(whoami, 0, 
4261                     "Unable to set the mailRoutingAddress for %s : %s",
4262                     user_name, ldap_err2string(rc));
4263           
4264           p = strdup(save_argv[3]);
4265           
4266           if((c = strchr(p, ',')) != NULL) 
4267             {
4268               q = strtok(p, ",");
4269               StringTrim(q);
4270
4271               if ((c = strchr(q, '@')) == NULL)
4272                 sprintf(temp, "%s@mit.edu", q);
4273               else
4274                 sprintf(temp, "%s", q);
4275               
4276               if(email_isvalid(temp) && State != US_DELETED) 
4277                 {
4278                   mail_routing_v[0]  = temp;
4279                   
4280                   n = 0;
4281                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4282                   mods[n] = NULL;
4283                   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4284
4285                   if (rc == LDAP_ALREADY_EXISTS || 
4286                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
4287                     rc = LDAP_SUCCESS;
4288     
4289                   if(rc)
4290                     com_err(whoami, 0, 
4291                             "Unable to set the mailRoutingAddress for %s : %s",
4292                             user_name, ldap_err2string(rc));
4293                 }
4294
4295               while((q = strtok(NULL, ",")) != NULL) {
4296                 StringTrim(q);
4297                 
4298                 if((c = strchr(q, '@')) == NULL) 
4299                   sprintf(temp, "%s@mit.edu", q);
4300                 else
4301                   sprintf(temp, "%s", q);
4302
4303                 if(email_isvalid(temp) && State != US_DELETED) 
4304                   {
4305                     mail_routing_v[0]  = temp;
4306                 
4307                     n = 0;
4308                     ADD_ATTR("mailRoutingAddress", mail_routing_v, 
4309                              LDAP_MOD_ADD);
4310                     mods[n] = NULL;
4311                     rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4312                     
4313                     if (rc == LDAP_ALREADY_EXISTS || 
4314                         rc == LDAP_TYPE_OR_VALUE_EXISTS)
4315                       rc = LDAP_SUCCESS;
4316                     
4317                     if(rc)
4318                       com_err(whoami, 0, 
4319                               "Unable to set the mailRoutingAddress for " 
4320                               "%s : %s",
4321                               user_name, ldap_err2string(rc));
4322                   }
4323               }
4324             } else {
4325               StringTrim(p);
4326
4327             if((c = strchr(p, '@')) == NULL)
4328               sprintf(temp, "%s@mit.edu", p);
4329             else
4330               sprintf(temp, "%s", p);
4331             
4332             if(email_isvalid(temp) && State != US_DELETED) 
4333               {
4334                 mail_routing_v[0]  = temp;
4335                 
4336                 n = 0;
4337                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4338                 mods[n] = NULL;
4339                 rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4340                 
4341                 if (rc == LDAP_ALREADY_EXISTS || 
4342                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
4343                   rc = LDAP_SUCCESS;
4344                 
4345                 if(rc)
4346                   com_err(whoami, 0, 
4347                           "Unable to set the mailRoutingAddress for %s : %s",
4348                           user_name, ldap_err2string(rc));
4349               }
4350             }
4351         }
4352       moira_disconnect();
4353     }
4354
4355   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
4356     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
4357                           "employeeID", user_name);
4358   else
4359     rc = attribute_update(ldap_handle, distinguished_name, "none", 
4360                           "employeeID", user_name);
4361
4362   if(strlen(first)) {
4363     strcat(displayName, first);
4364   }
4365
4366   if(strlen(middle)) {
4367     if(strlen(first)) 
4368       strcat(displayName, " ");
4369
4370     strcat(displayName, middle);
4371   }
4372
4373   if(strlen(last)) {
4374     if(strlen(middle) || strlen(first))
4375       strcat(displayName, " ");
4376
4377     strcat(displayName, last);
4378   }
4379
4380   if(strlen(displayName))
4381     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4382                           "displayName", user_name);
4383   else
4384     rc = attribute_update(ldap_handle, distinguished_name, user_name,
4385                           "displayName", user_name);
4386
4387   if(!ActiveDirectory)
4388     {
4389       if(strlen(displayName))
4390         rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4391                               "cn", user_name);
4392       else
4393         rc = attribute_update(ldap_handle, distinguished_name, user_name,
4394                               "cn", user_name);
4395     }
4396
4397   if(!ActiveDirectory)
4398     {
4399       rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4400                             "eduPersonNickname", user_name);
4401     }
4402
4403   if(strlen(first))
4404     rc = attribute_update(ldap_handle, distinguished_name, first, 
4405                           "givenName", user_name);
4406   else
4407     rc = attribute_update(ldap_handle, distinguished_name, "",
4408                           "givenName", user_name);
4409
4410   if(strlen(middle) == 1) 
4411     rc = attribute_update(ldap_handle, distinguished_name, middle,
4412                           "initials", user_name);
4413   else 
4414     rc = attribute_update(ldap_handle, distinguished_name, "",
4415                           "initials", user_name);
4416   
4417   if(strlen(last))
4418     rc = attribute_update(ldap_handle, distinguished_name, last,
4419                           "sn", user_name);
4420   else 
4421     rc = attribute_update(ldap_handle, distinguished_name, "",
4422                           "sn", user_name);
4423
4424   if(ActiveDirectory)
4425     {
4426       rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4427                             user_name);
4428     }
4429   else
4430     {
4431       rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", 
4432                             user_name);
4433     }
4434     
4435   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4436                         "mitMoiraId", user_name);
4437
4438   n = 0;
4439   uid_v[0] = Uid;
4440
4441   if(ActiveDirectory)
4442     {
4443       if (!UseSFU30)
4444         {
4445           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4446         }
4447       else
4448         {
4449           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4450         }
4451     }
4452   else
4453     {
4454       sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4455       sprintf(status, "%d", State);
4456       principal_v[0] = principal;
4457       loginshell_v[0] = shell;
4458       mitMoiraClass_v[0] = class;
4459       mitMoiraStatus_v[0] = status;
4460       gid_v[0] = "101";
4461       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4462       ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE);
4463       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE);
4464       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4465       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE);
4466       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE);
4467     }
4468
4469   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4470     {
4471       userAccountControl |= UF_ACCOUNTDISABLE;
4472
4473       if (Exchange)
4474         {
4475           hide_address_lists_v[0] = "TRUE";
4476           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4477                    LDAP_MOD_REPLACE);
4478         }
4479     }
4480   else
4481     {
4482       if (Exchange)
4483         {
4484           hide_address_lists_v[0] = NULL;
4485           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4486                    LDAP_MOD_REPLACE);
4487         }
4488     }
4489
4490   sprintf(userAccountControlStr, "%ld", userAccountControl);
4491   userAccountControl_v[0] = userAccountControlStr;
4492   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4493
4494   if (Exchange)
4495     {
4496       if (rc = moira_connect())
4497         {
4498           critical_alert("Ldap incremental", 
4499                          "Error contacting Moira server : %s",
4500                          error_message(rc));
4501           return;
4502         }
4503  
4504       argv[0] = user_name;
4505
4506       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4507         {
4508           if(!strcmp(save_argv[1], "EXCHANGE") || 
4509              (strstr(save_argv[3], search_string) != NULL))
4510             {
4511               alt_recipient_v[0] = NULL;
4512               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4513
4514               argv[0] = exchange_acl;
4515               argv[1] = "USER";
4516               argv[2] = user_name;
4517               
4518               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4519               
4520               if ((rc) && (rc != MR_EXISTS))
4521                 {
4522                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4523                           user_name, exchange_acl, error_message(rc));
4524                 }
4525             }
4526           else 
4527             {
4528               alt_recipient_v[0] = alt_recipient;
4529               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4530               
4531               argv[0] = exchange_acl;
4532               argv[1] = "USER";
4533               argv[2] = user_name;
4534               
4535               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4536               
4537               if ((rc) && (rc != MR_NO_MATCH))
4538                 {  
4539                   com_err(whoami, 0,
4540                           "Unable to remove user %s from %s: %s, %d",
4541                           user_name, exchange_acl, error_message(rc), rc);
4542                 }  
4543             }
4544         }
4545       else
4546         {
4547           alt_recipient_v[0] = alt_recipient;
4548           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4549           
4550           argv[0] = exchange_acl;
4551           argv[1] = "USER";
4552           argv[2] = user_name;
4553           
4554           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4555           
4556           if ((rc) && (rc != MR_NO_MATCH))
4557             {  
4558               com_err(whoami, 0,
4559                       "Unable to remove user %s from %s: %s, %d",
4560                       user_name, exchange_acl, error_message(rc), rc);
4561             }  
4562         }
4563       
4564       moira_disconnect();
4565     }
4566   else
4567     {
4568       mail_v[0] = contact_mail;
4569       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4570
4571       if(!ActiveDirectory)
4572         {
4573           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_REPLACE);
4574         }
4575     }
4576
4577   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4578                        WinProfileDir, homedir_v, winProfile_v,
4579                        drives_v, mods, LDAP_MOD_REPLACE, n);
4580
4581   if(ActiveDirectory)
4582     {
4583       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4584       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4585       attr_array[0] = "sAMAccountName";
4586       attr_array[1] = NULL;
4587       group_count = 0;
4588       group_base = NULL;
4589     
4590       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
4591                                attr_array,
4592                                &group_base, &group_count, 
4593                                LDAP_SCOPE_SUBTREE) != 0))
4594         return(1);
4595       
4596       if (group_count != 1)
4597         {
4598           com_err(whoami, 0, "Unable to process user security template: %s - "
4599                   "security not set", "UserTemplate.u");
4600           return(1);
4601         }
4602
4603       strcpy(TemplateDn, group_base->dn);
4604       strcpy(TemplateSamName, group_base->value);
4605       linklist_free(group_base);
4606       group_base = NULL;
4607       group_count = 0;
4608       
4609       rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4610                              filter_exp, NULL, 0, apsServerControls, NULL,
4611                              NULL, 0, &psMsg);
4612
4613       if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4614         {
4615           com_err(whoami, 0, "Unable to find user security template: %s - "
4616                   "security not set", "UserTemplate.u");
4617           return(1);
4618         }
4619       
4620       ppsValues = ldap_get_values_len(ldap_handle, psMsg, 
4621                                       "ntSecurityDescriptor");
4622
4623       if (ppsValues == NULL)
4624         {
4625           com_err(whoami, 0, "Unable to find user security template: %s - "
4626                   "security not set", "UserTemplate.u");
4627           return(1);
4628         }
4629       
4630       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4631                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4632     }
4633
4634   mods[n] = NULL;
4635
4636   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4637                           mods)) != LDAP_SUCCESS)
4638     {
4639       OldUseSFU30 = UseSFU30;
4640       SwitchSFU(mods, &UseSFU30, n);
4641       if (OldUseSFU30 != UseSFU30)
4642         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4643       if (rc)
4644         {
4645           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4646                   user_name, ldap_err2string(rc));
4647         }
4648     }
4649   
4650   for (i = 0; i < n; i++)
4651     free(mods[i]);
4652
4653   return(rc);
4654 }
4655
4656 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4657                 char *user_name)
4658 {
4659   LDAPMod *mods[20];
4660   char new_dn[256];
4661   char old_dn[256];
4662   char upn[256];
4663   char mail[256];
4664   char contact_mail[256];
4665   char proxy_address[256];
4666   char query_base_dn[256];
4667   char temp[256];
4668   char *userPrincipalName_v[] = {NULL, NULL};
4669   char *altSecurityIdentities_v[] = {NULL, NULL};
4670   char *name_v[] = {NULL, NULL};
4671   char *samAccountName_v[] = {NULL, NULL};
4672   char *mail_v[] = {NULL, NULL};
4673   char *mail_nickname_v[] = {NULL, NULL};
4674   char *proxy_address_v[] = {NULL, NULL};
4675   char *query_base_dn_v[] = {NULL, NULL};
4676   char *principal_v[] = {NULL, NULL};
4677   char principal[256];
4678   int  n;
4679   int  rc;
4680   int  i;
4681
4682   if (!check_string(before_user_name))
4683     {
4684       com_err(whoami, 0, 
4685               "Unable to process invalid LDAP user name %s", before_user_name);
4686       return(AD_INVALID_NAME);
4687     }
4688
4689   if (!check_string(user_name))
4690     {
4691       com_err(whoami, 0, 
4692               "Unable to process invalid LDAP user name %s", user_name);
4693       return(AD_INVALID_NAME);
4694     }
4695
4696   strcpy(user_name, user_name);
4697  
4698   if(ActiveDirectory)
4699     sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4700   else
4701     sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path);
4702
4703   if(ActiveDirectory)
4704     sprintf(new_dn, "cn=%s", user_name);
4705   else
4706     sprintf(new_dn, "uid=%s", user_name);
4707
4708   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4709   sprintf(contact_mail, "%s@mit.edu", user_name);
4710   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4711   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4712
4713   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4714                            NULL, NULL)) != LDAP_SUCCESS)
4715     {
4716       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4717               before_user_name, user_name, ldap_err2string(rc));
4718       return(rc);
4719     }
4720
4721   if (Exchange)
4722     {
4723       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4724               dn_path);
4725
4726       if(rc = ldap_delete_s(ldap_handle, temp))
4727         {
4728           com_err(whoami, 0, "Unable to delete user contact for %s",
4729                   user_name);
4730         }
4731       
4732       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4733         {
4734           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4735         }
4736     }
4737
4738   name_v[0] = user_name;
4739   sprintf(upn, "%s@%s", user_name, ldap_domain);
4740   userPrincipalName_v[0] = upn;
4741   principal_v[0] = principal;
4742   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4743   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4744   altSecurityIdentities_v[0] = temp;
4745   samAccountName_v[0] = user_name;
4746   mail_v[0] = mail;
4747   mail_nickname_v[0] = user_name;
4748   proxy_address_v[0] = proxy_address; 
4749   query_base_dn_v[0] = query_base_dn;
4750
4751   n = 0;
4752   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4753   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4754   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4755   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4756
4757   if(!ActiveDirectory)
4758     {
4759       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE);
4760       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4761       ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4762       ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE);
4763     }
4764
4765   if (Exchange)
4766     {
4767       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4768       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4769       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4770       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4771     }
4772   else
4773     {
4774       mail_v[0] = contact_mail;
4775       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4776
4777       if(!ActiveDirectory)
4778         {
4779           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_REPLACE);
4780         }
4781     }
4782
4783   mods[n] = NULL;
4784   
4785   if(ActiveDirectory)
4786     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4787   else
4788     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path);
4789
4790   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4791     {
4792       com_err(whoami, 0, 
4793               "Unable to modify user data for %s after renaming : %s",
4794               user_name, ldap_err2string(rc));
4795     }
4796   
4797   for (i = 0; i < n; i++)
4798     free(mods[i]);
4799
4800   return(rc);
4801 }
4802
4803 int user_create(int ac, char **av, void *ptr)
4804 {
4805   LDAPMod *mods[20];
4806   char new_dn[256];
4807   char user_name[256];
4808   char sam_name[256];
4809   char upn[256];
4810   char mail[256];
4811   char contact_mail[256];
4812   char proxy_address[256];
4813   char mail_nickname[256];
4814   char query_base_dn[256];
4815   char displayName[256];
4816   char address_book[256];
4817   char alt_recipient[256];
4818   char *cn_v[] = {NULL, NULL};
4819   char *objectClass_v[] = {"top", "person", "organizationalPerson",
4820                            "user", NULL};
4821   char *objectClass_ldap_v[] = {"top", 
4822                                 "eduPerson", "posixAccount", 
4823                                 "apple-user", "shadowAccount",
4824                                 "microsoftComTop", "securityPrincipal",
4825                                 "inetOrgPerson", "user", 
4826                                 "organizationalPerson", "person",
4827                                 "mailRecipient", NULL};
4828
4829   char *samAccountName_v[] = {NULL, NULL};
4830   char *altSecurityIdentities_v[] = {NULL, NULL};
4831   char *mitMoiraId_v[] = {NULL, NULL};
4832   char *mitMoiraClass_v[] = {NULL, NULL};
4833   char *mitMoiraStatus_v[] = {NULL, NULL};
4834   char *name_v[] = {NULL, NULL};
4835   char *desc_v[] = {NULL, NULL};
4836   char *userPrincipalName_v[] = {NULL, NULL};
4837   char *userAccountControl_v[] = {NULL, NULL};
4838   char *uid_v[] = {NULL, NULL};
4839   char *gid_v[] = {NULL, NULL};
4840   char *mitid_v[] = {NULL, NULL};
4841   char *homedir_v[] = {NULL, NULL};
4842   char *winProfile_v[] = {NULL, NULL};
4843   char *drives_v[] = {NULL, NULL};
4844   char *mail_v[] = {NULL, NULL};
4845   char *givenName_v[] = {NULL, NULL};
4846   char *sn_v[] = {NULL, NULL};
4847   char *initials_v[] = {NULL, NULL};
4848   char *displayName_v[] = {NULL, NULL};
4849   char *proxy_address_v[] = {NULL, NULL};
4850   char *mail_nickname_v[] = {NULL, NULL};
4851   char *query_base_dn_v[] = {NULL, NULL};
4852   char *address_book_v[] = {NULL, NULL};
4853   char *homeMDB_v[] = {NULL, NULL};
4854   char *homeServerName_v[] = {NULL, NULL};
4855   char *mdbUseDefaults_v[] = {NULL, NULL};
4856   char *mailbox_guid_v[] = {NULL, NULL};
4857   char *user_culture_v[] = {NULL, NULL};
4858   char *user_account_control_v[] = {NULL, NULL};
4859   char *msexch_version_v[] = {NULL, NULL};
4860   char *alt_recipient_v[] = {NULL, NULL};
4861   char *hide_address_lists_v[] = {NULL, NULL};
4862   char *principal_v[] = {NULL, NULL};
4863   char *loginshell_v[] = {NULL, NULL};
4864   char userAccountControlStr[80];
4865   char temp[1024];
4866   char principal[256];
4867   char filter_exp[1024];
4868   char search_path[512];
4869   char *attr_array[3];
4870   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4871     UF_PASSWD_CANT_CHANGE; 
4872   int  n;
4873   int  rc;
4874   int  i;
4875   int  OldUseSFU30;
4876   char **call_args;
4877   char WinHomeDir[1024];
4878   char WinProfileDir[1024];
4879   char *homeMDB;
4880   char *homeServerName;
4881   ULONG dwInfo;
4882   char acBERBuf[N_SD_BER_BYTES];
4883   LK_ENTRY  *group_base;
4884   int    group_count;
4885   char TemplateDn[512];
4886   char TemplateSamName[128];
4887   LDAP_BERVAL **ppsValues;
4888   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4889                           { N_SD_BER_BYTES, acBERBuf },
4890                           TRUE};
4891   LDAPControl *apsServerControls[] = {&sControl, NULL};
4892   LDAPMessage *psMsg;
4893   char *argv[3];
4894   char *save_argv[7];
4895   char search_string[256];
4896   char *o_v[] = {NULL, NULL};
4897   char *p, *q;
4898   char *mail_routing_v[] = {NULL, NULL};
4899   char *c;
4900
4901   call_args = ptr;
4902
4903   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4904     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4905   BEREncodeSecurityBits(dwInfo, acBERBuf);
4906
4907   if (!check_string(av[U_NAME]))
4908     {
4909       callback_rc = AD_INVALID_NAME;
4910       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4911               av[U_NAME]);
4912       return(AD_INVALID_NAME);
4913     }
4914
4915   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4916   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4917   memset(displayName, '\0', sizeof(displayName));
4918   memset(query_base_dn, '\0', sizeof(query_base_dn));
4919   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4920   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4921   strcpy(user_name, av[U_NAME]);
4922   sprintf(upn, "%s@%s", user_name, ldap_domain);
4923   sprintf(sam_name, "%s", av[U_NAME]);
4924
4925   if(strlen(av[U_FIRST])) {
4926     strcat(displayName, av[U_FIRST]);
4927   }
4928
4929   if(strlen(av[U_MIDDLE])) {
4930     if(strlen(av[U_FIRST]))
4931        strcat(displayName, " "); 
4932   
4933     strcat(displayName, av[U_MIDDLE]);
4934   }
4935
4936   if(strlen(av[U_LAST])) {
4937     if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]))
4938       strcat(displayName, " ");
4939
4940     strcat(displayName, av[U_LAST]);
4941   }
4942
4943   samAccountName_v[0] = sam_name;
4944   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4945       (atoi(av[U_STATE]) != US_REGISTERED))
4946     {
4947       userAccountControl |= UF_ACCOUNTDISABLE;
4948
4949       if (Exchange)
4950         {
4951           hide_address_lists_v[0] = "TRUE";
4952           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4953                    LDAP_MOD_ADD);
4954         }
4955     }
4956
4957   sprintf(userAccountControlStr, "%ld", userAccountControl);
4958   userAccountControl_v[0] = userAccountControlStr;
4959   userPrincipalName_v[0] = upn;
4960   
4961   if(ActiveDirectory)
4962     cn_v[0] = user_name;
4963   else
4964     cn_v[0] = displayName;
4965     
4966   name_v[0] = user_name;
4967   desc_v[0] = "Auto account created by Moira";
4968   mail_v[0] = mail;
4969   givenName_v[0] = av[U_FIRST];
4970
4971   if(ActiveDirectory)
4972     sn_v[0] = av[U_LAST];
4973   else
4974     if(strlen(av[U_LAST]))
4975       sn_v[0] = av[U_LAST];
4976     else
4977       sn_v[0] = av[U_NAME];
4978
4979   displayName_v[0] = displayName;
4980   mail_nickname_v[0] = user_name;
4981   o_v[0] = "Massachusetts Institute of Technology";
4982
4983   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4984   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4985   altSecurityIdentities_v[0] = temp;    
4986   principal_v[0] = principal;
4987
4988   if(ActiveDirectory)
4989     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4990   else
4991     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]);
4992
4993   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4994   sprintf(contact_mail, "%s@mit.edu", user_name);
4995   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4996   query_base_dn_v[0] = query_base_dn;
4997   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4998           call_args[1]);
4999   sprintf(search_string, "@%s", uppercase(ldap_domain));
5000
5001   if (Exchange)
5002     {
5003       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
5004                         contact_ou))
5005         {
5006           com_err(whoami, 0, "Unable to create user contact %s", 
5007                   contact_mail);
5008         }
5009       
5010       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
5011                       &homeServerName)) 
5012         {
5013           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
5014           return(1);
5015         }
5016       
5017       com_err(whoami, 0, "homeMDB:%s", homeMDB);
5018       com_err(whoami, 0, "homeServerName:%s", homeServerName);
5019   
5020       homeMDB_v[0] = homeMDB;
5021       homeServerName_v[0] = homeServerName; 
5022     }
5023
5024   n = 0;
5025
5026   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
5027   
5028   if(ActiveDirectory) 
5029     {
5030       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
5031     }
5032   else
5033     {
5034       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
5035     }
5036
5037   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
5038   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
5039   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
5040   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
5041   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
5042
5043   if (Exchange)
5044     {
5045       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
5046       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
5047       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
5048       mdbUseDefaults_v[0] = "TRUE";
5049       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
5050       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
5051       
5052       argv[0] = user_name;
5053     
5054       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5055         {
5056           if(!strcmp(save_argv[1], "EXCHANGE") || 
5057              (strstr(save_argv[3], search_string) != NULL))
5058             {
5059               argv[0] = exchange_acl;
5060               argv[1] = "USER";
5061               argv[2] = user_name;
5062               
5063               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
5064               
5065               if ((rc) && (rc != MR_EXISTS))
5066                 {
5067                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
5068                           user_name, exchange_acl, error_message(rc));
5069                 }
5070             } 
5071           else 
5072             {
5073               alt_recipient_v[0] = alt_recipient;
5074               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5075             }
5076         }
5077       else
5078         {
5079           alt_recipient_v[0] = alt_recipient;
5080           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5081           
5082           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
5083         }
5084     }
5085   else
5086     {
5087       mail_v[0] = contact_mail;
5088       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
5089
5090       if(!ActiveDirectory)
5091         {
5092           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_ADD);
5093         }
5094     }
5095
5096   if(strlen(av[U_FIRST])) {
5097     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
5098   }
5099
5100   if(strlen(av[U_LAST]) || strlen(av[U_NAME])) {
5101     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
5102   }
5103
5104   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
5105     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
5106
5107     if(!ActiveDirectory)
5108       {
5109         ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD);      
5110       }
5111   } else {
5112     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
5113
5114     if(!ActiveDirectory)
5115       {
5116         ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD);            
5117       }
5118   }
5119
5120   if (strlen(av[U_MIDDLE]) == 1) {
5121     initials_v[0] = av[U_MIDDLE];
5122     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
5123   }
5124
5125   if (strlen(call_args[2]) != 0)    
5126     {
5127       mitMoiraId_v[0] = call_args[2];
5128       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
5129     }
5130
5131   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
5132
5133   if(!ActiveDirectory)
5134     {
5135       loginshell_v[0] = av[U_SHELL];
5136       mitMoiraClass_v[0] = av[U_CLASS];
5137       mitMoiraStatus_v[0] = av[U_STATE];
5138       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD);
5139       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD);
5140       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD);
5141       ADD_ATTR("o", o_v, LDAP_MOD_ADD);
5142       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD);
5143       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD);
5144     }
5145
5146   if (strlen(av[U_UID]) != 0)
5147     {
5148       uid_v[0] = av[U_UID];
5149
5150       if(ActiveDirectory) 
5151         {
5152           ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
5153         }
5154       else
5155         {
5156           gid_v[0] = "101";
5157           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5158           ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD);
5159         }
5160
5161       if(ActiveDirectory)
5162         {
5163           if (!UseSFU30)
5164             {
5165               ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5166             }
5167           else
5168             {
5169               ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
5170             }
5171         }
5172     }
5173
5174   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
5175       mitid_v[0] = av[U_MITID];
5176   else
5177       mitid_v[0] = "none";
5178
5179   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
5180
5181   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, 
5182                        WinHomeDir, WinProfileDir, homedir_v, winProfile_v,
5183                        drives_v, mods, LDAP_MOD_ADD, n);
5184   
5185   if(ActiveDirectory) 
5186     {
5187       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
5188       sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
5189       attr_array[0] = "sAMAccountName";
5190       attr_array[1] = NULL;
5191       group_count = 0;
5192       group_base = NULL;
5193       
5194       if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
5195                                attr_array, &group_base, &group_count, 
5196                                LDAP_SCOPE_SUBTREE) != 0))
5197         return(1);
5198       
5199       if (group_count != 1)
5200         {
5201           com_err(whoami, 0, "Unable to process user security template: %s - "
5202                   "security not set", "UserTemplate.u");
5203           return(1);
5204         }
5205       
5206       strcpy(TemplateDn, group_base->dn);
5207       strcpy(TemplateSamName, group_base->value);
5208       linklist_free(group_base);
5209       group_base = NULL;
5210       group_count = 0;
5211       
5212       rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, 
5213                              LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, 
5214                              apsServerControls, NULL,
5215                              NULL, 0, &psMsg);
5216       
5217       if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
5218         {
5219           com_err(whoami, 0, "Unable to find user security template: %s - "
5220                   "security not set", "UserTemplate.u");
5221           return(1);
5222         }
5223       
5224       ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
5225                                       "ntSecurityDescriptor");
5226       if (ppsValues == NULL)
5227         {
5228           com_err(whoami, 0, "Unable to find user security template: %s - "
5229                   "security not set", "UserTemplate.u");
5230           return(1);
5231         }
5232       
5233       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
5234                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
5235     }
5236
5237   mods[n] = NULL;
5238
5239   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5240
5241   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5242     {
5243       OldUseSFU30 = UseSFU30;
5244       SwitchSFU(mods, &UseSFU30, n);
5245       if (OldUseSFU30 != UseSFU30)
5246         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5247     }
5248
5249   for (i = 0; i < n; i++)
5250     free(mods[i]);
5251
5252   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5253     {
5254       com_err(whoami, 0, "Unable to create user %s : %s",
5255               user_name, ldap_err2string(rc));
5256       callback_rc = rc;
5257       return(rc);
5258     }
5259
5260   if ((rc == LDAP_SUCCESS) && (SetPassword))
5261     {
5262       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5263         {
5264           ad_kdc_disconnect();
5265           if (!ad_server_connect(default_server, ldap_domain))
5266             {
5267               com_err(whoami, 0, "Unable to set password for user %s : %s",
5268                       user_name, 
5269                       "cannot get changepw ticket from windows domain");
5270             }
5271           else
5272             {
5273               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5274                 {
5275                   com_err(whoami, 0, "Unable to set password for user %s "
5276                           ": %ld", user_name, rc);
5277                 }
5278             }
5279         }
5280     }
5281
5282   if(!ActiveDirectory) 
5283     {
5284       if (rc = moira_connect())
5285         {
5286           critical_alert("Ldap incremental", 
5287                          "Error contacting Moira server : %s",
5288                          error_message(rc));
5289           return;
5290         }
5291   
5292       argv[0] = user_name;
5293       
5294       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5295         {
5296           n = 0;
5297           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
5298           mods[n] = NULL;
5299           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5300            
5301           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
5302             rc = LDAP_SUCCESS;
5303
5304           if(rc)
5305             com_err(whoami, 0,
5306                     "Unable to set the mailRoutingAddress for %s : %s",
5307                     user_name, ldap_err2string(rc));
5308
5309           p = strdup(save_argv[3]);
5310           
5311           if((c = strchr(p, ',')) != NULL) {
5312             q = strtok(p, ",");
5313             StringTrim(q);
5314
5315             if ((c = strchr(q, '@')) == NULL)
5316               sprintf(temp, "%s@mit.edu", q);
5317             else
5318               sprintf(temp, "%s", q);
5319
5320             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5321               {
5322                 mail_routing_v[0]  = temp;
5323
5324                 n = 0;
5325                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5326                 mods[n] = NULL;
5327                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5328                 
5329                 if (rc == LDAP_ALREADY_EXISTS || 
5330                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5331                   rc = LDAP_SUCCESS;
5332                 
5333                 if(rc)
5334                   com_err(whoami, 0, 
5335                           "Unable to set the mailRoutingAddress for %s : %s",
5336                           user_name, ldap_err2string(rc));
5337               }
5338
5339             while((q = strtok(NULL, ",")) != NULL) {
5340               StringTrim(q);
5341
5342               if((c = strchr(q, '@')) == NULL)
5343                 sprintf(temp, "%s@mit.edu", q);
5344               else
5345                 sprintf(temp, "%s", q);
5346
5347               if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED)
5348                 {
5349                   mail_routing_v[0]  = temp;
5350                   
5351                   n = 0;
5352                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5353                   mods[n] = NULL;
5354                   rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5355                   
5356                   if (rc == LDAP_ALREADY_EXISTS || 
5357                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
5358                     rc = LDAP_SUCCESS;
5359                   
5360                   if(rc)
5361                     com_err(whoami, 0, 
5362                             "Unable to set the mailRoutingAddress for %s : %s",
5363                             user_name, ldap_err2string(rc));
5364                 }
5365             }
5366           } else {
5367             StringTrim(p);
5368
5369             if((c = strchr(p, '@')) == NULL)
5370               sprintf(temp, "%s@mit.edu", p);
5371             else
5372               sprintf(temp, "%s", p);
5373
5374             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5375               {
5376                 mail_routing_v[0]  = temp;
5377                 
5378                 n = 0;
5379                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5380                 mods[n] = NULL;
5381                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5382                 
5383                 if (rc == LDAP_ALREADY_EXISTS || 
5384                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5385                   rc = LDAP_SUCCESS;
5386                 
5387                 if(rc)
5388                   com_err(whoami, 0, 
5389                           "Unable to set the mailRoutingAddress for %s : %s",
5390                           user_name, ldap_err2string(rc));
5391               }
5392           }
5393         }
5394       moira_disconnect();
5395     }
5396
5397   return(0);
5398 }
5399
5400 int user_change_status(LDAP *ldap_handle, char *dn_path, 
5401                        char *user_name, char *MoiraId,
5402                        int operation)
5403 {
5404   char      filter[128];
5405   char      *attr_array[3];
5406   char      temp[256];
5407   char      distinguished_name[1024];
5408   char      **modvalues;
5409   char      *mitMoiraId_v[] = {NULL, NULL};
5410   LDAPMod   *mods[20];
5411   LK_ENTRY  *group_base;
5412   int       group_count;
5413   int       rc;
5414   int       i;
5415   int       n;
5416   ULONG     ulongValue;
5417
5418   if (!check_string(user_name))
5419     {
5420       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
5421               user_name);
5422       return(AD_INVALID_NAME);
5423     }
5424
5425   group_count = 0;
5426   group_base = NULL;
5427
5428   if (strlen(MoiraId) != 0)
5429     {
5430       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5431       attr_array[0] = "UserAccountControl";
5432       attr_array[1] = NULL;
5433       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5434                                &group_base, &group_count, 
5435                                LDAP_SCOPE_SUBTREE)) != 0)
5436         {
5437           com_err(whoami, 0, "Unable to process user %s : %s",
5438                   user_name, ldap_err2string(rc));
5439           return(rc);
5440         }
5441     }
5442
5443   if (group_count != 1)
5444     {
5445       linklist_free(group_base);
5446       group_count = 0;
5447       group_base = NULL;
5448       sprintf(filter, "(sAMAccountName=%s)", user_name);
5449       attr_array[0] = "UserAccountControl";
5450       attr_array[1] = NULL;
5451       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5452                                &group_base, &group_count, 
5453                                LDAP_SCOPE_SUBTREE)) != 0)
5454         {
5455           com_err(whoami, 0, "Unable to process user %s : %s",
5456                   user_name, ldap_err2string(rc));
5457           return(rc);
5458         }
5459     }
5460   
5461   if (group_count != 1)
5462     {
5463       linklist_free(group_base);
5464       com_err(whoami, 0, "Unable to find user %s in directory",
5465               user_name);
5466       return(LDAP_NO_SUCH_OBJECT);
5467     }
5468
5469   strcpy(distinguished_name, group_base->dn);
5470   ulongValue = atoi((*group_base).value);
5471
5472   if (operation == MEMBER_DEACTIVATE)
5473     ulongValue |= UF_ACCOUNTDISABLE;
5474   else    
5475     ulongValue &= ~UF_ACCOUNTDISABLE;
5476
5477   sprintf(temp, "%ld", ulongValue);
5478
5479   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
5480                                 temp, &modvalues, REPLACE)) == 1)
5481     goto cleanup;
5482
5483   linklist_free(group_base);
5484   group_base = NULL;
5485   group_count = 0;
5486   n = 0;
5487   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
5488
5489   if (strlen(MoiraId) != 0)
5490     {
5491     mitMoiraId_v[0] = MoiraId;
5492     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
5493     }
5494
5495   mods[n] = NULL;
5496   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
5497
5498   for (i = 0; i < n; i++)
5499     free(mods[i]);
5500
5501   free_values(modvalues);
5502
5503   if (rc != LDAP_SUCCESS)
5504     {
5505       com_err(whoami, 0, "Unable to change status of user %s : %s",
5506               user_name, ldap_err2string(rc));
5507     }
5508   
5509  cleanup:
5510   return(rc);
5511 }
5512
5513 int user_delete(LDAP *ldap_handle, char *dn_path, 
5514                 char *u_name, char *MoiraId)
5515 {
5516   char      filter[128];
5517   char      *attr_array[3];
5518   char      distinguished_name[1024];
5519   char      user_name[512];
5520   LK_ENTRY  *group_base;
5521   int       group_count;
5522   int       rc;
5523   char      temp[256];
5524
5525   if (!check_string(u_name))
5526     return(AD_INVALID_NAME);
5527
5528   strcpy(user_name, u_name);
5529   group_count = 0;
5530   group_base = NULL;
5531
5532   if (strlen(MoiraId) != 0)
5533     {
5534       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5535       attr_array[0] = "name";
5536       attr_array[1] = NULL;
5537       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5538                                &group_base, &group_count, 
5539                                LDAP_SCOPE_SUBTREE)) != 0)
5540         {
5541           com_err(whoami, 0, "Unable to process user %s : %s",
5542                   user_name, ldap_err2string(rc));
5543           goto cleanup;
5544         }
5545     }
5546   
5547   if (group_count != 1)
5548     {
5549       linklist_free(group_base);
5550       group_count = 0;
5551       group_base = NULL;
5552       sprintf(filter, "(sAMAccountName=%s)", user_name);
5553       attr_array[0] = "name";
5554       attr_array[1] = NULL;
5555       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5556                                &group_base, &group_count, 
5557                                LDAP_SCOPE_SUBTREE)) != 0)
5558         {
5559           com_err(whoami, 0, "Unable to process user %s : %s",
5560                   user_name, ldap_err2string(rc));
5561           goto cleanup;
5562         }
5563     }
5564
5565   if (group_count != 1)
5566     {
5567       goto cleanup;
5568     }
5569   
5570   strcpy(distinguished_name, group_base->dn);
5571
5572   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
5573     {
5574       com_err(whoami, 0, "Unable to process user %s : %s",
5575               user_name, ldap_err2string(rc));
5576     }
5577
5578   /* Need to add code to delete mit.edu contact */
5579   
5580   if (Exchange)
5581     {
5582       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
5583
5584       if(rc = ldap_delete_s(ldap_handle, temp))
5585         {
5586           com_err(whoami, 0, "Unable to delete user contact for %s",
5587                   user_name);
5588         }
5589     }
5590
5591  cleanup:
5592   linklist_free(group_base);
5593
5594   return(0);
5595 }
5596
5597 void linklist_free(LK_ENTRY *linklist_base)
5598 {
5599   LK_ENTRY *linklist_previous;
5600
5601   while (linklist_base != NULL)
5602     {
5603       if (linklist_base->dn != NULL)
5604         free(linklist_base->dn);
5605
5606       if (linklist_base->attribute != NULL)
5607         free(linklist_base->attribute);
5608
5609       if (linklist_base->value != NULL)
5610         free(linklist_base->value);
5611
5612       if (linklist_base->member != NULL)
5613         free(linklist_base->member);
5614
5615       if (linklist_base->type != NULL)
5616         free(linklist_base->type);
5617
5618       if (linklist_base->list != NULL)
5619         free(linklist_base->list);
5620
5621       linklist_previous = linklist_base;
5622       linklist_base = linklist_previous->next;
5623       free(linklist_previous);
5624     }
5625 }
5626
5627 void free_values(char **modvalues)
5628 {
5629   int i;
5630
5631   i = 0;
5632
5633   if (modvalues != NULL)
5634     {
5635     while (modvalues[i] != NULL)
5636       {
5637         free(modvalues[i]);
5638         modvalues[i] = NULL;
5639         ++i;
5640       }
5641     free(modvalues);
5642   }
5643 }
5644
5645 static int illegalchars[] = {
5646   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5647   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5648   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
5649   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5650   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5651   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5652   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5653   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5654   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5655   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5656   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5657   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5658   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5659   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5660   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5661   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5662 };
5663
5664 static int illegalchars_ldap[] = {
5665   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5666   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5667   0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* SPACE - / */
5668   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
5669   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5670   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */
5671   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5672   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5673   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5674   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5675   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5676   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5677   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5678   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5679   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5680   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5681 };
5682
5683 int check_string(char *s)
5684 {
5685   char  character;
5686   char  *string;
5687
5688   string = s;
5689
5690   for (; *s; s++)
5691     {
5692       character = *s;
5693
5694       if (isupper(character))
5695         character = tolower(character);
5696
5697       if(ActiveDirectory)
5698         {
5699           if (illegalchars[(unsigned) character])
5700             {
5701               com_err(whoami, 0, "Found illegal char '%c' (%d) in string %s",
5702                       character, (unsigned) character, string);
5703               return 0;
5704             }
5705         }
5706       else
5707         {
5708           if (illegalchars_ldap[(unsigned) character])
5709             {
5710               com_err(whoami, 0, "Found illegal char '%c' (%d) in string %s",
5711                       character, (unsigned) character, string);
5712               return 0;
5713             }
5714         }
5715     }
5716
5717   return(1);
5718 }
5719
5720 int check_container_name(char *s)
5721 {
5722   char  character;
5723
5724   for (; *s; s++)
5725     {
5726       character = *s;
5727
5728       if (isupper(character))
5729         character = tolower(character);
5730
5731       if (character == ' ')
5732         continue;
5733
5734       if (illegalchars[(unsigned) character])
5735         return 0;
5736     }
5737
5738   return(1);
5739 }
5740
5741 int mr_connect_cl(char *server, char *client, int version, int auth)
5742 {
5743   int   status;
5744   char  *motd;
5745   char  temp[128];
5746
5747   status = mr_connect(server);
5748
5749   if (status)
5750     {
5751       com_err(whoami, status, "while connecting to Moira");
5752       return status;
5753     }
5754
5755   status = mr_motd(&motd);
5756
5757   if (status)
5758     {
5759       mr_disconnect();
5760       com_err(whoami, status, "while checking server status");
5761       return status;
5762     }
5763
5764   if (motd)
5765     {
5766       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5767       com_err(whoami, status, temp);
5768       mr_disconnect();
5769       return status;
5770     }
5771
5772   status = mr_version(version);
5773
5774   if (status)
5775     {
5776       if (status == MR_UNKNOWN_PROC)
5777         {
5778           if (version > 2)
5779             status = MR_VERSION_HIGH;
5780           else
5781             status = MR_SUCCESS;
5782         }
5783
5784       if (status == MR_VERSION_HIGH)
5785         {
5786           com_err(whoami, 0, "Warning: This client is running newer code "
5787                   "than the server.");
5788                   com_err(whoami, 0, "Some operations may not work.");
5789         }
5790       else if (status && status != MR_VERSION_LOW)
5791         {
5792           com_err(whoami, status, "while setting query version number.");
5793           mr_disconnect();
5794           return status;
5795         }
5796     }
5797
5798   if (auth)
5799     {
5800       status = mr_krb5_auth(client);
5801       if (status)
5802         {
5803           com_err(whoami, status, "while authenticating to Moira.");
5804           mr_disconnect();
5805           return status;
5806         }
5807     }
5808   
5809   return MR_SUCCESS;
5810 }
5811
5812 void AfsToWinAfs(char* path, char* winPath)
5813 {
5814   char* pathPtr;
5815   char* winPathPtr;
5816   strcpy(winPath, WINAFS);
5817   pathPtr = path + strlen(AFS);
5818   winPathPtr = winPath + strlen(WINAFS);
5819   
5820   while (*pathPtr)
5821     {
5822       if (*pathPtr == '/')
5823         *winPathPtr = '\\';
5824       else
5825         *winPathPtr = *pathPtr;
5826       
5827       pathPtr++;
5828       winPathPtr++;
5829     }
5830 }
5831
5832 int GetAceInfo(int ac, char **av, void *ptr)
5833 {
5834   char **call_args;
5835   int   security_flag;
5836
5837   call_args = ptr;
5838   
5839   strcpy(call_args[0], av[L_ACE_TYPE]);
5840   strcpy(call_args[1], av[L_ACE_NAME]);
5841   security_flag = 0;
5842   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5843   return(LDAP_SUCCESS);  
5844 }
5845
5846 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5847 {
5848   char filter[128];
5849   char *attr_array[3];
5850   int  group_count;
5851   int  rc;
5852   LK_ENTRY  *group_base;
5853   
5854   group_count = 0;
5855   group_base = NULL;
5856   
5857   sprintf(filter, "(sAMAccountName=%s)", Name);
5858   attr_array[0] = "sAMAccountName";
5859   attr_array[1] = NULL;
5860
5861   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5862                            &group_base, &group_count, 
5863                            LDAP_SCOPE_SUBTREE)) != 0)
5864     {
5865       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5866               Name, ldap_err2string(rc));
5867       return(1);
5868     }
5869
5870   linklist_free(group_base);
5871   group_base = NULL;
5872
5873   if (group_count == 0)
5874     return(0);
5875   
5876   return(1);
5877 }
5878
5879 #define MAX_ACE 7
5880
5881 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5882                int UpdateGroup, int *ProcessGroup, char *maillist)
5883 {
5884   char  *av[2];
5885   char  GroupName[256];
5886   char  *call_args[7];
5887   int   rc;
5888   char  *AceInfo[4];
5889   char  AceType[32];
5890   char  AceName[128];
5891   char  AceMembership[2];
5892   char  AceOu[256];
5893   char  temp[128];
5894   char  *save_argv[U_END];
5895
5896   if (!SetGroupAce)
5897     {
5898       com_err(whoami, 0, "ProcessAce disabled, skipping");
5899       return(0);
5900     }
5901
5902   strcpy(GroupName, Name);
5903   
5904   if (strcasecmp(Type, "LIST"))
5905     return(1);
5906
5907   while (1)
5908     {
5909       av[0] = GroupName;
5910       AceInfo[0] = AceType;
5911       AceInfo[1] = AceName;
5912       AceInfo[2] = AceMembership;
5913       AceInfo[3] = AceOu;
5914       memset(AceType, '\0', sizeof(AceType));
5915       memset(AceName, '\0', sizeof(AceName));
5916       memset(AceMembership, '\0', sizeof(AceMembership));
5917       memset(AceOu, '\0', sizeof(AceOu));
5918       callback_rc = 0;
5919     
5920       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5921         { 
5922           if(rc != MR_NO_MATCH)
5923             com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5924                     GroupName, error_message(rc));
5925
5926           return(1);
5927         }
5928
5929       if (callback_rc)
5930         {
5931           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5932           return(1);
5933         }
5934
5935       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5936         return(0);
5937
5938       strcpy(temp, AceName);
5939
5940       if (!strcasecmp(AceType, "LIST"))
5941         sprintf(temp, "%s%s", AceName, group_suffix);
5942
5943       if (!UpdateGroup)
5944         {
5945           if (checkADname(ldap_handle, dn_path, temp))
5946               return(0);
5947
5948           (*ProcessGroup) = 1;
5949         }
5950
5951       if (!strcasecmp(AceInfo[0], "LIST"))
5952         {
5953           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5954                              AceMembership, 0, UpdateGroup, maillist))
5955             return(1);
5956
5957           populate_group(ldap_handle, dn_path, AceName, AceOu, AceMembership,
5958                          0, "");
5959         }
5960       else if (!strcasecmp(AceInfo[0], "USER"))
5961         {
5962           av[0] = AceName;
5963           call_args[0] = (char *)ldap_handle;
5964           call_args[1] = dn_path;
5965           call_args[2] = "";
5966           call_args[3] = NULL;
5967           callback_rc = 0;
5968
5969           if(!strcasecmp(AceName, PRODUCTION_PRINCIPAL) ||
5970              !strcasecmp(AceName, TEST_PRINCIPAL))
5971             {
5972               return(1);
5973             }
5974
5975           if (rc = mr_query("get_user_account_by_login", 1, av, 
5976                             save_query_info, save_argv))
5977             {
5978               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5979                       AceName, Name);
5980               return(1);
5981             }
5982
5983           if (rc = user_create(U_END, save_argv, call_args)) 
5984             {
5985               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5986                       AceName, Name);
5987               return(1);
5988             }
5989           
5990           if (callback_rc)
5991             {
5992               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5993                       AceName, Name);
5994               return(1);
5995             }
5996
5997           return(0);
5998         }
5999       else
6000         return(1);
6001
6002       if (!strcasecmp(AceType, "LIST"))
6003         {
6004           if (!strcasecmp(GroupName, AceName))
6005             return(0);
6006         }
6007
6008       strcpy(GroupName, AceName);
6009     }
6010   
6011   return(1);
6012 }
6013
6014 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6015                    char *group_name, char *group_ou, char *group_membership, 
6016                    int group_security_flag, int updateGroup, char *maillist)
6017 {
6018   char  *av[3];
6019   char  *call_args[8];
6020   int   rc;
6021   LK_ENTRY  *group_base;
6022   int  group_count;
6023   char filter[128];
6024   char *attr_array[3];
6025
6026   av[0] = group_name;
6027   call_args[0] = (char *)ldap_handle;
6028   call_args[1] = dn_path;
6029   call_args[2] = group_name;
6030   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
6031   call_args[4] = (char *)updateGroup;
6032   call_args[5] = MoiraId;
6033   call_args[6] = "0";
6034   call_args[7] = NULL;
6035   callback_rc = 0;
6036
6037   group_count = 0;
6038   group_base = NULL;
6039
6040   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
6041     {
6042       moira_disconnect();
6043       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
6044               error_message(rc));
6045       return(rc);
6046     }
6047
6048   if (callback_rc)
6049     {
6050       moira_disconnect();
6051       com_err(whoami, 0, "Unable to create list %s", group_name);
6052       return(callback_rc);
6053     }
6054
6055   return(0);
6056 }
6057
6058 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
6059                    char *group_ou, char *group_membership, 
6060                    int group_security_flag, char *MoiraId)
6061 {
6062   char      *av[3];
6063   char      *call_args[7];
6064   char      *pUserOu;
6065   LK_ENTRY  *ptr;
6066   int       rc;
6067   char      member[512];
6068   char      *s;
6069   char      **members;
6070   int       i = 0;
6071   int       j = 0;
6072   int       n = 0;
6073   char      group_dn[512];
6074   LDAPMod   *mods[20];
6075   char      *member_v[] = {NULL, NULL};
6076   char      *save_argv[U_END];
6077   char      machine_ou[256];
6078   char      NewMachineName[1024];
6079
6080   com_err(whoami, 0, "Populating group %s", group_name);
6081   av[0] = group_name;
6082   call_args[0] = (char *)ldap_handle;
6083   call_args[1] = dn_path;
6084   call_args[2] = group_name;
6085   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS | 
6086                           MOIRA_MACHINE);
6087   call_args[4] = NULL;
6088   member_base = NULL;
6089
6090   if (rc = mr_query("get_end_members_of_list", 1, av,
6091                     member_list_build, call_args))
6092     {
6093       if(rc == MR_LIST)
6094         return(0);
6095       
6096       com_err(whoami, 0, "Unable to populate list %s : %s", 
6097               group_name, error_message(rc));
6098       return(3);
6099     }
6100
6101   members = (char **)malloc(sizeof(char *) * 2);
6102
6103   if (member_base != NULL)
6104     {
6105       ptr = member_base;
6106
6107       while (ptr != NULL)
6108         {
6109           if (!strcasecmp(ptr->type, "LIST"))
6110             {
6111               ptr = ptr->next;
6112               continue;
6113             }
6114           
6115           if (!strcasecmp(ptr->type, "MACHINE") && !ProcessMachineContainer)
6116             {
6117               ptr = ptr->next;
6118               continue;
6119             }
6120             
6121           if(!strcasecmp(ptr->type, "USER"))
6122             {
6123               if(!strcasecmp(ptr->member, PRODUCTION_PRINCIPAL) ||
6124                  !strcasecmp(ptr->member, TEST_PRINCIPAL))
6125                 {
6126                   ptr = ptr->next;
6127                   continue;
6128                 }
6129
6130               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6131                                    "")) == AD_NO_USER_FOUND)
6132                 {
6133                   com_err(whoami, 0, "creating user %s", ptr->member);
6134
6135                   av[0] = ptr->member;
6136                   call_args[0] = (char *)ldap_handle;
6137                   call_args[1] = dn_path;
6138                   call_args[2] = "";
6139                   call_args[3] = NULL;
6140                   callback_rc = 0;
6141                   
6142                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6143                                     save_query_info, save_argv))
6144                     {
6145                       com_err(whoami, 0, "Unable to create user %s " 
6146                               "while populating group %s.", ptr->member,
6147                               group_name);
6148
6149                       return(3);
6150                     }
6151
6152                   if (rc = user_create(U_END, save_argv, call_args)) 
6153                     {
6154                       com_err(whoami, 0, "Unable to create user %s "
6155                               "while populating group %s.", ptr->member,
6156                               group_name);
6157                       
6158                       return(3);
6159                     }
6160           
6161                   if (callback_rc)
6162                     {
6163                       com_err(whoami, 0, "Unable to create user %s "
6164                               "while populating group %s", ptr->member, 
6165                               group_name);
6166
6167                       return(3);
6168                     }
6169                 }
6170
6171               pUserOu = user_ou;
6172                   
6173               if(ActiveDirectory) 
6174                 {
6175                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6176                           dn_path);
6177                 }
6178               else 
6179                 {
6180                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6181                           dn_path);
6182                 }
6183             }
6184           else if (!strcasecmp(ptr->type, "STRING"))
6185             {
6186               if (contact_create(ldap_handle, dn_path, ptr->member,
6187                                  contact_ou))
6188                 return(3);
6189
6190               pUserOu = contact_ou;
6191               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6192                       pUserOu, dn_path);
6193             }
6194           else if (!strcasecmp(ptr->type, "KERBEROS"))
6195             {
6196               if (contact_create(ldap_handle, dn_path, ptr->member, 
6197                                  kerberos_ou))
6198                 return(3);
6199
6200               pUserOu = kerberos_ou;
6201               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6202                       pUserOu, dn_path);
6203             }
6204           else if (!strcasecmp(ptr->type, "MACHINE"))
6205             {
6206               memset(machine_ou, '\0', sizeof(machine_ou));
6207               memset(NewMachineName, '\0', sizeof(NewMachineName));
6208
6209               if (!get_machine_ou(ldap_handle, dn_path, ptr->member,
6210                                  machine_ou, NewMachineName))
6211                 {
6212                   pUserOu = machine_ou;
6213                   sprintf(member, "cn=%s,%s,%s", NewMachineName, pUserOu,
6214                           dn_path);
6215                 }
6216               else
6217                 {
6218                   ptr = ptr->next;                  
6219                   continue;
6220                 }
6221             }
6222
6223           if(i > 1) 
6224             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6225           members[i++] = strdup(member);
6226
6227           ptr = ptr->next;
6228         }
6229     
6230       linklist_free(member_base);
6231       member_base = NULL;
6232     }
6233
6234   members[i] = NULL;
6235
6236   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6237
6238   if(GroupPopulateDelete)
6239     {
6240       n = 0;
6241       ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
6242       mods[n] = NULL;
6243       
6244       if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6245                               mods)) != LDAP_SUCCESS)
6246         {
6247           com_err(whoami, 0,
6248                   "Unable to populate group membership for %s: %s",
6249                   group_dn, ldap_err2string(rc));
6250         }
6251   
6252       for (i = 0; i < n; i++)
6253         free(mods[i]);
6254     }
6255
6256   n = 0;
6257   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6258   mods[n] = NULL;
6259
6260   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6261                           mods)) != LDAP_SUCCESS)
6262     {
6263       com_err(whoami, 0,
6264               "Unable to populate group membership for %s: %s",
6265               group_dn, ldap_err2string(rc));
6266     }
6267   
6268   for (i = 0; i < n; i++)
6269     free(mods[i]);
6270     
6271   free(members);
6272
6273   return(0);
6274 }
6275
6276 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6277                   char *group_name, char *group_ou, char *group_membership, 
6278                   int group_security_flag, int type, char *maillist)
6279 {
6280   char      before_desc[512];
6281   char      before_name[256];
6282   char      before_group_ou[256];
6283   char      before_group_membership[2];
6284   char      distinguishedName[256];
6285   char      ad_distinguishedName[256];
6286   char      filter[128];
6287   char      *attr_array[3];
6288   int       before_security_flag;
6289   int       group_count;
6290   int       rc;
6291   LK_ENTRY  *group_base;
6292   LK_ENTRY  *ptr;
6293   char      ou_both[512];
6294   char      ou_security[512];
6295   char      ou_distribution[512];
6296   char      ou_neither[512];
6297   char      group_dn[512];
6298
6299   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6300   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6301
6302   memset(filter, '\0', sizeof(filter));
6303   group_base = NULL;
6304   group_count = 0;
6305
6306   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6307                         "*", MoiraId, 
6308                         "samAccountName", &group_base, 
6309                         &group_count, filter))
6310     return(rc);
6311
6312   if (type == CHECK_GROUPS)
6313     {
6314       if (group_count == 1)
6315         {
6316           strcpy(group_dn, group_base->dn);
6317
6318           if (!strcasecmp(group_dn, distinguishedName))
6319             {
6320               linklist_free(group_base);
6321               return(0);
6322             }
6323         }
6324
6325       linklist_free(group_base);
6326
6327       if (group_count == 0)
6328         return(AD_NO_GROUPS_FOUND);
6329
6330       if (group_count == 1)
6331         return(AD_WRONG_GROUP_DN_FOUND);
6332
6333       return(AD_MULTIPLE_GROUPS_FOUND);
6334     }
6335
6336   if (group_count == 0)
6337     {
6338       return(AD_NO_GROUPS_FOUND);
6339     }
6340
6341   if (group_count > 1)
6342     {
6343       ptr = group_base;
6344
6345       strcpy(group_dn, ptr->dn);
6346
6347       while (ptr != NULL)
6348         {
6349           if (!strcasecmp(group_dn, ptr->value))
6350             break;
6351
6352           ptr = ptr->next;
6353         }
6354
6355       if (ptr == NULL)
6356         {
6357           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6358                   MoiraId);
6359           ptr = group_base;
6360
6361           while (ptr != NULL)
6362             {
6363               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6364               ptr = ptr->next;
6365             }
6366
6367           linklist_free(group_base);
6368           return(AD_MULTIPLE_GROUPS_FOUND);
6369         }
6370
6371       ptr = group_base;
6372
6373       while (ptr != NULL)
6374         {
6375           strcpy(group_dn, ptr->dn);
6376
6377           if (strcasecmp(group_dn, ptr->value))
6378             rc = ldap_delete_s(ldap_handle, ptr->value);
6379
6380           ptr = ptr->next;
6381         }
6382
6383       linklist_free(group_base);
6384       memset(filter, '\0', sizeof(filter));
6385       group_base = NULL;
6386       group_count = 0;
6387
6388       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6389                             "*", MoiraId, 
6390                             "samAccountName", &group_base, 
6391                             &group_count, filter))
6392         return(rc);
6393
6394       if (group_count == 0)
6395         return(AD_NO_GROUPS_FOUND);
6396
6397       if (group_count > 1)
6398         return(AD_MULTIPLE_GROUPS_FOUND);
6399     }
6400
6401   strcpy(ad_distinguishedName, group_base->dn);
6402   linklist_free(group_base);
6403   group_base = NULL;
6404   group_count = 0;
6405
6406   attr_array[0] = "sAMAccountName";
6407   attr_array[1] = NULL;
6408   
6409   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6410                            &group_base, &group_count, 
6411                            LDAP_SCOPE_SUBTREE)) != 0)
6412     {
6413       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6414               MoiraId, ldap_err2string(rc));
6415       return(rc);
6416     }
6417   
6418   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6419
6420   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6421     {
6422       linklist_free(group_base);
6423       group_base = NULL;
6424       group_count = 0;
6425       return(0);
6426     }
6427
6428   linklist_free(group_base);
6429   group_base = NULL;
6430   group_count = 0;
6431   memset(ou_both, '\0', sizeof(ou_both));
6432   memset(ou_security, '\0', sizeof(ou_security));
6433   memset(ou_distribution, '\0', sizeof(ou_distribution));
6434   memset(ou_neither, '\0', sizeof(ou_neither));
6435   memset(before_name, '\0', sizeof(before_name));
6436   memset(before_desc, '\0', sizeof(before_desc));
6437   memset(before_group_membership, '\0', sizeof(before_group_membership));
6438   
6439   attr_array[0] = "name";
6440   attr_array[1] = NULL;
6441
6442   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6443                            &group_base, &group_count, 
6444                            LDAP_SCOPE_SUBTREE)) != 0)
6445     {
6446       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6447               MoiraId, ldap_err2string(rc));
6448       return(rc);
6449     }
6450
6451   strcpy(before_name, group_base->value);
6452   linklist_free(group_base);
6453   group_base = NULL;
6454   group_count = 0;
6455
6456   attr_array[0] = "description";
6457   attr_array[1] = NULL;
6458   
6459   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6460                            &group_base, &group_count, 
6461                            LDAP_SCOPE_SUBTREE)) != 0)
6462     {
6463       com_err(whoami, 0, 
6464               "Unable to get list description with MoiraId = %s: %s",
6465               MoiraId, ldap_err2string(rc));
6466       return(rc);
6467     }
6468
6469   if (group_count != 0)
6470     {
6471       strcpy(before_desc, group_base->value);
6472       linklist_free(group_base);
6473       group_base = NULL;
6474       group_count = 0;
6475     }
6476  
6477   change_to_lower_case(ad_distinguishedName);  
6478   strcpy(ou_both, group_ou_both);
6479   change_to_lower_case(ou_both);
6480   strcpy(ou_security, group_ou_security);
6481   change_to_lower_case(ou_security);
6482   strcpy(ou_distribution, group_ou_distribution);
6483   change_to_lower_case(ou_distribution);
6484   strcpy(ou_neither, group_ou_neither);
6485   change_to_lower_case(ou_neither);
6486
6487   if (strstr(ad_distinguishedName, ou_both))
6488     {
6489       strcpy(before_group_ou, group_ou_both);
6490       before_group_membership[0] = 'B';
6491       before_security_flag = 1;
6492     }
6493   else if (strstr(ad_distinguishedName, ou_security))
6494     {
6495       strcpy(before_group_ou, group_ou_security);
6496       before_group_membership[0] = 'S';
6497       before_security_flag = 1;
6498     }
6499   else if (strstr(ad_distinguishedName, ou_distribution))
6500     {
6501       strcpy(before_group_ou, group_ou_distribution);
6502       before_group_membership[0] = 'D';
6503       before_security_flag = 0;
6504     }
6505   else if (strstr(ad_distinguishedName, ou_neither))
6506     {
6507       strcpy(before_group_ou, group_ou_neither);
6508       before_group_membership[0] = 'N';
6509       before_security_flag = 0;
6510     }
6511   else
6512     return(AD_NO_OU_FOUND);
6513
6514   rc = group_rename(ldap_handle, dn_path, before_name, 
6515                     before_group_membership, 
6516                     before_group_ou, before_security_flag, before_desc,
6517                     group_name, group_membership, group_ou, 
6518                     group_security_flag,
6519                     before_desc, MoiraId, filter, maillist);
6520
6521   return(rc);
6522 }
6523
6524 void change_to_lower_case(char *ptr)
6525 {
6526   int i;
6527
6528   for (i = 0; i < (int)strlen(ptr); i++)
6529     {
6530       ptr[i] = tolower(ptr[i]);
6531     }
6532 }
6533
6534 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6535                  char *group_name, char *group_membership, 
6536                  char *MoiraId, char *attribute,
6537                  LK_ENTRY **linklist_base, int *linklist_count,
6538                  char *rFilter)
6539 {
6540   LK_ENTRY  *pPtr;
6541   char  filter[128];
6542   char  *attr_array[3];
6543   char  *dn;
6544   int   rc;
6545
6546   (*linklist_base) = NULL;
6547   (*linklist_count) = 0;
6548
6549   if (strlen(rFilter) != 0)
6550     {
6551       strcpy(filter, rFilter);
6552       attr_array[0] = attribute;
6553       attr_array[1] = NULL;
6554       
6555       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6556                                linklist_base, linklist_count, 
6557                                LDAP_SCOPE_SUBTREE)) != 0)
6558         {
6559           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6560                   MoiraId, ldap_err2string(rc));
6561          return(rc);
6562        }
6563
6564     if ((*linklist_count) == 1)
6565       {
6566         strcpy(rFilter, filter);
6567         return(0);
6568       }
6569     }
6570
6571   linklist_free((*linklist_base));
6572   (*linklist_base) = NULL;
6573   (*linklist_count) = 0;
6574
6575   if (strlen(MoiraId) != 0)
6576     {
6577       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6578
6579       attr_array[0] = attribute;
6580       attr_array[1] = NULL;
6581
6582       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6583                                linklist_base, linklist_count, 
6584                                LDAP_SCOPE_SUBTREE)) != 0)
6585         {
6586           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6587                   MoiraId, ldap_err2string(rc));
6588          return(rc);
6589        }
6590     }
6591
6592   if ((*linklist_count) > 1)
6593     {
6594       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6595       pPtr = (*linklist_base);
6596
6597       while (pPtr)
6598         {
6599           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6600                   MoiraId);
6601           pPtr = pPtr->next;
6602         }
6603
6604       linklist_free((*linklist_base));
6605       (*linklist_base) = NULL;
6606       (*linklist_count) = 0;
6607     }
6608
6609   if ((*linklist_count) == 1)
6610     {
6611
6612       pPtr = (*linklist_base);
6613       dn = strdup(pPtr->dn);
6614       dn += 3;
6615
6616       if (!memcmp(dn, group_name, strlen(group_name)))
6617         {
6618           strcpy(rFilter, filter);
6619           return(0);
6620         }
6621     }
6622
6623   linklist_free((*linklist_base));
6624   (*linklist_base) = NULL;
6625   (*linklist_count) = 0;
6626   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6627
6628   attr_array[0] = attribute;
6629   attr_array[1] = NULL;
6630
6631   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6632                            linklist_base, linklist_count, 
6633                            LDAP_SCOPE_SUBTREE)) != 0)
6634     {
6635       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6636               MoiraId, ldap_err2string(rc));
6637       return(rc);
6638     }
6639
6640   if ((*linklist_count) == 1)
6641     {
6642       strcpy(rFilter, filter);
6643       return(0);
6644     }
6645
6646   return(0);
6647 }
6648
6649 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6650 {
6651   char filter[128];
6652   char *attr_array[3];
6653   char SamAccountName[64];
6654   int  group_count;
6655   int  rc;
6656   LK_ENTRY  *group_base;
6657   LK_ENTRY  *gPtr;
6658
6659   group_count = 0;
6660   group_base = NULL;
6661
6662   if (strlen(MoiraId) != 0)
6663     {
6664       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6665
6666       attr_array[0] = "sAMAccountName";
6667       attr_array[1] = NULL;
6668       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6669                                &group_base, &group_count, 
6670                                LDAP_SCOPE_SUBTREE)) != 0)
6671         {
6672           com_err(whoami, 0, "Unable to process user %s : %s",
6673                   UserName, ldap_err2string(rc));
6674           return(rc);
6675         }
6676
6677       if (group_count > 1)
6678         {
6679           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6680                   MoiraId);
6681           gPtr = group_base;
6682
6683           while (gPtr)
6684             {
6685               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6686                       gPtr->value, MoiraId);
6687               gPtr = gPtr->next;
6688             }
6689         }
6690     }
6691
6692   if (group_count != 1)
6693     {
6694       linklist_free(group_base);
6695       group_count = 0;
6696       group_base = NULL;
6697       sprintf(filter, "(sAMAccountName=%s)", UserName);
6698       attr_array[0] = "sAMAccountName";
6699       attr_array[1] = NULL;
6700
6701       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6702                                &group_base, &group_count, 
6703                                LDAP_SCOPE_SUBTREE)) != 0)
6704         {
6705           com_err(whoami, 0, "Unable to process user %s : %s",
6706                   UserName, ldap_err2string(rc));
6707           return(rc);
6708         }
6709     }
6710
6711   if (group_count != 1)
6712     {
6713       linklist_free(group_base);
6714       return(AD_NO_USER_FOUND);
6715     }
6716
6717   strcpy(SamAccountName, group_base->value);
6718   linklist_free(group_base);
6719   group_count = 0;
6720   rc = 0;
6721
6722   if (strcmp(SamAccountName, UserName))
6723     {
6724       com_err(whoami, 0, 
6725               "User object %s with MoiraId %s has mismatched usernames " 
6726               "(LDAP username %s, Moira username %s)", SamAccountName,
6727               MoiraId, SamAccountName, UserName);
6728     }
6729
6730   return(0);
6731 }
6732
6733 void container_get_dn(char *src, char *dest)
6734 {
6735   char *sPtr;
6736   char *array[20];
6737   char name[256];
6738   int  n;
6739
6740   memset(array, '\0', 20 * sizeof(array[0]));
6741
6742   if (strlen(src) == 0)
6743     return;
6744
6745   strcpy(name, src);
6746   sPtr = name;
6747   n = 0;
6748   array[n] = name;
6749   ++n;
6750
6751   while (*sPtr)
6752     {
6753       if ((*sPtr) == '/')
6754         {
6755           (*sPtr) = '\0';
6756           ++sPtr;
6757           array[n] = sPtr;
6758           ++n;
6759         }
6760       else
6761         ++sPtr;
6762     }
6763
6764   strcpy(dest, "OU=");
6765
6766   while (n != 0)
6767     {
6768       strcat(dest, array[n-1]);
6769       --n;
6770       if (n > 0)
6771         {
6772           strcat(dest, ",OU=");
6773         }
6774     }
6775
6776   return;
6777 }
6778
6779 void container_get_name(char *src, char *dest)
6780 {
6781   char *sPtr;
6782   char *dPtr;
6783
6784   if (strlen(src) == 0)
6785     return;
6786
6787   sPtr = src;
6788   dPtr = src;
6789
6790   while (*sPtr)
6791     {
6792       if ((*sPtr) == '/')
6793         {
6794           dPtr = sPtr;
6795           ++dPtr;
6796         }
6797       ++sPtr;
6798     }
6799
6800   strcpy(dest, dPtr);
6801   return;
6802 }
6803
6804 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6805 {
6806   char cName[256];
6807   char *av[7];
6808   int  i;
6809   int  rc;
6810
6811   strcpy(cName, name);
6812
6813   for (i = 0; i < (int)strlen(cName); i++)
6814     {
6815       if (cName[i] == '/')
6816         {
6817           cName[i] = '\0';
6818           av[CONTAINER_NAME] = cName;
6819           av[CONTAINER_DESC] = "";
6820           av[CONTAINER_LOCATION] = "";
6821           av[CONTAINER_CONTACT] = "";
6822           av[CONTAINER_TYPE] = "";
6823           av[CONTAINER_ID] = "";
6824           av[CONTAINER_ROWID] = "";
6825           rc = container_create(ldap_handle, dn_path, 7, av);
6826
6827           if (rc == LDAP_SUCCESS)
6828             {
6829               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6830                       cName);
6831             }
6832
6833           cName[i] = '/';
6834         }
6835     }
6836 }
6837
6838 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6839                      char **before, int afterc, char **after)
6840 {
6841   char      dName[256];
6842   char      cName[256];
6843   char      new_cn[128];
6844   char      new_dn_path[256];
6845   char      temp[256];
6846   char      distinguishedName[256];
6847   char      *pPtr;
6848   int       rc;
6849   int       i;
6850
6851   memset(cName, '\0', sizeof(cName));
6852   container_get_name(after[CONTAINER_NAME], cName);
6853
6854   if (!check_container_name(cName))
6855     {
6856       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6857               cName);
6858       return(AD_INVALID_NAME);
6859     }
6860
6861   memset(distinguishedName, '\0', sizeof(distinguishedName));
6862
6863   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6864                                            distinguishedName, beforec, before))
6865     return(rc);
6866
6867   if (strlen(distinguishedName) == 0)
6868     {
6869       rc = container_create(ldap_handle, dn_path, afterc, after);
6870       return(rc);
6871     }
6872
6873   strcpy(temp, after[CONTAINER_NAME]);
6874   pPtr = temp;
6875
6876   for (i = 0; i < (int)strlen(temp); i++)
6877     {
6878       if (temp[i] == '/')
6879         {
6880           pPtr = &temp[i];
6881         }
6882     }
6883
6884   (*pPtr) = '\0';
6885
6886   container_get_dn(temp, dName);
6887
6888   if (strlen(temp) != 0)
6889     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6890   else
6891     sprintf(new_dn_path, "%s", dn_path);
6892
6893   sprintf(new_cn, "OU=%s", cName);
6894
6895   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6896
6897   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6898                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6899     {
6900       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6901               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6902               ldap_err2string(rc));
6903       return(rc);
6904     }
6905
6906   memset(dName, '\0', sizeof(dName));
6907   container_get_dn(after[CONTAINER_NAME], dName);
6908   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6909
6910   return(rc);
6911 }
6912
6913 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6914 {
6915   char      distinguishedName[256];
6916   int       rc;
6917
6918   memset(distinguishedName, '\0', sizeof(distinguishedName));
6919
6920   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6921                                            distinguishedName, count, av))
6922     return(rc);
6923
6924   if (strlen(distinguishedName) == 0)
6925     return(0);
6926
6927   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6928     {
6929       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6930         container_move_objects(ldap_handle, dn_path, distinguishedName);
6931       else
6932         com_err(whoami, 0, "Unable to delete container %s from directory : %s",
6933                 av[CONTAINER_NAME], ldap_err2string(rc));
6934     }
6935
6936   return(rc);
6937 }
6938
6939 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6940 {
6941   char      *attr_array[3];
6942   LK_ENTRY  *group_base;
6943   int       group_count;
6944   LDAPMod   *mods[20];
6945   char      *objectClass_v[] = {"top", 
6946                            "organizationalUnit", 
6947                            NULL};
6948
6949   char *ou_v[] = {NULL, NULL};
6950   char *name_v[] = {NULL, NULL};
6951   char *moiraId_v[] = {NULL, NULL};
6952   char *desc_v[] = {NULL, NULL};
6953   char *managedBy_v[] = {NULL, NULL};
6954   char dName[256];
6955   char cName[256];
6956   char managedByDN[256];
6957   char filter[256];
6958   char temp[256];
6959   int  n;
6960   int  i;
6961   int  rc;
6962     
6963   memset(filter, '\0', sizeof(filter));
6964   memset(dName, '\0', sizeof(dName));
6965   memset(cName, '\0', sizeof(cName));
6966   memset(managedByDN, '\0', sizeof(managedByDN));
6967   container_get_dn(av[CONTAINER_NAME], dName);
6968   container_get_name(av[CONTAINER_NAME], cName);
6969
6970   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6971     {
6972       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6973               cName);
6974       return(AD_INVALID_NAME);
6975     }
6976
6977   if (!check_container_name(cName))
6978     {
6979       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6980               cName);
6981       return(AD_INVALID_NAME);
6982     }
6983
6984   n = 0;
6985   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6986   name_v[0] = cName;
6987   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6988   ou_v[0] = cName;
6989   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6990
6991   if (strlen(av[CONTAINER_ROWID]) != 0)
6992     {
6993       moiraId_v[0] = av[CONTAINER_ROWID];
6994       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6995     }
6996
6997   if (strlen(av[CONTAINER_DESC]) != 0)
6998     {
6999       desc_v[0] = av[CONTAINER_DESC];
7000       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
7001     }
7002
7003   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7004     {
7005       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7006         {
7007           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7008                               kerberos_ou))
7009             {
7010               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7011                       kerberos_ou, dn_path);
7012               managedBy_v[0] = managedByDN;
7013               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
7014             }
7015         }
7016       else
7017         {
7018           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7019             {
7020               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7021                       "(objectClass=user)))", av[CONTAINER_ID]);
7022             }
7023
7024           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7025             {
7026               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7027                       av[CONTAINER_ID]);
7028             }
7029
7030           if (strlen(filter) != 0)
7031             {
7032               attr_array[0] = "distinguishedName";
7033               attr_array[1] = NULL;
7034               group_count = 0;
7035               group_base = NULL;
7036               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7037                                        attr_array, 
7038                                        &group_base, &group_count, 
7039                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7040                 {
7041                   if (group_count == 1)
7042                     {
7043                       strcpy(managedByDN, group_base->value);
7044                       managedBy_v[0] = managedByDN;
7045                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
7046                     }
7047                   linklist_free(group_base);
7048                   group_base = NULL;
7049                   group_count = 0;
7050                 }
7051             }
7052         }
7053     }
7054   
7055   mods[n] = NULL;
7056
7057   sprintf(temp, "%s,%s", dName, dn_path);
7058   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
7059   
7060   for (i = 0; i < n; i++)
7061     free(mods[i]);
7062   
7063   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
7064     {
7065       com_err(whoami, 0, "Unable to create container %s : %s",
7066               cName, ldap_err2string(rc));
7067       return(rc);
7068     }
7069
7070   if (rc == LDAP_ALREADY_EXISTS)
7071     {
7072       if (strlen(av[CONTAINER_ROWID]) != 0)
7073         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
7074     }
7075
7076   return(rc);
7077 }
7078
7079 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
7080                      char **before, int afterc, char **after)
7081 {
7082   char distinguishedName[256];
7083   int  rc;
7084
7085   memset(distinguishedName, '\0', sizeof(distinguishedName));
7086
7087   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
7088                                            distinguishedName, afterc, after))
7089     return(rc);
7090
7091   if (strlen(distinguishedName) == 0)
7092     {
7093       rc = container_create(ldap_handle, dn_path, afterc, after);
7094       return(rc);
7095     }
7096   
7097   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
7098   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
7099                           after);
7100
7101   return(rc);
7102 }
7103
7104 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
7105                                     char *distinguishedName, int count, 
7106                                     char **av)
7107 {
7108   char      *attr_array[3];
7109   LK_ENTRY  *group_base;
7110   int       group_count;
7111   char      dName[256];
7112   char      cName[256];
7113   char      filter[512];
7114   int       rc;
7115
7116   memset(filter, '\0', sizeof(filter));
7117   memset(dName, '\0', sizeof(dName));
7118   memset(cName, '\0', sizeof(cName));
7119   container_get_dn(av[CONTAINER_NAME], dName);
7120   container_get_name(av[CONTAINER_NAME], cName);
7121
7122   if (strlen(dName) == 0)
7123     {
7124       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7125               av[CONTAINER_NAME]);
7126       return(AD_INVALID_NAME);
7127     }
7128
7129   if (!check_container_name(cName))
7130     {
7131       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7132               cName);
7133       return(AD_INVALID_NAME);
7134     }
7135   
7136   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7137           av[CONTAINER_ROWID]);
7138   attr_array[0] = "distinguishedName";
7139   attr_array[1] = NULL;
7140   group_count = 0;
7141   group_base = NULL;
7142
7143   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7144                            &group_base, &group_count, 
7145                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7146     {
7147       if (group_count == 1)
7148         {
7149           strcpy(distinguishedName, group_base->value);
7150         }
7151
7152       linklist_free(group_base);
7153       group_base = NULL;
7154       group_count = 0;
7155     }
7156
7157   if (strlen(distinguishedName) == 0)
7158     {
7159       sprintf(filter, "(&(objectClass=organizationalUnit)"
7160               "(distinguishedName=%s,%s))", dName, dn_path);
7161       attr_array[0] = "distinguishedName";
7162       attr_array[1] = NULL;
7163       group_count = 0;
7164       group_base = NULL;
7165
7166       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7167                                &group_base, &group_count, 
7168                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7169         {
7170           if (group_count == 1)
7171             {
7172               strcpy(distinguishedName, group_base->value);
7173             }
7174
7175           linklist_free(group_base);
7176           group_base = NULL;
7177           group_count = 0;
7178         }
7179     }
7180
7181   return(0);
7182 }
7183
7184 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7185                        char *distinguishedName, int count, char **av)
7186 {
7187   char      *attr_array[5];
7188   LK_ENTRY  *group_base;
7189   LK_ENTRY  *pPtr;
7190   LDAPMod   *mods[20];
7191   int       group_count;
7192   char      filter[512];
7193   char      *moiraId_v[] = {NULL, NULL};
7194   char      *desc_v[] = {NULL, NULL};
7195   char      *managedBy_v[] = {NULL, NULL};
7196   char      managedByDN[256];
7197   char      moiraId[64];
7198   char      desc[256];
7199   char      ad_path[512];
7200   int       rc;
7201   int       i;
7202   int       n;
7203
7204
7205   strcpy(ad_path, distinguishedName);
7206
7207   if (strlen(dName) != 0)
7208     sprintf(ad_path, "%s,%s", dName, dn_path);
7209
7210   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7211           ad_path);
7212
7213   if (strlen(av[CONTAINER_ID]) != 0)
7214     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7215             av[CONTAINER_ROWID]);
7216
7217   attr_array[0] = "mitMoiraId";
7218   attr_array[1] = "description";
7219   attr_array[2] = "managedBy";
7220   attr_array[3] = NULL;
7221   group_count = 0;
7222   group_base = NULL;
7223
7224   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7225                            &group_base, &group_count, 
7226                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7227     {
7228       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7229               av[CONTAINER_NAME], ldap_err2string(rc));
7230       return(rc);
7231     }
7232
7233   memset(managedByDN, '\0', sizeof(managedByDN));
7234   memset(moiraId, '\0', sizeof(moiraId));
7235   memset(desc, '\0', sizeof(desc));
7236   pPtr = group_base;
7237
7238   while (pPtr)
7239     {
7240       if (!strcasecmp(pPtr->attribute, "description"))
7241         strcpy(desc, pPtr->value);
7242       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7243         strcpy(managedByDN, pPtr->value);
7244       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7245         strcpy(moiraId, pPtr->value);
7246       pPtr = pPtr->next;
7247     }
7248
7249   linklist_free(group_base);
7250   group_base = NULL;
7251   group_count = 0;
7252
7253   n = 0;
7254   if (strlen(av[CONTAINER_ROWID]) != 0)
7255     {
7256       moiraId_v[0] = av[CONTAINER_ROWID];
7257       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7258     }
7259
7260   if (strlen(av[CONTAINER_DESC]) != 0)
7261     {
7262       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7263                        dName);
7264     }
7265   else
7266     {
7267       if (strlen(desc) != 0)
7268         {
7269           attribute_update(ldap_handle, ad_path, "", "description", dName);
7270         }
7271     }
7272
7273   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7274     {
7275       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7276         {
7277           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7278                               kerberos_ou))
7279             {
7280               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7281                       kerberos_ou, dn_path);
7282               managedBy_v[0] = managedByDN;
7283               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7284             }
7285           else
7286             {
7287               if (strlen(managedByDN) != 0)
7288                 {
7289                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7290                                    dName);
7291                 }
7292             }
7293         }
7294       else
7295         {
7296           memset(filter, '\0', sizeof(filter));
7297
7298           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7299             {
7300               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7301                       "(objectClass=user)))", av[CONTAINER_ID]);
7302             }
7303
7304           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7305             {
7306               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7307                       av[CONTAINER_ID]);
7308             }
7309
7310           if (strlen(filter) != 0)
7311             {
7312               attr_array[0] = "distinguishedName";
7313               attr_array[1] = NULL;
7314               group_count = 0;
7315               group_base = NULL;
7316               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7317                                        attr_array, &group_base, &group_count, 
7318                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7319                 {
7320                   if (group_count == 1)
7321                     {
7322                       strcpy(managedByDN, group_base->value);
7323                       managedBy_v[0] = managedByDN;
7324                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7325                     }
7326                   else
7327                     {
7328                       if (strlen(managedByDN) != 0)
7329                         {
7330                           attribute_update(ldap_handle, ad_path, "", 
7331                                            "managedBy", dName);
7332                         }
7333                     }
7334
7335                   linklist_free(group_base);
7336                   group_base = NULL;
7337                   group_count = 0;
7338                 }
7339             }
7340           else
7341             {
7342               if (strlen(managedByDN) != 0)
7343                 {
7344                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7345                                    dName);
7346                 }
7347             }
7348         }
7349     }
7350
7351   mods[n] = NULL;
7352
7353   if (n == 0)
7354     return(LDAP_SUCCESS);
7355
7356   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7357
7358   for (i = 0; i < n; i++)
7359     free(mods[i]);
7360
7361   if (rc != LDAP_SUCCESS)
7362     {
7363       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7364               av[CONTAINER_NAME], ldap_err2string(rc));
7365       return(rc);
7366     }
7367   
7368   return(rc);
7369 }
7370
7371 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7372 {
7373   char      *attr_array[3];
7374   LK_ENTRY  *group_base;
7375   LK_ENTRY  *pPtr;
7376   int       group_count;
7377   char      filter[512];
7378   char      new_cn[128];
7379   char      temp[256];
7380   int       rc;
7381   int       NumberOfEntries = 10;
7382   int       i;
7383   int       count;
7384
7385   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7386
7387   for (i = 0; i < 3; i++)
7388     {
7389       memset(filter, '\0', sizeof(filter));
7390
7391       if (i == 0)
7392         {
7393           strcpy(filter, "(!(|(objectClass=computer)"
7394                  "(objectClass=organizationalUnit)))");
7395           attr_array[0] = "cn";
7396           attr_array[1] = NULL;
7397         }
7398       else if (i == 1)
7399         {
7400           strcpy(filter, "(objectClass=computer)");
7401           attr_array[0] = "cn";
7402           attr_array[1] = NULL;
7403         }
7404       else
7405         {
7406           strcpy(filter, "(objectClass=organizationalUnit)");
7407           attr_array[0] = "ou";
7408           attr_array[1] = NULL;
7409         }
7410
7411       while (1)
7412         {
7413           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7414                                    &group_base, &group_count, 
7415                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7416             {
7417               break;
7418             }
7419
7420           if (group_count == 0)
7421             break;
7422
7423           pPtr = group_base;
7424
7425           while(pPtr)
7426             {
7427               if (!strcasecmp(pPtr->attribute, "cn"))
7428                 {
7429                   sprintf(new_cn, "cn=%s", pPtr->value);
7430                   if (i == 0)
7431                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7432                   if (i == 1)
7433                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7434                   count = 1;
7435
7436                   while (1)
7437                     {
7438                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7439                                          TRUE, NULL, NULL);
7440                       if (rc == LDAP_ALREADY_EXISTS)
7441                         {
7442                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7443                           ++count;
7444                         }
7445                       else
7446                         break;
7447                     }
7448                 }
7449               else if (!strcasecmp(pPtr->attribute, "ou"))
7450                 {
7451                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7452                 }
7453
7454               pPtr = pPtr->next;
7455             }
7456
7457           linklist_free(group_base);
7458           group_base = NULL;
7459           group_count = 0;
7460         }
7461     }
7462
7463   return(0);
7464 }
7465
7466 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7467                    char *machine_ou, char *NewMachineName)
7468 {
7469   LK_ENTRY  *group_base;
7470   int  group_count;
7471   int  i;
7472   char filter[128];
7473   char *attr_array[3];
7474   char cn[256];
7475   char dn[256];
7476   char temp[256];
7477   char *pPtr;
7478   int   rc;
7479
7480   strcpy(NewMachineName, member);
7481   rc = moira_connect();
7482   rc = GetMachineName(NewMachineName);
7483   moira_disconnect();
7484
7485   if (strlen(NewMachineName) == 0)
7486     {
7487       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7488               member);
7489       return(1);
7490     }
7491
7492   pPtr = NULL;
7493   pPtr = strchr(NewMachineName, '.');
7494
7495   if (pPtr != NULL)
7496     (*pPtr) = '\0';
7497
7498   group_base = NULL;
7499   group_count = 0;
7500   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7501   attr_array[0] = "cn";
7502   attr_array[1] = NULL;
7503   sprintf(temp, "%s", dn_path);
7504
7505   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7506                            &group_base, &group_count, 
7507                            LDAP_SCOPE_SUBTREE)) != 0)
7508     {
7509       com_err(whoami, 0, "Unable to process machine %s : %s",
7510               member, ldap_err2string(rc));
7511       return(1);
7512     }
7513
7514   if (group_count != 1)
7515     {
7516       return(1);
7517     }
7518
7519   strcpy(dn, group_base->dn);
7520   strcpy(cn, group_base->value);
7521
7522   for (i = 0; i < (int)strlen(dn); i++)
7523     dn[i] = tolower(dn[i]);
7524
7525   for (i = 0; i < (int)strlen(cn); i++)
7526     cn[i] = tolower(cn[i]);
7527
7528   linklist_free(group_base);
7529   pPtr = NULL;
7530   pPtr = strstr(dn, cn);
7531
7532   if (pPtr == NULL)
7533     {
7534       com_err(whoami, 0, "Unable to process machine %s",
7535               member);
7536       return(1);
7537     }
7538
7539   pPtr += strlen(cn) + 1;
7540   strcpy(machine_ou, pPtr);
7541   pPtr = NULL;
7542   pPtr = strstr(machine_ou, "dc=");
7543
7544   if (pPtr == NULL)
7545     {
7546       com_err(whoami, 0, "Unable to process machine %s",
7547               member);
7548       return(1);
7549     }
7550
7551   --pPtr;
7552   (*pPtr) = '\0';
7553
7554   return(0);
7555 }
7556
7557 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7558                        char *MoiraMachineName, char *DestinationOu)
7559 {
7560   char        NewCn[128];
7561   char        OldDn[512];
7562   char        MachineName[128];
7563   char        filter[128];
7564   char        *attr_array[3];
7565   char        NewOu[256];
7566   char        *cPtr = NULL;
7567   int         group_count;
7568   long        rc;
7569   LK_ENTRY    *group_base;
7570
7571   group_count = 0;
7572   group_base = NULL;
7573   
7574   strcpy(MachineName, MoiraMachineName);
7575   rc = GetMachineName(MachineName);
7576
7577   if (strlen(MachineName) == 0)
7578     {
7579       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7580               MoiraMachineName);
7581       return(1);
7582     }
7583   
7584   cPtr = strchr(MachineName, '.');
7585
7586   if (cPtr != NULL)
7587     (*cPtr) = '\0';
7588
7589   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7590   attr_array[0] = "sAMAccountName";
7591   attr_array[1] = NULL;
7592
7593   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7594                            &group_base, 
7595                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7596     {
7597       com_err(whoami, 0, "Unable to process machine %s : %s",
7598               MoiraMachineName, ldap_err2string(rc));
7599       return(1);
7600     }
7601   
7602   if (group_count == 1)
7603     strcpy(OldDn, group_base->dn);
7604
7605   linklist_free(group_base);
7606   group_base = NULL;
7607
7608   if (group_count != 1)
7609     {
7610       com_err(whoami, 0, "Unable to find machine %s in directory: %s", 
7611               MoiraMachineName);
7612       return(1);
7613     }
7614
7615   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7616   cPtr = strchr(OldDn, ',');
7617
7618   if (cPtr != NULL)
7619     {
7620       ++cPtr;
7621       if (!strcasecmp(cPtr, NewOu))
7622         return(0);
7623     }
7624
7625   sprintf(NewCn, "CN=%s", MachineName);
7626   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7627
7628   return(rc);
7629 }
7630
7631 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7632 {
7633   char    Name[128];
7634   char    *pPtr;
7635   int     rc;
7636   
7637   memset(Name, '\0', sizeof(Name));
7638   strcpy(Name, machine_name);
7639   pPtr = NULL;
7640   pPtr = strchr(Name, '.');
7641
7642   if (pPtr != NULL)
7643     (*pPtr) = '\0';
7644
7645   strcat(Name, "$");
7646   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7647 }
7648
7649 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7650                                 char *machine_name, char *container_name)
7651 {
7652   int     rc;
7653   char    *av[2];
7654   char    *call_args[2];
7655   
7656   av[0] = machine_name;
7657   call_args[0] = (char *)container_name;
7658   rc = mr_query("get_machine_to_container_map", 1, av, 
7659                 machine_GetMoiraContainer, call_args);
7660   return(rc);
7661 }
7662
7663 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7664 {
7665   char **call_args;
7666   
7667   call_args = ptr;
7668   strcpy(call_args[0], av[1]);
7669   return(0);
7670 }
7671
7672 int Moira_container_group_create(char **after)
7673 {
7674   long rc;
7675   char GroupName[64];
7676   char *argv[20];
7677   
7678   memset(GroupName, '\0', sizeof(GroupName));
7679   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7680                               after[CONTAINER_ROWID]);
7681   if (rc)
7682     return rc;
7683   
7684   argv[L_NAME] = GroupName;
7685   argv[L_ACTIVE] = "1";
7686   argv[L_PUBLIC] = "0";
7687   argv[L_HIDDEN] = "0";
7688   argv[L_MAILLIST] = "0";
7689   argv[L_GROUP] = "1";
7690   argv[L_GID] = UNIQUE_GID;
7691   argv[L_NFSGROUP] = "0";
7692   argv[L_MAILMAN] = "0";
7693   argv[L_MAILMAN_SERVER] = "[NONE]";
7694   argv[L_DESC] = "auto created container group";
7695   argv[L_ACE_TYPE] = "USER";
7696   argv[L_MEMACE_TYPE] = "USER";
7697   argv[L_ACE_NAME] = "sms";
7698   argv[L_MEMACE_NAME] = "sms";
7699
7700   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7701     {
7702       com_err(whoami, 0, 
7703               "Unable to create container group %s for container %s: %s",
7704               GroupName, after[CONTAINER_NAME], error_message(rc));
7705     }
7706
7707   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7708   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7709   
7710   return(rc);
7711 }
7712
7713 int Moira_container_group_update(char **before, char **after)
7714 {
7715   long rc;
7716   char BeforeGroupName[64];
7717   char AfterGroupName[64];
7718   char *argv[20];
7719   
7720   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7721     return(0);
7722
7723   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7724   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7725   if (strlen(BeforeGroupName) == 0)
7726     return(0);
7727
7728   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7729   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7730                               after[CONTAINER_ROWID]);
7731   if (rc)
7732     return rc;
7733
7734   if (strcasecmp(BeforeGroupName, AfterGroupName))
7735     {
7736       argv[L_NAME] = BeforeGroupName;
7737       argv[L_NAME + 1] = AfterGroupName;
7738       argv[L_ACTIVE + 1] = "1";
7739       argv[L_PUBLIC + 1] = "0";
7740       argv[L_HIDDEN + 1] = "0";
7741       argv[L_MAILLIST + 1] = "0";
7742       argv[L_GROUP + 1] = "1";
7743       argv[L_GID + 1] = UNIQUE_GID;
7744       argv[L_NFSGROUP + 1] = "0";
7745       argv[L_MAILMAN + 1] = "0";
7746       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7747       argv[L_DESC + 1] = "auto created container group";
7748       argv[L_ACE_TYPE + 1] = "USER";
7749       argv[L_MEMACE_TYPE + 1] = "USER";
7750       argv[L_ACE_NAME + 1] = "sms";
7751       argv[L_MEMACE_NAME + 1] = "sms";
7752       
7753       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7754         {
7755           com_err(whoami, 0, 
7756                   "Unable to rename container group from %s to %s: %s",
7757                   BeforeGroupName, AfterGroupName, error_message(rc));
7758         }
7759     }
7760   
7761   return(rc);
7762 }
7763
7764 int Moira_container_group_delete(char **before)
7765 {
7766   long rc = 0;
7767   char *argv[13];
7768   char GroupName[64];
7769   char ParentGroupName[64];
7770   
7771   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7772   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7773
7774   memset(GroupName, '\0', sizeof(GroupName));
7775
7776   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7777     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7778   
7779   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7780     {
7781       argv[0] = ParentGroupName;
7782       argv[1] = "LIST";
7783       argv[2] = GroupName;
7784
7785       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7786         {
7787           com_err(whoami, 0, 
7788                   "Unable to delete container group %s from list: %s",
7789                   GroupName, ParentGroupName, error_message(rc));
7790         }
7791     }
7792   
7793   if (strlen(GroupName) != 0)
7794     {
7795       argv[0] = GroupName;
7796
7797       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7798         {
7799           com_err(whoami, 0, "Unable to delete container group %s : %s",
7800                   GroupName, error_message(rc));
7801         }
7802     }
7803   
7804   return(rc);
7805 }
7806
7807 int Moira_groupname_create(char *GroupName, char *ContainerName,
7808                            char *ContainerRowID)
7809 {
7810   char *ptr;
7811   char *ptr1;
7812   char temp[64];
7813   char newGroupName[64];
7814   char tempGroupName[64];
7815   char tempgname[64];
7816   char *argv[1];
7817   int  i;
7818   long rc;
7819
7820   strcpy(temp, ContainerName);
7821   
7822   ptr1 = strrchr(temp, '/');
7823
7824   if (ptr1 != NULL)
7825   {
7826     *ptr1 = '\0';
7827     ptr = ++ptr1;
7828     ptr1 = strrchr(temp, '/');
7829
7830     if (ptr1 != NULL)
7831     {
7832         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7833     }
7834     else
7835         strcpy(tempgname, ptr);
7836   }
7837   else
7838     strcpy(tempgname, temp);
7839
7840   if (strlen(tempgname) > 25)
7841     tempgname[25] ='\0';
7842
7843   sprintf(newGroupName, "cnt-%s", tempgname);
7844
7845   /* change everything to lower case */
7846   ptr = newGroupName;
7847
7848   while (*ptr)
7849     {
7850       if (isupper(*ptr))
7851         *ptr = tolower(*ptr);
7852
7853       if (*ptr == ' ')
7854         *ptr = '-';
7855
7856       ptr++;
7857     }
7858
7859   strcpy(tempGroupName, newGroupName);
7860   i = (int)'0';
7861
7862   /* append 0-9 then a-z if a duplicate is found */
7863   while(1)
7864     {
7865       argv[0] = newGroupName;
7866
7867       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7868         {
7869           if (rc == MR_NO_MATCH)
7870             break;
7871           com_err(whoami, 0, "Moira error while creating group name for "
7872                   "container %s : %s", ContainerName, error_message(rc));
7873           return rc;
7874         }
7875
7876       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7877
7878       if (i == (int)'z')
7879         {
7880           com_err(whoami, 0, "Unable to find a unique group name for "
7881                   "container %s: too many duplicate container names",
7882                   ContainerName);
7883           return 1;
7884         }
7885
7886       if (i == '9')
7887         i = 'a';
7888       else
7889         i++;
7890     }
7891
7892   strcpy(GroupName, newGroupName);
7893   return(0);
7894 }
7895
7896 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7897 {
7898   long rc;
7899   char *argv[3];
7900   
7901   argv[0] = origContainerName;
7902   argv[1] = GroupName;
7903   
7904   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7905     {
7906       com_err(whoami, 0, 
7907               "Unable to set container group %s in container %s: %s",
7908               GroupName, origContainerName, error_message(rc));
7909     }
7910   
7911   return(0);
7912 }
7913
7914 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7915  {
7916    char ContainerName[64];
7917    char ParentGroupName[64];
7918    char *argv[3];
7919    long rc;
7920
7921    strcpy(ContainerName, origContainerName);
7922    
7923    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7924
7925    /* top-level container */
7926    if (strlen(ParentGroupName) == 0)
7927      return(0);
7928    
7929    argv[0] = ParentGroupName;
7930    argv[1] = "LIST";
7931    argv[2] = GroupName;
7932
7933    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7934      {
7935        com_err(whoami, 0, 
7936                "Unable to add container group %s to parent group %s: %s",
7937                GroupName, ParentGroupName, error_message(rc));
7938      }
7939    
7940    return(0);
7941  }
7942
7943 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7944 {
7945   char **call_args;
7946   
7947   call_args = ptr;
7948   strcpy(call_args[0], av[1]);
7949
7950   return(0);
7951 }
7952
7953 int Moira_getGroupName(char *origContainerName, char *GroupName,
7954                        int ParentFlag)
7955 {
7956   char ContainerName[64];
7957   char *argv[3];
7958   char *call_args[3];
7959   char *ptr;
7960   long rc;
7961
7962   strcpy(ContainerName, origContainerName);
7963
7964   if (ParentFlag)
7965     {
7966       ptr = strrchr(ContainerName, '/');
7967
7968       if (ptr != NULL)
7969         (*ptr) = '\0';
7970       else
7971         return(0);
7972     }
7973
7974   argv[0] = ContainerName;
7975   argv[1] = NULL;
7976   call_args[0] = GroupName;
7977   call_args[1] = NULL;
7978
7979   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7980                       call_args)))
7981     {
7982       if (strlen(GroupName) != 0)
7983         return(0);
7984     }
7985
7986   if (rc)
7987     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7988             ContainerName, error_message(rc));
7989   else
7990     com_err(whoami, 0, "Unable to get container group from container %s",
7991             ContainerName);
7992   
7993   return(0);
7994 }
7995
7996 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7997                                           int DeleteMachine)
7998 {
7999   char *argv[3];
8000   long rc;
8001   
8002   if (strcmp(GroupName, "[none]") == 0)
8003     return 0;
8004
8005   argv[0] = GroupName;
8006   argv[1] = "MACHINE";
8007   argv[2] = MachineName;
8008
8009   if (!DeleteMachine)
8010     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
8011   else
8012     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
8013
8014   if (rc)
8015     {
8016       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
8017               MachineName, GroupName, error_message(rc));
8018     }
8019
8020   return(0);
8021 }
8022
8023 int GetMachineName(char *MachineName)
8024 {
8025   char    *args[2];
8026   char    NewMachineName[1024];
8027   char    *szDot;
8028   int     rc = 0;
8029   int     i;
8030   DWORD   dwLen = 0;
8031   char    *call_args[2];
8032   
8033   // If the address happens to be in the top-level MIT domain, great!
8034   strcpy(NewMachineName, MachineName);
8035
8036   for (i = 0; i < (int)strlen(NewMachineName); i++)
8037     NewMachineName[i] = toupper(NewMachineName[i]);
8038
8039   szDot = strchr(NewMachineName,'.');
8040
8041   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
8042     {
8043       return(0);
8044     }
8045   
8046   // If not, see if it has a Moira alias in the top-level MIT domain.
8047   memset(NewMachineName, '\0', sizeof(NewMachineName));
8048   args[0] = "*";
8049   args[1] = MachineName;
8050   call_args[0] = NewMachineName;
8051   call_args[1] = NULL;
8052
8053   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
8054     {
8055       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
8056               MachineName, error_message(rc));
8057       strcpy(MachineName, "");
8058       return(0);
8059     }
8060   
8061   if (strlen(NewMachineName) != 0)
8062     strcpy(MachineName, NewMachineName);
8063   else
8064     strcpy(MachineName, "");
8065
8066   return(0);
8067 }
8068
8069 int ProcessMachineName(int ac, char **av, void *ptr)
8070 {
8071   char    **call_args;
8072   char    MachineName[1024];
8073   char    *szDot;
8074   int     i;
8075   
8076   call_args = ptr;
8077
8078   if (strlen(call_args[0]) == 0)
8079     {
8080       strcpy(MachineName, av[0]);
8081
8082       for (i = 0; i < (int)strlen(MachineName); i++)
8083         MachineName[i] = toupper(MachineName[i]);
8084
8085       szDot = strchr(MachineName,'.');
8086
8087         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
8088           {
8089             strcpy(call_args[0], MachineName);
8090           }
8091     }
8092
8093   return(0);
8094 }
8095
8096 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
8097 {
8098   int i;
8099   
8100   if (*UseSFU30)
8101     {
8102       for (i = 0; i < n; i++)
8103         {
8104           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
8105             mods[i]->mod_type = "uidNumber";
8106         }
8107
8108       (*UseSFU30) = 0;
8109     }
8110   else
8111     {
8112       for (i = 0; i < n; i++)
8113         {
8114           if (!strcmp(mods[i]->mod_type, "uidNumber"))
8115             mods[i]->mod_type = "msSFU30UidNumber";
8116         }
8117
8118       (*UseSFU30) = 1;
8119     }
8120 }
8121
8122 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8123                      char *DistinguishedName,
8124                      char *WinHomeDir, char *WinProfileDir,
8125                      char **homedir_v, char **winProfile_v,
8126                      char **drives_v, LDAPMod **mods, 
8127                      int OpType, int n)
8128 {
8129   char cWeight[3];
8130   char cPath[1024];
8131   char path[1024];
8132   char winPath[1024];
8133   char winProfile[1024];
8134   char homeDrive[8];
8135   char homedir[1024];
8136   char apple_homedir[1024];
8137   char *apple_homedir_v[] = {NULL, NULL};
8138   int  last_weight;
8139   int  i;
8140   int  rc;
8141   LDAPMod *DelMods[20];
8142   char *argv[3];
8143   char *save_argv[FS_END];
8144   char *fsgroup_save_argv[2];
8145
8146   memset(homeDrive, '\0', sizeof(homeDrive));
8147   memset(path, '\0', sizeof(path));
8148   memset(winPath, '\0', sizeof(winPath));
8149   memset(winProfile, '\0', sizeof(winProfile));
8150
8151   if(!ActiveDirectory) 
8152     {
8153       if (rc = moira_connect())
8154         {
8155           critical_alert("Ldap incremental",
8156                          "Error contacting Moira server : %s",
8157                          error_message(rc));
8158           return;
8159         }
8160       
8161       argv[0] = user_name;
8162
8163       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8164                           save_argv)))
8165         {
8166           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8167              !strcmp(save_argv[FS_TYPE], "MUL"))
8168             {
8169         
8170               argv[0] = save_argv[FS_NAME];
8171               fsgCount = 0;
8172               
8173               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8174                                   save_fsgroup_info, fsgroup_save_argv)))
8175                 {
8176                   if(fsgCount)
8177                     {
8178                       argv[0] = fsgroup_save_argv[0];
8179                       
8180                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8181                                           save_query_info, save_argv)))
8182                         {
8183                           strcpy(path, save_argv[FS_PACK]);
8184                         }
8185                     }
8186                 }
8187             }
8188           else
8189             {
8190               strcpy(path, save_argv[FS_PACK]);
8191             }
8192         }
8193       
8194       moira_disconnect();
8195
8196       if (strlen(path))
8197         {
8198           if (!strnicmp(path, AFS, strlen(AFS)))
8199             {
8200               sprintf(homedir, "%s", path);
8201               sprintf(apple_homedir, "%s/MacData", path);
8202               homedir_v[0] = homedir;
8203               apple_homedir_v[0] = apple_homedir;
8204               ADD_ATTR("homeDirectory", homedir_v, OpType);
8205               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8206                        OpType);
8207             }
8208         }
8209       else
8210         {
8211           homedir_v[0] = "NONE";
8212           apple_homedir_v[0] = "NONE";
8213           ADD_ATTR("homeDirectory", homedir_v, OpType);
8214           ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8215                    OpType);
8216         }
8217
8218       return(n);
8219     }
8220  
8221   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8222       (!strcasecmp(WinProfileDir, "[afs]")))
8223     {
8224       if (rc = moira_connect())
8225         {
8226           critical_alert("Ldap incremental",
8227                          "Error contacting Moira server : %s",
8228                          error_message(rc));
8229           return;
8230         }
8231       
8232       argv[0] = user_name;
8233
8234       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8235                           save_argv)))
8236         {
8237           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8238              !strcmp(save_argv[FS_TYPE], "MUL"))
8239             {
8240         
8241               argv[0] = save_argv[FS_NAME];
8242               fsgCount = 0;
8243               
8244               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8245                                   save_fsgroup_info, fsgroup_save_argv)))
8246                 {
8247                   if(fsgCount)
8248                     {
8249                       argv[0] = fsgroup_save_argv[0];
8250                       
8251                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8252                                           save_query_info, save_argv)))
8253                         {
8254                           strcpy(path, save_argv[FS_PACK]);
8255                         }
8256                     }
8257                 }
8258             }
8259           else
8260             {
8261               strcpy(path, save_argv[FS_PACK]);
8262             }
8263         }
8264      
8265       moira_disconnect();
8266
8267       if (strlen(path))
8268         {
8269           if (!strnicmp(path, AFS, strlen(AFS)))
8270             {
8271               AfsToWinAfs(path, winPath);
8272               strcpy(winProfile, winPath);
8273               strcat(winProfile, "\\.winprofile");
8274             }
8275         }
8276       else
8277         return(n);
8278     }
8279
8280     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8281         (!strcasecmp(WinProfileDir, "[dfs]")))
8282     {
8283       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8284               user_name[0], user_name);
8285
8286       if (!strcasecmp(WinProfileDir, "[dfs]"))
8287         {
8288           strcpy(winProfile, path);
8289           strcat(winProfile, "\\.winprofile");
8290         }
8291
8292       if (!strcasecmp(WinHomeDir, "[dfs]"))
8293         strcpy(winPath, path);
8294     }
8295     
8296     if (!strcasecmp(WinHomeDir, "[local]"))
8297       memset(winPath, '\0', sizeof(winPath));
8298     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8299              !strcasecmp(WinHomeDir, "[dfs]"))
8300       {
8301         strcpy(homeDrive, "H:");
8302       }
8303     else
8304       {
8305         strcpy(winPath, WinHomeDir);
8306         if (!strncmp(WinHomeDir, "\\\\", 2))
8307           {
8308             strcpy(homeDrive, "H:");
8309           }        
8310       }
8311     
8312     // nothing needs to be done if WinProfileDir is [afs].
8313     if (!strcasecmp(WinProfileDir, "[local]"))
8314       memset(winProfile, '\0', sizeof(winProfile));
8315     else if (strcasecmp(WinProfileDir, "[afs]") && 
8316              strcasecmp(WinProfileDir, "[dfs]"))
8317       {
8318         strcpy(winProfile, WinProfileDir);
8319       }
8320     
8321     if (strlen(winProfile) != 0)
8322       {
8323         if (winProfile[strlen(winProfile) - 1] == '\\')
8324           winProfile[strlen(winProfile) - 1] = '\0';
8325       }
8326
8327     if (strlen(winPath) != 0)
8328       {
8329         if (winPath[strlen(winPath) - 1] == '\\')
8330           winPath[strlen(winPath) - 1] = '\0';
8331       }
8332     
8333     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8334       strcat(winProfile, "\\");
8335
8336     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8337       strcat(winPath, "\\");
8338     
8339     if (strlen(winPath) == 0)
8340       {
8341         if (OpType == LDAP_MOD_REPLACE)
8342           {
8343             i = 0;
8344             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8345             DelMods[i] = NULL;
8346             //unset homeDirectory attribute for user.
8347             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8348             free(DelMods[0]);
8349           }
8350       }
8351     else
8352       {
8353         homedir_v[0] = strdup(winPath);
8354         ADD_ATTR("homeDirectory", homedir_v, OpType);
8355       }
8356     
8357     if (strlen(winProfile) == 0)
8358       {
8359         if (OpType == LDAP_MOD_REPLACE)
8360           {
8361             i = 0;
8362             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8363             DelMods[i] = NULL;
8364             //unset profilePate attribute for user.
8365             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8366             free(DelMods[0]);
8367           }
8368       }
8369     else
8370       {
8371         winProfile_v[0] = strdup(winProfile);
8372         ADD_ATTR("profilePath", winProfile_v, OpType);
8373       }
8374     
8375     if (strlen(homeDrive) == 0)
8376       {
8377         if (OpType == LDAP_MOD_REPLACE)
8378           {
8379             i = 0;
8380             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8381             DelMods[i] = NULL;
8382             //unset homeDrive attribute for user
8383             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8384             free(DelMods[0]);
8385           }
8386       }
8387     else
8388       {
8389         drives_v[0] = strdup(homeDrive);
8390         ADD_ATTR("homeDrive", drives_v, OpType);
8391       }
8392
8393     return(n);
8394 }
8395
8396 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8397                      char *attribute_value, char *attribute, char *user_name)
8398 {
8399   char      *mod_v[] = {NULL, NULL};
8400   LDAPMod   *DelMods[20];
8401   LDAPMod   *mods[20];
8402   int       n;
8403   int       i;
8404   int       rc;
8405   
8406   if (strlen(attribute_value) == 0)
8407     {
8408       i = 0;
8409       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8410       DelMods[i] = NULL;
8411       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8412       free(DelMods[0]);
8413     }
8414   else
8415     {
8416       n = 0;
8417       mod_v[0] = attribute_value;
8418       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8419       mods[n] = NULL;
8420
8421       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8422                               mods)) != LDAP_SUCCESS)
8423         {
8424           free(mods[0]);
8425           n = 0;
8426           mod_v[0] = attribute_value;
8427           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8428           mods[n] = NULL;
8429
8430           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8431                                   mods)) != LDAP_SUCCESS)
8432             {
8433               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8434                       "in the directory : %s",
8435                       attribute, user_name, ldap_err2string(rc));
8436             }
8437         }
8438
8439       free(mods[0]);
8440     }
8441   
8442   return(rc);
8443 }
8444
8445 void StringTrim(char *StringToTrim)
8446 {
8447   char *t, *s;
8448   char *save;
8449
8450   save = strdup(StringToTrim);
8451
8452   s = save;
8453
8454   while (isspace(*s))
8455     s++;
8456
8457   /* skip to end of string */
8458   if (*s == '\0')
8459     {
8460       if (*save)
8461         *save = '\0';
8462       strcpy(StringToTrim, save);
8463       return;
8464     }
8465   
8466   for (t = s; *t; t++)
8467     continue;
8468
8469   while (t > s)
8470     {
8471       --t;
8472       if (!isspace(*t))
8473         {
8474           t++;
8475           break;
8476         }
8477     }
8478
8479   if (*t)
8480     *t = '\0';
8481   
8482   strcpy(StringToTrim, s);
8483   return;
8484 }
8485
8486 int ReadConfigFile(char *DomainName)
8487 {
8488     int     Count;
8489     int     i;
8490     int     k;
8491     char    temp[256];
8492     char    temp1[256];
8493     FILE    *fptr;
8494
8495     Count = 0;
8496
8497     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8498
8499     if ((fptr = fopen(temp, "r")) != NULL)
8500       {
8501         while (fgets(temp, sizeof(temp), fptr) != 0)
8502           {
8503             for (i = 0; i < (int)strlen(temp); i++)
8504               temp[i] = toupper(temp[i]);
8505
8506             if (temp[strlen(temp) - 1] == '\n')
8507               temp[strlen(temp) - 1] = '\0';
8508
8509             StringTrim(temp);
8510
8511             if (strlen(temp) == 0)
8512               continue;
8513
8514             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8515               {
8516                 if (strlen(temp) > (strlen(DOMAIN)))
8517                   {
8518                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8519                     StringTrim(ldap_domain);
8520                   }
8521               }
8522             else if (!strncmp(temp, REALM, strlen(REALM)))
8523               {
8524                 if (strlen(temp) > (strlen(REALM)))
8525                   {
8526                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8527                     StringTrim(ldap_realm);
8528                   }
8529               }
8530             else if (!strncmp(temp, PORT, strlen(PORT)))
8531               {
8532                 if (strlen(temp) > (strlen(PORT)))
8533                   {
8534                     strcpy(ldap_port, &temp[strlen(PORT)]);
8535                     StringTrim(ldap_port);
8536                   }
8537               }
8538             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8539               {
8540                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8541                   {
8542                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8543                     StringTrim(PrincipalName);
8544                   }
8545               }
8546             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8547               {
8548                 if (strlen(temp) > (strlen(SERVER)))
8549                   {
8550                     ServerList[Count] = calloc(1, 256);
8551                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8552                     StringTrim(ServerList[Count]);
8553                     ++Count;
8554                   }
8555               }
8556             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8557               {
8558                 if (strlen(temp) > (strlen(MSSFU)))
8559                   {
8560                     strcpy(temp1, &temp[strlen(MSSFU)]);
8561                     StringTrim(temp1);
8562                     if (!strcmp(temp1, SFUTYPE))
8563                       UseSFU30 = 1;
8564                   }
8565               }
8566             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8567               {
8568                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8569                   {
8570                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8571                     StringTrim(temp1);
8572                     if (!strcasecmp(temp1, "NO")) 
8573                       {
8574                         UseGroupSuffix = 0;
8575                         memset(group_suffix, '\0', sizeof(group_suffix));
8576                       }
8577                   }
8578               }
8579             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8580               {
8581                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8582                   {
8583                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8584                     StringTrim(temp1);
8585                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8586                       UseGroupUniversal = 1;
8587                   }
8588               }
8589             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8590               {
8591                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8592                   {
8593                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8594                     StringTrim(temp1);
8595                     if (!strcasecmp(temp1, "NO"))
8596                       SetGroupAce = 0;
8597                   }
8598               }
8599             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8600               {
8601                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8602                   {
8603                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8604                     StringTrim(temp1);
8605                     if (!strcasecmp(temp1, "NO"))
8606                       SetPassword = 0;
8607                   }
8608               }
8609             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8610               {
8611                 if (strlen(temp) > (strlen(EXCHANGE)))
8612                   {
8613                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8614                     StringTrim(temp1);
8615                     if (!strcasecmp(temp1, "YES"))
8616                       Exchange = 1;
8617                   }
8618               }
8619             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8620                               strlen(PROCESS_MACHINE_CONTAINER)))
8621               {
8622                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8623                   {
8624                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8625                     StringTrim(temp1);
8626                     if (!strcasecmp(temp1, "NO"))
8627                       ProcessMachineContainer = 0;
8628                   }
8629               }
8630             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8631                               strlen(ACTIVE_DIRECTORY)))
8632               {
8633                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8634                   {
8635                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8636                     StringTrim(temp1);
8637                     if (!strcasecmp(temp1, "NO"))
8638                       ActiveDirectory = 0;
8639                   }
8640               }
8641             else if (!strncmp(temp, GROUP_POPULATE_MEMBERS, 
8642                               strlen(GROUP_POPULATE_MEMBERS)))
8643               {
8644                 if (strlen(temp) > (strlen(GROUP_POPULATE_MEMBERS)))
8645                   {
8646                     strcpy(temp1, &temp[strlen(GROUP_POPULATE_MEMBERS)]);
8647                     StringTrim(temp1);
8648                     if (!strcasecmp(temp1, "DELETE")) 
8649                       {
8650                         GroupPopulateDelete = 1;
8651                       }
8652                   }
8653               }
8654             else
8655               {
8656                 if (strlen(ldap_domain) != 0)
8657                   {
8658                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8659                     break;
8660                   }
8661
8662                 if (strlen(temp) != 0)
8663                   strcpy(ldap_domain, temp);
8664               }
8665           }
8666         fclose(fptr);
8667       }
8668     
8669     if (strlen(ldap_domain) == 0)
8670       {
8671       strcpy(ldap_domain, DomainName);
8672       }
8673
8674     if (Count == 0)
8675         return(0);
8676
8677     for (i = 0; i < Count; i++)
8678       {
8679         if (ServerList[i] != 0)
8680           {
8681             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8682               ServerList[i][k] = toupper(ServerList[i][k]);
8683           }
8684       }
8685     
8686     return(0);
8687 }
8688
8689 int ReadDomainList()
8690 {
8691   int     Count;
8692   int     i;
8693   char    temp[128];
8694   char    temp1[128];
8695   FILE    *fptr;
8696   unsigned char c[11];
8697   unsigned char stuff[256];
8698   int     rc;
8699   int     ok;
8700
8701   Count = 0;
8702   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8703
8704   if ((fptr = fopen(temp, "r")) != NULL)
8705     {
8706       while (fgets(temp, sizeof(temp), fptr) != 0)
8707         {
8708           for (i = 0; i < (int)strlen(temp); i++)
8709             temp[i] = toupper(temp[i]);
8710
8711           if (temp[strlen(temp) - 1] == '\n')
8712             temp[strlen(temp) - 1] = '\0';
8713
8714           StringTrim(temp);
8715
8716           if (strlen(temp) == 0)
8717             continue;
8718
8719           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8720             {
8721               if (strlen(temp) > (strlen(DOMAIN)))
8722                 {
8723                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8724                   StringTrim(temp1);
8725                   strcpy(temp, temp1);
8726                 }
8727             }
8728           
8729           strcpy(DomainNames[Count], temp);
8730           StringTrim(DomainNames[Count]);
8731           ++Count;
8732         }
8733
8734       fclose(fptr);
8735     }
8736
8737   if (Count == 0)
8738     {
8739       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8740                      "configuration error in ldap.cfg");
8741       return(1);
8742     }
8743   
8744   return(0);
8745 }
8746
8747 int email_isvalid(const char *address) {
8748   int        count = 0;
8749   const char *c, *domain;
8750   static char *rfc822_specials = "()<>@,;:\\\"[]";
8751
8752   if(address[strlen(address) - 1] == '.') 
8753     return 0;
8754     
8755   /* first we validate the name portion (name@domain) */
8756   for (c = address;  *c;  c++) {
8757     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8758                        '\"')) {
8759       while (*++c) {
8760         if (*c == '\"') 
8761           break;
8762         if (*c == '\\' && (*++c == ' ')) 
8763           continue;
8764         if (*c <= ' ' || *c >= 127) 
8765           return 0;
8766       }
8767
8768       if (!*c++) 
8769         return 0;
8770       if (*c == '@') 
8771         break;
8772       if (*c != '.') 
8773         return 0;
8774       continue;
8775     }
8776
8777     if (*c == '@') 
8778       break;
8779     if (*c <= ' ' || *c >= 127) 
8780       return 0;
8781     if (strchr(rfc822_specials, *c)) 
8782       return 0;
8783   }
8784
8785   if (c == address || *(c - 1) == '.') 
8786     return 0;
8787
8788   /* next we validate the domain portion (name@domain) */
8789   if (!*(domain = ++c)) return 0;
8790   do {
8791     if (*c == '.') {
8792       if (c == domain || *(c - 1) == '.') 
8793         return 0;
8794       count++;
8795     }
8796     if (*c <= ' ' || *c >= 127) 
8797       return 0;
8798     if (strchr(rfc822_specials, *c)) 
8799       return 0;
8800   } while (*++c);
8801
8802   return (count >= 1);
8803 }
8804
8805 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8806              char **homeServerName) 
8807 {
8808   LK_ENTRY *group_base;
8809   LK_ENTRY *sub_group_base;
8810   LK_ENTRY *gPtr;
8811   LK_ENTRY *sub_gPtr;
8812   int      group_count;
8813   int      sub_group_count;
8814   char     filter[1024];
8815   char     sub_filter[1024];
8816   char     search_path[1024];
8817   char     range[1024];
8818   char     *attr_array[3];
8819   char     *s;
8820   int      homeMDB_count = -1;
8821   int      rc;
8822   int      i;
8823   int      mdbbl_count;
8824   int      rangeStep = 1500;
8825   int      rangeLow = 0;
8826   int      rangeHigh = rangeLow + (rangeStep - 1);
8827   int      isLast = 0;
8828
8829   /* Grumble..... microsoft not making it searchable from the root *grr* */
8830
8831   memset(filter, '\0', sizeof(filter));
8832   memset(search_path, '\0', sizeof(search_path));
8833   
8834   sprintf(filter, "(objectClass=msExchMDB)");
8835   sprintf(search_path, "CN=Configuration,%s", dn_path);
8836   attr_array[0] = "distinguishedName";
8837   attr_array[1] = NULL;
8838   
8839   group_base = NULL;
8840   group_count = 0;
8841   
8842   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8843                            &group_base, &group_count, 
8844                            LDAP_SCOPE_SUBTREE)) != 0) 
8845     {
8846       com_err(whoami, 0, "Unable to find msExchMDB %s",
8847               ldap_err2string(rc));
8848       return(rc);
8849     }
8850   
8851   if (group_count) 
8852     {
8853       gPtr = group_base;
8854       
8855       while(gPtr) {
8856         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8857             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8858             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8859           {
8860             gPtr = gPtr->next;
8861             continue;
8862           }
8863
8864         /* 
8865          * Due to limits in active directory we need to use the LDAP
8866          * range semantics to query and return all the values in 
8867          * large lists, we will stop increasing the range when
8868          * the result count is 0.
8869          */
8870
8871         i = 0;  
8872         mdbbl_count = 0;
8873
8874         for(;;) 
8875           {
8876             memset(sub_filter, '\0', sizeof(sub_filter));
8877             memset(range, '\0', sizeof(range));
8878             sprintf(sub_filter, "(objectClass=msExchMDB)");
8879
8880             if(isLast)
8881               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8882             else 
8883               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8884
8885             attr_array[0] = range;
8886             attr_array[1] = NULL;
8887             
8888             sub_group_base = NULL;
8889             sub_group_count = 0;
8890             
8891             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8892                                      attr_array, &sub_group_base, 
8893                                      &sub_group_count, 
8894                                      LDAP_SCOPE_SUBTREE)) != 0) 
8895               {
8896                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8897                         ldap_err2string(rc));
8898                 return(rc);
8899               }
8900
8901             if(!sub_group_count)
8902               {
8903                 if(isLast) 
8904                   {
8905                     isLast = 0;
8906                     rangeLow = 0;
8907                     rangeHigh = rangeLow + (rangeStep - 1);
8908                     break;
8909                   }
8910                 else
8911                   isLast++;
8912               }
8913
8914             mdbbl_count += sub_group_count;
8915             rangeLow = rangeHigh + 1;
8916             rangeHigh = rangeLow + (rangeStep - 1);
8917           }
8918
8919         /* First time through, need to initialize or update the least used */
8920         
8921         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8922                 mdbbl_count);
8923
8924         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8925           {
8926             homeMDB_count = mdbbl_count; 
8927             *homeMDB = strdup(gPtr->dn);
8928           }
8929
8930         gPtr = gPtr->next;
8931         linklist_free(sub_group_base);
8932       }
8933     }
8934
8935   linklist_free(group_base);
8936   
8937   /* 
8938    * Ok found the server least allocated need to now query to get its
8939    * msExchHomeServerName so we can set it as a user attribute
8940    */
8941   
8942   attr_array[0] = "legacyExchangeDN";
8943   attr_array[1] = NULL; 
8944   
8945   group_count = 0;
8946   group_base = NULL;
8947   
8948   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8949                            attr_array, &group_base, 
8950                            &group_count, 
8951                            LDAP_SCOPE_SUBTREE)) != 0) 
8952     {
8953       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8954               ldap_err2string(rc));
8955       return(rc);
8956     }  
8957   
8958   if(group_count) 
8959     {
8960       *homeServerName = strdup(group_base->value);
8961       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8962         {
8963           *s = '\0';
8964         }
8965     } 
8966
8967   linklist_free(group_base);
8968   
8969   return(rc);
8970 }
8971       
8972 char *lowercase(char *s)
8973 {
8974   char *p;
8975
8976   for (p = s; *p; p++)
8977     {
8978       if (isupper(*p))
8979         *p = tolower(*p);
8980     }
8981   return s;
8982 }
8983
8984 char *uppercase(char *s)
8985 {
8986   char *p;
8987
8988   for (p = s; *p; p++)
8989     {
8990       if (islower(*p))
8991         *p = toupper(*p);
8992     }
8993   return s;
8994 }
8995
8996 char *escape_string(char *s)
8997 {
8998   char *p, *q;
8999   char string[1024];
9000   char temp[1024];
9001   int i = 0;
9002   int spaces = 0;
9003
9004   memset(string, '\0', sizeof(string));
9005
9006   q = s;
9007
9008   /* Escape any special characters */
9009
9010   for(; *q != '\0'; q++) {
9011     if(*q == ',')
9012       string[i++] = '\\';
9013     if(*q == '+') 
9014       string[i++] = '\\';
9015     if(*q == '"') 
9016       string[i++] = '\\';
9017     if(*q == '\\') 
9018       string[i++] = '\\';
9019     if(*q == '<') 
9020       string[i++] = '\\';
9021     if(*q == '>') 
9022       string[i++] = '\\';
9023     if(*q == ';')
9024       string[i++] = '\\';
9025     if(*q == '#')
9026       string[i++] = '\\';
9027     if(*q == '=')
9028       string[i++] = '\\';
9029
9030     string[i++] = *q;
9031   }
9032
9033   return strdup(string);
9034 }
9035
9036 int save_query_info(int argc, char **argv, void *hint)
9037 {
9038   int i;
9039   char **nargv = hint;
9040
9041   for(i = 0; i < argc; i++)
9042     nargv[i] = strdup(argv[i]);
9043
9044   return MR_CONT;
9045 }
9046
9047 int save_fsgroup_info(int argc, char **argv, void *hint)
9048 {
9049   int i;
9050   char **nargv = hint;
9051
9052   if(!fsgCount) 
9053     {
9054       for(i = 0; i < argc; i++)
9055         nargv[i] = strdup(argv[i]);
9056
9057       fsgCount++;
9058     }
9059
9060   return MR_CONT;
9061 }
This page took 1.306926 seconds and 5 git commands to generate.