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