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