]> andersk Git - moira.git/blob - incremental/ldap/winad.c
d515c1fda876c2e6a8e5af7d6a4654a284bd76d7
[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   u_int     groupTypeControl;
2413   char      groupTypeControlStr[80];
2414   char      contact_mail[256];
2415   int       n;
2416   int       i;
2417   int       rc;
2418   LK_ENTRY  *group_base;
2419   int       group_count;
2420   int       MailDisabled = 0;
2421
2422   if(UseGroupUniversal)
2423     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2424   else
2425     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2426      
2427   if (!check_string(before_group_name))
2428     {
2429       com_err(whoami, 0, 
2430               "Unable to process invalid LDAP list name %s", 
2431               before_group_name);
2432       return(AD_INVALID_NAME);
2433     }
2434
2435   if (!check_string(after_group_name))
2436     {
2437       com_err(whoami, 0, 
2438               "Unable to process invalid LDAP list name %s", after_group_name);
2439       return(AD_INVALID_NAME);
2440     }
2441
2442   if (Exchange) 
2443     {
2444       if(atoi(maillist)) 
2445         {
2446           group_count = 0;
2447           group_base = NULL;
2448           
2449           sprintf(filter, "(&(objectClass=user)(cn=%s))", after_group_name);
2450           attr_array[0] = "cn";
2451           attr_array[1] = NULL;
2452
2453           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
2454                                    &group_base, &group_count,
2455                                    LDAP_SCOPE_SUBTREE)) != 0)
2456           {
2457             com_err(whoami, 0, "Unable to process group %s : %s",
2458                     after_group_name, ldap_err2string(rc));
2459             return(rc);
2460           }
2461           
2462           if (group_count)
2463             {
2464               com_err(whoami, 0, "Object already exists with name %s",
2465                       after_group_name);
2466               MailDisabled++;
2467             }
2468         
2469           linklist_free(group_base);
2470           group_base = NULL;
2471           group_count = 0;
2472         }
2473     }
2474
2475   group_count = 0;
2476   group_base = NULL;
2477
2478   if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, 
2479                         before_group_membership, 
2480                         MoiraId, "samAccountName", &group_base, 
2481                         &group_count, filter))
2482     return(rc);
2483
2484   if (group_count == 0)
2485     {
2486       return(AD_NO_GROUPS_FOUND);
2487     }
2488
2489   if (group_count != 1)
2490     {
2491       com_err(whoami, 0, "Unable to process multiple groups with "
2492               "MoiraId = %s exist in the directory", MoiraId);
2493       return(AD_MULTIPLE_GROUPS_FOUND);
2494     }
2495
2496   strcpy(old_dn, group_base->dn);
2497
2498   linklist_free(group_base);
2499   group_base = NULL;
2500   group_count = 0;
2501   attr_array[0] = "sAMAccountName";
2502   attr_array[1] = NULL;
2503
2504   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
2505                            &group_base, &group_count, 
2506                            LDAP_SCOPE_SUBTREE)) != 0)
2507     {
2508       com_err(whoami, 0, "Unable to get list %s dn : %s",
2509               after_group_name, ldap_err2string(rc));
2510       return(rc);
2511     }
2512
2513   if (group_count != 1)
2514     {
2515       com_err(whoami, 0,
2516               "Unable to get sAMAccountName for group %s", 
2517               before_group_name);
2518       return(AD_LDAP_FAILURE);
2519     }
2520   
2521   strcpy(sam_name, group_base->value);
2522   linklist_free(group_base);
2523   group_base = NULL;
2524   group_count = 0;
2525   
2526   sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path);
2527   sprintf(new_dn, "cn=%s", after_group_name);
2528   sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain));
2529   sprintf(contact_mail, "%s@mit.edu", after_group_name); 
2530   sprintf(proxy_address, "SMTP:%s@%s", after_group_name, 
2531           lowercase(ldap_domain));
2532   sprintf(mail_nickname, "%s", after_group_name);
2533
2534   com_err(whoami, 0, "Old %s New %s,%s", old_dn, new_dn, new_dn_path);
2535
2536   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path,
2537                               TRUE, NULL, NULL)) != LDAP_SUCCESS)
2538     {
2539       com_err(whoami, 0, "Unable to rename list from %s to %s : %s",
2540               before_group_name, after_group_name, ldap_err2string(rc));
2541       return(rc);
2542     }
2543   
2544   name_v[0] = after_group_name;
2545
2546   if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], 
2547                group_suffix, strlen(group_suffix)))
2548     {
2549       sprintf(sam_name, "%s%s", after_group_name, group_suffix);
2550     }
2551   else
2552     {
2553       com_err(whoami, 0, 
2554               "Unable to rename list from %s to %s : sAMAccountName not found",
2555               before_group_name, after_group_name);
2556       return(rc);
2557     }
2558
2559   samAccountName_v[0] = sam_name;
2560
2561   if (after_security_flag)
2562     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2563
2564   sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2565   groupTypeControl_v[0] = groupTypeControlStr;
2566   mitMoiraId_v[0] = MoiraId;
2567
2568   sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
2569   rc = attribute_update(ldap_handle, new_dn, after_desc, "description", 
2570                         after_group_name);
2571   n = 0;
2572   ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE);
2573   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
2574   ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2575   ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE);
2576
2577   if (Exchange)
2578     {
2579       if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) 
2580         {
2581           mail_nickname_v[0] = mail_nickname;
2582           proxy_address_v[0] = proxy_address;
2583           mail_v[0] = mail;
2584           report_to_originator_v[0] = "TRUE";
2585
2586           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2587           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2588           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2589           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2590                    LDAP_MOD_REPLACE);
2591         } 
2592       else 
2593         {
2594           mail_nickname_v[0] = NULL;
2595           proxy_address_v[0] = NULL;
2596           mail_v[0] = NULL;
2597           legacy_exchange_dn_v[0] = NULL;
2598           address_book_v[0] = NULL;
2599           report_to_originator_v[0] = NULL;
2600
2601           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2602           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2603           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2604           ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE);
2605           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2606           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2607                    LDAP_MOD_REPLACE);
2608         }
2609     }
2610   else
2611     {
2612       if(atoi(maillist) && email_isvalid(contact_mail)) 
2613         {
2614           mail_v[0] = contact_mail;
2615           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2616         }
2617     }
2618
2619   mods[n] = NULL;
2620
2621   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
2622     {
2623       com_err(whoami, 0, 
2624               "Unable to modify list data for %s after renaming: %s",
2625               after_group_name, ldap_err2string(rc));
2626     }
2627
2628   for (i = 0; i < n; i++)
2629     free(mods[i]);
2630
2631   return(rc);
2632 }
2633
2634 int group_create(int ac, char **av, void *ptr)
2635 {
2636   LDAPMod *mods[20];
2637   char new_dn[256];
2638   char group_ou[256];
2639   char new_group_name[256];
2640   char sam_group_name[256];
2641   char cn_group_name[256];
2642   char mail[256];
2643   char contact_mail[256];
2644   char mail_nickname[256];
2645   char proxy_address[256];
2646   char address_book[256];
2647   char *cn_v[] = {NULL, NULL};
2648   char *objectClass_v[] = {"top", "group", NULL};
2649   char *objectClass_ldap_v[] = {"top", "microsoftComTop", "securityPrincipal",
2650                                 "group", "mailRecipient", NULL};
2651   char info[256];
2652   char *samAccountName_v[] = {NULL, NULL};
2653   char *altSecurityIdentities_v[] = {NULL, NULL};
2654   char *member_v[] = {NULL, NULL};
2655   char *name_v[] = {NULL, NULL};
2656   char *desc_v[] = {NULL, NULL};
2657   char *info_v[] = {NULL, NULL};
2658   char *mitMoiraId_v[] = {NULL, NULL};
2659   char *mitMoiraPublic_v[] = {NULL, NULL};
2660   char *mitMoiraHidden_v[] = {NULL, NULL};
2661   char *groupTypeControl_v[] = {NULL, NULL};
2662   char *mail_v[] = {NULL, NULL};
2663   char *proxy_address_v[] = {NULL, NULL};
2664   char *mail_nickname_v[] = {NULL, NULL};
2665   char *report_to_originator_v[] = {NULL, NULL};
2666   char *address_book_v[] = {NULL, NULL};
2667   char *legacy_exchange_dn_v[] = {NULL, NULL};
2668   char *gidNumber_v[] = {NULL, NULL};
2669   char groupTypeControlStr[80];
2670   char group_membership[1];
2671   int  i;
2672   int  security_flag;
2673   u_int groupTypeControl;
2674   int  n;
2675   int  rc;
2676   int  updateGroup;
2677   int  MailDisabled = 0;
2678   char **call_args;
2679   LK_ENTRY *group_base;
2680   int  group_count;
2681   char filter[1024];
2682   char *attr_array[3];
2683   
2684   call_args = ptr;
2685
2686   if(UseGroupUniversal)
2687     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2688   else 
2689     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2690
2691   if (!check_string(av[L_NAME]))
2692     {
2693       com_err(whoami, 0, "Unable to process invalid LDAP list name %s", 
2694               av[L_NAME]);
2695       return(AD_INVALID_NAME);
2696     }
2697
2698   updateGroup = (int)call_args[4];
2699   memset(group_ou, 0, sizeof(group_ou));
2700   memset(group_membership, 0, sizeof(group_membership));
2701   security_flag = 0;
2702
2703   get_group_membership(group_membership, group_ou, &security_flag, av);
2704
2705   strcpy(new_group_name, av[L_NAME]);
2706   sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
2707   sprintf(contact_mail, "%s@mit.edu", av[L_NAME]);
2708   sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain));
2709   sprintf(mail_nickname, "%s", av[L_NAME]);
2710
2711   if (security_flag)
2712     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2713   
2714   sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix);
2715
2716   if (!updateGroup)
2717     {
2718       sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2719       groupTypeControl_v[0] = groupTypeControlStr;
2720
2721       strcpy(cn_group_name, av[L_NAME]);
2722       
2723       samAccountName_v[0] = sam_group_name;
2724       name_v[0] = new_group_name;
2725       cn_v[0] = new_group_name;
2726
2727       n = 0;
2728       ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
2729
2730       if(ActiveDirectory)
2731         {
2732           ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
2733         } 
2734       else
2735         {
2736           mitMoiraPublic_v[0] = av[L_PUBLIC];
2737           mitMoiraHidden_v[0] = av[L_HIDDEN];
2738           ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
2739           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_ADD);
2740           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_ADD);
2741           
2742           if(atoi(av[L_GROUP])) 
2743             {
2744               gidNumber_v[0] = av[L_GID];
2745               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_ADD);
2746             }
2747         }
2748
2749       ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
2750       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
2751       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
2752
2753       if (Exchange)
2754         {
2755           if(atoi(av[L_MAILLIST])) 
2756             {
2757               group_count = 0;
2758               group_base = NULL;
2759               
2760               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2761               attr_array[0] = "cn";
2762               attr_array[1] = NULL;
2763               
2764               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2765                                        filter, attr_array, &group_base, 
2766                                        &group_count,
2767                                        LDAP_SCOPE_SUBTREE)) != 0)
2768                 {
2769                   com_err(whoami, 0, "Unable to process group %s : %s",
2770                           av[L_NAME], ldap_err2string(rc));
2771                   return(rc);
2772                 }
2773               
2774               if (group_count)
2775                 {
2776                   com_err(whoami, 0, "Object already exists with name %s",
2777                           av[L_NAME]);
2778                   MailDisabled++;
2779                 }
2780         
2781               linklist_free(group_base);
2782               group_base = NULL;
2783               group_count = 0;
2784             }
2785           
2786           if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2787             {
2788               mail_nickname_v[0] = mail_nickname;
2789               report_to_originator_v[0] = "TRUE";
2790
2791               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
2792               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2793                        LDAP_MOD_ADD);
2794             }
2795         }
2796       else
2797         {
2798           if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2799             {
2800               mail_v[0] = contact_mail;
2801               ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
2802             }
2803         }
2804       
2805       if (strlen(av[L_DESC]) != 0)
2806         {
2807           desc_v[0] = av[L_DESC];
2808           ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
2809         }
2810       
2811       ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
2812
2813       if (strlen(av[L_ACE_NAME]) != 0)
2814         {
2815           sprintf(info, "The Administrator of this list is: %s", 
2816                   av[L_ACE_NAME]);
2817           info_v[0] = info;
2818           ADD_ATTR("info", info_v, LDAP_MOD_ADD);
2819         }
2820
2821       if (strlen(call_args[5]) != 0)
2822         {
2823           mitMoiraId_v[0] = call_args[5];
2824           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD);
2825         }
2826           
2827       mods[n] = NULL;
2828       
2829       rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
2830       
2831       for (i = 0; i < n; i++)
2832         free(mods[i]);
2833
2834       if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
2835         {
2836           com_err(whoami, 0, "Unable to create list %s in directory : %s",
2837                   av[L_NAME], ldap_err2string(rc));
2838           callback_rc = rc;
2839           return(rc);
2840         }
2841     }
2842
2843   if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup))
2844     {
2845       rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], 
2846                             "description", av[L_NAME]);
2847       sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]);
2848
2849       rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", 
2850                                 av[L_NAME]);
2851
2852       n = 0;
2853
2854       if (strlen(call_args[5]) != 0)
2855         {
2856           mitMoiraId_v[0] = call_args[5];
2857           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2858         }
2859
2860       if (!(atoi(av[L_ACTIVE])))
2861         {
2862           member_v[0] = NULL;
2863           ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
2864         }
2865    
2866       if (!ActiveDirectory) 
2867         {
2868           mitMoiraPublic_v[0] = av[L_PUBLIC];
2869           mitMoiraHidden_v[0] = av[L_HIDDEN];
2870           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_REPLACE);
2871           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_REPLACE);
2872
2873           if(atoi(av[L_GROUP])) 
2874             {
2875               gidNumber_v[0] = av[L_GID];
2876               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2877             }
2878           else
2879             {
2880               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2881             }
2882         }
2883
2884       if (Exchange)
2885         {
2886           if(atoi(av[L_MAILLIST])) 
2887             {
2888               group_count = 0;
2889               group_base = NULL;
2890               
2891               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2892               attr_array[0] = "cn";
2893               attr_array[1] = NULL;
2894               
2895               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2896                                        filter, attr_array, &group_base, 
2897                                        &group_count,
2898                                        LDAP_SCOPE_SUBTREE)) != 0)
2899                 {
2900                   com_err(whoami, 0, "Unable to process group %s : %s",
2901                           av[L_NAME], ldap_err2string(rc));
2902                   return(rc);
2903                 }
2904               
2905               if (group_count)
2906                 {
2907                   com_err(whoami, 0, "Object already exists with name %s",
2908                           av[L_NAME]);
2909                   MailDisabled++;
2910                 }
2911               
2912               linklist_free(group_base);
2913               group_base = NULL;
2914               group_count = 0;
2915             }
2916
2917           if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2918             {
2919               mail_nickname_v[0] = mail_nickname;
2920               report_to_originator_v[0] = "TRUE";
2921
2922               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2923               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2924                        LDAP_MOD_REPLACE);
2925             }
2926           else 
2927             {
2928               mail_v[0] = NULL;
2929               mail_nickname_v[0] = NULL;
2930               proxy_address_v[0] = NULL;
2931               legacy_exchange_dn_v[0] = NULL;
2932               address_book_v[0] = NULL;
2933               report_to_originator_v[0] = NULL;
2934
2935               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2936               ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2937               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2938               ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, 
2939                        LDAP_MOD_REPLACE);
2940               ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2941               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2942                        LDAP_MOD_REPLACE);
2943             }
2944         }
2945       else
2946         {
2947           if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2948             {
2949               mail_v[0] = contact_mail;
2950               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2951             }
2952           else
2953             {
2954               mail_v[0] = NULL;
2955               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2956             }
2957         }
2958    
2959       mods[n] = NULL;
2960       rc = LDAP_SUCCESS;
2961
2962       if (n != 0)
2963         {
2964           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
2965
2966           for (i = 0; i < n; i++)
2967               free(mods[i]);
2968
2969           if (rc != LDAP_SUCCESS)
2970             {
2971               com_err(whoami, 0, "Unable to update list %s in directory : %s",
2972                       av[L_NAME], ldap_err2string(rc));
2973               callback_rc = rc;
2974               return(rc);
2975             }
2976         }
2977     }
2978
2979   ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], 
2980                        atoi(av[L_HIDDEN]),  av[L_ACE_TYPE], av[L_ACE_NAME]);
2981
2982   return(LDAP_SUCCESS);
2983 }
2984
2985 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
2986                          char *TargetGroupName, int HiddenGroup, 
2987                          char *AceType, char *AceName)
2988 {
2989   char          filter_exp[1024];
2990   char          *attr_array[5];
2991   char          search_path[512];
2992   char          root_ou[128];
2993   char          TemplateDn[512];
2994   char          TemplateSamName[128];
2995   char          TargetDn[512];
2996   char          TargetSamName[128];
2997   char          AceSamAccountName[128];
2998   char          AceDn[256];
2999   unsigned char AceSid[128];
3000   unsigned char UserTemplateSid[128];
3001   char          acBERBuf[N_SD_BER_BYTES];
3002   char          GroupSecurityTemplate[256];
3003   char          hide_addres_lists[256];
3004   char          address_book[256];
3005   char          *hide_address_lists_v[] = {NULL, NULL};
3006   char          *address_book_v[] = {NULL, NULL};
3007   char          *owner_v[] = {NULL, NULL};
3008   int           AceSidCount;
3009   int           UserTemplateSidCount;
3010   int           group_count;
3011   int           n;
3012   int           i;
3013   int           rc;
3014   int           nVal;
3015   ULONG         dwInfo;
3016   int           array_count = 0;
3017   LDAPMod       *mods[20];
3018   LK_ENTRY      *group_base;
3019   LDAP_BERVAL   **ppsValues;
3020   LDAPControl sControl = {"1.2.840.113556.1.4.801",
3021                           { N_SD_BER_BYTES, acBERBuf },
3022                           TRUE
3023                          };
3024   LDAPControl *apsServerControls[] = {&sControl, NULL};
3025   LDAPMessage *psMsg;
3026
3027   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
3028     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
3029   BEREncodeSecurityBits(dwInfo, acBERBuf);
3030
3031   sprintf(search_path, "%s,%s", group_ou_root, dn_path);
3032   sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix);
3033   attr_array[0] = "sAMAccountName";
3034   attr_array[1] = NULL;
3035   group_count = 0;
3036   group_base = NULL;
3037
3038   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3039                            &group_base, &group_count, 
3040                            LDAP_SCOPE_SUBTREE) != 0))
3041     return(1);
3042
3043   if (group_count != 1)
3044     {
3045       linklist_free(group_base);
3046       return(1);
3047     }
3048
3049   strcpy(TargetDn, group_base->dn);
3050   strcpy(TargetSamName, group_base->value);
3051   linklist_free(group_base);
3052   group_base = NULL;
3053   group_count = 0;
3054
3055   UserTemplateSidCount = 0;
3056   memset(UserTemplateSid, '\0', sizeof(UserTemplateSid));
3057   memset(AceSamAccountName, '\0', sizeof(AceSamAccountName));
3058   memset(AceSid, '\0', sizeof(AceSid));
3059   AceSidCount = 0;
3060   group_base = NULL;
3061   group_count = 0;
3062
3063   if (strlen(AceName) != 0)
3064     {
3065       if (!strcmp(AceType, "LIST"))
3066         {
3067           sprintf(AceSamAccountName, "%s%s", AceName, group_suffix);
3068           strcpy(root_ou, group_ou_root);
3069         }
3070       else if (!strcmp(AceType, "USER"))
3071         {
3072           sprintf(AceSamAccountName, "%s", AceName);
3073           strcpy(root_ou, user_ou);
3074         }
3075
3076       if (ActiveDirectory)
3077         {
3078           if (strlen(AceSamAccountName) != 0)
3079             {
3080               sprintf(search_path, "%s", dn_path);
3081               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3082               attr_array[0] = "objectSid";
3083               attr_array[1] = NULL;
3084               group_count = 0;
3085               group_base = NULL;
3086               
3087               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3088                                        attr_array, &group_base, &group_count, 
3089                                        LDAP_SCOPE_SUBTREE) != 0))
3090                 return(1);
3091               if (group_count == 1)
3092                 {
3093                   strcpy(AceDn, group_base->dn);
3094                   AceSidCount = group_base->length;
3095                   memcpy(AceSid, group_base->value, AceSidCount);
3096                 }
3097               linklist_free(group_base);
3098               group_base = NULL;
3099               group_count = 0;
3100             }
3101         }
3102       else
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] = "samAccountName";
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                 }
3121               linklist_free(group_base);
3122               group_base = NULL;
3123               group_count = 0;
3124             }
3125         }
3126     }
3127
3128   if (!ActiveDirectory) 
3129     {
3130       if (strlen(AceDn) != 0) 
3131         {
3132           owner_v[0] = strdup(AceDn);
3133           n = 0;
3134           ADD_ATTR("owner", owner_v, LDAP_MOD_REPLACE);
3135
3136           mods[n] = NULL;
3137
3138           rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3139           
3140           for (i = 0; i < n; i++)
3141             free(mods[i]);
3142
3143           if (rc != LDAP_SUCCESS)
3144             com_err(whoami, 0, "Unable to set owner for group %s : %s",
3145               TargetGroupName, ldap_err2string(rc));
3146         }
3147
3148       return(rc);
3149     }
3150   
3151   if (AceSidCount == 0)
3152     {
3153       com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not "
3154               "have a directory SID.", TargetGroupName, AceName, AceType);
3155       com_err(whoami, 0, "   Non-admin security group template will be used.");
3156     }
3157   else
3158     {
3159       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3160       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
3161       attr_array[0] = "objectSid";
3162       attr_array[1] = NULL;
3163
3164       group_count = 0;
3165       group_base = NULL;
3166
3167       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3168                                attr_array, &group_base, &group_count, 
3169                                LDAP_SCOPE_SUBTREE) != 0))
3170         return(1);
3171
3172       if ((rc != 0) || (group_count != 1))
3173         {
3174           com_err(whoami, 0, "Unable to process user security template: %s", 
3175                   "UserTemplate");
3176           AceSidCount = 0;
3177         }
3178       else
3179         {
3180           UserTemplateSidCount = group_base->length;
3181           memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount);
3182         }
3183       linklist_free(group_base);
3184       group_base = NULL;
3185       group_count = 0;
3186     }
3187
3188   if (HiddenGroup)
3189     {
3190       if (AceSidCount == 0)
3191         {
3192           strcpy(GroupSecurityTemplate, HIDDEN_GROUP);
3193           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP);
3194         }
3195       else
3196         {
3197           strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN);
3198           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN);
3199         }
3200     }
3201   else
3202     {
3203       if (AceSidCount == 0)
3204         {
3205           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP);
3206           sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP);
3207         }
3208       else
3209         {
3210           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN);
3211           sprintf(filter_exp, "(sAMAccountName=%s)", 
3212                   NOT_HIDDEN_GROUP_WITH_ADMIN);
3213         }
3214     }
3215
3216   sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3217   attr_array[0] = "sAMAccountName";
3218   attr_array[1] = NULL;
3219   group_count = 0;
3220   group_base = NULL;
3221
3222   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3223                            &group_base, &group_count, 
3224                            LDAP_SCOPE_SUBTREE) != 0))
3225     return(1);
3226
3227   if (group_count != 1)
3228     {
3229       linklist_free(group_base);
3230       com_err(whoami, 0, "Unable to process group security template: %s - "
3231               "security not set", GroupSecurityTemplate);
3232       return(1);
3233     }
3234
3235   strcpy(TemplateDn, group_base->dn);
3236   strcpy(TemplateSamName, group_base->value);
3237   linklist_free(group_base);
3238   group_base = NULL;
3239   group_count = 0;
3240   
3241   sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName);
3242   rc = ldap_search_ext_s(ldap_handle,
3243                          TemplateDn,
3244                          LDAP_SCOPE_SUBTREE,
3245                          filter_exp,
3246                          NULL,
3247                          0,
3248                          apsServerControls,
3249                          NULL,
3250                          NULL,
3251                          0,
3252                          &psMsg);
3253
3254   if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
3255     {
3256       com_err(whoami, 0, "Unable to find group security template: %s - "
3257               "security not set", GroupSecurityTemplate);
3258       return(1);
3259     }
3260
3261   ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
3262
3263   if (ppsValues == NULL)
3264     {
3265       com_err(whoami, 0, "Unable to find group security descriptor for group "
3266               "%s - security not set", GroupSecurityTemplate);
3267       return(1);
3268     }
3269   
3270   if (AceSidCount != 0)
3271     {
3272       for (nVal = 0; ppsValues[nVal] != NULL; nVal++)
3273         {
3274           for (i = 0; 
3275                i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++)
3276             {
3277               if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, 
3278                           UserTemplateSidCount))
3279                 {
3280                   memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount);
3281                   break;
3282                 }
3283             }
3284         }
3285     }
3286
3287   n = 0;
3288   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, 
3289            LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
3290
3291   if (Exchange)
3292     {
3293       if(HiddenGroup) 
3294         {
3295           hide_address_lists_v[0] = "TRUE";
3296           address_book_v[0] = NULL;
3297           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3298                    LDAP_MOD_REPLACE);
3299           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
3300         } else {
3301           hide_address_lists_v[0] = NULL;
3302           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3303                    LDAP_MOD_REPLACE);
3304         }
3305     }
3306
3307   mods[n] = NULL;
3308
3309   rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3310
3311   for (i = 0; i < n; i++)
3312     free(mods[i]);
3313
3314   ldap_value_free_len(ppsValues);
3315   ldap_msgfree(psMsg);
3316
3317   if (rc != LDAP_SUCCESS)
3318     {
3319       com_err(whoami, 0, "Unable to set security settings for group %s : %s",
3320               TargetGroupName, ldap_err2string(rc));
3321
3322       if (AceSidCount != 0)
3323         {
3324           com_err(whoami, 0, 
3325                   "Trying to set security for group %s without admin.",
3326                   TargetGroupName);
3327
3328           if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, 
3329                                         HiddenGroup, "", ""))
3330             {
3331               com_err(whoami, 0, "Unable to set security for group %s.",
3332                       TargetGroupName);
3333               return(rc);
3334             }
3335         }
3336       return(rc);
3337     }
3338
3339   return(rc);
3340 }
3341
3342 int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, 
3343                  char *group_membership, char *MoiraId)
3344 {
3345   LK_ENTRY  *group_base;
3346   char      temp[512];
3347   char      filter[128];
3348   int       group_count;
3349   int       rc;
3350
3351   if (!check_string(group_name))
3352     {
3353       com_err(whoami, 0, 
3354               "Unable to process invalid LDAP list name %s", group_name);
3355       return(AD_INVALID_NAME);
3356     }
3357
3358   memset(filter, '\0', sizeof(filter));
3359   group_count = 0;
3360   group_base = NULL;
3361   sprintf(temp, "%s,%s", group_ou_root, dn_path);
3362
3363   if (rc = ad_get_group(ldap_handle, temp, group_name, 
3364                         group_membership, MoiraId, 
3365                         "samAccountName", &group_base, 
3366                         &group_count, filter))
3367     return(rc);
3368
3369   if (group_count == 1)
3370     {
3371       if ((rc = ldap_delete_s(ldap_handle, group_base->dn)) != LDAP_SUCCESS)
3372         {
3373           linklist_free(group_base);
3374           com_err(whoami, 0, "Unable to delete list %s from directory : %s",
3375                   group_name, ldap_err2string(rc));
3376           return(rc);
3377         }
3378       linklist_free(group_base);
3379     }
3380   else
3381     {
3382       linklist_free(group_base);
3383       com_err(whoami, 0, "Unable to find list %s in directory.", group_name);
3384       return(AD_NO_GROUPS_FOUND);
3385     }
3386   
3387   return(0);
3388 }
3389
3390 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer)
3391 {
3392     *pBuffer++ = 0x30;
3393     *pBuffer++ = 0x03;
3394     *pBuffer++ = 0x02;
3395     *pBuffer++ = 0x00;
3396     return(N_SD_BER_BYTES);
3397 }
3398
3399 int process_lists(int ac, char **av, void *ptr)
3400 {
3401   int   rc;
3402   int   security_flag;
3403   char  group_ou[256];
3404   char  group_membership[2];
3405   char  **call_args;
3406
3407   call_args = ptr;
3408
3409   security_flag = 0;
3410   memset(group_ou, '\0', sizeof(group_ou));
3411   memset(group_membership, '\0', sizeof(group_membership));
3412   get_group_membership(group_membership, group_ou, &security_flag, av);
3413   rc = populate_group((LDAP *)call_args[0], (char *)call_args[1], 
3414                       av[L_NAME], group_ou, group_membership, 
3415                       security_flag, "");
3416
3417   return(0);
3418 }
3419
3420 int member_list_build(int ac, char **av, void *ptr)
3421 {
3422   LK_ENTRY  *linklist;
3423   char      temp[1024];
3424   char      **call_args;
3425   char      *s;
3426   call_args = ptr;
3427
3428   strcpy(temp, av[ACE_NAME]);
3429   StringTrim(temp);
3430   
3431   if (!check_string(temp))
3432     return(0);
3433
3434   if (!strcmp(av[ACE_TYPE], "USER"))
3435     {
3436       if (!((int)call_args[3] & MOIRA_USERS))
3437         return(0);
3438     }
3439   else if (!strcmp(av[ACE_TYPE], "STRING"))
3440     {
3441       if (Exchange)
3442         {
3443           if((s = strchr(temp, '@')) == (char *) NULL) 
3444             {
3445               strcat(temp, "@mit.edu");
3446             }
3447           
3448           if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6))
3449             {
3450               s = strrchr(temp, '.');
3451               *s = '\0';
3452               strcat(s, ".mit.edu");
3453             }
3454         }
3455
3456       if (!((int)call_args[3] & MOIRA_STRINGS))
3457         return(0);
3458         
3459       if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou))
3460         return(0);
3461     }
3462   else if (!strcmp(av[ACE_TYPE], "LIST"))
3463     {
3464       if (!((int)call_args[3] & MOIRA_LISTS))
3465         return(0);
3466     }
3467   else if (!strcmp(av[ACE_TYPE], "KERBEROS"))
3468     {
3469       if (!((int)call_args[3] & MOIRA_KERBEROS))
3470         return(0);
3471
3472       if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
3473                          kerberos_ou))
3474         return(0);
3475
3476     }
3477   else if (!strcmp(av[ACE_TYPE], "MACHINE"))
3478     {
3479       if (!((int)call_args[3] & MOIRA_MACHINE))
3480         return(0);
3481     }
3482   else
3483     return(0);
3484
3485   linklist = member_base;
3486
3487   while (linklist)
3488     {
3489     if (!strcasecmp(temp, linklist->member) &&
3490         !strcasecmp(av[ACE_TYPE], linklist->type))
3491       return(0);
3492
3493     linklist = linklist->next;
3494     }
3495
3496   linklist = calloc(1, sizeof(LK_ENTRY));
3497   linklist->op = 1;
3498   linklist->dn = NULL;
3499   linklist->list = calloc(1, strlen(call_args[2]) + 1);
3500   strcpy(linklist->list, call_args[2]);
3501   linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1);
3502   strcpy(linklist->type, av[ACE_TYPE]);
3503   linklist->member = calloc(1, strlen(temp) + 1);
3504   strcpy(linklist->member, temp);
3505   linklist->next = member_base;
3506   member_base = linklist;
3507
3508   return(0);
3509 }
3510
3511 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
3512                   char *group_ou, char *group_membership, char *user_name,
3513                   char *UserOu, char *MoiraId)
3514 {
3515   char        distinguished_name[1024];
3516   char        *modvalues[2];
3517   char        temp[256];
3518   char        filter[128];
3519   char        *attr_array[3];
3520   int         group_count;
3521   int         i;
3522   int         n;
3523   LDAPMod     *mods[20];
3524   LK_ENTRY    *group_base;
3525   ULONG       rc;
3526   char        *s;
3527
3528   if (!check_string(group_name))
3529     return(AD_INVALID_NAME);
3530
3531   memset(filter, '\0', sizeof(filter));
3532   group_base = NULL;
3533   group_count = 0;
3534
3535   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3536                         group_membership, MoiraId, 
3537                         "samAccountName", &group_base, 
3538                         &group_count, filter))
3539     return(rc);
3540
3541   if (group_count != 1)
3542     {
3543       com_err(whoami, 0, "Unable to find list %s in directory",
3544               group_name);
3545       linklist_free(group_base);
3546       group_base = NULL;
3547       group_count = 0;
3548       goto cleanup;
3549     }
3550
3551   strcpy(distinguished_name, group_base->dn);
3552   linklist_free(group_base);
3553   group_base = NULL;
3554   group_count = 0;
3555
3556   if(ActiveDirectory)
3557     {
3558       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3559     }
3560   else
3561     {
3562       if(!strcmp(UserOu, user_ou))
3563         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3564       else
3565         sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3566     }
3567
3568   modvalues[0] = temp;
3569   modvalues[1] = NULL;
3570
3571   n = 0;
3572   ADD_ATTR("member", modvalues, LDAP_MOD_DELETE);
3573   mods[n] = NULL;
3574   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3575
3576   for (i = 0; i < n; i++)
3577     free(mods[i]);
3578
3579   if (rc == LDAP_UNWILLING_TO_PERFORM)
3580     rc = LDAP_SUCCESS;
3581
3582   if (rc != LDAP_SUCCESS)
3583     {
3584       com_err(whoami, 0, "Unable to modify list %s members : %s",
3585               group_name, ldap_err2string(rc));
3586       goto cleanup;
3587     }
3588
3589   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) 
3590     {
3591       if (Exchange)
3592         {
3593           if(!strcmp(UserOu, contact_ou) && 
3594              ((s = strstr(user_name, "@mit.edu")) != (char *) NULL))
3595             {
3596               memset(temp, '\0', sizeof(temp));
3597               strcpy(temp, user_name);
3598               s = strchr(temp, '@');
3599               *s = '\0';
3600               
3601               sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp);
3602           
3603               if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL,
3604                                        &group_base, &group_count, 
3605                                        LDAP_SCOPE_SUBTREE) != 0))
3606                 return(rc);       
3607               
3608               if(group_count)
3609                 goto cleanup;
3610               
3611               linklist_free(group_base);
3612               group_base = NULL;
3613               group_count = 0;
3614             }
3615           
3616           sprintf(filter, "(distinguishedName=%s)", temp);
3617           attr_array[0] = "memberOf";
3618           attr_array[1] = NULL;
3619           
3620           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
3621                                    &group_base, &group_count, 
3622                                    LDAP_SCOPE_SUBTREE) != 0))
3623             return(rc);
3624           
3625
3626           if(!group_count) 
3627             {
3628               com_err(whoami, 0, "Removing unreferenced object %s", temp);
3629           
3630               if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) 
3631                 return(rc);
3632             }
3633         }
3634     }
3635
3636  cleanup:
3637   return(rc);
3638 }
3639
3640 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
3641                char *group_ou, char *group_membership, char *user_name, 
3642                char *UserOu, char *MoiraId)
3643 {
3644   char        distinguished_name[1024];
3645   char        *modvalues[2];
3646   char        temp[256];
3647   char        filter[128];
3648   int         group_count;
3649   int         n;
3650   int         i;
3651   LDAPMod     *mods[20];
3652   LK_ENTRY    *group_base;
3653   ULONG       rc;
3654
3655   if (!check_string(group_name))
3656     return(AD_INVALID_NAME);
3657
3658   rc = 0;
3659   memset(filter, '\0', sizeof(filter));
3660   group_base = NULL;
3661   group_count = 0;
3662
3663   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3664                         group_membership, MoiraId, 
3665                         "samAccountName", &group_base, 
3666                         &group_count, filter))
3667     return(rc);
3668
3669   if (group_count != 1)
3670     {
3671       linklist_free(group_base);
3672       group_base = NULL;
3673       group_count = 0;
3674       com_err(whoami, 0, "Unable to find list %s %d in directory",
3675               group_name, group_count);
3676       return(AD_MULTIPLE_GROUPS_FOUND);
3677     }
3678
3679   strcpy(distinguished_name, group_base->dn);
3680   linklist_free(group_base);
3681   group_base = NULL;
3682   group_count = 0;
3683
3684   if(ActiveDirectory)
3685     {
3686       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3687     }
3688   else 
3689     {
3690       if(!strcmp(UserOu, user_ou))
3691         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3692       else
3693         sprintf(temp, "cn=%s,%s,%s", user_name, UserOu, dn_path);
3694     }
3695
3696   modvalues[0] = temp;
3697   modvalues[1] = NULL;
3698
3699   n = 0;
3700   ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
3701   mods[n] = NULL;
3702   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3703
3704   if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
3705     rc = LDAP_SUCCESS;
3706
3707   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou)))
3708     {
3709       if (rc == LDAP_UNWILLING_TO_PERFORM)
3710         rc = LDAP_SUCCESS;
3711     }
3712
3713   for (i = 0; i < n; i++)
3714     free(mods[i]);
3715
3716   if (rc != LDAP_SUCCESS)
3717     {
3718       com_err(whoami, 0, "Unable to add %s to list %s as a member : %s",
3719               user_name, group_name, ldap_err2string(rc));
3720     }
3721
3722   return(rc);
3723 }
3724
3725 int contact_remove_email(LDAP *ld, char *bind_path,
3726                          LK_ENTRY **linklist_base, int linklist_current)
3727 {
3728   LK_ENTRY  *gPtr;
3729   int       rc;
3730   char      *mail_v[] = {NULL, NULL};
3731   LDAPMod   *mods[20];
3732   int n;
3733   int i;
3734
3735   mail_v[0] = NULL;
3736
3737   n = 0;
3738   ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
3739   ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE);
3740   ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE);
3741   ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE);
3742   mods[n] = NULL;
3743
3744   gPtr = (*linklist_base);
3745   
3746   while(gPtr) {
3747     rc = ldap_modify_s(ld, gPtr->dn, mods);
3748     
3749     if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3750       {
3751         com_err(whoami, 0, "Unable to modify contact %s in directory : %s",
3752                 gPtr->dn, ldap_err2string(rc));
3753         return(rc);
3754       }
3755
3756     gPtr = gPtr->next;
3757   }
3758
3759   for (i = 0; i < n; i++)
3760     free(mods[i]);
3761   
3762     return(rc);
3763 }
3764
3765 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
3766 {
3767   LDAPMod *mods[20];
3768   LK_ENTRY  *group_base;
3769   int  group_count;
3770   char new_dn[256];
3771   char cn_user_name[256];
3772   char contact_name[256];
3773   char mail_nickname[256];
3774   char proxy_address_internal[256];
3775   char proxy_address_external[256];
3776   char target_address[256];
3777   char internal_contact_name[256];
3778   char filter[128];
3779   char mail[256];
3780   char principal[256];
3781   char mit_address_book[256];
3782   char default_address_book[256];
3783   char contact_address_book[256];
3784   char uid[256];
3785   char *email_v[] = {NULL, NULL};
3786   char *cn_v[] = {NULL, NULL};
3787   char *contact_v[] = {NULL, NULL};
3788   char *uid_v[] = {NULL, NULL};
3789   char *mail_nickname_v[] = {NULL, NULL};
3790   char *proxy_address_internal_v[] = {NULL, NULL};
3791   char *proxy_address_external_v[] = {NULL, NULL};
3792   char *target_address_v[] = {NULL, NULL};
3793   char *mit_address_book_v[] = {NULL, NULL};
3794   char *default_address_book_v[] = {NULL, NULL};
3795   char *contact_address_book_v[] = {NULL, NULL};
3796   char *hide_address_lists_v[] = {NULL, NULL};
3797   char *attr_array[3];
3798   char *objectClass_v[] = {"top", "person", 
3799                            "organizationalPerson", 
3800                            "contact", NULL};
3801   char *objectClass_ldap_v[] = {"top", "person", "microsoftComTop", 
3802                                 "inetOrgPerson", "organizationalPerson",
3803                                 "contact", "mailRecipient", "eduPerson",
3804                                 NULL};
3805   char *name_v[] = {NULL, NULL};
3806   char *desc_v[] = {NULL, NULL};
3807   char *s;
3808   int  n;
3809   int  rc;
3810   int  i;
3811   char temp[256];
3812   char *c;
3813   char *mail_routing_v[] = {NULL, NULL};
3814   char *principal_v[] = {NULL, NULL};
3815
3816   if (!check_string(user))
3817     {
3818       com_err(whoami, 0, "Unable to process invalid LDAP name %s", user);
3819       return(AD_INVALID_NAME);
3820     }
3821
3822   strcpy(mail, user);
3823   strcpy(contact_name, mail);
3824   strcpy(internal_contact_name, mail);
3825   
3826   if((s = strchr(internal_contact_name, '@')) != NULL) {
3827     *s = '?';
3828   }
3829
3830   sprintf(cn_user_name,"CN=%s,%s,%s", escape_string(contact_name), group_ou, 
3831           bind_path);
3832
3833   sprintf(target_address, "SMTP:%s", contact_name);
3834   sprintf(proxy_address_external, "SMTP:%s", contact_name);
3835   sprintf(mail_nickname, "%s", internal_contact_name);
3836  
3837   cn_v[0] = cn_user_name;
3838   contact_v[0] = contact_name;
3839   uid_v[0] = uid;
3840   name_v[0] = user;
3841   desc_v[0] = "Auto account created by Moira";
3842   email_v[0] = mail;
3843   proxy_address_internal_v[0] = proxy_address_internal;
3844   proxy_address_external_v[0] = proxy_address_external;
3845   mail_nickname_v[0] = mail_nickname;
3846   target_address_v[0] = target_address;
3847   mit_address_book_v[0] = mit_address_book;
3848   default_address_book_v[0] = default_address_book;
3849   contact_address_book_v[0] = contact_address_book;
3850   strcpy(new_dn, cn_user_name);
3851   n = 0;
3852
3853   ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
3854
3855   if(!ActiveDirectory)
3856     {
3857       if(!strcmp(group_ou, contact_ou))
3858         sprintf(uid, "%s%s", contact_name, "_strings");
3859       
3860       if(!strcmp(group_ou, kerberos_ou))
3861         sprintf(uid, "%s%s", contact_name, "_kerberos");
3862
3863       uid_v[0] = uid;
3864
3865       ADD_ATTR("sn", contact_v, LDAP_MOD_ADD);
3866       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
3867     }
3868
3869   if(ActiveDirectory)
3870     {
3871       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
3872     }
3873   else
3874     {
3875       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
3876     }
3877
3878   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
3879   ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
3880   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
3881
3882   if (Exchange)
3883     {
3884       if (!strcmp(group_ou, contact_ou) && email_isvalid(mail))
3885         {
3886           group_count = 0;
3887           group_base = NULL;
3888           
3889           sprintf(filter, "(&(objectClass=user)(cn=%s))", mail);
3890           attr_array[0] = "cn";
3891           attr_array[1] = NULL;
3892
3893           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3894                                    &group_base, &group_count, 
3895                                    LDAP_SCOPE_SUBTREE)) != 0) 
3896             {
3897               com_err(whoami, 0, "Unable to process contact %s : %s", 
3898                       user, ldap_err2string(rc));
3899               return(rc);
3900             }
3901       
3902           if (group_count) 
3903             {
3904               com_err(whoami, 0, "Object already exists with name %s",
3905                       user);
3906               return(1);
3907             }
3908
3909           linklist_free(group_base);
3910           group_base = NULL;
3911           group_count = 0;
3912       
3913           sprintf(filter, "(&(objectClass=group)(cn=%s))", mail);
3914           attr_array[0] = "cn";
3915           attr_array[1] = NULL;
3916
3917           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3918                                    &group_base, &group_count, 
3919                                    LDAP_SCOPE_SUBTREE)) != 0) 
3920             {
3921               com_err(whoami, 0, "Unable to process contact %s : %s", 
3922                       user, ldap_err2string(rc));
3923               return(rc);
3924             }
3925           
3926           if (group_count) 
3927             {
3928               com_err(whoami, 0, "Object already exists with name %s",
3929                       user);
3930               return(1);
3931             }
3932   
3933           linklist_free(group_base);
3934           group_count = 0;
3935           group_base = NULL;
3936           
3937           sprintf(filter, "(&(objectClass=user)(mail=%s))", mail);
3938           attr_array[0] = "cn";
3939           attr_array[1] = NULL;
3940
3941           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3942                                    &group_base, &group_count, 
3943                                    LDAP_SCOPE_SUBTREE)) != 0) 
3944             {
3945               com_err(whoami, 0, "Unable to process contact %s : %s", 
3946                       user, ldap_err2string(rc));
3947               return(rc);
3948             }
3949           
3950           if (group_count) 
3951             {
3952               com_err(whoami, 0, "Object already exists with name %s",
3953                       user);
3954               return(1);
3955             }
3956
3957           linklist_free(group_base);
3958           group_base = NULL;
3959           group_count = 0;
3960
3961           sprintf(filter, "(&(objectClass=group)(mail=%s))", mail);
3962           attr_array[0] = "cn";
3963           attr_array[1] = NULL;
3964
3965           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3966                                    &group_base, &group_count, 
3967                                    LDAP_SCOPE_SUBTREE)) != 0) 
3968             {
3969               com_err(whoami, 0, "Unable to process contact %s : %s", 
3970                       user, ldap_err2string(rc));
3971               return(rc);
3972             }
3973       
3974           if (group_count) 
3975             {
3976               com_err(whoami, 0, "Object already exists with name %s",
3977                       user);
3978               return(1);
3979             }
3980           
3981           linklist_free(group_base);
3982           group_base = NULL;
3983           group_count = 0;
3984           
3985           ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
3986           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
3987           ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD);
3988           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD);
3989           
3990           hide_address_lists_v[0] = "TRUE";
3991           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
3992                    LDAP_MOD_ADD);
3993         }
3994     }
3995
3996   if(!ActiveDirectory) 
3997     {
3998       if((c = strchr(mail, '@')) == NULL)
3999           sprintf(temp, "%s@mit.edu", mail);
4000       else
4001           sprintf(temp, "%s", mail);
4002
4003       mail_routing_v[0] = temp;
4004       email_v[0] = temp;
4005       principal_v[0] = principal;
4006
4007       if(!strcmp(group_ou, contact_ou))
4008         {
4009           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4010           ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD);
4011         }
4012     }
4013
4014   mods[n] = NULL;
4015
4016   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4017
4018   for (i = 0; i < n; i++)
4019     free(mods[i]);
4020   
4021   if (Exchange)
4022     {
4023       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
4024           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
4025         {
4026           n = 0;
4027           
4028           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
4029           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
4030           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
4031                    LDAP_MOD_REPLACE);
4032           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
4033
4034           hide_address_lists_v[0] = "TRUE";
4035           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4036                    LDAP_MOD_REPLACE);
4037     
4038           mods[n] = NULL;
4039           rc = ldap_modify_s(ld, new_dn, mods);
4040       
4041           if (rc) 
4042             {
4043               com_err(whoami, 0, "Unable to update contact %s", mail);
4044             }
4045       
4046           for (i = 0; i < n; i++)
4047             free(mods[i]);
4048         }
4049     }
4050
4051   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4052     {
4053       com_err(whoami, 0, "Unable to create contact %s : %s",
4054               user, ldap_err2string(rc));
4055       return(rc);
4056     }
4057
4058   return(0);
4059 }
4060
4061 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
4062                 char *Uid, char *MitId, char *MoiraId, int State,
4063                 char *WinHomeDir, char *WinProfileDir, char *first,
4064                 char *middle, char *last, char *shell, char *class)
4065 {
4066   LDAPMod   *mods[20];
4067   LK_ENTRY  *group_base;
4068   int  group_count;
4069   char distinguished_name[512];
4070   char displayName[256];
4071   char *mitMoiraId_v[] = {NULL, NULL};
4072   char *mitMoiraClass_v[] = {NULL, NULL};
4073   char *mitMoiraStatus_v[] = {NULL, NULL};
4074   char *uid_v[] = {NULL, NULL};
4075   char *mitid_v[] = {NULL, NULL};
4076   char *homedir_v[] = {NULL, NULL};
4077   char *winProfile_v[] = {NULL, NULL};
4078   char *drives_v[] = {NULL, NULL};
4079   char *userAccountControl_v[] = {NULL, NULL};
4080   char *alt_recipient_v[] = {NULL, NULL};
4081   char *hide_address_lists_v[] = {NULL, NULL};
4082   char *mail_v[] = {NULL, NULL};
4083   char *gid_v[] = {NULL, NULL};
4084   char *loginshell_v[] = {NULL, NULL};
4085   char *principal_v[] = {NULL, NULL};
4086   char userAccountControlStr[80];
4087   int  n;
4088   int  rc;
4089   int  i;
4090   int  OldUseSFU30;
4091   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4092     UF_PASSWD_CANT_CHANGE;
4093   char filter[128];
4094   char *attr_array[3];
4095   char temp[1024];
4096   char mail[256];
4097   char contact_mail[256];
4098   char filter_exp[1024];
4099   char search_path[512];
4100   char TemplateDn[512];
4101   char TemplateSamName[128];
4102   char alt_recipient[256];
4103   char principal[256];
4104   char status[256];
4105   char acBERBuf[N_SD_BER_BYTES];
4106   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4107                           { N_SD_BER_BYTES, acBERBuf },
4108                           TRUE};
4109   LDAPControl *apsServerControls[] = {&sControl, NULL};
4110   LDAPMessage *psMsg;
4111   LDAP_BERVAL   **ppsValues;
4112   ULONG dwInfo;
4113   char *argv[3];
4114   char *homeMDB;
4115   char *homeServerName;
4116   char *save_argv[7];
4117   char search_string[256];
4118   char *p, *q;
4119   char *mail_routing_v[] = {NULL, NULL};
4120   char *c;
4121
4122   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4123     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4124   BEREncodeSecurityBits(dwInfo, acBERBuf);
4125
4126   if (!check_string(user_name))
4127     {
4128       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4129               user_name);
4130       return(AD_INVALID_NAME);
4131     }
4132   
4133   memset(contact_mail, '\0', sizeof(contact_mail));
4134   sprintf(contact_mail, "%s@mit.edu", user_name);
4135   memset(mail, '\0', sizeof(mail));
4136   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4137   memset(alt_recipient, '\0', sizeof(alt_recipient));
4138   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4139           dn_path);
4140   sprintf(search_string, "@%s", uppercase(ldap_domain));
4141
4142   if (Exchange)
4143     {
4144       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4145         {
4146           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4147         }
4148     }
4149
4150   group_count = 0;
4151   group_base = NULL;
4152
4153   memset(displayName, '\0', sizeof(displayName));
4154
4155   if (strlen(MoiraId) != 0)
4156     {
4157       if(ActiveDirectory)
4158         {
4159           sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4160         }
4161       else
4162         {
4163           sprintf(filter, 
4164                   "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId);
4165         }
4166
4167       attr_array[0] = "cn";
4168       attr_array[1] = NULL;
4169       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4170                                &group_base, &group_count, 
4171                                LDAP_SCOPE_SUBTREE)) != 0)
4172         {
4173           com_err(whoami, 0, "Unable to process user %s : %s",
4174                   user_name, ldap_err2string(rc));
4175           return(rc);
4176         }
4177     }
4178
4179   if (group_count != 1)
4180     {
4181       linklist_free(group_base);
4182       group_base = NULL;
4183       group_count = 0;
4184       sprintf(filter, "(sAMAccountName=%s)", user_name);
4185       attr_array[0] = "cn";
4186       attr_array[1] = NULL;
4187       sprintf(temp, "%s,%s", user_ou, dn_path);
4188       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
4189                                &group_base, &group_count, 
4190                                LDAP_SCOPE_SUBTREE)) != 0)
4191         {
4192           com_err(whoami, 0, "Unable to process user %s : %s",
4193                   user_name, ldap_err2string(rc));
4194           return(rc);
4195         }
4196     }
4197
4198   if (group_count != 1)
4199     {
4200       com_err(whoami, 0, "Unable to find user %s in directory",
4201               user_name);
4202       linklist_free(group_base);
4203       return(AD_NO_USER_FOUND);
4204     }
4205
4206   strcpy(distinguished_name, group_base->dn);
4207
4208   linklist_free(group_base);
4209   group_count = 0;
4210
4211   if(!ActiveDirectory) 
4212     {
4213       if (rc = moira_connect())
4214         {
4215           critical_alert("Ldap incremental", 
4216                          "Error contacting Moira server : %s",
4217                          error_message(rc));
4218           return;
4219         }
4220   
4221       argv[0] = user_name;
4222       
4223       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4224         {
4225           n = 0;
4226           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
4227           mods[n] = NULL;
4228           rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4229           
4230           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
4231             rc = LDAP_SUCCESS;
4232
4233           if(rc)
4234             com_err(whoami, 0, 
4235                     "Unable to set the mailRoutingAddress for %s : %s",
4236                     user_name, ldap_err2string(rc));
4237           
4238           p = strdup(save_argv[3]);
4239           
4240           if((c = strchr(p, ',')) != NULL) 
4241             {
4242               q = strtok(p, ",");
4243               StringTrim(q);
4244
4245               if ((c = strchr(q, '@')) == NULL)
4246                 sprintf(temp, "%s@mit.edu", q);
4247               else
4248                 sprintf(temp, "%s", q);
4249               
4250               if(email_isvalid(temp) && State != US_DELETED) 
4251                 {
4252                   mail_routing_v[0]  = temp;
4253                   
4254                   n = 0;
4255                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4256                   mods[n] = NULL;
4257                   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4258
4259                   if (rc == LDAP_ALREADY_EXISTS || 
4260                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
4261                     rc = LDAP_SUCCESS;
4262     
4263                   if(rc)
4264                     com_err(whoami, 0, 
4265                             "Unable to set the mailRoutingAddress for %s : %s",
4266                             user_name, ldap_err2string(rc));
4267                 }
4268
4269               while((q = strtok(NULL, ",")) != NULL) {
4270                 StringTrim(q);
4271                 
4272                 if((c = strchr(q, '@')) == NULL) 
4273                   sprintf(temp, "%s@mit.edu", q);
4274                 else
4275                   sprintf(temp, "%s", q);
4276
4277                 if(email_isvalid(temp) && State != US_DELETED) 
4278                   {
4279                     mail_routing_v[0]  = temp;
4280                 
4281                     n = 0;
4282                     ADD_ATTR("mailRoutingAddress", mail_routing_v, 
4283                              LDAP_MOD_ADD);
4284                     mods[n] = NULL;
4285                     rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4286                     
4287                     if (rc == LDAP_ALREADY_EXISTS || 
4288                         rc == LDAP_TYPE_OR_VALUE_EXISTS)
4289                       rc = LDAP_SUCCESS;
4290                     
4291                     if(rc)
4292                       com_err(whoami, 0, 
4293                               "Unable to set the mailRoutingAddress for " 
4294                               "%s : %s",
4295                               user_name, ldap_err2string(rc));
4296                   }
4297               }
4298             } else {
4299               StringTrim(p);
4300
4301             if((c = strchr(p, '@')) == NULL)
4302               sprintf(temp, "%s@mit.edu", p);
4303             else
4304               sprintf(temp, "%s", p);
4305             
4306             if(email_isvalid(temp) && State != US_DELETED) 
4307               {
4308                 mail_routing_v[0]  = temp;
4309                 
4310                 n = 0;
4311                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4312                 mods[n] = NULL;
4313                 rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4314                 
4315                 if (rc == LDAP_ALREADY_EXISTS || 
4316                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
4317                   rc = LDAP_SUCCESS;
4318                 
4319                 if(rc)
4320                   com_err(whoami, 0, 
4321                           "Unable to set the mailRoutingAddress for %s : %s",
4322                           user_name, ldap_err2string(rc));
4323               }
4324             }
4325         }
4326       moira_disconnect();
4327     }
4328
4329   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
4330     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
4331                           "employeeID", user_name);
4332   else
4333     rc = attribute_update(ldap_handle, distinguished_name, "none", 
4334                           "employeeID", user_name);
4335
4336   if(strlen(first)) {
4337     strcat(displayName, first);
4338   }
4339
4340   if(strlen(middle)) {
4341     if(strlen(first)) 
4342       strcat(displayName, " ");
4343
4344     strcat(displayName, middle);
4345   }
4346
4347   if(strlen(last)) {
4348     if(strlen(middle) || strlen(first))
4349       strcat(displayName, " ");
4350
4351     strcat(displayName, last);
4352   }
4353
4354   if(strlen(displayName))
4355     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4356                           "displayName", user_name);
4357   else
4358     rc = attribute_update(ldap_handle, distinguished_name, user_name,
4359                           "displayName", user_name);
4360
4361   if(!ActiveDirectory)
4362     {
4363       if(strlen(displayName))
4364         rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4365                               "cn", user_name);
4366       else
4367         rc = attribute_update(ldap_handle, distinguished_name, user_name,
4368                               "cn", user_name);
4369     }
4370
4371   if(!ActiveDirectory)
4372     {
4373       rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4374                             "eduPersonNickname", user_name);
4375     }
4376
4377   if(strlen(first))
4378     rc = attribute_update(ldap_handle, distinguished_name, first, 
4379                           "givenName", user_name);
4380   else
4381     rc = attribute_update(ldap_handle, distinguished_name, "",
4382                           "givenName", user_name);
4383
4384   if(strlen(middle) == 1) 
4385     rc = attribute_update(ldap_handle, distinguished_name, middle,
4386                           "initials", user_name);
4387   else 
4388     rc = attribute_update(ldap_handle, distinguished_name, "",
4389                           "initials", user_name);
4390   
4391   if(strlen(last))
4392     rc = attribute_update(ldap_handle, distinguished_name, last,
4393                           "sn", user_name);
4394   else 
4395     rc = attribute_update(ldap_handle, distinguished_name, "",
4396                           "sn", user_name);
4397
4398   if(ActiveDirectory)
4399     {
4400       rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4401                             user_name);
4402     }
4403   else
4404     {
4405       rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", 
4406                             user_name);
4407     }
4408     
4409   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4410                         "mitMoiraId", user_name);
4411
4412   n = 0;
4413   uid_v[0] = Uid;
4414
4415   if(ActiveDirectory)
4416     {
4417       if (!UseSFU30)
4418         {
4419           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4420         }
4421       else
4422         {
4423           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4424         }
4425     }
4426   else
4427     {
4428       sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4429       sprintf(status, "%d", State);
4430       principal_v[0] = principal;
4431       loginshell_v[0] = shell;
4432       mitMoiraClass_v[0] = class;
4433       mitMoiraStatus_v[0] = status;
4434       gid_v[0] = "101";
4435       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4436       ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE);
4437       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE);
4438       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4439       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE);
4440       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE);
4441     }
4442
4443   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4444     {
4445       userAccountControl |= UF_ACCOUNTDISABLE;
4446
4447       if (Exchange)
4448         {
4449           hide_address_lists_v[0] = "TRUE";
4450           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4451                    LDAP_MOD_REPLACE);
4452         }
4453     }
4454   else
4455     {
4456       if (Exchange)
4457         {
4458           hide_address_lists_v[0] = NULL;
4459           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4460                    LDAP_MOD_REPLACE);
4461         }
4462     }
4463
4464   sprintf(userAccountControlStr, "%ld", userAccountControl);
4465   userAccountControl_v[0] = userAccountControlStr;
4466   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4467
4468   if (Exchange)
4469     {
4470       if (rc = moira_connect())
4471         {
4472           critical_alert("Ldap incremental", 
4473                          "Error contacting Moira server : %s",
4474                          error_message(rc));
4475           return;
4476         }
4477  
4478       argv[0] = user_name;
4479
4480       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4481         {
4482           if(!strcmp(save_argv[1], "EXCHANGE") || 
4483              (strstr(save_argv[3], search_string) != NULL))
4484             {
4485               alt_recipient_v[0] = NULL;
4486               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4487
4488               argv[0] = exchange_acl;
4489               argv[1] = "USER";
4490               argv[2] = user_name;
4491               
4492               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4493               
4494               if ((rc) && (rc != MR_EXISTS))
4495                 {
4496                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4497                           user_name, exchange_acl, error_message(rc));
4498                 }
4499             }
4500           else 
4501             {
4502               alt_recipient_v[0] = alt_recipient;
4503               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4504               
4505               argv[0] = exchange_acl;
4506               argv[1] = "USER";
4507               argv[2] = user_name;
4508               
4509               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4510               
4511               if ((rc) && (rc != MR_NO_MATCH))
4512                 {  
4513                   com_err(whoami, 0,
4514                           "Unable to remove user %s from %s: %s, %d",
4515                           user_name, exchange_acl, error_message(rc), rc);
4516                 }  
4517             }
4518         }
4519       else
4520         {
4521           alt_recipient_v[0] = alt_recipient;
4522           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4523           
4524           argv[0] = exchange_acl;
4525           argv[1] = "USER";
4526           argv[2] = user_name;
4527           
4528           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4529           
4530           if ((rc) && (rc != MR_NO_MATCH))
4531             {  
4532               com_err(whoami, 0,
4533                       "Unable to remove user %s from %s: %s, %d",
4534                       user_name, exchange_acl, error_message(rc), rc);
4535             }  
4536         }
4537       
4538       moira_disconnect();
4539     }
4540   else
4541     {
4542       mail_v[0] = contact_mail;
4543       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4544     }
4545
4546   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4547                        WinProfileDir, homedir_v, winProfile_v,
4548                        drives_v, mods, LDAP_MOD_REPLACE, n);
4549
4550   if(ActiveDirectory)
4551     {
4552       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4553       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4554       attr_array[0] = "sAMAccountName";
4555       attr_array[1] = NULL;
4556       group_count = 0;
4557       group_base = NULL;
4558     
4559       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
4560                                attr_array,
4561                                &group_base, &group_count, 
4562                                LDAP_SCOPE_SUBTREE) != 0))
4563         return(1);
4564       
4565       if (group_count != 1)
4566         {
4567           com_err(whoami, 0, "Unable to process user security template: %s - "
4568                   "security not set", "UserTemplate.u");
4569           return(1);
4570         }
4571
4572       strcpy(TemplateDn, group_base->dn);
4573       strcpy(TemplateSamName, group_base->value);
4574       linklist_free(group_base);
4575       group_base = NULL;
4576       group_count = 0;
4577       
4578       rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4579                              filter_exp, NULL, 0, apsServerControls, NULL,
4580                              NULL, 0, &psMsg);
4581
4582       if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4583         {
4584           com_err(whoami, 0, "Unable to find user security template: %s - "
4585                   "security not set", "UserTemplate.u");
4586           return(1);
4587         }
4588       
4589       ppsValues = ldap_get_values_len(ldap_handle, psMsg, 
4590                                       "ntSecurityDescriptor");
4591
4592       if (ppsValues == NULL)
4593         {
4594           com_err(whoami, 0, "Unable to find user security template: %s - "
4595                   "security not set", "UserTemplate.u");
4596           return(1);
4597         }
4598       
4599       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4600                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4601     }
4602
4603   mods[n] = NULL;
4604
4605   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4606                           mods)) != LDAP_SUCCESS)
4607     {
4608       OldUseSFU30 = UseSFU30;
4609       SwitchSFU(mods, &UseSFU30, n);
4610       if (OldUseSFU30 != UseSFU30)
4611         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4612       if (rc)
4613         {
4614           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4615                   user_name, ldap_err2string(rc));
4616         }
4617     }
4618   
4619   for (i = 0; i < n; i++)
4620     free(mods[i]);
4621
4622   return(rc);
4623 }
4624
4625 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4626                 char *user_name)
4627 {
4628   LDAPMod *mods[20];
4629   char new_dn[256];
4630   char old_dn[256];
4631   char upn[256];
4632   char mail[256];
4633   char contact_mail[256];
4634   char proxy_address[256];
4635   char query_base_dn[256];
4636   char temp[256];
4637   char *userPrincipalName_v[] = {NULL, NULL};
4638   char *altSecurityIdentities_v[] = {NULL, NULL};
4639   char *name_v[] = {NULL, NULL};
4640   char *samAccountName_v[] = {NULL, NULL};
4641   char *mail_v[] = {NULL, NULL};
4642   char *mail_nickname_v[] = {NULL, NULL};
4643   char *proxy_address_v[] = {NULL, NULL};
4644   char *query_base_dn_v[] = {NULL, NULL};
4645   char *principal_v[] = {NULL, NULL};
4646   char principal[256];
4647   int  n;
4648   int  rc;
4649   int  i;
4650
4651   if (!check_string(before_user_name))
4652     {
4653       com_err(whoami, 0, 
4654               "Unable to process invalid LDAP user name %s", before_user_name);
4655       return(AD_INVALID_NAME);
4656     }
4657
4658   if (!check_string(user_name))
4659     {
4660       com_err(whoami, 0, 
4661               "Unable to process invalid LDAP user name %s", user_name);
4662       return(AD_INVALID_NAME);
4663     }
4664
4665   strcpy(user_name, user_name);
4666  
4667   if(ActiveDirectory)
4668     sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4669   else
4670     sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path);
4671
4672   if(ActiveDirectory)
4673     sprintf(new_dn, "cn=%s", user_name);
4674   else
4675     sprintf(new_dn, "uid=%s", user_name);
4676
4677   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4678   sprintf(contact_mail, "%s@mit.edu", user_name);
4679   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4680   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4681
4682   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4683                            NULL, NULL)) != LDAP_SUCCESS)
4684     {
4685       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4686               before_user_name, user_name, ldap_err2string(rc));
4687       return(rc);
4688     }
4689
4690   if (Exchange)
4691     {
4692       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4693               dn_path);
4694
4695       if(rc = ldap_delete_s(ldap_handle, temp))
4696         {
4697           com_err(whoami, 0, "Unable to delete user contact for %s",
4698                   user_name);
4699         }
4700       
4701       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4702         {
4703           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4704         }
4705     }
4706
4707   name_v[0] = user_name;
4708   sprintf(upn, "%s@%s", user_name, ldap_domain);
4709   userPrincipalName_v[0] = upn;
4710   principal_v[0] = principal;
4711   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4712   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4713   altSecurityIdentities_v[0] = temp;
4714   samAccountName_v[0] = user_name;
4715   mail_v[0] = mail;
4716   mail_nickname_v[0] = user_name;
4717   proxy_address_v[0] = proxy_address; 
4718   query_base_dn_v[0] = query_base_dn;
4719
4720   n = 0;
4721   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4722   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4723   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4724   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4725
4726   if(!ActiveDirectory)
4727     {
4728       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE);
4729       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4730       ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4731       ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE);
4732     }
4733
4734   if (Exchange)
4735     {
4736       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4737       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4738       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4739       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4740     }
4741   else
4742     {
4743       mail_v[0] = contact_mail;
4744       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4745     }
4746
4747   mods[n] = NULL;
4748   
4749   if(ActiveDirectory)
4750     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4751   else
4752     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path);
4753
4754   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4755     {
4756       com_err(whoami, 0, 
4757               "Unable to modify user data for %s after renaming : %s",
4758               user_name, ldap_err2string(rc));
4759     }
4760   
4761   for (i = 0; i < n; i++)
4762     free(mods[i]);
4763
4764   return(rc);
4765 }
4766
4767 int user_create(int ac, char **av, void *ptr)
4768 {
4769   LDAPMod *mods[20];
4770   char new_dn[256];
4771   char user_name[256];
4772   char sam_name[256];
4773   char upn[256];
4774   char mail[256];
4775   char contact_mail[256];
4776   char proxy_address[256];
4777   char mail_nickname[256];
4778   char query_base_dn[256];
4779   char displayName[256];
4780   char address_book[256];
4781   char alt_recipient[256];
4782   char *cn_v[] = {NULL, NULL};
4783   char *objectClass_v[] = {"top", "person", "organizationalPerson",
4784                            "user", NULL};
4785   char *objectClass_ldap_v[] = {"top", 
4786                                 "eduPerson", "posixAccount", 
4787                                 "apple-user", "shadowAccount",
4788                                 "microsoftComTop", "securityPrincipal",
4789                                 "inetOrgPerson", "user", 
4790                                 "organizationalPerson", "person",
4791                                 "mailRecipient", NULL};
4792
4793   char *samAccountName_v[] = {NULL, NULL};
4794   char *altSecurityIdentities_v[] = {NULL, NULL};
4795   char *mitMoiraId_v[] = {NULL, NULL};
4796   char *mitMoiraClass_v[] = {NULL, NULL};
4797   char *mitMoiraStatus_v[] = {NULL, NULL};
4798   char *name_v[] = {NULL, NULL};
4799   char *desc_v[] = {NULL, NULL};
4800   char *userPrincipalName_v[] = {NULL, NULL};
4801   char *userAccountControl_v[] = {NULL, NULL};
4802   char *uid_v[] = {NULL, NULL};
4803   char *gid_v[] = {NULL, NULL};
4804   char *mitid_v[] = {NULL, NULL};
4805   char *homedir_v[] = {NULL, NULL};
4806   char *winProfile_v[] = {NULL, NULL};
4807   char *drives_v[] = {NULL, NULL};
4808   char *mail_v[] = {NULL, NULL};
4809   char *givenName_v[] = {NULL, NULL};
4810   char *sn_v[] = {NULL, NULL};
4811   char *initials_v[] = {NULL, NULL};
4812   char *displayName_v[] = {NULL, NULL};
4813   char *proxy_address_v[] = {NULL, NULL};
4814   char *mail_nickname_v[] = {NULL, NULL};
4815   char *query_base_dn_v[] = {NULL, NULL};
4816   char *address_book_v[] = {NULL, NULL};
4817   char *homeMDB_v[] = {NULL, NULL};
4818   char *homeServerName_v[] = {NULL, NULL};
4819   char *mdbUseDefaults_v[] = {NULL, NULL};
4820   char *mailbox_guid_v[] = {NULL, NULL};
4821   char *user_culture_v[] = {NULL, NULL};
4822   char *user_account_control_v[] = {NULL, NULL};
4823   char *msexch_version_v[] = {NULL, NULL};
4824   char *alt_recipient_v[] = {NULL, NULL};
4825   char *hide_address_lists_v[] = {NULL, NULL};
4826   char *principal_v[] = {NULL, NULL};
4827   char *loginshell_v[] = {NULL, NULL};
4828   char userAccountControlStr[80];
4829   char temp[1024];
4830   char principal[256];
4831   char filter_exp[1024];
4832   char search_path[512];
4833   char *attr_array[3];
4834   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4835     UF_PASSWD_CANT_CHANGE; 
4836   int  n;
4837   int  rc;
4838   int  i;
4839   int  OldUseSFU30;
4840   char **call_args;
4841   char WinHomeDir[1024];
4842   char WinProfileDir[1024];
4843   char *homeMDB;
4844   char *homeServerName;
4845   ULONG dwInfo;
4846   char acBERBuf[N_SD_BER_BYTES];
4847   LK_ENTRY  *group_base;
4848   int    group_count;
4849   char TemplateDn[512];
4850   char TemplateSamName[128];
4851   LDAP_BERVAL **ppsValues;
4852   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4853                           { N_SD_BER_BYTES, acBERBuf },
4854                           TRUE};
4855   LDAPControl *apsServerControls[] = {&sControl, NULL};
4856   LDAPMessage *psMsg;
4857   char *argv[3];
4858   char *save_argv[7];
4859   char search_string[256];
4860   char *o_v[] = {NULL, NULL};
4861   char *p, *q;
4862   char *mail_routing_v[] = {NULL, NULL};
4863   char *c;
4864
4865   call_args = ptr;
4866
4867   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4868     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4869   BEREncodeSecurityBits(dwInfo, acBERBuf);
4870
4871   if (!check_string(av[U_NAME]))
4872     {
4873       callback_rc = AD_INVALID_NAME;
4874       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4875               av[U_NAME]);
4876       return(AD_INVALID_NAME);
4877     }
4878
4879   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4880   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4881   memset(displayName, '\0', sizeof(displayName));
4882   memset(query_base_dn, '\0', sizeof(query_base_dn));
4883   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4884   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4885   strcpy(user_name, av[U_NAME]);
4886   sprintf(upn, "%s@%s", user_name, ldap_domain);
4887   sprintf(sam_name, "%s", av[U_NAME]);
4888
4889   if(strlen(av[U_FIRST])) {
4890     strcat(displayName, av[U_FIRST]);
4891   }
4892
4893   if(strlen(av[U_MIDDLE])) {
4894     if(strlen(av[U_FIRST]))
4895        strcat(displayName, " "); 
4896   
4897     strcat(displayName, av[U_MIDDLE]);
4898   }
4899
4900   if(strlen(av[U_LAST])) {
4901     if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]))
4902       strcat(displayName, " ");
4903
4904     strcat(displayName, av[U_LAST]);
4905   }
4906
4907   samAccountName_v[0] = sam_name;
4908   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4909       (atoi(av[U_STATE]) != US_REGISTERED))
4910     {
4911       userAccountControl |= UF_ACCOUNTDISABLE;
4912
4913       if (Exchange)
4914         {
4915           hide_address_lists_v[0] = "TRUE";
4916           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4917                    LDAP_MOD_ADD);
4918         }
4919     }
4920
4921   sprintf(userAccountControlStr, "%ld", userAccountControl);
4922   userAccountControl_v[0] = userAccountControlStr;
4923   userPrincipalName_v[0] = upn;
4924   
4925   if(ActiveDirectory)
4926     cn_v[0] = user_name;
4927   else
4928     cn_v[0] = displayName;
4929     
4930   name_v[0] = user_name;
4931   desc_v[0] = "Auto account created by Moira";
4932   mail_v[0] = mail;
4933   givenName_v[0] = av[U_FIRST];
4934
4935   if(ActiveDirectory)
4936     sn_v[0] = av[U_LAST];
4937   else
4938     if(strlen(av[U_LAST]))
4939       sn_v[0] = av[U_LAST];
4940     else
4941       sn_v[0] = av[U_NAME];
4942
4943   displayName_v[0] = displayName;
4944   mail_nickname_v[0] = user_name;
4945   o_v[0] = "Massachusetts Institute of Technology";
4946
4947   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4948   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4949   altSecurityIdentities_v[0] = temp;    
4950   principal_v[0] = principal;
4951
4952   if(ActiveDirectory)
4953     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4954   else
4955     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]);
4956
4957   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4958   sprintf(contact_mail, "%s@mit.edu", user_name);
4959   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4960   query_base_dn_v[0] = query_base_dn;
4961   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4962           call_args[1]);
4963   sprintf(search_string, "@%s", uppercase(ldap_domain));
4964
4965   if (Exchange)
4966     {
4967       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
4968                         contact_ou))
4969         {
4970           com_err(whoami, 0, "Unable to create user contact %s", 
4971                   contact_mail);
4972         }
4973       
4974       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
4975                       &homeServerName)) 
4976         {
4977           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
4978           return(1);
4979         }
4980       
4981       com_err(whoami, 0, "homeMDB:%s", homeMDB);
4982       com_err(whoami, 0, "homeServerName:%s", homeServerName);
4983   
4984       homeMDB_v[0] = homeMDB;
4985       homeServerName_v[0] = homeServerName; 
4986     }
4987
4988   n = 0;
4989
4990   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
4991   
4992   if(ActiveDirectory) 
4993     {
4994       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
4995     }
4996   else
4997     {
4998       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
4999     }
5000
5001   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
5002   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
5003   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
5004   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
5005   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
5006
5007   if (Exchange)
5008     {
5009       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
5010       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
5011       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
5012       mdbUseDefaults_v[0] = "TRUE";
5013       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
5014       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
5015       
5016       argv[0] = user_name;
5017     
5018       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5019         {
5020           if(!strcmp(save_argv[1], "EXCHANGE") || 
5021              (strstr(save_argv[3], search_string) != NULL))
5022             {
5023               argv[0] = exchange_acl;
5024               argv[1] = "USER";
5025               argv[2] = user_name;
5026               
5027               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
5028               
5029               if ((rc) && (rc != MR_EXISTS))
5030                 {
5031                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
5032                           user_name, exchange_acl, error_message(rc));
5033                 }
5034             } 
5035           else 
5036             {
5037               alt_recipient_v[0] = alt_recipient;
5038               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5039             }
5040         }
5041       else
5042         {
5043           alt_recipient_v[0] = alt_recipient;
5044           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5045           
5046           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
5047         }
5048     }
5049   else
5050     {
5051       mail_v[0] = contact_mail;
5052       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
5053     }
5054
5055   if(strlen(av[U_FIRST])) {
5056     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
5057   }
5058
5059   if(strlen(av[U_LAST]) || strlen(av[U_NAME])) {
5060     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
5061   }
5062
5063   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
5064     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
5065
5066     if(!ActiveDirectory)
5067       {
5068         ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD);      
5069       }
5070   } else {
5071     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
5072
5073     if(!ActiveDirectory)
5074       {
5075         ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD);            
5076       }
5077   }
5078
5079   if (strlen(av[U_MIDDLE]) == 1) {
5080     initials_v[0] = av[U_MIDDLE];
5081     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
5082   }
5083
5084   if (strlen(call_args[2]) != 0)    
5085     {
5086       mitMoiraId_v[0] = call_args[2];
5087       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
5088     }
5089
5090   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
5091
5092   if(!ActiveDirectory)
5093     {
5094       loginshell_v[0] = av[U_SHELL];
5095       mitMoiraClass_v[0] = av[U_CLASS];
5096       mitMoiraStatus_v[0] = av[U_STATE];
5097       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD);
5098       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD);
5099       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD);
5100       ADD_ATTR("o", o_v, LDAP_MOD_ADD);
5101       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD);
5102       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD);
5103     }
5104
5105   if (strlen(av[U_UID]) != 0)
5106     {
5107       uid_v[0] = av[U_UID];
5108
5109       if(ActiveDirectory) 
5110         {
5111           ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
5112         }
5113       else
5114         {
5115           gid_v[0] = "101";
5116           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5117           ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD);
5118         }
5119
5120       if(ActiveDirectory)
5121         {
5122           if (!UseSFU30)
5123             {
5124               ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5125             }
5126           else
5127             {
5128               ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
5129             }
5130         }
5131     }
5132
5133   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
5134       mitid_v[0] = av[U_MITID];
5135   else
5136       mitid_v[0] = "none";
5137
5138   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
5139
5140   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, 
5141                        WinHomeDir, WinProfileDir, homedir_v, winProfile_v,
5142                        drives_v, mods, LDAP_MOD_ADD, n);
5143   
5144   if(ActiveDirectory) 
5145     {
5146       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
5147       sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
5148       attr_array[0] = "sAMAccountName";
5149       attr_array[1] = NULL;
5150       group_count = 0;
5151       group_base = NULL;
5152       
5153       if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
5154                                attr_array, &group_base, &group_count, 
5155                                LDAP_SCOPE_SUBTREE) != 0))
5156         return(1);
5157       
5158       if (group_count != 1)
5159         {
5160           com_err(whoami, 0, "Unable to process user security template: %s - "
5161                   "security not set", "UserTemplate.u");
5162           return(1);
5163         }
5164       
5165       strcpy(TemplateDn, group_base->dn);
5166       strcpy(TemplateSamName, group_base->value);
5167       linklist_free(group_base);
5168       group_base = NULL;
5169       group_count = 0;
5170       
5171       rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, 
5172                              LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, 
5173                              apsServerControls, NULL,
5174                              NULL, 0, &psMsg);
5175       
5176       if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
5177         {
5178           com_err(whoami, 0, "Unable to find user security template: %s - "
5179                   "security not set", "UserTemplate.u");
5180           return(1);
5181         }
5182       
5183       ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
5184                                       "ntSecurityDescriptor");
5185       if (ppsValues == NULL)
5186         {
5187           com_err(whoami, 0, "Unable to find user security template: %s - "
5188                   "security not set", "UserTemplate.u");
5189           return(1);
5190         }
5191       
5192       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
5193                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
5194     }
5195
5196   mods[n] = NULL;
5197
5198   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5199
5200   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5201     {
5202       OldUseSFU30 = UseSFU30;
5203       SwitchSFU(mods, &UseSFU30, n);
5204       if (OldUseSFU30 != UseSFU30)
5205         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5206     }
5207
5208   for (i = 0; i < n; i++)
5209     free(mods[i]);
5210
5211   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5212     {
5213       com_err(whoami, 0, "Unable to create user %s : %s",
5214               user_name, ldap_err2string(rc));
5215       callback_rc = rc;
5216       return(rc);
5217     }
5218
5219   if ((rc == LDAP_SUCCESS) && (SetPassword))
5220     {
5221       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5222         {
5223           ad_kdc_disconnect();
5224           if (!ad_server_connect(default_server, ldap_domain))
5225             {
5226               com_err(whoami, 0, "Unable to set password for user %s : %s",
5227                       user_name, 
5228                       "cannot get changepw ticket from windows domain");
5229             }
5230           else
5231             {
5232               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5233                 {
5234                   com_err(whoami, 0, "Unable to set password for user %s "
5235                           ": %ld", user_name, rc);
5236                 }
5237             }
5238         }
5239     }
5240
5241   if(!ActiveDirectory) 
5242     {
5243       if (rc = moira_connect())
5244         {
5245           critical_alert("Ldap incremental", 
5246                          "Error contacting Moira server : %s",
5247                          error_message(rc));
5248           return;
5249         }
5250   
5251       argv[0] = user_name;
5252       
5253       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5254         {
5255           n = 0;
5256           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
5257           mods[n] = NULL;
5258           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5259            
5260           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
5261             rc = LDAP_SUCCESS;
5262
5263           if(rc)
5264             com_err(whoami, 0,
5265                     "Unable to set the mailRoutingAddress for %s : %s",
5266                     user_name, ldap_err2string(rc));
5267
5268           p = strdup(save_argv[3]);
5269           
5270           if((c = strchr(p, ',')) != NULL) {
5271             q = strtok(p, ",");
5272             StringTrim(q);
5273
5274             if ((c = strchr(q, '@')) == NULL)
5275               sprintf(temp, "%s@mit.edu", q);
5276             else
5277               sprintf(temp, "%s", q);
5278
5279             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5280               {
5281                 mail_routing_v[0]  = temp;
5282
5283                 n = 0;
5284                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5285                 mods[n] = NULL;
5286                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5287                 
5288                 if (rc == LDAP_ALREADY_EXISTS || 
5289                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5290                   rc = LDAP_SUCCESS;
5291                 
5292                 if(rc)
5293                   com_err(whoami, 0, 
5294                           "Unable to set the mailRoutingAddress for %s : %s",
5295                           user_name, ldap_err2string(rc));
5296               }
5297
5298             while((q = strtok(NULL, ",")) != NULL) {
5299               StringTrim(q);
5300
5301               if((c = strchr(q, '@')) == NULL)
5302                 sprintf(temp, "%s@mit.edu", q);
5303               else
5304                 sprintf(temp, "%s", q);
5305
5306               if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED)
5307                 {
5308                   mail_routing_v[0]  = temp;
5309                   
5310                   n = 0;
5311                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5312                   mods[n] = NULL;
5313                   rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5314                   
5315                   if (rc == LDAP_ALREADY_EXISTS || 
5316                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
5317                     rc = LDAP_SUCCESS;
5318                   
5319                   if(rc)
5320                     com_err(whoami, 0, 
5321                             "Unable to set the mailRoutingAddress for %s : %s",
5322                             user_name, ldap_err2string(rc));
5323                 }
5324             }
5325           } else {
5326             StringTrim(p);
5327
5328             if((c = strchr(p, '@')) == NULL)
5329               sprintf(temp, "%s@mit.edu", p);
5330             else
5331               sprintf(temp, "%s", p);
5332
5333             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5334               {
5335                 mail_routing_v[0]  = temp;
5336                 
5337                 n = 0;
5338                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5339                 mods[n] = NULL;
5340                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5341                 
5342                 if (rc == LDAP_ALREADY_EXISTS || 
5343                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5344                   rc = LDAP_SUCCESS;
5345                 
5346                 if(rc)
5347                   com_err(whoami, 0, 
5348                           "Unable to set the mailRoutingAddress for %s : %s",
5349                           user_name, ldap_err2string(rc));
5350               }
5351           }
5352         }
5353       moira_disconnect();
5354     }
5355
5356   return(0);
5357 }
5358
5359 int user_change_status(LDAP *ldap_handle, char *dn_path, 
5360                        char *user_name, char *MoiraId,
5361                        int operation)
5362 {
5363   char      filter[128];
5364   char      *attr_array[3];
5365   char      temp[256];
5366   char      distinguished_name[1024];
5367   char      **modvalues;
5368   char      *mitMoiraId_v[] = {NULL, NULL};
5369   LDAPMod   *mods[20];
5370   LK_ENTRY  *group_base;
5371   int       group_count;
5372   int       rc;
5373   int       i;
5374   int       n;
5375   ULONG     ulongValue;
5376
5377   if (!check_string(user_name))
5378     {
5379       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
5380               user_name);
5381       return(AD_INVALID_NAME);
5382     }
5383
5384   group_count = 0;
5385   group_base = NULL;
5386
5387   if (strlen(MoiraId) != 0)
5388     {
5389       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5390       attr_array[0] = "UserAccountControl";
5391       attr_array[1] = NULL;
5392       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5393                                &group_base, &group_count, 
5394                                LDAP_SCOPE_SUBTREE)) != 0)
5395         {
5396           com_err(whoami, 0, "Unable to process user %s : %s",
5397                   user_name, ldap_err2string(rc));
5398           return(rc);
5399         }
5400     }
5401
5402   if (group_count != 1)
5403     {
5404       linklist_free(group_base);
5405       group_count = 0;
5406       group_base = NULL;
5407       sprintf(filter, "(sAMAccountName=%s)", user_name);
5408       attr_array[0] = "UserAccountControl";
5409       attr_array[1] = NULL;
5410       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5411                                &group_base, &group_count, 
5412                                LDAP_SCOPE_SUBTREE)) != 0)
5413         {
5414           com_err(whoami, 0, "Unable to process user %s : %s",
5415                   user_name, ldap_err2string(rc));
5416           return(rc);
5417         }
5418     }
5419   
5420   if (group_count != 1)
5421     {
5422       linklist_free(group_base);
5423       com_err(whoami, 0, "Unable to find user %s in directory",
5424               user_name);
5425       return(LDAP_NO_SUCH_OBJECT);
5426     }
5427
5428   strcpy(distinguished_name, group_base->dn);
5429   ulongValue = atoi((*group_base).value);
5430
5431   if (operation == MEMBER_DEACTIVATE)
5432     ulongValue |= UF_ACCOUNTDISABLE;
5433   else    
5434     ulongValue &= ~UF_ACCOUNTDISABLE;
5435
5436   sprintf(temp, "%ld", ulongValue);
5437
5438   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
5439                                 temp, &modvalues, REPLACE)) == 1)
5440     goto cleanup;
5441
5442   linklist_free(group_base);
5443   group_base = NULL;
5444   group_count = 0;
5445   n = 0;
5446   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
5447
5448   if (strlen(MoiraId) != 0)
5449     {
5450     mitMoiraId_v[0] = MoiraId;
5451     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
5452     }
5453
5454   mods[n] = NULL;
5455   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
5456
5457   for (i = 0; i < n; i++)
5458     free(mods[i]);
5459
5460   free_values(modvalues);
5461
5462   if (rc != LDAP_SUCCESS)
5463     {
5464       com_err(whoami, 0, "Unable to change status of user %s : %s",
5465               user_name, ldap_err2string(rc));
5466     }
5467   
5468  cleanup:
5469   return(rc);
5470 }
5471
5472 int user_delete(LDAP *ldap_handle, char *dn_path, 
5473                 char *u_name, char *MoiraId)
5474 {
5475   char      filter[128];
5476   char      *attr_array[3];
5477   char      distinguished_name[1024];
5478   char      user_name[512];
5479   LK_ENTRY  *group_base;
5480   int       group_count;
5481   int       rc;
5482   char      temp[256];
5483
5484   if (!check_string(u_name))
5485     return(AD_INVALID_NAME);
5486
5487   strcpy(user_name, u_name);
5488   group_count = 0;
5489   group_base = NULL;
5490
5491   if (strlen(MoiraId) != 0)
5492     {
5493       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5494       attr_array[0] = "name";
5495       attr_array[1] = NULL;
5496       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5497                                &group_base, &group_count, 
5498                                LDAP_SCOPE_SUBTREE)) != 0)
5499         {
5500           com_err(whoami, 0, "Unable to process user %s : %s",
5501                   user_name, ldap_err2string(rc));
5502           goto cleanup;
5503         }
5504     }
5505   
5506   if (group_count != 1)
5507     {
5508       linklist_free(group_base);
5509       group_count = 0;
5510       group_base = NULL;
5511       sprintf(filter, "(sAMAccountName=%s)", user_name);
5512       attr_array[0] = "name";
5513       attr_array[1] = NULL;
5514       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5515                                &group_base, &group_count, 
5516                                LDAP_SCOPE_SUBTREE)) != 0)
5517         {
5518           com_err(whoami, 0, "Unable to process user %s : %s",
5519                   user_name, ldap_err2string(rc));
5520           goto cleanup;
5521         }
5522     }
5523
5524   if (group_count != 1)
5525     {
5526       com_err(whoami, 0, "Unable to find user %s in directory",
5527               user_name);
5528       goto cleanup;
5529     }
5530   
5531   strcpy(distinguished_name, group_base->dn);
5532
5533   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
5534     {
5535       com_err(whoami, 0, "Unable to process user %s : %s",
5536               user_name, ldap_err2string(rc));
5537     }
5538
5539   /* Need to add code to delete mit.edu contact */
5540   
5541   if (Exchange)
5542     {
5543       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
5544
5545       if(rc = ldap_delete_s(ldap_handle, temp))
5546         {
5547           com_err(whoami, 0, "Unable to delete user contact for %s",
5548                   user_name);
5549         }
5550     }
5551
5552  cleanup:
5553   linklist_free(group_base);
5554
5555   return(0);
5556 }
5557
5558 void linklist_free(LK_ENTRY *linklist_base)
5559 {
5560   LK_ENTRY *linklist_previous;
5561
5562   while (linklist_base != NULL)
5563     {
5564       if (linklist_base->dn != NULL)
5565         free(linklist_base->dn);
5566
5567       if (linklist_base->attribute != NULL)
5568         free(linklist_base->attribute);
5569
5570       if (linklist_base->value != NULL)
5571         free(linklist_base->value);
5572
5573       if (linklist_base->member != NULL)
5574         free(linklist_base->member);
5575
5576       if (linklist_base->type != NULL)
5577         free(linklist_base->type);
5578
5579       if (linklist_base->list != NULL)
5580         free(linklist_base->list);
5581
5582       linklist_previous = linklist_base;
5583       linklist_base = linklist_previous->next;
5584       free(linklist_previous);
5585     }
5586 }
5587
5588 void free_values(char **modvalues)
5589 {
5590   int i;
5591
5592   i = 0;
5593
5594   if (modvalues != NULL)
5595     {
5596     while (modvalues[i] != NULL)
5597       {
5598         free(modvalues[i]);
5599         modvalues[i] = NULL;
5600         ++i;
5601       }
5602     free(modvalues);
5603   }
5604 }
5605
5606 static int illegalchars[] = {
5607   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5608   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5609   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
5610   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5611   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5612   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5613   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5614   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5615   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5616   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5617   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5618   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5619   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5620   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5621   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5622   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5623 };
5624
5625 static int illegalchars_ldap[] = {
5626   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5627   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5628   0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, /* SPACE - / */
5629   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
5630   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5631   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */
5632   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5633   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5634   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5635   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5636   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5637   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5638   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5639   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5640   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5641   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5642 };
5643
5644 int check_string(char *s)
5645 {
5646   char  character;
5647
5648   for (; *s; s++)
5649     {
5650       character = *s;
5651
5652       if (isupper(character))
5653         character = tolower(character);
5654
5655       if(ActiveDirectory)
5656         {
5657           if (illegalchars[(unsigned) character])
5658             return 0;
5659         }
5660       else
5661         {
5662           if (illegalchars_ldap[(unsigned) character])
5663             return 0;
5664         }
5665     }
5666
5667   return(1);
5668 }
5669
5670 int check_container_name(char *s)
5671 {
5672   char  character;
5673
5674   for (; *s; s++)
5675     {
5676       character = *s;
5677
5678       if (isupper(character))
5679         character = tolower(character);
5680
5681       if (character == ' ')
5682         continue;
5683
5684       if (illegalchars[(unsigned) character])
5685         return 0;
5686     }
5687
5688   return(1);
5689 }
5690
5691 int mr_connect_cl(char *server, char *client, int version, int auth)
5692 {
5693   int   status;
5694   char  *motd;
5695   char  temp[128];
5696
5697   status = mr_connect(server);
5698
5699   if (status)
5700     {
5701       com_err(whoami, status, "while connecting to Moira");
5702       return status;
5703     }
5704
5705   status = mr_motd(&motd);
5706
5707   if (status)
5708     {
5709       mr_disconnect();
5710       com_err(whoami, status, "while checking server status");
5711       return status;
5712     }
5713
5714   if (motd)
5715     {
5716       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5717       com_err(whoami, status, temp);
5718       mr_disconnect();
5719       return status;
5720     }
5721
5722   status = mr_version(version);
5723
5724   if (status)
5725     {
5726       if (status == MR_UNKNOWN_PROC)
5727         {
5728           if (version > 2)
5729             status = MR_VERSION_HIGH;
5730           else
5731             status = MR_SUCCESS;
5732         }
5733
5734       if (status == MR_VERSION_HIGH)
5735         {
5736           com_err(whoami, 0, "Warning: This client is running newer code "
5737                   "than the server.");
5738                   com_err(whoami, 0, "Some operations may not work.");
5739         }
5740       else if (status && status != MR_VERSION_LOW)
5741         {
5742           com_err(whoami, status, "while setting query version number.");
5743           mr_disconnect();
5744           return status;
5745         }
5746     }
5747
5748   if (auth)
5749     {
5750       status = mr_krb5_auth(client);
5751       if (status)
5752         {
5753           com_err(whoami, status, "while authenticating to Moira.");
5754           mr_disconnect();
5755           return status;
5756         }
5757     }
5758   
5759   return MR_SUCCESS;
5760 }
5761
5762 void AfsToWinAfs(char* path, char* winPath)
5763 {
5764   char* pathPtr;
5765   char* winPathPtr;
5766   strcpy(winPath, WINAFS);
5767   pathPtr = path + strlen(AFS);
5768   winPathPtr = winPath + strlen(WINAFS);
5769   
5770   while (*pathPtr)
5771     {
5772       if (*pathPtr == '/')
5773         *winPathPtr = '\\';
5774       else
5775         *winPathPtr = *pathPtr;
5776       
5777       pathPtr++;
5778       winPathPtr++;
5779     }
5780 }
5781
5782 int GetAceInfo(int ac, char **av, void *ptr)
5783 {
5784   char **call_args;
5785   int   security_flag;
5786
5787   call_args = ptr;
5788   
5789   strcpy(call_args[0], av[L_ACE_TYPE]);
5790   strcpy(call_args[1], av[L_ACE_NAME]);
5791   security_flag = 0;
5792   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5793   return(LDAP_SUCCESS);  
5794 }
5795
5796 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5797 {
5798   char filter[128];
5799   char *attr_array[3];
5800   int  group_count;
5801   int  rc;
5802   LK_ENTRY  *group_base;
5803   
5804   group_count = 0;
5805   group_base = NULL;
5806   
5807   sprintf(filter, "(sAMAccountName=%s)", Name);
5808   attr_array[0] = "sAMAccountName";
5809   attr_array[1] = NULL;
5810
5811   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5812                            &group_base, &group_count, 
5813                            LDAP_SCOPE_SUBTREE)) != 0)
5814     {
5815       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5816               Name, ldap_err2string(rc));
5817       return(1);
5818     }
5819
5820   linklist_free(group_base);
5821   group_base = NULL;
5822
5823   if (group_count == 0)
5824     return(0);
5825   
5826   return(1);
5827 }
5828
5829 #define MAX_ACE 7
5830
5831 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5832                int UpdateGroup, int *ProcessGroup, char *maillist)
5833 {
5834   char  *av[2];
5835   char  GroupName[256];
5836   char  *call_args[7];
5837   int   rc;
5838   char  *AceInfo[4];
5839   char  AceType[32];
5840   char  AceName[128];
5841   char  AceMembership[2];
5842   char  AceOu[256];
5843   char  temp[128];
5844   char  *save_argv[U_END];
5845
5846   if (!SetGroupAce)
5847     {
5848       com_err(whoami, 0, "ProcessAce disabled, skipping");
5849       return(0);
5850     }
5851
5852   strcpy(GroupName, Name);
5853   
5854   if (strcasecmp(Type, "LIST"))
5855     return(1);
5856
5857   while (1)
5858     {
5859       av[0] = GroupName;
5860       AceInfo[0] = AceType;
5861       AceInfo[1] = AceName;
5862       AceInfo[2] = AceMembership;
5863       AceInfo[3] = AceOu;
5864       memset(AceType, '\0', sizeof(AceType));
5865       memset(AceName, '\0', sizeof(AceName));
5866       memset(AceMembership, '\0', sizeof(AceMembership));
5867       memset(AceOu, '\0', sizeof(AceOu));
5868       callback_rc = 0;
5869     
5870       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5871         { 
5872           com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5873                   GroupName, error_message(rc));
5874           return(1);
5875         }
5876
5877       if (callback_rc)
5878         {
5879           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5880           return(1);
5881         }
5882
5883       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5884         return(0);
5885
5886       strcpy(temp, AceName);
5887
5888       if (!strcasecmp(AceType, "LIST"))
5889         sprintf(temp, "%s%s", AceName, group_suffix);
5890
5891       if (!UpdateGroup)
5892         {
5893           if (checkADname(ldap_handle, dn_path, temp))
5894               return(0);
5895
5896           (*ProcessGroup) = 1;
5897         }
5898
5899       if (!strcasecmp(AceInfo[0], "LIST"))
5900         {
5901           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5902                              AceMembership, 0, UpdateGroup, maillist))
5903             return(1);
5904
5905           populate_group(ldap_handle, dn_path, AceName, AceOu, AceMembership,
5906                          0, "");
5907         }
5908       else if (!strcasecmp(AceInfo[0], "USER"))
5909         {
5910           av[0] = AceName;
5911           call_args[0] = (char *)ldap_handle;
5912           call_args[1] = dn_path;
5913           call_args[2] = "";
5914           call_args[3] = NULL;
5915           callback_rc = 0;
5916
5917           if (rc = mr_query("get_user_account_by_login", 1, av, 
5918                             save_query_info, save_argv))
5919             {
5920               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5921                       AceName, Name);
5922               return(1);
5923             }
5924
5925           if (rc = user_create(U_END, save_argv, call_args)) 
5926             {
5927               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5928                       AceName, Name);
5929               return(1);
5930             }
5931           
5932           if (callback_rc)
5933             {
5934               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5935                       AceName, Name);
5936               return(1);
5937             }
5938
5939           return(0);
5940         }
5941       else
5942         return(1);
5943
5944       if (!strcasecmp(AceType, "LIST"))
5945         {
5946           if (!strcasecmp(GroupName, AceName))
5947             return(0);
5948         }
5949
5950       strcpy(GroupName, AceName);
5951     }
5952   
5953   return(1);
5954 }
5955
5956 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
5957                    char *group_name, char *group_ou, char *group_membership, 
5958                    int group_security_flag, int updateGroup, char *maillist)
5959 {
5960   char  *av[3];
5961   char  *call_args[8];
5962   int   rc;
5963   LK_ENTRY  *group_base;
5964   int  group_count;
5965   char filter[128];
5966   char *attr_array[3];
5967
5968   av[0] = group_name;
5969   call_args[0] = (char *)ldap_handle;
5970   call_args[1] = dn_path;
5971   call_args[2] = group_name;
5972   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
5973   call_args[4] = (char *)updateGroup;
5974   call_args[5] = MoiraId;
5975   call_args[6] = "0";
5976   call_args[7] = NULL;
5977   callback_rc = 0;
5978
5979   group_count = 0;
5980   group_base = NULL;
5981
5982   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
5983     {
5984       moira_disconnect();
5985       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
5986               error_message(rc));
5987       return(rc);
5988     }
5989
5990   if (callback_rc)
5991     {
5992       moira_disconnect();
5993       com_err(whoami, 0, "Unable to create list %s", group_name);
5994       return(callback_rc);
5995     }
5996
5997   return(0);
5998 }
5999
6000 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
6001                    char *group_ou, char *group_membership, 
6002                    int group_security_flag, char *MoiraId)
6003 {
6004   char      *av[3];
6005   char      *call_args[7];
6006   char      *pUserOu;
6007   LK_ENTRY  *ptr;
6008   int       rc;
6009   char      member[512];
6010   char      *s;
6011   char      **members;
6012   int       i = 0;
6013   int       j = 0;
6014   int       n = 0;
6015   char      group_dn[512];
6016   LDAPMod   *mods[20];
6017   char      *member_v[] = {NULL, NULL};
6018   char      *save_argv[U_END];
6019   char      machine_ou[256];
6020   char      NewMachineName[1024];
6021
6022   com_err(whoami, 0, "Populating group %s", group_name);
6023   av[0] = group_name;
6024   call_args[0] = (char *)ldap_handle;
6025   call_args[1] = dn_path;
6026   call_args[2] = group_name;
6027   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS | 
6028                           MOIRA_MACHINE);
6029   call_args[4] = NULL;
6030   member_base = NULL;
6031
6032   if (rc = mr_query("get_end_members_of_list", 1, av,
6033                     member_list_build, call_args))
6034     {
6035       if(rc == MR_LIST)
6036         return(0);
6037       
6038       com_err(whoami, 0, "Unable to populate list %s : %s", 
6039               group_name, error_message(rc));
6040       return(3);
6041     }
6042
6043   members = (char **)malloc(sizeof(char *) * 2);
6044
6045   if (member_base != NULL)
6046     {
6047       ptr = member_base;
6048
6049       while (ptr != NULL)
6050         {
6051           if (!strcasecmp(ptr->type, "LIST"))
6052             {
6053               ptr = ptr->next;
6054               continue;
6055             }
6056           
6057           if (!strcasecmp(ptr->type, "MACHINE") && !ProcessMachineContainer)
6058             {
6059               ptr = ptr->next;
6060               continue;
6061             }
6062             
6063           if(!strcasecmp(ptr->type, "USER"))
6064             {
6065               if(!strcasecmp(ptr->member, PRODUCTION_PRINCIPAL) ||
6066                  !strcasecmp(ptr->member, TEST_PRINCIPAL))
6067                 {
6068                   ptr = ptr->next;
6069                   continue;
6070                 }
6071
6072               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6073                                    "")) == AD_NO_USER_FOUND)
6074                 {
6075                   com_err(whoami, 0, "creating user %s", ptr->member);
6076
6077                   av[0] = ptr->member;
6078                   call_args[0] = (char *)ldap_handle;
6079                   call_args[1] = dn_path;
6080                   call_args[2] = "";
6081                   call_args[3] = NULL;
6082                   callback_rc = 0;
6083                   
6084                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6085                                     save_query_info, save_argv))
6086                     {
6087                       com_err(whoami, 0, "Unable to create user %s " 
6088                               "while populating group %s.", ptr->member,
6089                               group_name);
6090
6091                       return(3);
6092                     }
6093
6094                   if (rc = user_create(U_END, save_argv, call_args)) 
6095                     {
6096                       com_err(whoami, 0, "Unable to create user %s "
6097                               "while populating group %s.", ptr->member,
6098                               group_name);
6099                       
6100                       return(3);
6101                     }
6102           
6103                   if (callback_rc)
6104                     {
6105                       com_err(whoami, 0, "Unable to create user %s "
6106                               "while populating group %s", ptr->member, 
6107                               group_name);
6108
6109                       return(3);
6110                     }
6111                 }
6112
6113               pUserOu = user_ou;
6114                   
6115               if(ActiveDirectory) 
6116                 {
6117                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6118                           dn_path);
6119                 }
6120               else 
6121                 {
6122                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6123                           dn_path);
6124                 }
6125
6126             }
6127           else if (!strcasecmp(ptr->type, "STRING"))
6128             {
6129               if (contact_create(ldap_handle, dn_path, ptr->member,
6130                                  contact_ou))
6131                 return(3);
6132
6133               pUserOu = contact_ou;
6134               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6135                       pUserOu, dn_path);
6136             }
6137           else if (!strcasecmp(ptr->type, "KERBEROS"))
6138             {
6139               if (contact_create(ldap_handle, dn_path, ptr->member, 
6140                                  kerberos_ou))
6141                 return(3);
6142
6143               pUserOu = kerberos_ou;
6144               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6145                       pUserOu, dn_path);
6146             }
6147           else if (!strcasecmp(ptr->type, "MACHINE"))
6148             {
6149               memset(machine_ou, '\0', sizeof(machine_ou));
6150               memset(NewMachineName, '\0', sizeof(NewMachineName));
6151
6152               if (!get_machine_ou(ldap_handle, dn_path, ptr->member,
6153                                  machine_ou, NewMachineName))
6154                 {
6155                   pUserOu = machine_ou;
6156                   sprintf(member, "cn=%s,%s,%s", NewMachineName, pUserOu,
6157                           dn_path);
6158                 }
6159               else
6160                 {
6161                   ptr = ptr->next;                  
6162                   continue;
6163                 }
6164             }
6165
6166           if(i > 1) 
6167             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6168           members[i++] = strdup(member);
6169
6170           ptr = ptr->next;
6171         }
6172     
6173       linklist_free(member_base);
6174       member_base = NULL;
6175     }
6176
6177   members[i] = NULL;
6178
6179   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6180
6181   if(GroupPopulateDelete)
6182     {
6183       n = 0;
6184       ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
6185       mods[n] = NULL;
6186       
6187       if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6188                               mods)) != LDAP_SUCCESS)
6189         {
6190           com_err(whoami, 0,
6191                   "Unable to populate group membership for %s: %s",
6192                   group_dn, ldap_err2string(rc));
6193         }
6194   
6195       for (i = 0; i < n; i++)
6196         free(mods[i]);
6197     }
6198
6199   n = 0;
6200   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6201   mods[n] = NULL;
6202
6203   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6204                           mods)) != LDAP_SUCCESS)
6205     {
6206       com_err(whoami, 0,
6207               "Unable to populate group membership for %s: %s",
6208               group_dn, ldap_err2string(rc));
6209     }
6210   
6211   for (i = 0; i < n; i++)
6212     free(mods[i]);
6213     
6214   free(members);
6215
6216   return(0);
6217 }
6218
6219 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6220                   char *group_name, char *group_ou, char *group_membership, 
6221                   int group_security_flag, int type, char *maillist)
6222 {
6223   char      before_desc[512];
6224   char      before_name[256];
6225   char      before_group_ou[256];
6226   char      before_group_membership[2];
6227   char      distinguishedName[256];
6228   char      ad_distinguishedName[256];
6229   char      filter[128];
6230   char      *attr_array[3];
6231   int       before_security_flag;
6232   int       group_count;
6233   int       rc;
6234   LK_ENTRY  *group_base;
6235   LK_ENTRY  *ptr;
6236   char      ou_both[512];
6237   char      ou_security[512];
6238   char      ou_distribution[512];
6239   char      ou_neither[512];
6240   char      group_dn[512];
6241
6242   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6243   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6244
6245   memset(filter, '\0', sizeof(filter));
6246   group_base = NULL;
6247   group_count = 0;
6248
6249   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6250                         "*", MoiraId, 
6251                         "samAccountName", &group_base, 
6252                         &group_count, filter))
6253     return(rc);
6254
6255   if (type == CHECK_GROUPS)
6256     {
6257       if (group_count == 1)
6258         {
6259           strcpy(group_dn, group_base->dn);
6260
6261           if (!strcasecmp(group_dn, distinguishedName))
6262             {
6263               linklist_free(group_base);
6264               return(0);
6265             }
6266         }
6267
6268       linklist_free(group_base);
6269
6270       if (group_count == 0)
6271         return(AD_NO_GROUPS_FOUND);
6272
6273       if (group_count == 1)
6274         return(AD_WRONG_GROUP_DN_FOUND);
6275
6276       return(AD_MULTIPLE_GROUPS_FOUND);
6277     }
6278
6279   if (group_count == 0)
6280     {
6281       return(AD_NO_GROUPS_FOUND);
6282     }
6283
6284   if (group_count > 1)
6285     {
6286       ptr = group_base;
6287
6288       strcpy(group_dn, ptr->dn);
6289
6290       while (ptr != NULL)
6291         {
6292           if (!strcasecmp(group_dn, ptr->value))
6293             break;
6294
6295           ptr = ptr->next;
6296         }
6297
6298       if (ptr == NULL)
6299         {
6300           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6301                   MoiraId);
6302           ptr = group_base;
6303
6304           while (ptr != NULL)
6305             {
6306               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6307               ptr = ptr->next;
6308             }
6309
6310           linklist_free(group_base);
6311           return(AD_MULTIPLE_GROUPS_FOUND);
6312         }
6313
6314       ptr = group_base;
6315
6316       while (ptr != NULL)
6317         {
6318           strcpy(group_dn, ptr->dn);
6319
6320           if (strcasecmp(group_dn, ptr->value))
6321             rc = ldap_delete_s(ldap_handle, ptr->value);
6322
6323           ptr = ptr->next;
6324         }
6325
6326       linklist_free(group_base);
6327       memset(filter, '\0', sizeof(filter));
6328       group_base = NULL;
6329       group_count = 0;
6330
6331       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6332                             "*", MoiraId, 
6333                             "samAccountName", &group_base, 
6334                             &group_count, filter))
6335         return(rc);
6336
6337       if (group_count == 0)
6338         return(AD_NO_GROUPS_FOUND);
6339
6340       if (group_count > 1)
6341         return(AD_MULTIPLE_GROUPS_FOUND);
6342     }
6343
6344   strcpy(ad_distinguishedName, group_base->dn);
6345   linklist_free(group_base);
6346   group_base = NULL;
6347   group_count = 0;
6348
6349   attr_array[0] = "sAMAccountName";
6350   attr_array[1] = NULL;
6351   
6352   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6353                            &group_base, &group_count, 
6354                            LDAP_SCOPE_SUBTREE)) != 0)
6355     {
6356       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6357               MoiraId, ldap_err2string(rc));
6358       return(rc);
6359     }
6360   
6361   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6362
6363   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6364     {
6365       linklist_free(group_base);
6366       group_base = NULL;
6367       group_count = 0;
6368       return(0);
6369     }
6370
6371   linklist_free(group_base);
6372   group_base = NULL;
6373   group_count = 0;
6374   memset(ou_both, '\0', sizeof(ou_both));
6375   memset(ou_security, '\0', sizeof(ou_security));
6376   memset(ou_distribution, '\0', sizeof(ou_distribution));
6377   memset(ou_neither, '\0', sizeof(ou_neither));
6378   memset(before_name, '\0', sizeof(before_name));
6379   memset(before_desc, '\0', sizeof(before_desc));
6380   memset(before_group_membership, '\0', sizeof(before_group_membership));
6381   
6382   attr_array[0] = "name";
6383   attr_array[1] = NULL;
6384
6385   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6386                            &group_base, &group_count, 
6387                            LDAP_SCOPE_SUBTREE)) != 0)
6388     {
6389       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6390               MoiraId, ldap_err2string(rc));
6391       return(rc);
6392     }
6393
6394   strcpy(before_name, group_base->value);
6395   linklist_free(group_base);
6396   group_base = NULL;
6397   group_count = 0;
6398
6399   attr_array[0] = "description";
6400   attr_array[1] = NULL;
6401   
6402   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6403                            &group_base, &group_count, 
6404                            LDAP_SCOPE_SUBTREE)) != 0)
6405     {
6406       com_err(whoami, 0, 
6407               "Unable to get list description with MoiraId = %s: %s",
6408               MoiraId, ldap_err2string(rc));
6409       return(rc);
6410     }
6411
6412   if (group_count != 0)
6413     {
6414       strcpy(before_desc, group_base->value);
6415       linklist_free(group_base);
6416       group_base = NULL;
6417       group_count = 0;
6418     }
6419  
6420   change_to_lower_case(ad_distinguishedName);  
6421   strcpy(ou_both, group_ou_both);
6422   change_to_lower_case(ou_both);
6423   strcpy(ou_security, group_ou_security);
6424   change_to_lower_case(ou_security);
6425   strcpy(ou_distribution, group_ou_distribution);
6426   change_to_lower_case(ou_distribution);
6427   strcpy(ou_neither, group_ou_neither);
6428   change_to_lower_case(ou_neither);
6429
6430   if (strstr(ad_distinguishedName, ou_both))
6431     {
6432       strcpy(before_group_ou, group_ou_both);
6433       before_group_membership[0] = 'B';
6434       before_security_flag = 1;
6435     }
6436   else if (strstr(ad_distinguishedName, ou_security))
6437     {
6438       strcpy(before_group_ou, group_ou_security);
6439       before_group_membership[0] = 'S';
6440       before_security_flag = 1;
6441     }
6442   else if (strstr(ad_distinguishedName, ou_distribution))
6443     {
6444       strcpy(before_group_ou, group_ou_distribution);
6445       before_group_membership[0] = 'D';
6446       before_security_flag = 0;
6447     }
6448   else if (strstr(ad_distinguishedName, ou_neither))
6449     {
6450       strcpy(before_group_ou, group_ou_neither);
6451       before_group_membership[0] = 'N';
6452       before_security_flag = 0;
6453     }
6454   else
6455     return(AD_NO_OU_FOUND);
6456
6457   rc = group_rename(ldap_handle, dn_path, before_name, 
6458                     before_group_membership, 
6459                     before_group_ou, before_security_flag, before_desc,
6460                     group_name, group_membership, group_ou, 
6461                     group_security_flag,
6462                     before_desc, MoiraId, filter, maillist);
6463
6464   return(rc);
6465 }
6466
6467 void change_to_lower_case(char *ptr)
6468 {
6469   int i;
6470
6471   for (i = 0; i < (int)strlen(ptr); i++)
6472     {
6473       ptr[i] = tolower(ptr[i]);
6474     }
6475 }
6476
6477 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6478                  char *group_name, char *group_membership, 
6479                  char *MoiraId, char *attribute,
6480                  LK_ENTRY **linklist_base, int *linklist_count,
6481                  char *rFilter)
6482 {
6483   LK_ENTRY  *pPtr;
6484   char  filter[128];
6485   char  *attr_array[3];
6486   char  *dn;
6487   int   rc;
6488
6489   (*linklist_base) = NULL;
6490   (*linklist_count) = 0;
6491
6492   if (strlen(rFilter) != 0)
6493     {
6494       strcpy(filter, rFilter);
6495       attr_array[0] = attribute;
6496       attr_array[1] = NULL;
6497       
6498       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6499                                linklist_base, linklist_count, 
6500                                LDAP_SCOPE_SUBTREE)) != 0)
6501         {
6502           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6503                   MoiraId, ldap_err2string(rc));
6504          return(rc);
6505        }
6506
6507     if ((*linklist_count) == 1)
6508       {
6509         strcpy(rFilter, filter);
6510         return(0);
6511       }
6512     }
6513
6514   linklist_free((*linklist_base));
6515   (*linklist_base) = NULL;
6516   (*linklist_count) = 0;
6517
6518   if (strlen(MoiraId) != 0)
6519     {
6520       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6521
6522       attr_array[0] = attribute;
6523       attr_array[1] = NULL;
6524
6525       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6526                                linklist_base, linklist_count, 
6527                                LDAP_SCOPE_SUBTREE)) != 0)
6528         {
6529           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6530                   MoiraId, ldap_err2string(rc));
6531          return(rc);
6532        }
6533     }
6534
6535   if ((*linklist_count) > 1)
6536     {
6537       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6538       pPtr = (*linklist_base);
6539
6540       while (pPtr)
6541         {
6542           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6543                   MoiraId);
6544           pPtr = pPtr->next;
6545         }
6546
6547       linklist_free((*linklist_base));
6548       (*linklist_base) = NULL;
6549       (*linklist_count) = 0;
6550     }
6551
6552   if ((*linklist_count) == 1)
6553     {
6554
6555       pPtr = (*linklist_base);
6556       dn = strdup(pPtr->dn);
6557       dn += 3;
6558
6559       if (!memcmp(dn, group_name, strlen(group_name)))
6560         {
6561           strcpy(rFilter, filter);
6562           return(0);
6563         }
6564     }
6565
6566   linklist_free((*linklist_base));
6567   (*linklist_base) = NULL;
6568   (*linklist_count) = 0;
6569   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6570
6571   attr_array[0] = attribute;
6572   attr_array[1] = NULL;
6573
6574   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6575                            linklist_base, linklist_count, 
6576                            LDAP_SCOPE_SUBTREE)) != 0)
6577     {
6578       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6579               MoiraId, ldap_err2string(rc));
6580       return(rc);
6581     }
6582
6583   if ((*linklist_count) == 1)
6584     {
6585       strcpy(rFilter, filter);
6586       return(0);
6587     }
6588
6589   return(0);
6590 }
6591
6592 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6593 {
6594   char filter[128];
6595   char *attr_array[3];
6596   char SamAccountName[64];
6597   int  group_count;
6598   int  rc;
6599   LK_ENTRY  *group_base;
6600   LK_ENTRY  *gPtr;
6601
6602   group_count = 0;
6603   group_base = NULL;
6604
6605   if (strlen(MoiraId) != 0)
6606     {
6607       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6608
6609       attr_array[0] = "sAMAccountName";
6610       attr_array[1] = NULL;
6611       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6612                                &group_base, &group_count, 
6613                                LDAP_SCOPE_SUBTREE)) != 0)
6614         {
6615           com_err(whoami, 0, "Unable to process user %s : %s",
6616                   UserName, ldap_err2string(rc));
6617           return(rc);
6618         }
6619
6620       if (group_count > 1)
6621         {
6622           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6623                   MoiraId);
6624           gPtr = group_base;
6625
6626           while (gPtr)
6627             {
6628               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6629                       gPtr->value, MoiraId);
6630               gPtr = gPtr->next;
6631             }
6632         }
6633     }
6634
6635   if (group_count != 1)
6636     {
6637       linklist_free(group_base);
6638       group_count = 0;
6639       group_base = NULL;
6640       sprintf(filter, "(sAMAccountName=%s)", UserName);
6641       attr_array[0] = "sAMAccountName";
6642       attr_array[1] = NULL;
6643
6644       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6645                                &group_base, &group_count, 
6646                                LDAP_SCOPE_SUBTREE)) != 0)
6647         {
6648           com_err(whoami, 0, "Unable to process user %s : %s",
6649                   UserName, ldap_err2string(rc));
6650           return(rc);
6651         }
6652     }
6653
6654   if (group_count != 1)
6655     {
6656       linklist_free(group_base);
6657       return(AD_NO_USER_FOUND);
6658     }
6659
6660   strcpy(SamAccountName, group_base->value);
6661   linklist_free(group_base);
6662   group_count = 0;
6663   rc = 0;
6664
6665   if (strcmp(SamAccountName, UserName))
6666     {
6667       com_err(whoami, 0, 
6668               "User object %s with MoiraId %s has mismatched usernames " 
6669               "(LDAP username %s, Moira username %s)", SamAccountName,
6670               MoiraId, SamAccountName, UserName);
6671     }
6672
6673   return(0);
6674 }
6675
6676 void container_get_dn(char *src, char *dest)
6677 {
6678   char *sPtr;
6679   char *array[20];
6680   char name[256];
6681   int  n;
6682
6683   memset(array, '\0', 20 * sizeof(array[0]));
6684
6685   if (strlen(src) == 0)
6686     return;
6687
6688   strcpy(name, src);
6689   sPtr = name;
6690   n = 0;
6691   array[n] = name;
6692   ++n;
6693
6694   while (*sPtr)
6695     {
6696       if ((*sPtr) == '/')
6697         {
6698           (*sPtr) = '\0';
6699           ++sPtr;
6700           array[n] = sPtr;
6701           ++n;
6702         }
6703       else
6704         ++sPtr;
6705     }
6706
6707   strcpy(dest, "OU=");
6708
6709   while (n != 0)
6710     {
6711       strcat(dest, array[n-1]);
6712       --n;
6713       if (n > 0)
6714         {
6715           strcat(dest, ",OU=");
6716         }
6717     }
6718
6719   return;
6720 }
6721
6722 void container_get_name(char *src, char *dest)
6723 {
6724   char *sPtr;
6725   char *dPtr;
6726
6727   if (strlen(src) == 0)
6728     return;
6729
6730   sPtr = src;
6731   dPtr = src;
6732
6733   while (*sPtr)
6734     {
6735       if ((*sPtr) == '/')
6736         {
6737           dPtr = sPtr;
6738           ++dPtr;
6739         }
6740       ++sPtr;
6741     }
6742
6743   strcpy(dest, dPtr);
6744   return;
6745 }
6746
6747 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6748 {
6749   char cName[256];
6750   char *av[7];
6751   int  i;
6752   int  rc;
6753
6754   strcpy(cName, name);
6755
6756   for (i = 0; i < (int)strlen(cName); i++)
6757     {
6758       if (cName[i] == '/')
6759         {
6760           cName[i] = '\0';
6761           av[CONTAINER_NAME] = cName;
6762           av[CONTAINER_DESC] = "";
6763           av[CONTAINER_LOCATION] = "";
6764           av[CONTAINER_CONTACT] = "";
6765           av[CONTAINER_TYPE] = "";
6766           av[CONTAINER_ID] = "";
6767           av[CONTAINER_ROWID] = "";
6768           rc = container_create(ldap_handle, dn_path, 7, av);
6769
6770           if (rc == LDAP_SUCCESS)
6771             {
6772               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6773                       cName);
6774             }
6775
6776           cName[i] = '/';
6777         }
6778     }
6779 }
6780
6781 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6782                      char **before, int afterc, char **after)
6783 {
6784   char      dName[256];
6785   char      cName[256];
6786   char      new_cn[128];
6787   char      new_dn_path[256];
6788   char      temp[256];
6789   char      distinguishedName[256];
6790   char      *pPtr;
6791   int       rc;
6792   int       i;
6793
6794   memset(cName, '\0', sizeof(cName));
6795   container_get_name(after[CONTAINER_NAME], cName);
6796
6797   if (!check_container_name(cName))
6798     {
6799       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6800               cName);
6801       return(AD_INVALID_NAME);
6802     }
6803
6804   memset(distinguishedName, '\0', sizeof(distinguishedName));
6805
6806   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6807                                            distinguishedName, beforec, before))
6808     return(rc);
6809
6810   if (strlen(distinguishedName) == 0)
6811     {
6812       rc = container_create(ldap_handle, dn_path, afterc, after);
6813       return(rc);
6814     }
6815
6816   strcpy(temp, after[CONTAINER_NAME]);
6817   pPtr = temp;
6818
6819   for (i = 0; i < (int)strlen(temp); i++)
6820     {
6821       if (temp[i] == '/')
6822         {
6823           pPtr = &temp[i];
6824         }
6825     }
6826
6827   (*pPtr) = '\0';
6828
6829   container_get_dn(temp, dName);
6830
6831   if (strlen(temp) != 0)
6832     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6833   else
6834     sprintf(new_dn_path, "%s", dn_path);
6835
6836   sprintf(new_cn, "OU=%s", cName);
6837
6838   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6839
6840   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6841                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6842     {
6843       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6844               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6845               ldap_err2string(rc));
6846       return(rc);
6847     }
6848
6849   memset(dName, '\0', sizeof(dName));
6850   container_get_dn(after[CONTAINER_NAME], dName);
6851   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6852
6853   return(rc);
6854 }
6855
6856 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6857 {
6858   char      distinguishedName[256];
6859   int       rc;
6860
6861   memset(distinguishedName, '\0', sizeof(distinguishedName));
6862
6863   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6864                                            distinguishedName, count, av))
6865     return(rc);
6866
6867   if (strlen(distinguishedName) == 0)
6868     return(0);
6869
6870   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6871     {
6872       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6873         container_move_objects(ldap_handle, dn_path, distinguishedName);
6874       else
6875         com_err(whoami, 0, "Unable to delete container %s from directory : %s",
6876                 av[CONTAINER_NAME], ldap_err2string(rc));
6877     }
6878
6879   return(rc);
6880 }
6881
6882 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6883 {
6884   char      *attr_array[3];
6885   LK_ENTRY  *group_base;
6886   int       group_count;
6887   LDAPMod   *mods[20];
6888   char      *objectClass_v[] = {"top", 
6889                            "organizationalUnit", 
6890                            NULL};
6891
6892   char *ou_v[] = {NULL, NULL};
6893   char *name_v[] = {NULL, NULL};
6894   char *moiraId_v[] = {NULL, NULL};
6895   char *desc_v[] = {NULL, NULL};
6896   char *managedBy_v[] = {NULL, NULL};
6897   char dName[256];
6898   char cName[256];
6899   char managedByDN[256];
6900   char filter[256];
6901   char temp[256];
6902   int  n;
6903   int  i;
6904   int  rc;
6905     
6906   memset(filter, '\0', sizeof(filter));
6907   memset(dName, '\0', sizeof(dName));
6908   memset(cName, '\0', sizeof(cName));
6909   memset(managedByDN, '\0', sizeof(managedByDN));
6910   container_get_dn(av[CONTAINER_NAME], dName);
6911   container_get_name(av[CONTAINER_NAME], cName);
6912
6913   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6914     {
6915       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6916               cName);
6917       return(AD_INVALID_NAME);
6918     }
6919
6920   if (!check_container_name(cName))
6921     {
6922       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6923               cName);
6924       return(AD_INVALID_NAME);
6925     }
6926
6927   n = 0;
6928   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6929   name_v[0] = cName;
6930   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6931   ou_v[0] = cName;
6932   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6933
6934   if (strlen(av[CONTAINER_ROWID]) != 0)
6935     {
6936       moiraId_v[0] = av[CONTAINER_ROWID];
6937       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6938     }
6939
6940   if (strlen(av[CONTAINER_DESC]) != 0)
6941     {
6942       desc_v[0] = av[CONTAINER_DESC];
6943       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6944     }
6945
6946   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6947     {
6948       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6949         {
6950           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6951                               kerberos_ou))
6952             {
6953               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6954                       kerberos_ou, dn_path);
6955               managedBy_v[0] = managedByDN;
6956               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6957             }
6958         }
6959       else
6960         {
6961           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6962             {
6963               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6964                       "(objectClass=user)))", av[CONTAINER_ID]);
6965             }
6966
6967           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6968             {
6969               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6970                       av[CONTAINER_ID]);
6971             }
6972
6973           if (strlen(filter) != 0)
6974             {
6975               attr_array[0] = "distinguishedName";
6976               attr_array[1] = NULL;
6977               group_count = 0;
6978               group_base = NULL;
6979               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6980                                        attr_array, 
6981                                        &group_base, &group_count, 
6982                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6983                 {
6984                   if (group_count == 1)
6985                     {
6986                       strcpy(managedByDN, group_base->value);
6987                       managedBy_v[0] = managedByDN;
6988                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6989                     }
6990                   linklist_free(group_base);
6991                   group_base = NULL;
6992                   group_count = 0;
6993                 }
6994             }
6995         }
6996     }
6997   
6998   mods[n] = NULL;
6999
7000   sprintf(temp, "%s,%s", dName, dn_path);
7001   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
7002   
7003   for (i = 0; i < n; i++)
7004     free(mods[i]);
7005   
7006   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
7007     {
7008       com_err(whoami, 0, "Unable to create container %s : %s",
7009               cName, ldap_err2string(rc));
7010       return(rc);
7011     }
7012
7013   if (rc == LDAP_ALREADY_EXISTS)
7014     {
7015       if (strlen(av[CONTAINER_ROWID]) != 0)
7016         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
7017     }
7018
7019   return(rc);
7020 }
7021
7022 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
7023                      char **before, int afterc, char **after)
7024 {
7025   char distinguishedName[256];
7026   int  rc;
7027
7028   memset(distinguishedName, '\0', sizeof(distinguishedName));
7029
7030   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
7031                                            distinguishedName, afterc, after))
7032     return(rc);
7033
7034   if (strlen(distinguishedName) == 0)
7035     {
7036       rc = container_create(ldap_handle, dn_path, afterc, after);
7037       return(rc);
7038     }
7039   
7040   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
7041   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
7042                           after);
7043
7044   return(rc);
7045 }
7046
7047 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
7048                                     char *distinguishedName, int count, 
7049                                     char **av)
7050 {
7051   char      *attr_array[3];
7052   LK_ENTRY  *group_base;
7053   int       group_count;
7054   char      dName[256];
7055   char      cName[256];
7056   char      filter[512];
7057   int       rc;
7058
7059   memset(filter, '\0', sizeof(filter));
7060   memset(dName, '\0', sizeof(dName));
7061   memset(cName, '\0', sizeof(cName));
7062   container_get_dn(av[CONTAINER_NAME], dName);
7063   container_get_name(av[CONTAINER_NAME], cName);
7064
7065   if (strlen(dName) == 0)
7066     {
7067       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7068               av[CONTAINER_NAME]);
7069       return(AD_INVALID_NAME);
7070     }
7071
7072   if (!check_container_name(cName))
7073     {
7074       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7075               cName);
7076       return(AD_INVALID_NAME);
7077     }
7078   
7079   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7080           av[CONTAINER_ROWID]);
7081   attr_array[0] = "distinguishedName";
7082   attr_array[1] = NULL;
7083   group_count = 0;
7084   group_base = NULL;
7085
7086   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7087                            &group_base, &group_count, 
7088                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7089     {
7090       if (group_count == 1)
7091         {
7092           strcpy(distinguishedName, group_base->value);
7093         }
7094
7095       linklist_free(group_base);
7096       group_base = NULL;
7097       group_count = 0;
7098     }
7099
7100   if (strlen(distinguishedName) == 0)
7101     {
7102       sprintf(filter, "(&(objectClass=organizationalUnit)"
7103               "(distinguishedName=%s,%s))", dName, dn_path);
7104       attr_array[0] = "distinguishedName";
7105       attr_array[1] = NULL;
7106       group_count = 0;
7107       group_base = NULL;
7108
7109       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7110                                &group_base, &group_count, 
7111                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7112         {
7113           if (group_count == 1)
7114             {
7115               strcpy(distinguishedName, group_base->value);
7116             }
7117
7118           linklist_free(group_base);
7119           group_base = NULL;
7120           group_count = 0;
7121         }
7122     }
7123
7124   return(0);
7125 }
7126
7127 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7128                        char *distinguishedName, int count, char **av)
7129 {
7130   char      *attr_array[5];
7131   LK_ENTRY  *group_base;
7132   LK_ENTRY  *pPtr;
7133   LDAPMod   *mods[20];
7134   int       group_count;
7135   char      filter[512];
7136   char      *moiraId_v[] = {NULL, NULL};
7137   char      *desc_v[] = {NULL, NULL};
7138   char      *managedBy_v[] = {NULL, NULL};
7139   char      managedByDN[256];
7140   char      moiraId[64];
7141   char      desc[256];
7142   char      ad_path[512];
7143   int       rc;
7144   int       i;
7145   int       n;
7146
7147
7148   strcpy(ad_path, distinguishedName);
7149
7150   if (strlen(dName) != 0)
7151     sprintf(ad_path, "%s,%s", dName, dn_path);
7152
7153   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7154           ad_path);
7155
7156   if (strlen(av[CONTAINER_ID]) != 0)
7157     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7158             av[CONTAINER_ROWID]);
7159
7160   attr_array[0] = "mitMoiraId";
7161   attr_array[1] = "description";
7162   attr_array[2] = "managedBy";
7163   attr_array[3] = NULL;
7164   group_count = 0;
7165   group_base = NULL;
7166
7167   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7168                            &group_base, &group_count, 
7169                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7170     {
7171       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7172               av[CONTAINER_NAME], ldap_err2string(rc));
7173       return(rc);
7174     }
7175
7176   memset(managedByDN, '\0', sizeof(managedByDN));
7177   memset(moiraId, '\0', sizeof(moiraId));
7178   memset(desc, '\0', sizeof(desc));
7179   pPtr = group_base;
7180
7181   while (pPtr)
7182     {
7183       if (!strcasecmp(pPtr->attribute, "description"))
7184         strcpy(desc, pPtr->value);
7185       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7186         strcpy(managedByDN, pPtr->value);
7187       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7188         strcpy(moiraId, pPtr->value);
7189       pPtr = pPtr->next;
7190     }
7191
7192   linklist_free(group_base);
7193   group_base = NULL;
7194   group_count = 0;
7195
7196   n = 0;
7197   if (strlen(av[CONTAINER_ROWID]) != 0)
7198     {
7199       moiraId_v[0] = av[CONTAINER_ROWID];
7200       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7201     }
7202
7203   if (strlen(av[CONTAINER_DESC]) != 0)
7204     {
7205       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7206                        dName);
7207     }
7208   else
7209     {
7210       if (strlen(desc) != 0)
7211         {
7212           attribute_update(ldap_handle, ad_path, "", "description", dName);
7213         }
7214     }
7215
7216   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7217     {
7218       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7219         {
7220           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7221                               kerberos_ou))
7222             {
7223               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7224                       kerberos_ou, dn_path);
7225               managedBy_v[0] = managedByDN;
7226               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7227             }
7228           else
7229             {
7230               if (strlen(managedByDN) != 0)
7231                 {
7232                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7233                                    dName);
7234                 }
7235             }
7236         }
7237       else
7238         {
7239           memset(filter, '\0', sizeof(filter));
7240
7241           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7242             {
7243               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7244                       "(objectClass=user)))", av[CONTAINER_ID]);
7245             }
7246
7247           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7248             {
7249               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7250                       av[CONTAINER_ID]);
7251             }
7252
7253           if (strlen(filter) != 0)
7254             {
7255               attr_array[0] = "distinguishedName";
7256               attr_array[1] = NULL;
7257               group_count = 0;
7258               group_base = NULL;
7259               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7260                                        attr_array, &group_base, &group_count, 
7261                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7262                 {
7263                   if (group_count == 1)
7264                     {
7265                       strcpy(managedByDN, group_base->value);
7266                       managedBy_v[0] = managedByDN;
7267                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7268                     }
7269                   else
7270                     {
7271                       if (strlen(managedByDN) != 0)
7272                         {
7273                           attribute_update(ldap_handle, ad_path, "", 
7274                                            "managedBy", dName);
7275                         }
7276                     }
7277
7278                   linklist_free(group_base);
7279                   group_base = NULL;
7280                   group_count = 0;
7281                 }
7282             }
7283           else
7284             {
7285               if (strlen(managedByDN) != 0)
7286                 {
7287                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7288                                    dName);
7289                 }
7290             }
7291         }
7292     }
7293
7294   mods[n] = NULL;
7295
7296   if (n == 0)
7297     return(LDAP_SUCCESS);
7298
7299   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7300
7301   for (i = 0; i < n; i++)
7302     free(mods[i]);
7303
7304   if (rc != LDAP_SUCCESS)
7305     {
7306       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7307               av[CONTAINER_NAME], ldap_err2string(rc));
7308       return(rc);
7309     }
7310   
7311   return(rc);
7312 }
7313
7314 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7315 {
7316   char      *attr_array[3];
7317   LK_ENTRY  *group_base;
7318   LK_ENTRY  *pPtr;
7319   int       group_count;
7320   char      filter[512];
7321   char      new_cn[128];
7322   char      temp[256];
7323   int       rc;
7324   int       NumberOfEntries = 10;
7325   int       i;
7326   int       count;
7327
7328   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7329
7330   for (i = 0; i < 3; i++)
7331     {
7332       memset(filter, '\0', sizeof(filter));
7333
7334       if (i == 0)
7335         {
7336           strcpy(filter, "(!(|(objectClass=computer)"
7337                  "(objectClass=organizationalUnit)))");
7338           attr_array[0] = "cn";
7339           attr_array[1] = NULL;
7340         }
7341       else if (i == 1)
7342         {
7343           strcpy(filter, "(objectClass=computer)");
7344           attr_array[0] = "cn";
7345           attr_array[1] = NULL;
7346         }
7347       else
7348         {
7349           strcpy(filter, "(objectClass=organizationalUnit)");
7350           attr_array[0] = "ou";
7351           attr_array[1] = NULL;
7352         }
7353
7354       while (1)
7355         {
7356           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7357                                    &group_base, &group_count, 
7358                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7359             {
7360               break;
7361             }
7362
7363           if (group_count == 0)
7364             break;
7365
7366           pPtr = group_base;
7367
7368           while(pPtr)
7369             {
7370               if (!strcasecmp(pPtr->attribute, "cn"))
7371                 {
7372                   sprintf(new_cn, "cn=%s", pPtr->value);
7373                   if (i == 0)
7374                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7375                   if (i == 1)
7376                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7377                   count = 1;
7378
7379                   while (1)
7380                     {
7381                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7382                                          TRUE, NULL, NULL);
7383                       if (rc == LDAP_ALREADY_EXISTS)
7384                         {
7385                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7386                           ++count;
7387                         }
7388                       else
7389                         break;
7390                     }
7391                 }
7392               else if (!strcasecmp(pPtr->attribute, "ou"))
7393                 {
7394                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7395                 }
7396
7397               pPtr = pPtr->next;
7398             }
7399
7400           linklist_free(group_base);
7401           group_base = NULL;
7402           group_count = 0;
7403         }
7404     }
7405
7406   return(0);
7407 }
7408
7409 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7410                    char *machine_ou, char *NewMachineName)
7411 {
7412   LK_ENTRY  *group_base;
7413   int  group_count;
7414   int  i;
7415   char filter[128];
7416   char *attr_array[3];
7417   char cn[256];
7418   char dn[256];
7419   char temp[256];
7420   char *pPtr;
7421   int   rc;
7422
7423   strcpy(NewMachineName, member);
7424   rc = moira_connect();
7425   rc = GetMachineName(NewMachineName);
7426   moira_disconnect();
7427
7428   if (strlen(NewMachineName) == 0)
7429     {
7430       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7431               member);
7432       return(1);
7433     }
7434
7435   pPtr = NULL;
7436   pPtr = strchr(NewMachineName, '.');
7437
7438   if (pPtr != NULL)
7439     (*pPtr) = '\0';
7440
7441   group_base = NULL;
7442   group_count = 0;
7443   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7444   attr_array[0] = "cn";
7445   attr_array[1] = NULL;
7446   sprintf(temp, "%s", dn_path);
7447
7448   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7449                            &group_base, &group_count, 
7450                            LDAP_SCOPE_SUBTREE)) != 0)
7451     {
7452       com_err(whoami, 0, "Unable to process machine %s : %s",
7453               member, ldap_err2string(rc));
7454       return(1);
7455     }
7456
7457   if (group_count != 1)
7458     {
7459       return(1);
7460     }
7461
7462   strcpy(dn, group_base->dn);
7463   strcpy(cn, group_base->value);
7464
7465   for (i = 0; i < (int)strlen(dn); i++)
7466     dn[i] = tolower(dn[i]);
7467
7468   for (i = 0; i < (int)strlen(cn); i++)
7469     cn[i] = tolower(cn[i]);
7470
7471   linklist_free(group_base);
7472   pPtr = NULL;
7473   pPtr = strstr(dn, cn);
7474
7475   if (pPtr == NULL)
7476     {
7477       com_err(whoami, 0, "Unable to process machine %s",
7478               member);
7479       return(1);
7480     }
7481
7482   pPtr += strlen(cn) + 1;
7483   strcpy(machine_ou, pPtr);
7484   pPtr = NULL;
7485   pPtr = strstr(machine_ou, "dc=");
7486
7487   if (pPtr == NULL)
7488     {
7489       com_err(whoami, 0, "Unable to process machine %s",
7490               member);
7491       return(1);
7492     }
7493
7494   --pPtr;
7495   (*pPtr) = '\0';
7496
7497   return(0);
7498 }
7499
7500 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7501                        char *MoiraMachineName, char *DestinationOu)
7502 {
7503   char        NewCn[128];
7504   char        OldDn[512];
7505   char        MachineName[128];
7506   char        filter[128];
7507   char        *attr_array[3];
7508   char        NewOu[256];
7509   char        *cPtr = NULL;
7510   int         group_count;
7511   long        rc;
7512   LK_ENTRY    *group_base;
7513
7514   group_count = 0;
7515   group_base = NULL;
7516   
7517   strcpy(MachineName, MoiraMachineName);
7518   rc = GetMachineName(MachineName);
7519
7520   if (strlen(MachineName) == 0)
7521     {
7522       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7523               MoiraMachineName);
7524       return(1);
7525     }
7526   
7527   cPtr = strchr(MachineName, '.');
7528
7529   if (cPtr != NULL)
7530     (*cPtr) = '\0';
7531
7532   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7533   attr_array[0] = "sAMAccountName";
7534   attr_array[1] = NULL;
7535
7536   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7537                            &group_base, 
7538                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7539     {
7540       com_err(whoami, 0, "Unable to process machine %s : %s",
7541               MoiraMachineName, ldap_err2string(rc));
7542       return(1);
7543     }
7544   
7545   if (group_count == 1)
7546     strcpy(OldDn, group_base->dn);
7547
7548   linklist_free(group_base);
7549   group_base = NULL;
7550
7551   if (group_count != 1)
7552     {
7553       com_err(whoami, 0, "Unable to find machine %s in directory: %s", 
7554               MoiraMachineName);
7555       return(1);
7556     }
7557
7558   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7559   cPtr = strchr(OldDn, ',');
7560
7561   if (cPtr != NULL)
7562     {
7563       ++cPtr;
7564       if (!strcasecmp(cPtr, NewOu))
7565         return(0);
7566     }
7567
7568   sprintf(NewCn, "CN=%s", MachineName);
7569   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7570
7571   return(rc);
7572 }
7573
7574 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7575 {
7576   char    Name[128];
7577   char    *pPtr;
7578   int     rc;
7579   
7580   memset(Name, '\0', sizeof(Name));
7581   strcpy(Name, machine_name);
7582   pPtr = NULL;
7583   pPtr = strchr(Name, '.');
7584
7585   if (pPtr != NULL)
7586     (*pPtr) = '\0';
7587
7588   strcat(Name, "$");
7589   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7590 }
7591
7592 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7593                                 char *machine_name, char *container_name)
7594 {
7595   int     rc;
7596   char    *av[2];
7597   char    *call_args[2];
7598   
7599   av[0] = machine_name;
7600   call_args[0] = (char *)container_name;
7601   rc = mr_query("get_machine_to_container_map", 1, av, 
7602                 machine_GetMoiraContainer, call_args);
7603   return(rc);
7604 }
7605
7606 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7607 {
7608   char **call_args;
7609   
7610   call_args = ptr;
7611   strcpy(call_args[0], av[1]);
7612   return(0);
7613 }
7614
7615 int Moira_container_group_create(char **after)
7616 {
7617   long rc;
7618   char GroupName[64];
7619   char *argv[20];
7620   
7621   memset(GroupName, '\0', sizeof(GroupName));
7622   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7623                               after[CONTAINER_ROWID]);
7624   if (rc)
7625     return rc;
7626   
7627   argv[L_NAME] = GroupName;
7628   argv[L_ACTIVE] = "1";
7629   argv[L_PUBLIC] = "0";
7630   argv[L_HIDDEN] = "0";
7631   argv[L_MAILLIST] = "0";
7632   argv[L_GROUP] = "1";
7633   argv[L_GID] = UNIQUE_GID;
7634   argv[L_NFSGROUP] = "0";
7635   argv[L_MAILMAN] = "0";
7636   argv[L_MAILMAN_SERVER] = "[NONE]";
7637   argv[L_DESC] = "auto created container group";
7638   argv[L_ACE_TYPE] = "USER";
7639   argv[L_MEMACE_TYPE] = "USER";
7640   argv[L_ACE_NAME] = "sms";
7641   argv[L_MEMACE_NAME] = "sms";
7642
7643   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7644     {
7645       com_err(whoami, 0, 
7646               "Unable to create container group %s for container %s: %s",
7647               GroupName, after[CONTAINER_NAME], error_message(rc));
7648     }
7649
7650   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7651   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7652   
7653   return(rc);
7654 }
7655
7656 int Moira_container_group_update(char **before, char **after)
7657 {
7658   long rc;
7659   char BeforeGroupName[64];
7660   char AfterGroupName[64];
7661   char *argv[20];
7662   
7663   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7664     return(0);
7665
7666   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7667   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7668   if (strlen(BeforeGroupName) == 0)
7669     return(0);
7670
7671   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7672   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7673                               after[CONTAINER_ROWID]);
7674   if (rc)
7675     return rc;
7676
7677   if (strcasecmp(BeforeGroupName, AfterGroupName))
7678     {
7679       argv[L_NAME] = BeforeGroupName;
7680       argv[L_NAME + 1] = AfterGroupName;
7681       argv[L_ACTIVE + 1] = "1";
7682       argv[L_PUBLIC + 1] = "0";
7683       argv[L_HIDDEN + 1] = "0";
7684       argv[L_MAILLIST + 1] = "0";
7685       argv[L_GROUP + 1] = "1";
7686       argv[L_GID + 1] = UNIQUE_GID;
7687       argv[L_NFSGROUP + 1] = "0";
7688       argv[L_MAILMAN + 1] = "0";
7689       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7690       argv[L_DESC + 1] = "auto created container group";
7691       argv[L_ACE_TYPE + 1] = "USER";
7692       argv[L_MEMACE_TYPE + 1] = "USER";
7693       argv[L_ACE_NAME + 1] = "sms";
7694       argv[L_MEMACE_NAME + 1] = "sms";
7695       
7696       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7697         {
7698           com_err(whoami, 0, 
7699                   "Unable to rename container group from %s to %s: %s",
7700                   BeforeGroupName, AfterGroupName, error_message(rc));
7701         }
7702     }
7703   
7704   return(rc);
7705 }
7706
7707 int Moira_container_group_delete(char **before)
7708 {
7709   long rc = 0;
7710   char *argv[13];
7711   char GroupName[64];
7712   char ParentGroupName[64];
7713   
7714   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7715   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7716
7717   memset(GroupName, '\0', sizeof(GroupName));
7718
7719   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7720     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7721   
7722   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7723     {
7724       argv[0] = ParentGroupName;
7725       argv[1] = "LIST";
7726       argv[2] = GroupName;
7727
7728       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7729         {
7730           com_err(whoami, 0, 
7731                   "Unable to delete container group %s from list: %s",
7732                   GroupName, ParentGroupName, error_message(rc));
7733         }
7734     }
7735   
7736   if (strlen(GroupName) != 0)
7737     {
7738       argv[0] = GroupName;
7739
7740       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7741         {
7742           com_err(whoami, 0, "Unable to delete container group %s : %s",
7743                   GroupName, error_message(rc));
7744         }
7745     }
7746   
7747   return(rc);
7748 }
7749
7750 int Moira_groupname_create(char *GroupName, char *ContainerName,
7751                            char *ContainerRowID)
7752 {
7753   char *ptr;
7754   char *ptr1;
7755   char temp[64];
7756   char newGroupName[64];
7757   char tempGroupName[64];
7758   char tempgname[64];
7759   char *argv[1];
7760   int  i;
7761   long rc;
7762
7763   strcpy(temp, ContainerName);
7764   
7765   ptr1 = strrchr(temp, '/');
7766
7767   if (ptr1 != NULL)
7768   {
7769     *ptr1 = '\0';
7770     ptr = ++ptr1;
7771     ptr1 = strrchr(temp, '/');
7772
7773     if (ptr1 != NULL)
7774     {
7775         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7776     }
7777     else
7778         strcpy(tempgname, ptr);
7779   }
7780   else
7781     strcpy(tempgname, temp);
7782
7783   if (strlen(tempgname) > 25)
7784     tempgname[25] ='\0';
7785
7786   sprintf(newGroupName, "cnt-%s", tempgname);
7787
7788   /* change everything to lower case */
7789   ptr = newGroupName;
7790
7791   while (*ptr)
7792     {
7793       if (isupper(*ptr))
7794         *ptr = tolower(*ptr);
7795
7796       if (*ptr == ' ')
7797         *ptr = '-';
7798
7799       ptr++;
7800     }
7801
7802   strcpy(tempGroupName, newGroupName);
7803   i = (int)'0';
7804
7805   /* append 0-9 then a-z if a duplicate is found */
7806   while(1)
7807     {
7808       argv[0] = newGroupName;
7809
7810       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7811         {
7812           if (rc == MR_NO_MATCH)
7813             break;
7814           com_err(whoami, 0, "Moira error while creating group name for "
7815                   "container %s : %s", ContainerName, error_message(rc));
7816           return rc;
7817         }
7818
7819       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7820
7821       if (i == (int)'z')
7822         {
7823           com_err(whoami, 0, "Unable to find a unique group name for "
7824                   "container %s: too many duplicate container names",
7825                   ContainerName);
7826           return 1;
7827         }
7828
7829       if (i == '9')
7830         i = 'a';
7831       else
7832         i++;
7833     }
7834
7835   strcpy(GroupName, newGroupName);
7836   return(0);
7837 }
7838
7839 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7840 {
7841   long rc;
7842   char *argv[3];
7843   
7844   argv[0] = origContainerName;
7845   argv[1] = GroupName;
7846   
7847   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7848     {
7849       com_err(whoami, 0, 
7850               "Unable to set container group %s in container %s: %s",
7851               GroupName, origContainerName, error_message(rc));
7852     }
7853   
7854   return(0);
7855 }
7856
7857 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7858  {
7859    char ContainerName[64];
7860    char ParentGroupName[64];
7861    char *argv[3];
7862    long rc;
7863
7864    strcpy(ContainerName, origContainerName);
7865    
7866    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7867
7868    /* top-level container */
7869    if (strlen(ParentGroupName) == 0)
7870      return(0);
7871    
7872    argv[0] = ParentGroupName;
7873    argv[1] = "LIST";
7874    argv[2] = GroupName;
7875
7876    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7877      {
7878        com_err(whoami, 0, 
7879                "Unable to add container group %s to parent group %s: %s",
7880                GroupName, ParentGroupName, error_message(rc));
7881      }
7882    
7883    return(0);
7884  }
7885
7886 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7887 {
7888   char **call_args;
7889   
7890   call_args = ptr;
7891   strcpy(call_args[0], av[1]);
7892
7893   return(0);
7894 }
7895
7896 int Moira_getGroupName(char *origContainerName, char *GroupName,
7897                        int ParentFlag)
7898 {
7899   char ContainerName[64];
7900   char *argv[3];
7901   char *call_args[3];
7902   char *ptr;
7903   long rc;
7904
7905   strcpy(ContainerName, origContainerName);
7906
7907   if (ParentFlag)
7908     {
7909       ptr = strrchr(ContainerName, '/');
7910
7911       if (ptr != NULL)
7912         (*ptr) = '\0';
7913       else
7914         return(0);
7915     }
7916
7917   argv[0] = ContainerName;
7918   argv[1] = NULL;
7919   call_args[0] = GroupName;
7920   call_args[1] = NULL;
7921
7922   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7923                       call_args)))
7924     {
7925       if (strlen(GroupName) != 0)
7926         return(0);
7927     }
7928
7929   if (rc)
7930     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7931             ContainerName, error_message(rc));
7932   else
7933     com_err(whoami, 0, "Unable to get container group from container %s",
7934             ContainerName);
7935   
7936   return(0);
7937 }
7938
7939 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7940                                           int DeleteMachine)
7941 {
7942   char *argv[3];
7943   long rc;
7944   
7945   if (strcmp(GroupName, "[none]") == 0)
7946     return 0;
7947
7948   argv[0] = GroupName;
7949   argv[1] = "MACHINE";
7950   argv[2] = MachineName;
7951
7952   if (!DeleteMachine)
7953     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7954   else
7955     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7956
7957   if (rc)
7958     {
7959       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7960               MachineName, GroupName, error_message(rc));
7961     }
7962
7963   return(0);
7964 }
7965
7966 int GetMachineName(char *MachineName)
7967 {
7968   char    *args[2];
7969   char    NewMachineName[1024];
7970   char    *szDot;
7971   int     rc = 0;
7972   int     i;
7973   DWORD   dwLen = 0;
7974   char    *call_args[2];
7975   
7976   // If the address happens to be in the top-level MIT domain, great!
7977   strcpy(NewMachineName, MachineName);
7978
7979   for (i = 0; i < (int)strlen(NewMachineName); i++)
7980     NewMachineName[i] = toupper(NewMachineName[i]);
7981
7982   szDot = strchr(NewMachineName,'.');
7983
7984   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7985     {
7986       return(0);
7987     }
7988   
7989   // If not, see if it has a Moira alias in the top-level MIT domain.
7990   memset(NewMachineName, '\0', sizeof(NewMachineName));
7991   args[0] = "*";
7992   args[1] = MachineName;
7993   call_args[0] = NewMachineName;
7994   call_args[1] = NULL;
7995
7996   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7997     {
7998       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7999               MachineName, error_message(rc));
8000       strcpy(MachineName, "");
8001       return(0);
8002     }
8003   
8004   if (strlen(NewMachineName) != 0)
8005     strcpy(MachineName, NewMachineName);
8006   else
8007     strcpy(MachineName, "");
8008
8009   return(0);
8010 }
8011
8012 int ProcessMachineName(int ac, char **av, void *ptr)
8013 {
8014   char    **call_args;
8015   char    MachineName[1024];
8016   char    *szDot;
8017   int     i;
8018   
8019   call_args = ptr;
8020
8021   if (strlen(call_args[0]) == 0)
8022     {
8023       strcpy(MachineName, av[0]);
8024
8025       for (i = 0; i < (int)strlen(MachineName); i++)
8026         MachineName[i] = toupper(MachineName[i]);
8027
8028       szDot = strchr(MachineName,'.');
8029
8030         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
8031           {
8032             strcpy(call_args[0], MachineName);
8033           }
8034     }
8035
8036   return(0);
8037 }
8038
8039 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
8040 {
8041   int i;
8042   
8043   if (*UseSFU30)
8044     {
8045       for (i = 0; i < n; i++)
8046         {
8047           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
8048             mods[i]->mod_type = "uidNumber";
8049         }
8050
8051       (*UseSFU30) = 0;
8052     }
8053   else
8054     {
8055       for (i = 0; i < n; i++)
8056         {
8057           if (!strcmp(mods[i]->mod_type, "uidNumber"))
8058             mods[i]->mod_type = "msSFU30UidNumber";
8059         }
8060
8061       (*UseSFU30) = 1;
8062     }
8063 }
8064
8065 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8066                      char *DistinguishedName,
8067                      char *WinHomeDir, char *WinProfileDir,
8068                      char **homedir_v, char **winProfile_v,
8069                      char **drives_v, LDAPMod **mods, 
8070                      int OpType, int n)
8071 {
8072   char cWeight[3];
8073   char cPath[1024];
8074   char path[1024];
8075   char winPath[1024];
8076   char winProfile[1024];
8077   char homeDrive[8];
8078   char homedir[1024];
8079   char apple_homedir[1024];
8080   char *apple_homedir_v[] = {NULL, NULL};
8081   int  last_weight;
8082   int  i;
8083   int  rc;
8084   LDAPMod *DelMods[20];
8085   char *argv[3];
8086   char *save_argv[FS_END];
8087   char *fsgroup_save_argv[2];
8088
8089   memset(homeDrive, '\0', sizeof(homeDrive));
8090   memset(path, '\0', sizeof(path));
8091   memset(winPath, '\0', sizeof(winPath));
8092   memset(winProfile, '\0', sizeof(winProfile));
8093
8094   if(!ActiveDirectory) 
8095     {
8096       if (rc = moira_connect())
8097         {
8098           critical_alert("Ldap incremental",
8099                          "Error contacting Moira server : %s",
8100                          error_message(rc));
8101           return;
8102         }
8103       
8104       argv[0] = user_name;
8105
8106       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8107                           save_argv)))
8108         {
8109           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8110              !strcmp(save_argv[FS_TYPE], "MUL"))
8111             {
8112         
8113               argv[0] = save_argv[FS_NAME];
8114               fsgCount = 0;
8115               
8116               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8117                                   save_fsgroup_info, fsgroup_save_argv)))
8118                 {
8119                   if(fsgCount)
8120                     {
8121                       argv[0] = fsgroup_save_argv[0];
8122                       
8123                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8124                                           save_query_info, save_argv)))
8125                         {
8126                           strcpy(path, save_argv[FS_PACK]);
8127                         }
8128                     }
8129                 }
8130             }
8131           else
8132             {
8133               strcpy(path, save_argv[FS_PACK]);
8134             }
8135         }
8136       
8137       moira_disconnect();
8138
8139       if (strlen(path))
8140         {
8141           if (!strnicmp(path, AFS, strlen(AFS)))
8142             {
8143               sprintf(homedir, "%s", path);
8144               sprintf(apple_homedir, "%s/MacData", path);
8145               homedir_v[0] = homedir;
8146               apple_homedir_v[0] = apple_homedir;
8147               ADD_ATTR("homeDirectory", homedir_v, OpType);
8148               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8149                        OpType);
8150             }
8151         }
8152       else
8153         {
8154           homedir_v[0] = "NONE";
8155           apple_homedir_v[0] = "NONE";
8156           ADD_ATTR("homeDirectory", homedir_v, OpType);
8157           ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8158                    OpType);
8159         }
8160
8161       return(n);
8162     }
8163  
8164   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8165       (!strcasecmp(WinProfileDir, "[afs]")))
8166     {
8167       if (rc = moira_connect())
8168         {
8169           critical_alert("Ldap incremental",
8170                          "Error contacting Moira server : %s",
8171                          error_message(rc));
8172           return;
8173         }
8174       
8175       argv[0] = user_name;
8176
8177       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8178                           save_argv)))
8179         {
8180           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8181              !strcmp(save_argv[FS_TYPE], "MUL"))
8182             {
8183         
8184               argv[0] = save_argv[FS_NAME];
8185               fsgCount = 0;
8186               
8187               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8188                                   save_fsgroup_info, fsgroup_save_argv)))
8189                 {
8190                   if(fsgCount)
8191                     {
8192                       argv[0] = fsgroup_save_argv[0];
8193                       
8194                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8195                                           save_query_info, save_argv)))
8196                         {
8197                           strcpy(path, save_argv[FS_PACK]);
8198                         }
8199                     }
8200                 }
8201             }
8202           else
8203             {
8204               strcpy(path, save_argv[FS_PACK]);
8205             }
8206         }
8207      
8208       moira_disconnect();
8209
8210       if (strlen(path))
8211         {
8212           if (!strnicmp(path, AFS, strlen(AFS)))
8213             {
8214               AfsToWinAfs(path, winPath);
8215               strcpy(winProfile, winPath);
8216               strcat(winProfile, "\\.winprofile");
8217             }
8218         }
8219       else
8220         return(n);
8221     }
8222
8223     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8224         (!strcasecmp(WinProfileDir, "[dfs]")))
8225     {
8226       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8227               user_name[0], user_name);
8228
8229       if (!strcasecmp(WinProfileDir, "[dfs]"))
8230         {
8231           strcpy(winProfile, path);
8232           strcat(winProfile, "\\.winprofile");
8233         }
8234
8235       if (!strcasecmp(WinHomeDir, "[dfs]"))
8236         strcpy(winPath, path);
8237     }
8238     
8239     if (!strcasecmp(WinHomeDir, "[local]"))
8240       memset(winPath, '\0', sizeof(winPath));
8241     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8242              !strcasecmp(WinHomeDir, "[dfs]"))
8243       {
8244         strcpy(homeDrive, "H:");
8245       }
8246     else
8247       {
8248         strcpy(winPath, WinHomeDir);
8249         if (!strncmp(WinHomeDir, "\\\\", 2))
8250           {
8251             strcpy(homeDrive, "H:");
8252           }        
8253       }
8254     
8255     // nothing needs to be done if WinProfileDir is [afs].
8256     if (!strcasecmp(WinProfileDir, "[local]"))
8257       memset(winProfile, '\0', sizeof(winProfile));
8258     else if (strcasecmp(WinProfileDir, "[afs]") && 
8259              strcasecmp(WinProfileDir, "[dfs]"))
8260       {
8261         strcpy(winProfile, WinProfileDir);
8262       }
8263     
8264     if (strlen(winProfile) != 0)
8265       {
8266         if (winProfile[strlen(winProfile) - 1] == '\\')
8267           winProfile[strlen(winProfile) - 1] = '\0';
8268       }
8269
8270     if (strlen(winPath) != 0)
8271       {
8272         if (winPath[strlen(winPath) - 1] == '\\')
8273           winPath[strlen(winPath) - 1] = '\0';
8274       }
8275     
8276     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8277       strcat(winProfile, "\\");
8278
8279     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8280       strcat(winPath, "\\");
8281     
8282     if (strlen(winPath) == 0)
8283       {
8284         if (OpType == LDAP_MOD_REPLACE)
8285           {
8286             i = 0;
8287             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8288             DelMods[i] = NULL;
8289             //unset homeDirectory attribute for user.
8290             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8291             free(DelMods[0]);
8292           }
8293       }
8294     else
8295       {
8296         homedir_v[0] = strdup(winPath);
8297         ADD_ATTR("homeDirectory", homedir_v, OpType);
8298       }
8299     
8300     if (strlen(winProfile) == 0)
8301       {
8302         if (OpType == LDAP_MOD_REPLACE)
8303           {
8304             i = 0;
8305             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8306             DelMods[i] = NULL;
8307             //unset profilePate attribute for user.
8308             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8309             free(DelMods[0]);
8310           }
8311       }
8312     else
8313       {
8314         winProfile_v[0] = strdup(winProfile);
8315         ADD_ATTR("profilePath", winProfile_v, OpType);
8316       }
8317     
8318     if (strlen(homeDrive) == 0)
8319       {
8320         if (OpType == LDAP_MOD_REPLACE)
8321           {
8322             i = 0;
8323             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8324             DelMods[i] = NULL;
8325             //unset homeDrive attribute for user
8326             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8327             free(DelMods[0]);
8328           }
8329       }
8330     else
8331       {
8332         drives_v[0] = strdup(homeDrive);
8333         ADD_ATTR("homeDrive", drives_v, OpType);
8334       }
8335
8336     return(n);
8337 }
8338
8339 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8340                      char *attribute_value, char *attribute, char *user_name)
8341 {
8342   char      *mod_v[] = {NULL, NULL};
8343   LDAPMod   *DelMods[20];
8344   LDAPMod   *mods[20];
8345   int       n;
8346   int       i;
8347   int       rc;
8348   
8349   if (strlen(attribute_value) == 0)
8350     {
8351       i = 0;
8352       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8353       DelMods[i] = NULL;
8354       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8355       free(DelMods[0]);
8356     }
8357   else
8358     {
8359       n = 0;
8360       mod_v[0] = attribute_value;
8361       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8362       mods[n] = NULL;
8363
8364       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8365                               mods)) != LDAP_SUCCESS)
8366         {
8367           free(mods[0]);
8368           n = 0;
8369           mod_v[0] = attribute_value;
8370           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8371           mods[n] = NULL;
8372
8373           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8374                                   mods)) != LDAP_SUCCESS)
8375             {
8376               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8377                       "in the directory : %s",
8378                       attribute, user_name, ldap_err2string(rc));
8379             }
8380         }
8381
8382       free(mods[0]);
8383     }
8384   
8385   return(rc);
8386 }
8387
8388 void StringTrim(char *StringToTrim)
8389 {
8390   char *t, *s;
8391   char *save;
8392
8393   save = strdup(StringToTrim);
8394
8395   s = save;
8396
8397   while (isspace(*s))
8398     s++;
8399
8400   /* skip to end of string */
8401   if (*s == '\0')
8402     {
8403       if (*save)
8404         *save = '\0';
8405       strcpy(StringToTrim, save);
8406       return;
8407     }
8408   
8409   for (t = s; *t; t++)
8410     continue;
8411
8412   while (t > s)
8413     {
8414       --t;
8415       if (!isspace(*t))
8416         {
8417           t++;
8418           break;
8419         }
8420     }
8421
8422   if (*t)
8423     *t = '\0';
8424   
8425   strcpy(StringToTrim, s);
8426   return;
8427 }
8428
8429 int ReadConfigFile(char *DomainName)
8430 {
8431     int     Count;
8432     int     i;
8433     int     k;
8434     char    temp[256];
8435     char    temp1[256];
8436     FILE    *fptr;
8437
8438     Count = 0;
8439
8440     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8441
8442     if ((fptr = fopen(temp, "r")) != NULL)
8443       {
8444         while (fgets(temp, sizeof(temp), fptr) != 0)
8445           {
8446             for (i = 0; i < (int)strlen(temp); i++)
8447               temp[i] = toupper(temp[i]);
8448
8449             if (temp[strlen(temp) - 1] == '\n')
8450               temp[strlen(temp) - 1] = '\0';
8451
8452             StringTrim(temp);
8453
8454             if (strlen(temp) == 0)
8455               continue;
8456
8457             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8458               {
8459                 if (strlen(temp) > (strlen(DOMAIN)))
8460                   {
8461                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8462                     StringTrim(ldap_domain);
8463                   }
8464               }
8465             else if (!strncmp(temp, REALM, strlen(REALM)))
8466               {
8467                 if (strlen(temp) > (strlen(REALM)))
8468                   {
8469                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8470                     StringTrim(ldap_realm);
8471                   }
8472               }
8473             else if (!strncmp(temp, PORT, strlen(PORT)))
8474               {
8475                 if (strlen(temp) > (strlen(PORT)))
8476                   {
8477                     strcpy(ldap_port, &temp[strlen(PORT)]);
8478                     StringTrim(ldap_port);
8479                   }
8480               }
8481             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8482               {
8483                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8484                   {
8485                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8486                     StringTrim(PrincipalName);
8487                   }
8488               }
8489             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8490               {
8491                 if (strlen(temp) > (strlen(SERVER)))
8492                   {
8493                     ServerList[Count] = calloc(1, 256);
8494                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8495                     StringTrim(ServerList[Count]);
8496                     ++Count;
8497                   }
8498               }
8499             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8500               {
8501                 if (strlen(temp) > (strlen(MSSFU)))
8502                   {
8503                     strcpy(temp1, &temp[strlen(MSSFU)]);
8504                     StringTrim(temp1);
8505                     if (!strcmp(temp1, SFUTYPE))
8506                       UseSFU30 = 1;
8507                   }
8508               }
8509             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8510               {
8511                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8512                   {
8513                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8514                     StringTrim(temp1);
8515                     if (!strcasecmp(temp1, "NO")) 
8516                       {
8517                         UseGroupSuffix = 0;
8518                         memset(group_suffix, '\0', sizeof(group_suffix));
8519                       }
8520                   }
8521               }
8522             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8523               {
8524                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8525                   {
8526                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8527                     StringTrim(temp1);
8528                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8529                       UseGroupUniversal = 1;
8530                   }
8531               }
8532             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8533               {
8534                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8535                   {
8536                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8537                     StringTrim(temp1);
8538                     if (!strcasecmp(temp1, "NO"))
8539                       SetGroupAce = 0;
8540                   }
8541               }
8542             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8543               {
8544                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8545                   {
8546                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8547                     StringTrim(temp1);
8548                     if (!strcasecmp(temp1, "NO"))
8549                       SetPassword = 0;
8550                   }
8551               }
8552             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8553               {
8554                 if (strlen(temp) > (strlen(EXCHANGE)))
8555                   {
8556                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8557                     StringTrim(temp1);
8558                     if (!strcasecmp(temp1, "YES"))
8559                       Exchange = 1;
8560                   }
8561               }
8562             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8563                               strlen(PROCESS_MACHINE_CONTAINER)))
8564               {
8565                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8566                   {
8567                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8568                     StringTrim(temp1);
8569                     if (!strcasecmp(temp1, "NO"))
8570                       ProcessMachineContainer = 0;
8571                   }
8572               }
8573             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8574                               strlen(ACTIVE_DIRECTORY)))
8575               {
8576                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8577                   {
8578                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8579                     StringTrim(temp1);
8580                     if (!strcasecmp(temp1, "NO"))
8581                       ActiveDirectory = 0;
8582                   }
8583               }
8584             else if (!strncmp(temp, GROUP_POPULATE_MEMBERS, 
8585                               strlen(GROUP_POPULATE_MEMBERS)))
8586               {
8587                 if (strlen(temp) > (strlen(GROUP_POPULATE_MEMBERS)))
8588                   {
8589                     strcpy(temp1, &temp[strlen(GROUP_POPULATE_MEMBERS)]);
8590                     StringTrim(temp1);
8591                     if (!strcasecmp(temp1, "DELETE")) 
8592                       {
8593                         GroupPopulateDelete = 1;
8594                       }
8595                   }
8596               }
8597             else
8598               {
8599                 if (strlen(ldap_domain) != 0)
8600                   {
8601                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8602                     break;
8603                   }
8604
8605                 if (strlen(temp) != 0)
8606                   strcpy(ldap_domain, temp);
8607               }
8608           }
8609         fclose(fptr);
8610       }
8611     
8612     if (strlen(ldap_domain) == 0)
8613       {
8614       strcpy(ldap_domain, DomainName);
8615       }
8616
8617     if (Count == 0)
8618         return(0);
8619
8620     for (i = 0; i < Count; i++)
8621       {
8622         if (ServerList[i] != 0)
8623           {
8624             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8625               ServerList[i][k] = toupper(ServerList[i][k]);
8626           }
8627       }
8628     
8629     return(0);
8630 }
8631
8632 int ReadDomainList()
8633 {
8634   int     Count;
8635   int     i;
8636   char    temp[128];
8637   char    temp1[128];
8638   FILE    *fptr;
8639   unsigned char c[11];
8640   unsigned char stuff[256];
8641   int     rc;
8642   int     ok;
8643
8644   Count = 0;
8645   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8646
8647   if ((fptr = fopen(temp, "r")) != NULL)
8648     {
8649       while (fgets(temp, sizeof(temp), fptr) != 0)
8650         {
8651           for (i = 0; i < (int)strlen(temp); i++)
8652             temp[i] = toupper(temp[i]);
8653
8654           if (temp[strlen(temp) - 1] == '\n')
8655             temp[strlen(temp) - 1] = '\0';
8656
8657           StringTrim(temp);
8658
8659           if (strlen(temp) == 0)
8660             continue;
8661
8662           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8663             {
8664               if (strlen(temp) > (strlen(DOMAIN)))
8665                 {
8666                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8667                   StringTrim(temp1);
8668                   strcpy(temp, temp1);
8669                 }
8670             }
8671           
8672           strcpy(DomainNames[Count], temp);
8673           StringTrim(DomainNames[Count]);
8674           ++Count;
8675         }
8676
8677       fclose(fptr);
8678     }
8679
8680   if (Count == 0)
8681     {
8682       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8683                      "configuration error in ldap.cfg");
8684       return(1);
8685     }
8686   
8687   return(0);
8688 }
8689
8690 int email_isvalid(const char *address) {
8691   int        count = 0;
8692   const char *c, *domain;
8693   static char *rfc822_specials = "()<>@,;:\\\"[]";
8694
8695   if(address[strlen(address) - 1] == '.') 
8696     return 0;
8697     
8698   /* first we validate the name portion (name@domain) */
8699   for (c = address;  *c;  c++) {
8700     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8701                        '\"')) {
8702       while (*++c) {
8703         if (*c == '\"') 
8704           break;
8705         if (*c == '\\' && (*++c == ' ')) 
8706           continue;
8707         if (*c <= ' ' || *c >= 127) 
8708           return 0;
8709       }
8710
8711       if (!*c++) 
8712         return 0;
8713       if (*c == '@') 
8714         break;
8715       if (*c != '.') 
8716         return 0;
8717       continue;
8718     }
8719
8720     if (*c == '@') 
8721       break;
8722     if (*c <= ' ' || *c >= 127) 
8723       return 0;
8724     if (strchr(rfc822_specials, *c)) 
8725       return 0;
8726   }
8727
8728   if (c == address || *(c - 1) == '.') 
8729     return 0;
8730
8731   /* next we validate the domain portion (name@domain) */
8732   if (!*(domain = ++c)) return 0;
8733   do {
8734     if (*c == '.') {
8735       if (c == domain || *(c - 1) == '.') 
8736         return 0;
8737       count++;
8738     }
8739     if (*c <= ' ' || *c >= 127) 
8740       return 0;
8741     if (strchr(rfc822_specials, *c)) 
8742       return 0;
8743   } while (*++c);
8744
8745   return (count >= 1);
8746 }
8747
8748 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8749              char **homeServerName) 
8750 {
8751   LK_ENTRY *group_base;
8752   LK_ENTRY *sub_group_base;
8753   LK_ENTRY *gPtr;
8754   LK_ENTRY *sub_gPtr;
8755   int      group_count;
8756   int      sub_group_count;
8757   char     filter[1024];
8758   char     sub_filter[1024];
8759   char     search_path[1024];
8760   char     range[1024];
8761   char     *attr_array[3];
8762   char     *s;
8763   int      homeMDB_count = -1;
8764   int      rc;
8765   int      i;
8766   int      mdbbl_count;
8767   int      rangeStep = 1500;
8768   int      rangeLow = 0;
8769   int      rangeHigh = rangeLow + (rangeStep - 1);
8770   int      isLast = 0;
8771
8772   /* Grumble..... microsoft not making it searchable from the root *grr* */
8773
8774   memset(filter, '\0', sizeof(filter));
8775   memset(search_path, '\0', sizeof(search_path));
8776   
8777   sprintf(filter, "(objectClass=msExchMDB)");
8778   sprintf(search_path, "CN=Configuration,%s", dn_path);
8779   attr_array[0] = "distinguishedName";
8780   attr_array[1] = NULL;
8781   
8782   group_base = NULL;
8783   group_count = 0;
8784   
8785   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8786                            &group_base, &group_count, 
8787                            LDAP_SCOPE_SUBTREE)) != 0) 
8788     {
8789       com_err(whoami, 0, "Unable to find msExchMDB %s",
8790               ldap_err2string(rc));
8791       return(rc);
8792     }
8793   
8794   if (group_count) 
8795     {
8796       gPtr = group_base;
8797       
8798       while(gPtr) {
8799         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8800             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8801             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8802           {
8803             gPtr = gPtr->next;
8804             continue;
8805           }
8806
8807         /* 
8808          * Due to limits in active directory we need to use the LDAP
8809          * range semantics to query and return all the values in 
8810          * large lists, we will stop increasing the range when
8811          * the result count is 0.
8812          */
8813
8814         i = 0;  
8815         mdbbl_count = 0;
8816
8817         for(;;) 
8818           {
8819             memset(sub_filter, '\0', sizeof(sub_filter));
8820             memset(range, '\0', sizeof(range));
8821             sprintf(sub_filter, "(objectClass=msExchMDB)");
8822
8823             if(isLast)
8824               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8825             else 
8826               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8827
8828             attr_array[0] = range;
8829             attr_array[1] = NULL;
8830             
8831             sub_group_base = NULL;
8832             sub_group_count = 0;
8833             
8834             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8835                                      attr_array, &sub_group_base, 
8836                                      &sub_group_count, 
8837                                      LDAP_SCOPE_SUBTREE)) != 0) 
8838               {
8839                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8840                         ldap_err2string(rc));
8841                 return(rc);
8842               }
8843
8844             if(!sub_group_count)
8845               {
8846                 if(isLast) 
8847                   {
8848                     isLast = 0;
8849                     rangeLow = 0;
8850                     rangeHigh = rangeLow + (rangeStep - 1);
8851                     break;
8852                   }
8853                 else
8854                   isLast++;
8855               }
8856
8857             mdbbl_count += sub_group_count;
8858             rangeLow = rangeHigh + 1;
8859             rangeHigh = rangeLow + (rangeStep - 1);
8860           }
8861
8862         /* First time through, need to initialize or update the least used */
8863         
8864         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8865                 mdbbl_count);
8866
8867         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8868           {
8869             homeMDB_count = mdbbl_count; 
8870             *homeMDB = strdup(gPtr->dn);
8871           }
8872
8873         gPtr = gPtr->next;
8874         linklist_free(sub_group_base);
8875       }
8876     }
8877
8878   linklist_free(group_base);
8879   
8880   /* 
8881    * Ok found the server least allocated need to now query to get its
8882    * msExchHomeServerName so we can set it as a user attribute
8883    */
8884   
8885   attr_array[0] = "legacyExchangeDN";
8886   attr_array[1] = NULL; 
8887   
8888   group_count = 0;
8889   group_base = NULL;
8890   
8891   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8892                            attr_array, &group_base, 
8893                            &group_count, 
8894                            LDAP_SCOPE_SUBTREE)) != 0) 
8895     {
8896       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8897               ldap_err2string(rc));
8898       return(rc);
8899     }  
8900   
8901   if(group_count) 
8902     {
8903       *homeServerName = strdup(group_base->value);
8904       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8905         {
8906           *s = '\0';
8907         }
8908     } 
8909
8910   linklist_free(group_base);
8911   
8912   return(rc);
8913 }
8914       
8915 char *lowercase(char *s)
8916 {
8917   char *p;
8918
8919   for (p = s; *p; p++)
8920     {
8921       if (isupper(*p))
8922         *p = tolower(*p);
8923     }
8924   return s;
8925 }
8926
8927 char *uppercase(char *s)
8928 {
8929   char *p;
8930
8931   for (p = s; *p; p++)
8932     {
8933       if (islower(*p))
8934         *p = toupper(*p);
8935     }
8936   return s;
8937 }
8938
8939 char *escape_string(char *s)
8940 {
8941   char *p, *q;
8942   char string[1024];
8943   char temp[1024];
8944   int i = 0;
8945   int spaces = 0;
8946
8947   memset(string, '\0', sizeof(string));
8948
8949   q = s;
8950
8951   /* Escape any special characters */
8952
8953   for(; *q != '\0'; q++) {
8954     if(*q == ',')
8955       string[i++] = '\\';
8956     if(*q == '+') 
8957       string[i++] = '\\';
8958     if(*q == '"') 
8959       string[i++] = '\\';
8960     if(*q == '\\') 
8961       string[i++] = '\\';
8962     if(*q == '<') 
8963       string[i++] = '\\';
8964     if(*q == '>') 
8965       string[i++] = '\\';
8966     if(*q == ';')
8967       string[i++] = '\\';
8968     if(*q == '#')
8969       string[i++] = '\\';
8970     if(*q == '=')
8971       string[i++] = '\\';
8972
8973     string[i++] = *q;
8974   }
8975
8976   return strdup(string);
8977 }
8978
8979 int save_query_info(int argc, char **argv, void *hint)
8980 {
8981   int i;
8982   char **nargv = hint;
8983
8984   for(i = 0; i < argc; i++)
8985     nargv[i] = strdup(argv[i]);
8986
8987   return MR_CONT;
8988 }
8989
8990 int save_fsgroup_info(int argc, char **argv, void *hint)
8991 {
8992   int i;
8993   char **nargv = hint;
8994
8995   if(!fsgCount) 
8996     {
8997       for(i = 0; i < argc; i++)
8998         nargv[i] = strdup(argv[i]);
8999
9000       fsgCount++;
9001     }
9002
9003   return MR_CONT;
9004 }
This page took 0.7479 seconds and 3 git commands to generate.