]> andersk Git - moira.git/blob - incremental/ldap/winad.c
3CVS: ----------------------------------------------------------------------
[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 remove %s from group %s : group not active", 
1267                   before[2], before[0]);
1268           return;
1269         }
1270
1271       ptr = before;
1272
1273       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1274         return;
1275
1276       strcpy(user_name, before[LM_MEMBER]);
1277       strcpy(group_name, before[LM_LIST]);
1278       strcpy(user_type, before[LM_TYPE]);
1279
1280       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1281         {
1282           if (beforec > LM_EXTRA_GROUP)
1283             {
1284               strcpy(moira_list_id, before[LMN_LIST_ID]);
1285               strcpy(moira_user_id, before[LM_LIST_ID]);
1286             }
1287         }
1288       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1289         {
1290           if (beforec > LMN_LIST_ID)
1291             {
1292               strcpy(moira_list_id, before[LM_LIST_ID]);
1293               strcpy(moira_user_id, before[LM_USER_ID]);
1294             }
1295         }
1296       else
1297         {
1298           if (beforec > LM_EXTRA_GID)
1299             strcpy(moira_list_id, before[LMN_LIST_ID]);
1300         }
1301     }
1302
1303   if (ptr == NULL)
1304     {
1305       com_err(whoami, 0, 
1306               "Unable to process group : beforec = %d, afterc = %d", 
1307               beforec, afterc);
1308       return;
1309     }
1310
1311   args[L_NAME] = ptr[LM_LIST];
1312   args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE];
1313   args[L_PUBLIC] = ptr[LM_EXTRA_PUBLIC];
1314   args[L_HIDDEN] = ptr[LM_EXTRA_HIDDEN];
1315   args[L_MAILLIST] = ptr[LM_EXTRA_MAILLIST];
1316   args[L_GROUP] = ptr[LM_EXTRA_GROUP];
1317   args[L_GID] = ptr[LM_EXTRA_GID];
1318
1319   security_flag = 0;
1320   memset(group_ou, '\0', sizeof(group_ou));
1321   get_group_membership(group_membership, group_ou, &security_flag, args);
1322
1323   if (strlen(group_ou) == 0)
1324     {
1325       com_err(whoami, 0, "Unable to find the group OU for group %s", 
1326               group_name);
1327       return;
1328     }
1329
1330   if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, 
1331                          group_ou, group_membership, security_flag, 
1332                          CHECK_GROUPS, args[L_MAILLIST]))
1333     {
1334       if (rc != AD_NO_GROUPS_FOUND)
1335         {
1336           if (rc = process_group(ldap_handle, dn_path, moira_list_id, 
1337                                  group_name, group_ou, group_membership, 
1338                                  security_flag, CLEANUP_GROUPS,
1339                                  args[L_MAILLIST]))
1340             {
1341               if (rc != AD_NO_GROUPS_FOUND)
1342                 {
1343                   if (afterc)
1344                     com_err(whoami, 0, "Unable to add %s to group %s - " 
1345                             "unable to process group", user_name, group_name);
1346                   else
1347                     com_err(whoami, 0, "Unable to remove %s from group %s - "
1348                             "unable to process group", user_name, group_name);
1349                   return;
1350                 }
1351             }
1352         }
1353     }
1354
1355   if (rc == AD_NO_GROUPS_FOUND)
1356     {
1357       if (rc = moira_connect())
1358         {
1359           critical_alert("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   else if (!strcmp(av[ACE_TYPE], "LIST"))
3461     {
3462       if (!((int)call_args[3] & MOIRA_LISTS))
3463         return(0);
3464     }
3465   else if (!strcmp(av[ACE_TYPE], "KERBEROS"))
3466     {
3467       if (!((int)call_args[3] & MOIRA_KERBEROS))
3468         return(0);
3469
3470       if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
3471                          kerberos_ou))
3472         return(0);
3473
3474     }
3475   else if (!strcmp(av[ACE_TYPE], "MACHINE"))
3476     {
3477       if (!((int)call_args[3] & MOIRA_MACHINE))
3478         return(0);
3479     }
3480   else
3481     return(0);
3482
3483   linklist = member_base;
3484
3485   while (linklist)
3486     {
3487     if (!strcasecmp(temp, linklist->member) &&
3488         !strcasecmp(av[ACE_TYPE], linklist->type))
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           ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD);
4009         }
4010     }
4011
4012   mods[n] = NULL;
4013
4014   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4015
4016   for (i = 0; i < n; i++)
4017     free(mods[i]);
4018   
4019   if (Exchange)
4020     {
4021       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
4022           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
4023         {
4024           n = 0;
4025           
4026           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
4027           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
4028           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
4029                    LDAP_MOD_REPLACE);
4030           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
4031
4032           hide_address_lists_v[0] = "TRUE";
4033           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4034                    LDAP_MOD_REPLACE);
4035     
4036           mods[n] = NULL;
4037           rc = ldap_modify_s(ld, new_dn, mods);
4038       
4039           if (rc) 
4040             {
4041               com_err(whoami, 0, "Unable to update contact %s", mail);
4042             }
4043       
4044           for (i = 0; i < n; i++)
4045             free(mods[i]);
4046         }
4047     }
4048
4049   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4050     {
4051       com_err(whoami, 0, "Unable to create contact %s : %s",
4052               user, ldap_err2string(rc));
4053       return(rc);
4054     }
4055
4056   return(0);
4057 }
4058
4059 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
4060                 char *Uid, char *MitId, char *MoiraId, int State,
4061                 char *WinHomeDir, char *WinProfileDir, char *first,
4062                 char *middle, char *last, char *shell, char *class)
4063 {
4064   LDAPMod   *mods[20];
4065   LK_ENTRY  *group_base;
4066   int  group_count;
4067   char distinguished_name[512];
4068   char displayName[256];
4069   char *mitMoiraId_v[] = {NULL, NULL};
4070   char *mitMoiraClass_v[] = {NULL, NULL};
4071   char *mitMoiraStatus_v[] = {NULL, NULL};
4072   char *uid_v[] = {NULL, NULL};
4073   char *mitid_v[] = {NULL, NULL};
4074   char *homedir_v[] = {NULL, NULL};
4075   char *winProfile_v[] = {NULL, NULL};
4076   char *drives_v[] = {NULL, NULL};
4077   char *userAccountControl_v[] = {NULL, NULL};
4078   char *alt_recipient_v[] = {NULL, NULL};
4079   char *hide_address_lists_v[] = {NULL, NULL};
4080   char *mail_v[] = {NULL, NULL};
4081   char *gid_v[] = {NULL, NULL};
4082   char *loginshell_v[] = {NULL, NULL};
4083   char *principal_v[] = {NULL, NULL};
4084   char userAccountControlStr[80];
4085   int  n;
4086   int  rc;
4087   int  i;
4088   int  OldUseSFU30;
4089   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4090     UF_PASSWD_CANT_CHANGE;
4091   char filter[128];
4092   char *attr_array[3];
4093   char temp[1024];
4094   char mail[256];
4095   char contact_mail[256];
4096   char filter_exp[1024];
4097   char search_path[512];
4098   char TemplateDn[512];
4099   char TemplateSamName[128];
4100   char alt_recipient[256];
4101   char principal[256];
4102   char status[256];
4103   char acBERBuf[N_SD_BER_BYTES];
4104   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4105                           { N_SD_BER_BYTES, acBERBuf },
4106                           TRUE};
4107   LDAPControl *apsServerControls[] = {&sControl, NULL};
4108   LDAPMessage *psMsg;
4109   LDAP_BERVAL   **ppsValues;
4110   ULONG dwInfo;
4111   char *argv[3];
4112   char *homeMDB;
4113   char *homeServerName;
4114   char *save_argv[7];
4115   char search_string[256];
4116   char *p, *q;
4117   char *mail_routing_v[] = {NULL, NULL};
4118   char *c;
4119
4120   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4121     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4122   BEREncodeSecurityBits(dwInfo, acBERBuf);
4123
4124   if (!check_string(user_name))
4125     {
4126       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4127               user_name);
4128       return(AD_INVALID_NAME);
4129     }
4130   
4131   memset(contact_mail, '\0', sizeof(contact_mail));
4132   sprintf(contact_mail, "%s@mit.edu", user_name);
4133   memset(mail, '\0', sizeof(mail));
4134   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4135   memset(alt_recipient, '\0', sizeof(alt_recipient));
4136   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4137           dn_path);
4138   sprintf(search_string, "@%s", uppercase(ldap_domain));
4139
4140   if (Exchange)
4141     {
4142       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4143         {
4144           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4145         }
4146     }
4147
4148   group_count = 0;
4149   group_base = NULL;
4150
4151   memset(displayName, '\0', sizeof(displayName));
4152
4153   if (strlen(MoiraId) != 0)
4154     {
4155       if(ActiveDirectory)
4156         {
4157           sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4158         }
4159       else
4160         {
4161           sprintf(filter, 
4162                   "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId);
4163         }
4164
4165       attr_array[0] = "cn";
4166       attr_array[1] = NULL;
4167       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4168                                &group_base, &group_count, 
4169                                LDAP_SCOPE_SUBTREE)) != 0)
4170         {
4171           com_err(whoami, 0, "Unable to process user %s : %s",
4172                   user_name, ldap_err2string(rc));
4173           return(rc);
4174         }
4175     }
4176
4177   if (group_count != 1)
4178     {
4179       linklist_free(group_base);
4180       group_base = NULL;
4181       group_count = 0;
4182       sprintf(filter, "(sAMAccountName=%s)", user_name);
4183       attr_array[0] = "cn";
4184       attr_array[1] = NULL;
4185       sprintf(temp, "%s,%s", user_ou, dn_path);
4186       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
4187                                &group_base, &group_count, 
4188                                LDAP_SCOPE_SUBTREE)) != 0)
4189         {
4190           com_err(whoami, 0, "Unable to process user %s : %s",
4191                   user_name, ldap_err2string(rc));
4192           return(rc);
4193         }
4194     }
4195
4196   if (group_count != 1)
4197     {
4198       com_err(whoami, 0, "Unable to find user %s in AD",
4199               user_name);
4200       linklist_free(group_base);
4201       return(AD_NO_USER_FOUND);
4202     }
4203
4204   strcpy(distinguished_name, group_base->dn);
4205
4206   linklist_free(group_base);
4207   group_count = 0;
4208
4209   if(!ActiveDirectory) 
4210     {
4211       if (rc = moira_connect())
4212         {
4213           critical_alert("AD incremental", 
4214                          "Error contacting Moira server : %s",
4215                          error_message(rc));
4216           return;
4217         }
4218   
4219       argv[0] = user_name;
4220       
4221       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4222         {
4223           n = 0;
4224           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
4225           mods[n] = NULL;
4226           rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4227           
4228           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
4229             rc = LDAP_SUCCESS;
4230
4231           if(rc)
4232             com_err(whoami, 0, 
4233                     "Unable to set the mailRoutingAddress for %s : %s",
4234                     user_name, ldap_err2string(rc));
4235           
4236           p = strdup(save_argv[3]);
4237           
4238           if((c = strchr(p, ',')) != NULL) 
4239             {
4240               q = strtok(p, ",");
4241               StringTrim(q);
4242
4243               if ((c = strchr(q, '@')) == NULL)
4244                 sprintf(temp, "%s@mit.edu", q);
4245               else
4246                 sprintf(temp, "%s", q);
4247               
4248               if(email_isvalid(temp) && State != US_DELETED) 
4249                 {
4250                   mail_routing_v[0]  = temp;
4251                   
4252                   n = 0;
4253                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4254                   mods[n] = NULL;
4255                   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4256
4257                   if (rc == LDAP_ALREADY_EXISTS || 
4258                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
4259                     rc = LDAP_SUCCESS;
4260     
4261                   if(rc)
4262                     com_err(whoami, 0, 
4263                             "Unable to set the mailRoutingAddress for %s : %s",
4264                             user_name, ldap_err2string(rc));
4265                 }
4266
4267               while((q = strtok(NULL, ",")) != NULL) {
4268                 StringTrim(q);
4269                 
4270                 if((c = strchr(q, '@')) == NULL) 
4271                   sprintf(temp, "%s@mit.edu", q);
4272                 else
4273                   sprintf(temp, "%s", q);
4274
4275                 if(email_isvalid(temp) && State != US_DELETED) 
4276                   {
4277                     mail_routing_v[0]  = temp;
4278                 
4279                     n = 0;
4280                     ADD_ATTR("mailRoutingAddress", mail_routing_v, 
4281                              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 " 
4292                               "%s : %s",
4293                               user_name, ldap_err2string(rc));
4294                   }
4295               }
4296             } else {
4297               StringTrim(p);
4298
4299             if((c = strchr(p, '@')) == NULL)
4300               sprintf(temp, "%s@mit.edu", p);
4301             else
4302               sprintf(temp, "%s", p);
4303             
4304             if(email_isvalid(temp) && State != US_DELETED) 
4305               {
4306                 mail_routing_v[0]  = temp;
4307                 
4308                 n = 0;
4309                 ADD_ATTR("mailRoutingAddress", mail_routing_v, 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 %s : %s",
4320                           user_name, ldap_err2string(rc));
4321               }
4322             }
4323         }
4324       moira_disconnect();
4325     }
4326
4327   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
4328     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
4329                           "employeeID", user_name);
4330   else
4331     rc = attribute_update(ldap_handle, distinguished_name, "none", 
4332                           "employeeID", user_name);
4333
4334   if(strlen(first)) {
4335     strcat(displayName, first);
4336   }
4337
4338   if(strlen(middle)) {
4339     if(strlen(first)) 
4340       strcat(displayName, " ");
4341
4342     strcat(displayName, middle);
4343   }
4344
4345   if(strlen(last)) {
4346     if(strlen(middle) || strlen(first))
4347       strcat(displayName, " ");
4348
4349     strcat(displayName, last);
4350   }
4351
4352   if(strlen(displayName))
4353     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4354                           "displayName", user_name);
4355   else
4356     rc = attribute_update(ldap_handle, distinguished_name, user_name,
4357                           "displayName", user_name);
4358
4359   if(!ActiveDirectory)
4360     {
4361       if(strlen(displayName))
4362         rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4363                               "cn", user_name);
4364       else
4365         rc = attribute_update(ldap_handle, distinguished_name, user_name,
4366                               "cn", user_name);
4367     }
4368
4369   if(!ActiveDirectory)
4370     {
4371       rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4372                             "eduPersonNickname", user_name);
4373     }
4374
4375   if(strlen(first))
4376     rc = attribute_update(ldap_handle, distinguished_name, first, 
4377                           "givenName", user_name);
4378   else
4379     rc = attribute_update(ldap_handle, distinguished_name, "",
4380                           "givenName", user_name);
4381
4382   if(strlen(middle) == 1) 
4383     rc = attribute_update(ldap_handle, distinguished_name, middle,
4384                           "initials", user_name);
4385   else 
4386     rc = attribute_update(ldap_handle, distinguished_name, "",
4387                           "initials", user_name);
4388   
4389   if(strlen(last))
4390     rc = attribute_update(ldap_handle, distinguished_name, last,
4391                           "sn", user_name);
4392   else 
4393     rc = attribute_update(ldap_handle, distinguished_name, "",
4394                           "sn", user_name);
4395
4396   if(ActiveDirectory)
4397     {
4398       rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4399                             user_name);
4400     }
4401   else
4402     {
4403       rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", 
4404                             user_name);
4405     }
4406     
4407   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4408                         "mitMoiraId", user_name);
4409
4410   n = 0;
4411   uid_v[0] = Uid;
4412
4413   if(ActiveDirectory)
4414     {
4415       if (!UseSFU30)
4416         {
4417           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4418         }
4419       else
4420         {
4421           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4422         }
4423     }
4424   else
4425     {
4426       sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4427       sprintf(status, "%d", State);
4428       principal_v[0] = principal;
4429       loginshell_v[0] = shell;
4430       mitMoiraClass_v[0] = class;
4431       mitMoiraStatus_v[0] = status;
4432       gid_v[0] = "101";
4433       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4434       ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE);
4435       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE);
4436       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4437       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE);
4438       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE);
4439     }
4440
4441   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4442     {
4443       userAccountControl |= UF_ACCOUNTDISABLE;
4444
4445       if (Exchange)
4446         {
4447           hide_address_lists_v[0] = "TRUE";
4448           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4449                    LDAP_MOD_REPLACE);
4450         }
4451     }
4452   else
4453     {
4454       if (Exchange)
4455         {
4456           hide_address_lists_v[0] = NULL;
4457           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4458                    LDAP_MOD_REPLACE);
4459         }
4460     }
4461
4462   sprintf(userAccountControlStr, "%ld", userAccountControl);
4463   userAccountControl_v[0] = userAccountControlStr;
4464   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4465
4466   if (Exchange)
4467     {
4468       if (rc = moira_connect())
4469         {
4470           critical_alert("AD incremental", 
4471                          "Error contacting Moira server : %s",
4472                          error_message(rc));
4473           return;
4474         }
4475  
4476       argv[0] = user_name;
4477
4478       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4479         {
4480           if(!strcmp(save_argv[1], "EXCHANGE") || 
4481              (strstr(save_argv[3], search_string) != NULL))
4482             {
4483               alt_recipient_v[0] = NULL;
4484               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4485
4486               argv[0] = exchange_acl;
4487               argv[1] = "USER";
4488               argv[2] = user_name;
4489               
4490               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4491               
4492               if ((rc) && (rc != MR_EXISTS))
4493                 {
4494                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4495                           user_name, exchange_acl, error_message(rc));
4496                 }
4497             }
4498           else 
4499             {
4500               alt_recipient_v[0] = alt_recipient;
4501               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4502               
4503               argv[0] = exchange_acl;
4504               argv[1] = "USER";
4505               argv[2] = user_name;
4506               
4507               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4508               
4509               if ((rc) && (rc != MR_NO_MATCH))
4510                 {  
4511                   com_err(whoami, 0,
4512                           "Unable to remove user %s from %s: %s, %d",
4513                           user_name, exchange_acl, error_message(rc), rc);
4514                 }  
4515             }
4516         }
4517       else
4518         {
4519           alt_recipient_v[0] = alt_recipient;
4520           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4521           
4522           argv[0] = exchange_acl;
4523           argv[1] = "USER";
4524           argv[2] = user_name;
4525           
4526           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4527           
4528           if ((rc) && (rc != MR_NO_MATCH))
4529             {  
4530               com_err(whoami, 0,
4531                       "Unable to remove user %s from %s: %s, %d",
4532                       user_name, exchange_acl, error_message(rc), rc);
4533             }  
4534         }
4535       
4536       moira_disconnect();
4537     }
4538   else
4539     {
4540       mail_v[0] = contact_mail;
4541       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4542     }
4543
4544   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4545                        WinProfileDir, homedir_v, winProfile_v,
4546                        drives_v, mods, LDAP_MOD_REPLACE, n);
4547
4548   if(ActiveDirectory)
4549     {
4550       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4551       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4552       attr_array[0] = "sAMAccountName";
4553       attr_array[1] = NULL;
4554       group_count = 0;
4555       group_base = NULL;
4556     
4557       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
4558                                attr_array,
4559                                &group_base, &group_count, 
4560                                LDAP_SCOPE_SUBTREE) != 0))
4561         return(1);
4562       
4563       if (group_count != 1)
4564         {
4565           com_err(whoami, 0, "Unable to process user security template: %s - "
4566                   "security not set", "UserTemplate.u");
4567           return(1);
4568         }
4569
4570       strcpy(TemplateDn, group_base->dn);
4571       strcpy(TemplateSamName, group_base->value);
4572       linklist_free(group_base);
4573       group_base = NULL;
4574       group_count = 0;
4575       
4576       rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4577                              filter_exp, NULL, 0, apsServerControls, NULL,
4578                              NULL, 0, &psMsg);
4579
4580       if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4581         {
4582           com_err(whoami, 0, "Unable to find user security template: %s - "
4583                   "security not set", "UserTemplate.u");
4584           return(1);
4585         }
4586       
4587       ppsValues = ldap_get_values_len(ldap_handle, psMsg, 
4588                                       "ntSecurityDescriptor");
4589
4590       if (ppsValues == NULL)
4591         {
4592           com_err(whoami, 0, "Unable to find user security template: %s - "
4593                   "security not set", "UserTemplate.u");
4594           return(1);
4595         }
4596       
4597       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4598                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4599     }
4600
4601   mods[n] = NULL;
4602
4603   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4604                           mods)) != LDAP_SUCCESS)
4605     {
4606       OldUseSFU30 = UseSFU30;
4607       SwitchSFU(mods, &UseSFU30, n);
4608       if (OldUseSFU30 != UseSFU30)
4609         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4610       if (rc)
4611         {
4612           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4613                   user_name, ldap_err2string(rc));
4614         }
4615     }
4616   
4617   for (i = 0; i < n; i++)
4618     free(mods[i]);
4619
4620   return(rc);
4621 }
4622
4623 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4624                 char *user_name)
4625 {
4626   LDAPMod *mods[20];
4627   char new_dn[256];
4628   char old_dn[256];
4629   char upn[256];
4630   char mail[256];
4631   char contact_mail[256];
4632   char proxy_address[256];
4633   char query_base_dn[256];
4634   char temp[256];
4635   char *userPrincipalName_v[] = {NULL, NULL};
4636   char *altSecurityIdentities_v[] = {NULL, NULL};
4637   char *name_v[] = {NULL, NULL};
4638   char *samAccountName_v[] = {NULL, NULL};
4639   char *mail_v[] = {NULL, NULL};
4640   char *mail_nickname_v[] = {NULL, NULL};
4641   char *proxy_address_v[] = {NULL, NULL};
4642   char *query_base_dn_v[] = {NULL, NULL};
4643   char *principal_v[] = {NULL, NULL};
4644   char principal[256];
4645   int  n;
4646   int  rc;
4647   int  i;
4648
4649   if (!check_string(before_user_name))
4650     {
4651       com_err(whoami, 0, 
4652               "Unable to process invalid LDAP user name %s", before_user_name);
4653       return(AD_INVALID_NAME);
4654     }
4655
4656   if (!check_string(user_name))
4657     {
4658       com_err(whoami, 0, 
4659               "Unable to process invalid LDAP user name %s", user_name);
4660       return(AD_INVALID_NAME);
4661     }
4662
4663   strcpy(user_name, user_name);
4664  
4665   if(ActiveDirectory)
4666     sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4667   else
4668     sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path);
4669
4670   if(ActiveDirectory)
4671     sprintf(new_dn, "cn=%s", user_name);
4672   else
4673     sprintf(new_dn, "uid=%s", user_name);
4674
4675   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4676   sprintf(contact_mail, "%s@mit.edu", user_name);
4677   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4678   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4679
4680   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4681                            NULL, NULL)) != LDAP_SUCCESS)
4682     {
4683       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4684               before_user_name, user_name, ldap_err2string(rc));
4685       return(rc);
4686     }
4687
4688   if (Exchange)
4689     {
4690       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4691               dn_path);
4692
4693       if(rc = ldap_delete_s(ldap_handle, temp))
4694         {
4695           com_err(whoami, 0, "Unable to delete user contact for %s",
4696                   user_name);
4697         }
4698       
4699       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4700         {
4701           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4702         }
4703     }
4704
4705   name_v[0] = user_name;
4706   sprintf(upn, "%s@%s", user_name, ldap_domain);
4707   userPrincipalName_v[0] = upn;
4708   principal_v[0] = principal;
4709   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4710   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4711   altSecurityIdentities_v[0] = temp;
4712   samAccountName_v[0] = user_name;
4713   mail_v[0] = mail;
4714   mail_nickname_v[0] = user_name;
4715   proxy_address_v[0] = proxy_address; 
4716   query_base_dn_v[0] = query_base_dn;
4717
4718   n = 0;
4719   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4720   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4721   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4722   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4723
4724   if(!ActiveDirectory)
4725     {
4726       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE);
4727       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4728       ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4729       ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE);
4730     }
4731
4732   if (Exchange)
4733     {
4734       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4735       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4736       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4737       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4738     }
4739   else
4740     {
4741       mail_v[0] = contact_mail;
4742       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4743     }
4744
4745   mods[n] = NULL;
4746   
4747   if(ActiveDirectory)
4748     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4749   else
4750     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path);
4751
4752   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4753     {
4754       com_err(whoami, 0, 
4755               "Unable to modify user data for %s after renaming : %s",
4756               user_name, ldap_err2string(rc));
4757     }
4758   
4759   for (i = 0; i < n; i++)
4760     free(mods[i]);
4761
4762   return(rc);
4763 }
4764
4765 int user_create(int ac, char **av, void *ptr)
4766 {
4767   LDAPMod *mods[20];
4768   char new_dn[256];
4769   char user_name[256];
4770   char sam_name[256];
4771   char upn[256];
4772   char mail[256];
4773   char contact_mail[256];
4774   char proxy_address[256];
4775   char mail_nickname[256];
4776   char query_base_dn[256];
4777   char displayName[256];
4778   char address_book[256];
4779   char alt_recipient[256];
4780   char *cn_v[] = {NULL, NULL};
4781   char *objectClass_v[] = {"top", "person", "organizationalPerson",
4782                            "user", NULL};
4783   char *objectClass_ldap_v[] = {"top", 
4784                                 "eduPerson", "posixAccount", 
4785                                 "apple-user", "shadowAccount",
4786                                 "microsoftComTop", "securityPrincipal",
4787                                 "inetOrgPerson", "user", 
4788                                 "organizationalPerson", "person",
4789                                 "mailRecipient", NULL};
4790
4791   char *samAccountName_v[] = {NULL, NULL};
4792   char *altSecurityIdentities_v[] = {NULL, NULL};
4793   char *mitMoiraId_v[] = {NULL, NULL};
4794   char *mitMoiraClass_v[] = {NULL, NULL};
4795   char *mitMoiraStatus_v[] = {NULL, NULL};
4796   char *name_v[] = {NULL, NULL};
4797   char *desc_v[] = {NULL, NULL};
4798   char *userPrincipalName_v[] = {NULL, NULL};
4799   char *userAccountControl_v[] = {NULL, NULL};
4800   char *uid_v[] = {NULL, NULL};
4801   char *gid_v[] = {NULL, NULL};
4802   char *mitid_v[] = {NULL, NULL};
4803   char *homedir_v[] = {NULL, NULL};
4804   char *winProfile_v[] = {NULL, NULL};
4805   char *drives_v[] = {NULL, NULL};
4806   char *mail_v[] = {NULL, NULL};
4807   char *givenName_v[] = {NULL, NULL};
4808   char *sn_v[] = {NULL, NULL};
4809   char *initials_v[] = {NULL, NULL};
4810   char *displayName_v[] = {NULL, NULL};
4811   char *proxy_address_v[] = {NULL, NULL};
4812   char *mail_nickname_v[] = {NULL, NULL};
4813   char *query_base_dn_v[] = {NULL, NULL};
4814   char *address_book_v[] = {NULL, NULL};
4815   char *homeMDB_v[] = {NULL, NULL};
4816   char *homeServerName_v[] = {NULL, NULL};
4817   char *mdbUseDefaults_v[] = {NULL, NULL};
4818   char *mailbox_guid_v[] = {NULL, NULL};
4819   char *user_culture_v[] = {NULL, NULL};
4820   char *user_account_control_v[] = {NULL, NULL};
4821   char *msexch_version_v[] = {NULL, NULL};
4822   char *alt_recipient_v[] = {NULL, NULL};
4823   char *hide_address_lists_v[] = {NULL, NULL};
4824   char *principal_v[] = {NULL, NULL};
4825   char *loginshell_v[] = {NULL, NULL};
4826   char userAccountControlStr[80];
4827   char temp[1024];
4828   char principal[256];
4829   char filter_exp[1024];
4830   char search_path[512];
4831   char *attr_array[3];
4832   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4833     UF_PASSWD_CANT_CHANGE; 
4834   int  n;
4835   int  rc;
4836   int  i;
4837   int  OldUseSFU30;
4838   char **call_args;
4839   char WinHomeDir[1024];
4840   char WinProfileDir[1024];
4841   char *homeMDB;
4842   char *homeServerName;
4843   ULONG dwInfo;
4844   char acBERBuf[N_SD_BER_BYTES];
4845   LK_ENTRY  *group_base;
4846   int    group_count;
4847   char TemplateDn[512];
4848   char TemplateSamName[128];
4849   LDAP_BERVAL **ppsValues;
4850   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4851                           { N_SD_BER_BYTES, acBERBuf },
4852                           TRUE};
4853   LDAPControl *apsServerControls[] = {&sControl, NULL};
4854   LDAPMessage *psMsg;
4855   char *argv[3];
4856   char *save_argv[7];
4857   char search_string[256];
4858   char *o_v[] = {NULL, NULL};
4859   char *p, *q;
4860   char *mail_routing_v[] = {NULL, NULL};
4861   char *c;
4862
4863   call_args = ptr;
4864
4865   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4866     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4867   BEREncodeSecurityBits(dwInfo, acBERBuf);
4868
4869   if (!check_string(av[U_NAME]))
4870     {
4871       callback_rc = AD_INVALID_NAME;
4872       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4873               av[U_NAME]);
4874       return(AD_INVALID_NAME);
4875     }
4876
4877   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4878   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4879   memset(displayName, '\0', sizeof(displayName));
4880   memset(query_base_dn, '\0', sizeof(query_base_dn));
4881   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4882   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4883   strcpy(user_name, av[U_NAME]);
4884   sprintf(upn, "%s@%s", user_name, ldap_domain);
4885   sprintf(sam_name, "%s", av[U_NAME]);
4886
4887   if(strlen(av[U_FIRST])) {
4888     strcat(displayName, av[U_FIRST]);
4889   }
4890
4891   if(strlen(av[U_MIDDLE])) {
4892     if(strlen(av[U_FIRST]))
4893        strcat(displayName, " "); 
4894   
4895     strcat(displayName, av[U_MIDDLE]);
4896   }
4897
4898   if(strlen(av[U_LAST])) {
4899     if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]))
4900       strcat(displayName, " ");
4901
4902     strcat(displayName, av[U_LAST]);
4903   }
4904
4905   samAccountName_v[0] = sam_name;
4906   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4907       (atoi(av[U_STATE]) != US_REGISTERED))
4908     {
4909       userAccountControl |= UF_ACCOUNTDISABLE;
4910
4911       if (Exchange)
4912         {
4913           hide_address_lists_v[0] = "TRUE";
4914           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4915                    LDAP_MOD_ADD);
4916         }
4917     }
4918
4919   sprintf(userAccountControlStr, "%ld", userAccountControl);
4920   userAccountControl_v[0] = userAccountControlStr;
4921   userPrincipalName_v[0] = upn;
4922   
4923   if(ActiveDirectory)
4924     cn_v[0] = user_name;
4925   else
4926     cn_v[0] = displayName;
4927     
4928   name_v[0] = user_name;
4929   desc_v[0] = "Auto account created by Moira";
4930   mail_v[0] = mail;
4931   givenName_v[0] = av[U_FIRST];
4932
4933   if(ActiveDirectory)
4934     sn_v[0] = av[U_LAST];
4935   else
4936     if(strlen(av[U_LAST]))
4937       sn_v[0] = av[U_LAST];
4938     else
4939       sn_v[0] = av[U_NAME];
4940
4941   displayName_v[0] = displayName;
4942   mail_nickname_v[0] = user_name;
4943   o_v[0] = "Massachusetts Institute of Technology";
4944
4945   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4946   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4947   altSecurityIdentities_v[0] = temp;    
4948   principal_v[0] = principal;
4949
4950   if(ActiveDirectory)
4951     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4952   else
4953     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]);
4954
4955   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4956   sprintf(contact_mail, "%s@mit.edu", user_name);
4957   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4958   query_base_dn_v[0] = query_base_dn;
4959   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4960           call_args[1]);
4961   sprintf(search_string, "@%s", uppercase(ldap_domain));
4962
4963   if (Exchange)
4964     {
4965       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
4966                         contact_ou))
4967         {
4968           com_err(whoami, 0, "Unable to create user contact %s", 
4969                   contact_mail);
4970         }
4971       
4972       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
4973                       &homeServerName)) 
4974         {
4975           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
4976           return(1);
4977         }
4978       
4979       com_err(whoami, 0, "homeMDB:%s", homeMDB);
4980       com_err(whoami, 0, "homeServerName:%s", homeServerName);
4981   
4982       homeMDB_v[0] = homeMDB;
4983       homeServerName_v[0] = homeServerName; 
4984     }
4985
4986   n = 0;
4987
4988   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
4989   
4990   if(ActiveDirectory) 
4991     {
4992       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
4993     }
4994   else
4995     {
4996       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
4997     }
4998
4999   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
5000   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
5001   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
5002   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
5003   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
5004
5005   if (Exchange)
5006     {
5007       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
5008       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
5009       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
5010       mdbUseDefaults_v[0] = "TRUE";
5011       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
5012       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
5013       
5014       argv[0] = user_name;
5015     
5016       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5017         {
5018           if(!strcmp(save_argv[1], "EXCHANGE") || 
5019              (strstr(save_argv[3], search_string) != NULL))
5020             {
5021               argv[0] = exchange_acl;
5022               argv[1] = "USER";
5023               argv[2] = user_name;
5024               
5025               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
5026               
5027               if ((rc) && (rc != MR_EXISTS))
5028                 {
5029                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
5030                           user_name, exchange_acl, error_message(rc));
5031                 }
5032             } 
5033           else 
5034             {
5035               alt_recipient_v[0] = alt_recipient;
5036               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5037             }
5038         }
5039       else
5040         {
5041           alt_recipient_v[0] = alt_recipient;
5042           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5043           
5044           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
5045         }
5046     }
5047   else
5048     {
5049       mail_v[0] = contact_mail;
5050       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
5051     }
5052
5053   if(strlen(av[U_FIRST])) {
5054     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
5055   }
5056
5057   if(strlen(av[U_LAST]) || strlen(av[U_NAME])) {
5058     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
5059   }
5060
5061   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
5062     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
5063
5064     if(!ActiveDirectory)
5065       {
5066         ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD);      
5067       }
5068   } else {
5069     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
5070
5071     if(!ActiveDirectory)
5072       {
5073         ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD);            
5074       }
5075   }
5076
5077   if (strlen(av[U_MIDDLE]) == 1) {
5078     initials_v[0] = av[U_MIDDLE];
5079     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
5080   }
5081
5082   if (strlen(call_args[2]) != 0)    
5083     {
5084       mitMoiraId_v[0] = call_args[2];
5085       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
5086     }
5087
5088   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
5089
5090   if(!ActiveDirectory)
5091     {
5092       loginshell_v[0] = av[U_SHELL];
5093       mitMoiraClass_v[0] = av[U_CLASS];
5094       mitMoiraStatus_v[0] = av[U_STATE];
5095       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD);
5096       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD);
5097       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD);
5098       ADD_ATTR("o", o_v, LDAP_MOD_ADD);
5099       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD);
5100       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD);
5101     }
5102
5103   if (strlen(av[U_UID]) != 0)
5104     {
5105       uid_v[0] = av[U_UID];
5106
5107       if(ActiveDirectory) 
5108         {
5109           ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
5110         }
5111       else
5112         {
5113           gid_v[0] = "101";
5114           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5115           ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD);
5116         }
5117
5118       if(ActiveDirectory)
5119         {
5120           if (!UseSFU30)
5121             {
5122               ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5123             }
5124           else
5125             {
5126               ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
5127             }
5128         }
5129     }
5130
5131   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
5132       mitid_v[0] = av[U_MITID];
5133   else
5134       mitid_v[0] = "none";
5135
5136   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
5137
5138   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, 
5139                        WinHomeDir, WinProfileDir, homedir_v, winProfile_v,
5140                        drives_v, mods, LDAP_MOD_ADD, n);
5141   
5142   if(ActiveDirectory) 
5143     {
5144       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
5145       sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
5146       attr_array[0] = "sAMAccountName";
5147       attr_array[1] = NULL;
5148       group_count = 0;
5149       group_base = NULL;
5150       
5151       if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
5152                                attr_array, &group_base, &group_count, 
5153                                LDAP_SCOPE_SUBTREE) != 0))
5154         return(1);
5155       
5156       if (group_count != 1)
5157         {
5158           com_err(whoami, 0, "Unable to process user security template: %s - "
5159                   "security not set", "UserTemplate.u");
5160           return(1);
5161         }
5162       
5163       strcpy(TemplateDn, group_base->dn);
5164       strcpy(TemplateSamName, group_base->value);
5165       linklist_free(group_base);
5166       group_base = NULL;
5167       group_count = 0;
5168       
5169       rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, 
5170                              LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, 
5171                              apsServerControls, NULL,
5172                              NULL, 0, &psMsg);
5173       
5174       if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
5175         {
5176           com_err(whoami, 0, "Unable to find user security template: %s - "
5177                   "security not set", "UserTemplate.u");
5178           return(1);
5179         }
5180       
5181       ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
5182                                       "ntSecurityDescriptor");
5183       if (ppsValues == NULL)
5184         {
5185           com_err(whoami, 0, "Unable to find user security template: %s - "
5186                   "security not set", "UserTemplate.u");
5187           return(1);
5188         }
5189       
5190       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
5191                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
5192     }
5193
5194   mods[n] = NULL;
5195
5196   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5197
5198   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5199     {
5200       OldUseSFU30 = UseSFU30;
5201       SwitchSFU(mods, &UseSFU30, n);
5202       if (OldUseSFU30 != UseSFU30)
5203         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5204     }
5205
5206   for (i = 0; i < n; i++)
5207     free(mods[i]);
5208
5209   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5210     {
5211       com_err(whoami, 0, "Unable to create user %s : %s",
5212               user_name, ldap_err2string(rc));
5213       callback_rc = rc;
5214       return(rc);
5215     }
5216
5217   if ((rc == LDAP_SUCCESS) && (SetPassword))
5218     {
5219       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5220         {
5221           ad_kdc_disconnect();
5222           if (!ad_server_connect(default_server, ldap_domain))
5223             {
5224               com_err(whoami, 0, "Unable to set password for user %s : %s",
5225                       user_name, 
5226                       "cannot get changepw ticket from windows domain");
5227             }
5228           else
5229             {
5230               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5231                 {
5232                   com_err(whoami, 0, "Unable to set password for user %s "
5233                           ": %ld", user_name, rc);
5234                 }
5235             }
5236         }
5237     }
5238
5239   if(!ActiveDirectory) 
5240     {
5241       if (rc = moira_connect())
5242         {
5243           critical_alert("AD incremental", 
5244                          "Error contacting Moira server : %s",
5245                          error_message(rc));
5246           return;
5247         }
5248   
5249       argv[0] = user_name;
5250       
5251       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5252         {
5253           n = 0;
5254           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
5255           mods[n] = NULL;
5256           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5257            
5258           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
5259             rc = LDAP_SUCCESS;
5260
5261           if(rc)
5262             com_err(whoami, 0,
5263                     "Unable to set the mailRoutingAddress for %s : %s",
5264                     user_name, ldap_err2string(rc));
5265
5266           p = strdup(save_argv[3]);
5267           
5268           if((c = strchr(p, ',')) != NULL) {
5269             q = strtok(p, ",");
5270             StringTrim(q);
5271
5272             if ((c = strchr(q, '@')) == NULL)
5273               sprintf(temp, "%s@mit.edu", q);
5274             else
5275               sprintf(temp, "%s", q);
5276
5277             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5278               {
5279                 mail_routing_v[0]  = temp;
5280
5281                 n = 0;
5282                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5283                 mods[n] = NULL;
5284                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5285                 
5286                 if (rc == LDAP_ALREADY_EXISTS || 
5287                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5288                   rc = LDAP_SUCCESS;
5289                 
5290                 if(rc)
5291                   com_err(whoami, 0, 
5292                           "Unable to set the mailRoutingAddress for %s : %s",
5293                           user_name, ldap_err2string(rc));
5294               }
5295
5296             while((q = strtok(NULL, ",")) != NULL) {
5297               StringTrim(q);
5298
5299               if((c = strchr(q, '@')) == NULL)
5300                 sprintf(temp, "%s@mit.edu", q);
5301               else
5302                 sprintf(temp, "%s", q);
5303
5304               if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED)
5305                 {
5306                   mail_routing_v[0]  = temp;
5307                   
5308                   n = 0;
5309                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5310                   mods[n] = NULL;
5311                   rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5312                   
5313                   if (rc == LDAP_ALREADY_EXISTS || 
5314                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
5315                     rc = LDAP_SUCCESS;
5316                   
5317                   if(rc)
5318                     com_err(whoami, 0, 
5319                             "Unable to set the mailRoutingAddress for %s : %s",
5320                             user_name, ldap_err2string(rc));
5321                 }
5322             }
5323           } else {
5324             StringTrim(p);
5325
5326             if((c = strchr(p, '@')) == NULL)
5327               sprintf(temp, "%s@mit.edu", p);
5328             else
5329               sprintf(temp, "%s", p);
5330
5331             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5332               {
5333                 mail_routing_v[0]  = temp;
5334                 
5335                 n = 0;
5336                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5337                 mods[n] = NULL;
5338                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5339                 
5340                 if (rc == LDAP_ALREADY_EXISTS || 
5341                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5342                   rc = LDAP_SUCCESS;
5343                 
5344                 if(rc)
5345                   com_err(whoami, 0, 
5346                           "Unable to set the mailRoutingAddress for %s : %s",
5347                           user_name, ldap_err2string(rc));
5348               }
5349           }
5350         }
5351       moira_disconnect();
5352     }
5353
5354   return(0);
5355 }
5356
5357 int user_change_status(LDAP *ldap_handle, char *dn_path, 
5358                        char *user_name, char *MoiraId,
5359                        int operation)
5360 {
5361   char      filter[128];
5362   char      *attr_array[3];
5363   char      temp[256];
5364   char      distinguished_name[1024];
5365   char      **modvalues;
5366   char      *mitMoiraId_v[] = {NULL, NULL};
5367   LDAPMod   *mods[20];
5368   LK_ENTRY  *group_base;
5369   int       group_count;
5370   int       rc;
5371   int       i;
5372   int       n;
5373   ULONG     ulongValue;
5374
5375   if (!check_string(user_name))
5376     {
5377       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
5378               user_name);
5379       return(AD_INVALID_NAME);
5380     }
5381
5382   group_count = 0;
5383   group_base = NULL;
5384
5385   if (strlen(MoiraId) != 0)
5386     {
5387       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5388       attr_array[0] = "UserAccountControl";
5389       attr_array[1] = NULL;
5390       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5391                                &group_base, &group_count, 
5392                                LDAP_SCOPE_SUBTREE)) != 0)
5393         {
5394           com_err(whoami, 0, "Unable to process user %s : %s",
5395                   user_name, ldap_err2string(rc));
5396           return(rc);
5397         }
5398     }
5399
5400   if (group_count != 1)
5401     {
5402       linklist_free(group_base);
5403       group_count = 0;
5404       group_base = NULL;
5405       sprintf(filter, "(sAMAccountName=%s)", user_name);
5406       attr_array[0] = "UserAccountControl";
5407       attr_array[1] = NULL;
5408       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5409                                &group_base, &group_count, 
5410                                LDAP_SCOPE_SUBTREE)) != 0)
5411         {
5412           com_err(whoami, 0, "Unable to process user %s : %s",
5413                   user_name, ldap_err2string(rc));
5414           return(rc);
5415         }
5416     }
5417   
5418   if (group_count != 1)
5419     {
5420       linklist_free(group_base);
5421       com_err(whoami, 0, "Unable to find user %s in AD",
5422               user_name);
5423       return(LDAP_NO_SUCH_OBJECT);
5424     }
5425
5426   strcpy(distinguished_name, group_base->dn);
5427   ulongValue = atoi((*group_base).value);
5428
5429   if (operation == MEMBER_DEACTIVATE)
5430     ulongValue |= UF_ACCOUNTDISABLE;
5431   else    
5432     ulongValue &= ~UF_ACCOUNTDISABLE;
5433
5434   sprintf(temp, "%ld", ulongValue);
5435
5436   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
5437                                 temp, &modvalues, REPLACE)) == 1)
5438     goto cleanup;
5439
5440   linklist_free(group_base);
5441   group_base = NULL;
5442   group_count = 0;
5443   n = 0;
5444   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
5445
5446   if (strlen(MoiraId) != 0)
5447     {
5448     mitMoiraId_v[0] = MoiraId;
5449     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
5450     }
5451
5452   mods[n] = NULL;
5453   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
5454
5455   for (i = 0; i < n; i++)
5456     free(mods[i]);
5457
5458   free_values(modvalues);
5459
5460   if (rc != LDAP_SUCCESS)
5461     {
5462       com_err(whoami, 0, "Unable to change status of user %s : %s",
5463               user_name, ldap_err2string(rc));
5464     }
5465   
5466  cleanup:
5467   return(rc);
5468 }
5469
5470 int user_delete(LDAP *ldap_handle, char *dn_path, 
5471                 char *u_name, char *MoiraId)
5472 {
5473   char      filter[128];
5474   char      *attr_array[3];
5475   char      distinguished_name[1024];
5476   char      user_name[512];
5477   LK_ENTRY  *group_base;
5478   int       group_count;
5479   int       rc;
5480   char      temp[256];
5481
5482   if (!check_string(u_name))
5483     return(AD_INVALID_NAME);
5484
5485   strcpy(user_name, u_name);
5486   group_count = 0;
5487   group_base = NULL;
5488
5489   if (strlen(MoiraId) != 0)
5490     {
5491       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5492       attr_array[0] = "name";
5493       attr_array[1] = NULL;
5494       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5495                                &group_base, &group_count, 
5496                                LDAP_SCOPE_SUBTREE)) != 0)
5497         {
5498           com_err(whoami, 0, "Unable to process user %s : %s",
5499                   user_name, ldap_err2string(rc));
5500           goto cleanup;
5501         }
5502     }
5503   
5504   if (group_count != 1)
5505     {
5506       linklist_free(group_base);
5507       group_count = 0;
5508       group_base = NULL;
5509       sprintf(filter, "(sAMAccountName=%s)", user_name);
5510       attr_array[0] = "name";
5511       attr_array[1] = NULL;
5512       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5513                                &group_base, &group_count, 
5514                                LDAP_SCOPE_SUBTREE)) != 0)
5515         {
5516           com_err(whoami, 0, "Unable to process user %s : %s",
5517                   user_name, ldap_err2string(rc));
5518           goto cleanup;
5519         }
5520     }
5521
5522   if (group_count != 1)
5523     {
5524       com_err(whoami, 0, "Unable to find user %s in AD",
5525               user_name);
5526       goto cleanup;
5527     }
5528   
5529   strcpy(distinguished_name, group_base->dn);
5530
5531   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
5532     {
5533       com_err(whoami, 0, "Unable to process user %s : %s",
5534               user_name, ldap_err2string(rc));
5535     }
5536
5537   /* Need to add code to delete mit.edu contact */
5538   
5539   if (Exchange)
5540     {
5541       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
5542
5543       if(rc = ldap_delete_s(ldap_handle, temp))
5544         {
5545           com_err(whoami, 0, "Unable to delete user contact for %s",
5546                   user_name);
5547         }
5548     }
5549
5550  cleanup:
5551   linklist_free(group_base);
5552
5553   return(0);
5554 }
5555
5556 void linklist_free(LK_ENTRY *linklist_base)
5557 {
5558   LK_ENTRY *linklist_previous;
5559
5560   while (linklist_base != NULL)
5561     {
5562       if (linklist_base->dn != NULL)
5563         free(linklist_base->dn);
5564
5565       if (linklist_base->attribute != NULL)
5566         free(linklist_base->attribute);
5567
5568       if (linklist_base->value != NULL)
5569         free(linklist_base->value);
5570
5571       if (linklist_base->member != NULL)
5572         free(linklist_base->member);
5573
5574       if (linklist_base->type != NULL)
5575         free(linklist_base->type);
5576
5577       if (linklist_base->list != NULL)
5578         free(linklist_base->list);
5579
5580       linklist_previous = linklist_base;
5581       linklist_base = linklist_previous->next;
5582       free(linklist_previous);
5583     }
5584 }
5585
5586 void free_values(char **modvalues)
5587 {
5588   int i;
5589
5590   i = 0;
5591
5592   if (modvalues != NULL)
5593     {
5594     while (modvalues[i] != NULL)
5595       {
5596         free(modvalues[i]);
5597         modvalues[i] = NULL;
5598         ++i;
5599       }
5600     free(modvalues);
5601   }
5602 }
5603
5604 static int illegalchars[] = {
5605   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5606   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5607   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
5608   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5609   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5610   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5611   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5612   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5613   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5614   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5615   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5616   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5617   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5618   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5619   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5620   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5621 };
5622
5623 static int illegalchars_ldap[] = {
5624   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5625   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5626   0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, /* SPACE - / */
5627   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
5628   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5629   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */
5630   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5631   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5632   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5633   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5634   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5635   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5636   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5637   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5638   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5639   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5640 };
5641
5642 int check_string(char *s)
5643 {
5644   char  character;
5645
5646   for (; *s; s++)
5647     {
5648       character = *s;
5649
5650       if (isupper(character))
5651         character = tolower(character);
5652
5653       if(ActiveDirectory)
5654         {
5655           if (illegalchars[(unsigned) character])
5656             return 0;
5657         }
5658       else
5659         {
5660           if (illegalchars_ldap[(unsigned) character])
5661             return 0;
5662         }
5663     }
5664
5665   return(1);
5666 }
5667
5668 int check_container_name(char *s)
5669 {
5670   char  character;
5671
5672   for (; *s; s++)
5673     {
5674       character = *s;
5675
5676       if (isupper(character))
5677         character = tolower(character);
5678
5679       if (character == ' ')
5680         continue;
5681
5682       if (illegalchars[(unsigned) character])
5683         return 0;
5684     }
5685
5686   return(1);
5687 }
5688
5689 int mr_connect_cl(char *server, char *client, int version, int auth)
5690 {
5691   int   status;
5692   char  *motd;
5693   char  temp[128];
5694
5695   status = mr_connect(server);
5696
5697   if (status)
5698     {
5699       com_err(whoami, status, "while connecting to Moira");
5700       return status;
5701     }
5702
5703   status = mr_motd(&motd);
5704
5705   if (status)
5706     {
5707       mr_disconnect();
5708       com_err(whoami, status, "while checking server status");
5709       return status;
5710     }
5711
5712   if (motd)
5713     {
5714       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5715       com_err(whoami, status, temp);
5716       mr_disconnect();
5717       return status;
5718     }
5719
5720   status = mr_version(version);
5721
5722   if (status)
5723     {
5724       if (status == MR_UNKNOWN_PROC)
5725         {
5726           if (version > 2)
5727             status = MR_VERSION_HIGH;
5728           else
5729             status = MR_SUCCESS;
5730         }
5731
5732       if (status == MR_VERSION_HIGH)
5733         {
5734           com_err(whoami, 0, "Warning: This client is running newer code "
5735                   "than the server.");
5736                   com_err(whoami, 0, "Some operations may not work.");
5737         }
5738       else if (status && status != MR_VERSION_LOW)
5739         {
5740           com_err(whoami, status, "while setting query version number.");
5741           mr_disconnect();
5742           return status;
5743         }
5744     }
5745
5746   if (auth)
5747     {
5748       status = mr_krb5_auth(client);
5749       if (status)
5750         {
5751           com_err(whoami, status, "while authenticating to Moira.");
5752           mr_disconnect();
5753           return status;
5754         }
5755     }
5756   
5757   return MR_SUCCESS;
5758 }
5759
5760 void AfsToWinAfs(char* path, char* winPath)
5761 {
5762   char* pathPtr;
5763   char* winPathPtr;
5764   strcpy(winPath, WINAFS);
5765   pathPtr = path + strlen(AFS);
5766   winPathPtr = winPath + strlen(WINAFS);
5767   
5768   while (*pathPtr)
5769     {
5770       if (*pathPtr == '/')
5771         *winPathPtr = '\\';
5772       else
5773         *winPathPtr = *pathPtr;
5774       
5775       pathPtr++;
5776       winPathPtr++;
5777     }
5778 }
5779
5780 int GetAceInfo(int ac, char **av, void *ptr)
5781 {
5782   char **call_args;
5783   int   security_flag;
5784
5785   call_args = ptr;
5786   
5787   strcpy(call_args[0], av[L_ACE_TYPE]);
5788   strcpy(call_args[1], av[L_ACE_NAME]);
5789   security_flag = 0;
5790   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5791   return(LDAP_SUCCESS);  
5792 }
5793
5794 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5795 {
5796   char filter[128];
5797   char *attr_array[3];
5798   int  group_count;
5799   int  rc;
5800   LK_ENTRY  *group_base;
5801   
5802   group_count = 0;
5803   group_base = NULL;
5804   
5805   sprintf(filter, "(sAMAccountName=%s)", Name);
5806   attr_array[0] = "sAMAccountName";
5807   attr_array[1] = NULL;
5808
5809   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5810                            &group_base, &group_count, 
5811                            LDAP_SCOPE_SUBTREE)) != 0)
5812     {
5813       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5814               Name, ldap_err2string(rc));
5815       return(1);
5816     }
5817
5818   linklist_free(group_base);
5819   group_base = NULL;
5820
5821   if (group_count == 0)
5822     return(0);
5823   
5824   return(1);
5825 }
5826
5827 #define MAX_ACE 7
5828
5829 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5830                int UpdateGroup, int *ProcessGroup, char *maillist)
5831 {
5832   char  *av[2];
5833   char  GroupName[256];
5834   char  *call_args[7];
5835   int   rc;
5836   char  *AceInfo[4];
5837   char  AceType[32];
5838   char  AceName[128];
5839   char  AceMembership[2];
5840   char  AceOu[256];
5841   char  temp[128];
5842   char  *save_argv[U_END];
5843
5844   if (!SetGroupAce)
5845     {
5846       com_err(whoami, 0, "ProcessAce disabled, skipping");
5847       return(0);
5848     }
5849
5850   strcpy(GroupName, Name);
5851   
5852   if (strcasecmp(Type, "LIST"))
5853     return(1);
5854
5855   while (1)
5856     {
5857       av[0] = GroupName;
5858       AceInfo[0] = AceType;
5859       AceInfo[1] = AceName;
5860       AceInfo[2] = AceMembership;
5861       AceInfo[3] = AceOu;
5862       memset(AceType, '\0', sizeof(AceType));
5863       memset(AceName, '\0', sizeof(AceName));
5864       memset(AceMembership, '\0', sizeof(AceMembership));
5865       memset(AceOu, '\0', sizeof(AceOu));
5866       callback_rc = 0;
5867     
5868       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5869         { 
5870           com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5871                   GroupName, error_message(rc));
5872           return(1);
5873         }
5874
5875       if (callback_rc)
5876         {
5877           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5878           return(1);
5879         }
5880
5881       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5882         return(0);
5883
5884       strcpy(temp, AceName);
5885
5886       if (!strcasecmp(AceType, "LIST"))
5887         sprintf(temp, "%s%s", AceName, group_suffix);
5888
5889       if (!UpdateGroup)
5890         {
5891           if (checkADname(ldap_handle, dn_path, temp))
5892               return(0);
5893
5894           (*ProcessGroup) = 1;
5895         }
5896
5897       if (!strcasecmp(AceInfo[0], "LIST"))
5898         {
5899           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5900                              AceMembership, 0, UpdateGroup, maillist))
5901             return(1);
5902         }
5903       else if (!strcasecmp(AceInfo[0], "USER"))
5904         {
5905           av[0] = AceName;
5906           call_args[0] = (char *)ldap_handle;
5907           call_args[1] = dn_path;
5908           call_args[2] = "";
5909           call_args[3] = NULL;
5910           callback_rc = 0;
5911
5912           if (rc = mr_query("get_user_account_by_login", 1, av, 
5913                             save_query_info, save_argv))
5914             {
5915               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5916                       AceName, Name);
5917               return(1);
5918             }
5919
5920           if (rc = user_create(U_END, save_argv, call_args)) 
5921             {
5922               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5923                       AceName, Name);
5924               return(1);
5925             }
5926           
5927           if (callback_rc)
5928             {
5929               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5930                       AceName, Name);
5931               return(1);
5932             }
5933
5934           return(0);
5935         }
5936       else
5937         return(1);
5938
5939       if (!strcasecmp(AceType, "LIST"))
5940         {
5941           if (!strcasecmp(GroupName, AceName))
5942             return(0);
5943         }
5944
5945       strcpy(GroupName, AceName);
5946     }
5947   
5948   return(1);
5949 }
5950
5951 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
5952                    char *group_name, char *group_ou, char *group_membership, 
5953                    int group_security_flag, int updateGroup, char *maillist)
5954 {
5955   char  *av[3];
5956   char  *call_args[8];
5957   int   rc;
5958   LK_ENTRY  *group_base;
5959   int  group_count;
5960   char filter[128];
5961   char *attr_array[3];
5962
5963   av[0] = group_name;
5964   call_args[0] = (char *)ldap_handle;
5965   call_args[1] = dn_path;
5966   call_args[2] = group_name;
5967   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
5968   call_args[4] = (char *)updateGroup;
5969   call_args[5] = MoiraId;
5970   call_args[6] = "0";
5971   call_args[7] = NULL;
5972   callback_rc = 0;
5973
5974   group_count = 0;
5975   group_base = NULL;
5976
5977   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
5978     {
5979       moira_disconnect();
5980       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
5981               error_message(rc));
5982       return(rc);
5983     }
5984
5985   if (callback_rc)
5986     {
5987       moira_disconnect();
5988       com_err(whoami, 0, "Unable to create list %s", group_name);
5989       return(callback_rc);
5990     }
5991
5992   return(0);
5993 }
5994
5995 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
5996                    char *group_ou, char *group_membership, 
5997                    int group_security_flag, char *MoiraId)
5998 {
5999   char      *av[3];
6000   char      *call_args[7];
6001   char      *pUserOu;
6002   LK_ENTRY  *ptr;
6003   int       rc;
6004   char      member[512];
6005   char      *s;
6006   char      **members;
6007   int       i = 0;
6008   int       j = 0;
6009   int       n = 0;
6010   char      group_dn[512];
6011   LDAPMod   *mods[20];
6012   char      *member_v[] = {NULL, NULL};
6013   char      *save_argv[U_END];
6014   char      machine_ou[256];
6015   char      NewMachineName[1024];
6016
6017   com_err(whoami, 0, "Populating group %s", group_name);
6018   av[0] = group_name;
6019   call_args[0] = (char *)ldap_handle;
6020   call_args[1] = dn_path;
6021   call_args[2] = group_name;
6022   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS | 
6023                           MOIRA_MACHINE);
6024   call_args[4] = NULL;
6025   member_base = NULL;
6026
6027   if (rc = mr_query("get_end_members_of_list", 1, av,
6028                     member_list_build, call_args))
6029     {
6030       com_err(whoami, 0, "Unable to populate list %s : %s", 
6031               group_name, error_message(rc));
6032       return(3);
6033     }
6034
6035   members = (char **)malloc(sizeof(char *) * 2);
6036
6037   if (member_base != NULL)
6038     {
6039       ptr = member_base;
6040
6041       while (ptr != NULL)
6042         {
6043           if (!strcasecmp(ptr->type, "LIST"))
6044             {
6045               ptr = ptr->next;
6046               continue;
6047             }
6048           
6049           if (!strcasecmp(ptr->type, "MACHINE") && !ProcessMachineContainer)
6050             {
6051               ptr = ptr->next;
6052               continue;
6053             }
6054             
6055           if(!strcasecmp(ptr->type, "USER"))
6056             {
6057               if(!strcasecmp(ptr->member, PRODUCTION_PRINCIPAL) ||
6058                  !strcasecmp(ptr->member, TEST_PRINCIPAL))
6059                 {
6060                   ptr = ptr->next;
6061                   continue;
6062                 }
6063
6064               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6065                                    "")) == AD_NO_USER_FOUND)
6066                 {
6067                   com_err(whoami, 0, "creating user %s", ptr->member);
6068
6069                   av[0] = ptr->member;
6070                   call_args[0] = (char *)ldap_handle;
6071                   call_args[1] = dn_path;
6072                   call_args[2] = "";
6073                   call_args[3] = NULL;
6074                   callback_rc = 0;
6075                   
6076                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6077                                     save_query_info, save_argv))
6078                     {
6079                       com_err(whoami, 0, "Unable to create user %s " 
6080                               "while populating group %s.", ptr->member,
6081                               group_name);
6082
6083                       return(3);
6084                     }
6085
6086                   if (rc = user_create(U_END, save_argv, call_args)) 
6087                     {
6088                       com_err(whoami, 0, "Unable to create user %s "
6089                               "while populating group %s.", ptr->member,
6090                               group_name);
6091                       
6092                       return(3);
6093                     }
6094           
6095                   if (callback_rc)
6096                     {
6097                       com_err(whoami, 0, "Unable to create user %s "
6098                               "while populating group %s", ptr->member, 
6099                               group_name);
6100
6101                       return(3);
6102                     }
6103                 }
6104
6105               pUserOu = user_ou;
6106                   
6107               if(ActiveDirectory) 
6108                 {
6109                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6110                           dn_path);
6111                 }
6112               else 
6113                 {
6114                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6115                           dn_path);
6116                 }
6117
6118             }
6119           else if (!strcasecmp(ptr->type, "STRING"))
6120             {
6121               if (contact_create(ldap_handle, dn_path, ptr->member,
6122                                  contact_ou))
6123                 return(3);
6124
6125               pUserOu = contact_ou;
6126               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6127                       pUserOu, dn_path);
6128             }
6129           else if (!strcasecmp(ptr->type, "KERBEROS"))
6130             {
6131               if (contact_create(ldap_handle, dn_path, ptr->member, 
6132                                  kerberos_ou))
6133                 return(3);
6134
6135               pUserOu = kerberos_ou;
6136               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6137                       pUserOu, dn_path);
6138             }
6139           else if (!strcasecmp(ptr->type, "MACHINE"))
6140             {
6141               memset(machine_ou, '\0', sizeof(machine_ou));
6142               memset(NewMachineName, '\0', sizeof(NewMachineName));
6143
6144               if (!get_machine_ou(ldap_handle, dn_path, ptr->member,
6145                                  machine_ou, NewMachineName))
6146                 {
6147                   pUserOu = machine_ou;
6148                   sprintf(member, "cn=%s,%s,%s", NewMachineName, pUserOu,
6149                           dn_path);
6150                 }
6151               else
6152                 {
6153                   ptr = ptr->next;                  
6154                   continue;
6155                 }
6156             }
6157
6158           if(i > 1) 
6159             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6160           members[i++] = strdup(member);
6161
6162           ptr = ptr->next;
6163         }
6164     
6165       linklist_free(member_base);
6166       member_base = NULL;
6167     }
6168
6169   members[i] = NULL;
6170
6171   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6172
6173   if(GroupPopulateDelete)
6174     {
6175       n = 0;
6176       ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
6177       mods[n] = NULL;
6178       
6179       if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6180                               mods)) != LDAP_SUCCESS)
6181         {
6182           com_err(whoami, 0,
6183                   "Unable to populate group membership for %s: %s",
6184                   group_dn, ldap_err2string(rc));
6185         }
6186   
6187       for (i = 0; i < n; i++)
6188         free(mods[i]);
6189     }
6190
6191   n = 0;
6192   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6193   mods[n] = NULL;
6194
6195   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6196                           mods)) != LDAP_SUCCESS)
6197     {
6198       com_err(whoami, 0,
6199               "Unable to populate group membership for %s: %s",
6200               group_dn, ldap_err2string(rc));
6201     }
6202   
6203   for (i = 0; i < n; i++)
6204     free(mods[i]);
6205     
6206   free(members);
6207
6208   return(0);
6209 }
6210
6211 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6212                   char *group_name, char *group_ou, char *group_membership, 
6213                   int group_security_flag, int type, char *maillist)
6214 {
6215   char      before_desc[512];
6216   char      before_name[256];
6217   char      before_group_ou[256];
6218   char      before_group_membership[2];
6219   char      distinguishedName[256];
6220   char      ad_distinguishedName[256];
6221   char      filter[128];
6222   char      *attr_array[3];
6223   int       before_security_flag;
6224   int       group_count;
6225   int       rc;
6226   LK_ENTRY  *group_base;
6227   LK_ENTRY  *ptr;
6228   char      ou_both[512];
6229   char      ou_security[512];
6230   char      ou_distribution[512];
6231   char      ou_neither[512];
6232   char      group_dn[512];
6233
6234   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6235   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6236
6237   memset(filter, '\0', sizeof(filter));
6238   group_base = NULL;
6239   group_count = 0;
6240
6241   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6242                         "*", MoiraId, 
6243                         "samAccountName", &group_base, 
6244                         &group_count, filter))
6245     return(rc);
6246
6247   if (type == CHECK_GROUPS)
6248     {
6249       if (group_count == 1)
6250         {
6251           strcpy(group_dn, group_base->dn);
6252
6253           if (!strcasecmp(group_dn, distinguishedName))
6254             {
6255               linklist_free(group_base);
6256               return(0);
6257             }
6258         }
6259
6260       linklist_free(group_base);
6261
6262       if (group_count == 0)
6263         return(AD_NO_GROUPS_FOUND);
6264
6265       if (group_count == 1)
6266         return(AD_WRONG_GROUP_DN_FOUND);
6267
6268       return(AD_MULTIPLE_GROUPS_FOUND);
6269     }
6270
6271   if (group_count == 0)
6272     {
6273       return(AD_NO_GROUPS_FOUND);
6274     }
6275
6276   if (group_count > 1)
6277     {
6278       ptr = group_base;
6279
6280       strcpy(group_dn, ptr->dn);
6281
6282       while (ptr != NULL)
6283         {
6284           if (!strcasecmp(group_dn, ptr->value))
6285             break;
6286
6287           ptr = ptr->next;
6288         }
6289
6290       if (ptr == NULL)
6291         {
6292           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6293                   MoiraId);
6294           ptr = group_base;
6295
6296           while (ptr != NULL)
6297             {
6298               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6299               ptr = ptr->next;
6300             }
6301
6302           linklist_free(group_base);
6303           return(AD_MULTIPLE_GROUPS_FOUND);
6304         }
6305
6306       ptr = group_base;
6307
6308       while (ptr != NULL)
6309         {
6310           strcpy(group_dn, ptr->dn);
6311
6312           if (strcasecmp(group_dn, ptr->value))
6313             rc = ldap_delete_s(ldap_handle, ptr->value);
6314
6315           ptr = ptr->next;
6316         }
6317
6318       linklist_free(group_base);
6319       memset(filter, '\0', sizeof(filter));
6320       group_base = NULL;
6321       group_count = 0;
6322
6323       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6324                             "*", MoiraId, 
6325                             "samAccountName", &group_base, 
6326                             &group_count, filter))
6327         return(rc);
6328
6329       if (group_count == 0)
6330         return(AD_NO_GROUPS_FOUND);
6331
6332       if (group_count > 1)
6333         return(AD_MULTIPLE_GROUPS_FOUND);
6334     }
6335
6336   strcpy(ad_distinguishedName, group_base->dn);
6337   linklist_free(group_base);
6338   group_base = NULL;
6339   group_count = 0;
6340
6341   attr_array[0] = "sAMAccountName";
6342   attr_array[1] = NULL;
6343   
6344   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6345                            &group_base, &group_count, 
6346                            LDAP_SCOPE_SUBTREE)) != 0)
6347     {
6348       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6349               MoiraId, ldap_err2string(rc));
6350       return(rc);
6351     }
6352   
6353   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6354
6355   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6356     {
6357       linklist_free(group_base);
6358       group_base = NULL;
6359       group_count = 0;
6360       return(0);
6361     }
6362
6363   linklist_free(group_base);
6364   group_base = NULL;
6365   group_count = 0;
6366   memset(ou_both, '\0', sizeof(ou_both));
6367   memset(ou_security, '\0', sizeof(ou_security));
6368   memset(ou_distribution, '\0', sizeof(ou_distribution));
6369   memset(ou_neither, '\0', sizeof(ou_neither));
6370   memset(before_name, '\0', sizeof(before_name));
6371   memset(before_desc, '\0', sizeof(before_desc));
6372   memset(before_group_membership, '\0', sizeof(before_group_membership));
6373   
6374   attr_array[0] = "name";
6375   attr_array[1] = NULL;
6376
6377   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6378                            &group_base, &group_count, 
6379                            LDAP_SCOPE_SUBTREE)) != 0)
6380     {
6381       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6382               MoiraId, ldap_err2string(rc));
6383       return(rc);
6384     }
6385
6386   strcpy(before_name, group_base->value);
6387   linklist_free(group_base);
6388   group_base = NULL;
6389   group_count = 0;
6390
6391   attr_array[0] = "description";
6392   attr_array[1] = NULL;
6393   
6394   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6395                            &group_base, &group_count, 
6396                            LDAP_SCOPE_SUBTREE)) != 0)
6397     {
6398       com_err(whoami, 0, 
6399               "Unable to get list description with MoiraId = %s: %s",
6400               MoiraId, ldap_err2string(rc));
6401       return(rc);
6402     }
6403
6404   if (group_count != 0)
6405     {
6406       strcpy(before_desc, group_base->value);
6407       linklist_free(group_base);
6408       group_base = NULL;
6409       group_count = 0;
6410     }
6411  
6412   change_to_lower_case(ad_distinguishedName);  
6413   strcpy(ou_both, group_ou_both);
6414   change_to_lower_case(ou_both);
6415   strcpy(ou_security, group_ou_security);
6416   change_to_lower_case(ou_security);
6417   strcpy(ou_distribution, group_ou_distribution);
6418   change_to_lower_case(ou_distribution);
6419   strcpy(ou_neither, group_ou_neither);
6420   change_to_lower_case(ou_neither);
6421
6422   if (strstr(ad_distinguishedName, ou_both))
6423     {
6424       strcpy(before_group_ou, group_ou_both);
6425       before_group_membership[0] = 'B';
6426       before_security_flag = 1;
6427     }
6428   else if (strstr(ad_distinguishedName, ou_security))
6429     {
6430       strcpy(before_group_ou, group_ou_security);
6431       before_group_membership[0] = 'S';
6432       before_security_flag = 1;
6433     }
6434   else if (strstr(ad_distinguishedName, ou_distribution))
6435     {
6436       strcpy(before_group_ou, group_ou_distribution);
6437       before_group_membership[0] = 'D';
6438       before_security_flag = 0;
6439     }
6440   else if (strstr(ad_distinguishedName, ou_neither))
6441     {
6442       strcpy(before_group_ou, group_ou_neither);
6443       before_group_membership[0] = 'N';
6444       before_security_flag = 0;
6445     }
6446   else
6447     return(AD_NO_OU_FOUND);
6448
6449   rc = group_rename(ldap_handle, dn_path, before_name, 
6450                     before_group_membership, 
6451                     before_group_ou, before_security_flag, before_desc,
6452                     group_name, group_membership, group_ou, 
6453                     group_security_flag,
6454                     before_desc, MoiraId, filter, maillist);
6455
6456   return(rc);
6457 }
6458
6459 void change_to_lower_case(char *ptr)
6460 {
6461   int i;
6462
6463   for (i = 0; i < (int)strlen(ptr); i++)
6464     {
6465       ptr[i] = tolower(ptr[i]);
6466     }
6467 }
6468
6469 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6470                  char *group_name, char *group_membership, 
6471                  char *MoiraId, char *attribute,
6472                  LK_ENTRY **linklist_base, int *linklist_count,
6473                  char *rFilter)
6474 {
6475   LK_ENTRY  *pPtr;
6476   char  filter[128];
6477   char  *attr_array[3];
6478   char  *dn;
6479   int   rc;
6480
6481   (*linklist_base) = NULL;
6482   (*linklist_count) = 0;
6483
6484   if (strlen(rFilter) != 0)
6485     {
6486       strcpy(filter, rFilter);
6487       attr_array[0] = attribute;
6488       attr_array[1] = NULL;
6489       
6490       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6491                                linklist_base, linklist_count, 
6492                                LDAP_SCOPE_SUBTREE)) != 0)
6493         {
6494           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6495                   MoiraId, ldap_err2string(rc));
6496          return(rc);
6497        }
6498
6499     if ((*linklist_count) == 1)
6500       {
6501         strcpy(rFilter, filter);
6502         return(0);
6503       }
6504     }
6505
6506   linklist_free((*linklist_base));
6507   (*linklist_base) = NULL;
6508   (*linklist_count) = 0;
6509
6510   if (strlen(MoiraId) != 0)
6511     {
6512       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6513
6514       attr_array[0] = attribute;
6515       attr_array[1] = NULL;
6516
6517       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6518                                linklist_base, linklist_count, 
6519                                LDAP_SCOPE_SUBTREE)) != 0)
6520         {
6521           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6522                   MoiraId, ldap_err2string(rc));
6523          return(rc);
6524        }
6525     }
6526
6527   if ((*linklist_count) > 1)
6528     {
6529       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6530       pPtr = (*linklist_base);
6531
6532       while (pPtr)
6533         {
6534           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6535                   MoiraId);
6536           pPtr = pPtr->next;
6537         }
6538
6539       linklist_free((*linklist_base));
6540       (*linklist_base) = NULL;
6541       (*linklist_count) = 0;
6542     }
6543
6544   if ((*linklist_count) == 1)
6545     {
6546
6547       pPtr = (*linklist_base);
6548       dn = strdup(pPtr->dn);
6549       dn += 3;
6550
6551       if (!memcmp(dn, group_name, strlen(group_name)))
6552         {
6553           strcpy(rFilter, filter);
6554           return(0);
6555         }
6556     }
6557
6558   linklist_free((*linklist_base));
6559   (*linklist_base) = NULL;
6560   (*linklist_count) = 0;
6561   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6562
6563   attr_array[0] = attribute;
6564   attr_array[1] = NULL;
6565
6566   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6567                            linklist_base, linklist_count, 
6568                            LDAP_SCOPE_SUBTREE)) != 0)
6569     {
6570       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6571               MoiraId, ldap_err2string(rc));
6572       return(rc);
6573     }
6574
6575   if ((*linklist_count) == 1)
6576     {
6577       strcpy(rFilter, filter);
6578       return(0);
6579     }
6580
6581   return(0);
6582 }
6583
6584 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6585 {
6586   char filter[128];
6587   char *attr_array[3];
6588   char SamAccountName[64];
6589   int  group_count;
6590   int  rc;
6591   LK_ENTRY  *group_base;
6592   LK_ENTRY  *gPtr;
6593
6594   group_count = 0;
6595   group_base = NULL;
6596
6597   if (strlen(MoiraId) != 0)
6598     {
6599       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6600
6601       attr_array[0] = "sAMAccountName";
6602       attr_array[1] = NULL;
6603       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6604                                &group_base, &group_count, 
6605                                LDAP_SCOPE_SUBTREE)) != 0)
6606         {
6607           com_err(whoami, 0, "Unable to process user %s : %s",
6608                   UserName, ldap_err2string(rc));
6609           return(rc);
6610         }
6611
6612       if (group_count > 1)
6613         {
6614           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6615                   MoiraId);
6616           gPtr = group_base;
6617
6618           while (gPtr)
6619             {
6620               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6621                       gPtr->value, MoiraId);
6622               gPtr = gPtr->next;
6623             }
6624         }
6625     }
6626
6627   if (group_count != 1)
6628     {
6629       linklist_free(group_base);
6630       group_count = 0;
6631       group_base = NULL;
6632       sprintf(filter, "(sAMAccountName=%s)", UserName);
6633       attr_array[0] = "sAMAccountName";
6634       attr_array[1] = NULL;
6635
6636       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6637                                &group_base, &group_count, 
6638                                LDAP_SCOPE_SUBTREE)) != 0)
6639         {
6640           com_err(whoami, 0, "Unable to process user %s : %s",
6641                   UserName, ldap_err2string(rc));
6642           return(rc);
6643         }
6644     }
6645
6646   if (group_count != 1)
6647     {
6648       linklist_free(group_base);
6649       return(AD_NO_USER_FOUND);
6650     }
6651
6652   strcpy(SamAccountName, group_base->value);
6653   linklist_free(group_base);
6654   group_count = 0;
6655   rc = 0;
6656
6657   if (strcmp(SamAccountName, UserName))
6658     {
6659       com_err(whoami, 0, 
6660               "User object %s with MoiraId %s has mismatched usernames " 
6661               "(LDAP username %s, Moira username %s)", SamAccountName,
6662               MoiraId, SamAccountName, UserName);
6663     }
6664
6665   return(0);
6666 }
6667
6668 void container_get_dn(char *src, char *dest)
6669 {
6670   char *sPtr;
6671   char *array[20];
6672   char name[256];
6673   int  n;
6674
6675   memset(array, '\0', 20 * sizeof(array[0]));
6676
6677   if (strlen(src) == 0)
6678     return;
6679
6680   strcpy(name, src);
6681   sPtr = name;
6682   n = 0;
6683   array[n] = name;
6684   ++n;
6685
6686   while (*sPtr)
6687     {
6688       if ((*sPtr) == '/')
6689         {
6690           (*sPtr) = '\0';
6691           ++sPtr;
6692           array[n] = sPtr;
6693           ++n;
6694         }
6695       else
6696         ++sPtr;
6697     }
6698
6699   strcpy(dest, "OU=");
6700
6701   while (n != 0)
6702     {
6703       strcat(dest, array[n-1]);
6704       --n;
6705       if (n > 0)
6706         {
6707           strcat(dest, ",OU=");
6708         }
6709     }
6710
6711   return;
6712 }
6713
6714 void container_get_name(char *src, char *dest)
6715 {
6716   char *sPtr;
6717   char *dPtr;
6718
6719   if (strlen(src) == 0)
6720     return;
6721
6722   sPtr = src;
6723   dPtr = src;
6724
6725   while (*sPtr)
6726     {
6727       if ((*sPtr) == '/')
6728         {
6729           dPtr = sPtr;
6730           ++dPtr;
6731         }
6732       ++sPtr;
6733     }
6734
6735   strcpy(dest, dPtr);
6736   return;
6737 }
6738
6739 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6740 {
6741   char cName[256];
6742   char *av[7];
6743   int  i;
6744   int  rc;
6745
6746   strcpy(cName, name);
6747
6748   for (i = 0; i < (int)strlen(cName); i++)
6749     {
6750       if (cName[i] == '/')
6751         {
6752           cName[i] = '\0';
6753           av[CONTAINER_NAME] = cName;
6754           av[CONTAINER_DESC] = "";
6755           av[CONTAINER_LOCATION] = "";
6756           av[CONTAINER_CONTACT] = "";
6757           av[CONTAINER_TYPE] = "";
6758           av[CONTAINER_ID] = "";
6759           av[CONTAINER_ROWID] = "";
6760           rc = container_create(ldap_handle, dn_path, 7, av);
6761
6762           if (rc == LDAP_SUCCESS)
6763             {
6764               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6765                       cName);
6766             }
6767
6768           cName[i] = '/';
6769         }
6770     }
6771 }
6772
6773 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6774                      char **before, int afterc, char **after)
6775 {
6776   char      dName[256];
6777   char      cName[256];
6778   char      new_cn[128];
6779   char      new_dn_path[256];
6780   char      temp[256];
6781   char      distinguishedName[256];
6782   char      *pPtr;
6783   int       rc;
6784   int       i;
6785
6786   memset(cName, '\0', sizeof(cName));
6787   container_get_name(after[CONTAINER_NAME], cName);
6788
6789   if (!check_container_name(cName))
6790     {
6791       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6792               cName);
6793       return(AD_INVALID_NAME);
6794     }
6795
6796   memset(distinguishedName, '\0', sizeof(distinguishedName));
6797
6798   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6799                                            distinguishedName, beforec, before))
6800     return(rc);
6801
6802   if (strlen(distinguishedName) == 0)
6803     {
6804       rc = container_create(ldap_handle, dn_path, afterc, after);
6805       return(rc);
6806     }
6807
6808   strcpy(temp, after[CONTAINER_NAME]);
6809   pPtr = temp;
6810
6811   for (i = 0; i < (int)strlen(temp); i++)
6812     {
6813       if (temp[i] == '/')
6814         {
6815           pPtr = &temp[i];
6816         }
6817     }
6818
6819   (*pPtr) = '\0';
6820
6821   container_get_dn(temp, dName);
6822
6823   if (strlen(temp) != 0)
6824     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6825   else
6826     sprintf(new_dn_path, "%s", dn_path);
6827
6828   sprintf(new_cn, "OU=%s", cName);
6829
6830   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6831
6832   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6833                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6834     {
6835       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6836               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6837               ldap_err2string(rc));
6838       return(rc);
6839     }
6840
6841   memset(dName, '\0', sizeof(dName));
6842   container_get_dn(after[CONTAINER_NAME], dName);
6843   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6844
6845   return(rc);
6846 }
6847
6848 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6849 {
6850   char      distinguishedName[256];
6851   int       rc;
6852
6853   memset(distinguishedName, '\0', sizeof(distinguishedName));
6854
6855   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6856                                            distinguishedName, count, av))
6857     return(rc);
6858
6859   if (strlen(distinguishedName) == 0)
6860     return(0);
6861
6862   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6863     {
6864       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6865         container_move_objects(ldap_handle, dn_path, distinguishedName);
6866       else
6867         com_err(whoami, 0, "Unable to delete container %s from AD : %s",
6868                 av[CONTAINER_NAME], ldap_err2string(rc));
6869     }
6870
6871   return(rc);
6872 }
6873
6874 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6875 {
6876   char      *attr_array[3];
6877   LK_ENTRY  *group_base;
6878   int       group_count;
6879   LDAPMod   *mods[20];
6880   char      *objectClass_v[] = {"top", 
6881                            "organizationalUnit", 
6882                            NULL};
6883
6884   char *ou_v[] = {NULL, NULL};
6885   char *name_v[] = {NULL, NULL};
6886   char *moiraId_v[] = {NULL, NULL};
6887   char *desc_v[] = {NULL, NULL};
6888   char *managedBy_v[] = {NULL, NULL};
6889   char dName[256];
6890   char cName[256];
6891   char managedByDN[256];
6892   char filter[256];
6893   char temp[256];
6894   int  n;
6895   int  i;
6896   int  rc;
6897     
6898   memset(filter, '\0', sizeof(filter));
6899   memset(dName, '\0', sizeof(dName));
6900   memset(cName, '\0', sizeof(cName));
6901   memset(managedByDN, '\0', sizeof(managedByDN));
6902   container_get_dn(av[CONTAINER_NAME], dName);
6903   container_get_name(av[CONTAINER_NAME], cName);
6904
6905   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6906     {
6907       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6908               cName);
6909       return(AD_INVALID_NAME);
6910     }
6911
6912   if (!check_container_name(cName))
6913     {
6914       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6915               cName);
6916       return(AD_INVALID_NAME);
6917     }
6918
6919   n = 0;
6920   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6921   name_v[0] = cName;
6922   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6923   ou_v[0] = cName;
6924   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6925
6926   if (strlen(av[CONTAINER_ROWID]) != 0)
6927     {
6928       moiraId_v[0] = av[CONTAINER_ROWID];
6929       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6930     }
6931
6932   if (strlen(av[CONTAINER_DESC]) != 0)
6933     {
6934       desc_v[0] = av[CONTAINER_DESC];
6935       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6936     }
6937
6938   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6939     {
6940       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6941         {
6942           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6943                               kerberos_ou))
6944             {
6945               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6946                       kerberos_ou, dn_path);
6947               managedBy_v[0] = managedByDN;
6948               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6949             }
6950         }
6951       else
6952         {
6953           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6954             {
6955               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6956                       "(objectClass=user)))", av[CONTAINER_ID]);
6957             }
6958
6959           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6960             {
6961               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6962                       av[CONTAINER_ID]);
6963             }
6964
6965           if (strlen(filter) != 0)
6966             {
6967               attr_array[0] = "distinguishedName";
6968               attr_array[1] = NULL;
6969               group_count = 0;
6970               group_base = NULL;
6971               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6972                                        attr_array, 
6973                                        &group_base, &group_count, 
6974                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6975                 {
6976                   if (group_count == 1)
6977                     {
6978                       strcpy(managedByDN, group_base->value);
6979                       managedBy_v[0] = managedByDN;
6980                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6981                     }
6982                   linklist_free(group_base);
6983                   group_base = NULL;
6984                   group_count = 0;
6985                 }
6986             }
6987         }
6988     }
6989   
6990   mods[n] = NULL;
6991
6992   sprintf(temp, "%s,%s", dName, dn_path);
6993   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
6994   
6995   for (i = 0; i < n; i++)
6996     free(mods[i]);
6997   
6998   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
6999     {
7000       com_err(whoami, 0, "Unable to create container %s : %s",
7001               cName, ldap_err2string(rc));
7002       return(rc);
7003     }
7004
7005   if (rc == LDAP_ALREADY_EXISTS)
7006     {
7007       if (strlen(av[CONTAINER_ROWID]) != 0)
7008         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
7009     }
7010
7011   return(rc);
7012 }
7013
7014 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
7015                      char **before, int afterc, char **after)
7016 {
7017   char distinguishedName[256];
7018   int  rc;
7019
7020   memset(distinguishedName, '\0', sizeof(distinguishedName));
7021
7022   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
7023                                            distinguishedName, afterc, after))
7024     return(rc);
7025
7026   if (strlen(distinguishedName) == 0)
7027     {
7028       rc = container_create(ldap_handle, dn_path, afterc, after);
7029       return(rc);
7030     }
7031   
7032   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
7033   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
7034                           after);
7035
7036   return(rc);
7037 }
7038
7039 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
7040                                     char *distinguishedName, int count, 
7041                                     char **av)
7042 {
7043   char      *attr_array[3];
7044   LK_ENTRY  *group_base;
7045   int       group_count;
7046   char      dName[256];
7047   char      cName[256];
7048   char      filter[512];
7049   int       rc;
7050
7051   memset(filter, '\0', sizeof(filter));
7052   memset(dName, '\0', sizeof(dName));
7053   memset(cName, '\0', sizeof(cName));
7054   container_get_dn(av[CONTAINER_NAME], dName);
7055   container_get_name(av[CONTAINER_NAME], cName);
7056
7057   if (strlen(dName) == 0)
7058     {
7059       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7060               av[CONTAINER_NAME]);
7061       return(AD_INVALID_NAME);
7062     }
7063
7064   if (!check_container_name(cName))
7065     {
7066       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7067               cName);
7068       return(AD_INVALID_NAME);
7069     }
7070   
7071   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7072           av[CONTAINER_ROWID]);
7073   attr_array[0] = "distinguishedName";
7074   attr_array[1] = NULL;
7075   group_count = 0;
7076   group_base = NULL;
7077
7078   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7079                            &group_base, &group_count, 
7080                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7081     {
7082       if (group_count == 1)
7083         {
7084           strcpy(distinguishedName, group_base->value);
7085         }
7086
7087       linklist_free(group_base);
7088       group_base = NULL;
7089       group_count = 0;
7090     }
7091
7092   if (strlen(distinguishedName) == 0)
7093     {
7094       sprintf(filter, "(&(objectClass=organizationalUnit)"
7095               "(distinguishedName=%s,%s))", dName, dn_path);
7096       attr_array[0] = "distinguishedName";
7097       attr_array[1] = NULL;
7098       group_count = 0;
7099       group_base = NULL;
7100
7101       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7102                                &group_base, &group_count, 
7103                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7104         {
7105           if (group_count == 1)
7106             {
7107               strcpy(distinguishedName, group_base->value);
7108             }
7109
7110           linklist_free(group_base);
7111           group_base = NULL;
7112           group_count = 0;
7113         }
7114     }
7115
7116   return(0);
7117 }
7118
7119 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7120                        char *distinguishedName, int count, char **av)
7121 {
7122   char      *attr_array[5];
7123   LK_ENTRY  *group_base;
7124   LK_ENTRY  *pPtr;
7125   LDAPMod   *mods[20];
7126   int       group_count;
7127   char      filter[512];
7128   char      *moiraId_v[] = {NULL, NULL};
7129   char      *desc_v[] = {NULL, NULL};
7130   char      *managedBy_v[] = {NULL, NULL};
7131   char      managedByDN[256];
7132   char      moiraId[64];
7133   char      desc[256];
7134   char      ad_path[512];
7135   int       rc;
7136   int       i;
7137   int       n;
7138
7139
7140   strcpy(ad_path, distinguishedName);
7141
7142   if (strlen(dName) != 0)
7143     sprintf(ad_path, "%s,%s", dName, dn_path);
7144
7145   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7146           ad_path);
7147
7148   if (strlen(av[CONTAINER_ID]) != 0)
7149     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7150             av[CONTAINER_ROWID]);
7151
7152   attr_array[0] = "mitMoiraId";
7153   attr_array[1] = "description";
7154   attr_array[2] = "managedBy";
7155   attr_array[3] = NULL;
7156   group_count = 0;
7157   group_base = NULL;
7158
7159   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7160                            &group_base, &group_count, 
7161                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7162     {
7163       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7164               av[CONTAINER_NAME], ldap_err2string(rc));
7165       return(rc);
7166     }
7167
7168   memset(managedByDN, '\0', sizeof(managedByDN));
7169   memset(moiraId, '\0', sizeof(moiraId));
7170   memset(desc, '\0', sizeof(desc));
7171   pPtr = group_base;
7172
7173   while (pPtr)
7174     {
7175       if (!strcasecmp(pPtr->attribute, "description"))
7176         strcpy(desc, pPtr->value);
7177       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7178         strcpy(managedByDN, pPtr->value);
7179       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7180         strcpy(moiraId, pPtr->value);
7181       pPtr = pPtr->next;
7182     }
7183
7184   linklist_free(group_base);
7185   group_base = NULL;
7186   group_count = 0;
7187
7188   n = 0;
7189   if (strlen(av[CONTAINER_ROWID]) != 0)
7190     {
7191       moiraId_v[0] = av[CONTAINER_ROWID];
7192       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7193     }
7194
7195   if (strlen(av[CONTAINER_DESC]) != 0)
7196     {
7197       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7198                        dName);
7199     }
7200   else
7201     {
7202       if (strlen(desc) != 0)
7203         {
7204           attribute_update(ldap_handle, ad_path, "", "description", dName);
7205         }
7206     }
7207
7208   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7209     {
7210       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7211         {
7212           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7213                               kerberos_ou))
7214             {
7215               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7216                       kerberos_ou, dn_path);
7217               managedBy_v[0] = managedByDN;
7218               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7219             }
7220           else
7221             {
7222               if (strlen(managedByDN) != 0)
7223                 {
7224                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7225                                    dName);
7226                 }
7227             }
7228         }
7229       else
7230         {
7231           memset(filter, '\0', sizeof(filter));
7232
7233           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7234             {
7235               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7236                       "(objectClass=user)))", av[CONTAINER_ID]);
7237             }
7238
7239           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7240             {
7241               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7242                       av[CONTAINER_ID]);
7243             }
7244
7245           if (strlen(filter) != 0)
7246             {
7247               attr_array[0] = "distinguishedName";
7248               attr_array[1] = NULL;
7249               group_count = 0;
7250               group_base = NULL;
7251               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7252                                        attr_array, &group_base, &group_count, 
7253                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7254                 {
7255                   if (group_count == 1)
7256                     {
7257                       strcpy(managedByDN, group_base->value);
7258                       managedBy_v[0] = managedByDN;
7259                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7260                     }
7261                   else
7262                     {
7263                       if (strlen(managedByDN) != 0)
7264                         {
7265                           attribute_update(ldap_handle, ad_path, "", 
7266                                            "managedBy", dName);
7267                         }
7268                     }
7269
7270                   linklist_free(group_base);
7271                   group_base = NULL;
7272                   group_count = 0;
7273                 }
7274             }
7275           else
7276             {
7277               if (strlen(managedByDN) != 0)
7278                 {
7279                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7280                                    dName);
7281                 }
7282             }
7283         }
7284     }
7285
7286   mods[n] = NULL;
7287
7288   if (n == 0)
7289     return(LDAP_SUCCESS);
7290
7291   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7292
7293   for (i = 0; i < n; i++)
7294     free(mods[i]);
7295
7296   if (rc != LDAP_SUCCESS)
7297     {
7298       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7299               av[CONTAINER_NAME], ldap_err2string(rc));
7300       return(rc);
7301     }
7302   
7303   return(rc);
7304 }
7305
7306 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7307 {
7308   char      *attr_array[3];
7309   LK_ENTRY  *group_base;
7310   LK_ENTRY  *pPtr;
7311   int       group_count;
7312   char      filter[512];
7313   char      new_cn[128];
7314   char      temp[256];
7315   int       rc;
7316   int       NumberOfEntries = 10;
7317   int       i;
7318   int       count;
7319
7320   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7321
7322   for (i = 0; i < 3; i++)
7323     {
7324       memset(filter, '\0', sizeof(filter));
7325
7326       if (i == 0)
7327         {
7328           strcpy(filter, "(!(|(objectClass=computer)"
7329                  "(objectClass=organizationalUnit)))");
7330           attr_array[0] = "cn";
7331           attr_array[1] = NULL;
7332         }
7333       else if (i == 1)
7334         {
7335           strcpy(filter, "(objectClass=computer)");
7336           attr_array[0] = "cn";
7337           attr_array[1] = NULL;
7338         }
7339       else
7340         {
7341           strcpy(filter, "(objectClass=organizationalUnit)");
7342           attr_array[0] = "ou";
7343           attr_array[1] = NULL;
7344         }
7345
7346       while (1)
7347         {
7348           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7349                                    &group_base, &group_count, 
7350                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7351             {
7352               break;
7353             }
7354
7355           if (group_count == 0)
7356             break;
7357
7358           pPtr = group_base;
7359
7360           while(pPtr)
7361             {
7362               if (!strcasecmp(pPtr->attribute, "cn"))
7363                 {
7364                   sprintf(new_cn, "cn=%s", pPtr->value);
7365                   if (i == 0)
7366                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7367                   if (i == 1)
7368                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7369                   count = 1;
7370
7371                   while (1)
7372                     {
7373                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7374                                          TRUE, NULL, NULL);
7375                       if (rc == LDAP_ALREADY_EXISTS)
7376                         {
7377                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7378                           ++count;
7379                         }
7380                       else
7381                         break;
7382                     }
7383                 }
7384               else if (!strcasecmp(pPtr->attribute, "ou"))
7385                 {
7386                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7387                 }
7388
7389               pPtr = pPtr->next;
7390             }
7391
7392           linklist_free(group_base);
7393           group_base = NULL;
7394           group_count = 0;
7395         }
7396     }
7397
7398   return(0);
7399 }
7400
7401 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7402                    char *machine_ou, char *NewMachineName)
7403 {
7404   LK_ENTRY  *group_base;
7405   int  group_count;
7406   int  i;
7407   char filter[128];
7408   char *attr_array[3];
7409   char cn[256];
7410   char dn[256];
7411   char temp[256];
7412   char *pPtr;
7413   int   rc;
7414
7415   strcpy(NewMachineName, member);
7416   rc = moira_connect();
7417   rc = GetMachineName(NewMachineName);
7418   moira_disconnect();
7419
7420   if (strlen(NewMachineName) == 0)
7421     {
7422       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7423               member);
7424       return(1);
7425     }
7426
7427   pPtr = NULL;
7428   pPtr = strchr(NewMachineName, '.');
7429
7430   if (pPtr != NULL)
7431     (*pPtr) = '\0';
7432
7433   group_base = NULL;
7434   group_count = 0;
7435   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7436   attr_array[0] = "cn";
7437   attr_array[1] = NULL;
7438   sprintf(temp, "%s", dn_path);
7439
7440   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7441                            &group_base, &group_count, 
7442                            LDAP_SCOPE_SUBTREE)) != 0)
7443     {
7444       com_err(whoami, 0, "Unable to process machine %s : %s",
7445               member, ldap_err2string(rc));
7446       return(1);
7447     }
7448
7449   if (group_count != 1)
7450     {
7451       return(1);
7452     }
7453
7454   strcpy(dn, group_base->dn);
7455   strcpy(cn, group_base->value);
7456
7457   for (i = 0; i < (int)strlen(dn); i++)
7458     dn[i] = tolower(dn[i]);
7459
7460   for (i = 0; i < (int)strlen(cn); i++)
7461     cn[i] = tolower(cn[i]);
7462
7463   linklist_free(group_base);
7464   pPtr = NULL;
7465   pPtr = strstr(dn, cn);
7466
7467   if (pPtr == NULL)
7468     {
7469       com_err(whoami, 0, "Unable to process machine %s",
7470               member);
7471       return(1);
7472     }
7473
7474   pPtr += strlen(cn) + 1;
7475   strcpy(machine_ou, pPtr);
7476   pPtr = NULL;
7477   pPtr = strstr(machine_ou, "dc=");
7478
7479   if (pPtr == NULL)
7480     {
7481       com_err(whoami, 0, "Unable to process machine %s",
7482               member);
7483       return(1);
7484     }
7485
7486   --pPtr;
7487   (*pPtr) = '\0';
7488
7489   return(0);
7490 }
7491
7492 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7493                        char *MoiraMachineName, char *DestinationOu)
7494 {
7495   char        NewCn[128];
7496   char        OldDn[512];
7497   char        MachineName[128];
7498   char        filter[128];
7499   char        *attr_array[3];
7500   char        NewOu[256];
7501   char        *cPtr = NULL;
7502   int         group_count;
7503   long        rc;
7504   LK_ENTRY    *group_base;
7505
7506   group_count = 0;
7507   group_base = NULL;
7508   
7509   strcpy(MachineName, MoiraMachineName);
7510   rc = GetMachineName(MachineName);
7511
7512   if (strlen(MachineName) == 0)
7513     {
7514       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7515               MoiraMachineName);
7516       return(1);
7517     }
7518   
7519   cPtr = strchr(MachineName, '.');
7520
7521   if (cPtr != NULL)
7522     (*cPtr) = '\0';
7523
7524   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7525   attr_array[0] = "sAMAccountName";
7526   attr_array[1] = NULL;
7527
7528   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7529                            &group_base, 
7530                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7531     {
7532       com_err(whoami, 0, "Unable to process machine %s : %s",
7533               MoiraMachineName, ldap_err2string(rc));
7534       return(1);
7535     }
7536   
7537   if (group_count == 1)
7538     strcpy(OldDn, group_base->dn);
7539
7540   linklist_free(group_base);
7541   group_base = NULL;
7542
7543   if (group_count != 1)
7544     {
7545       com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
7546               MoiraMachineName);
7547       return(1);
7548     }
7549
7550   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7551   cPtr = strchr(OldDn, ',');
7552
7553   if (cPtr != NULL)
7554     {
7555       ++cPtr;
7556       if (!strcasecmp(cPtr, NewOu))
7557         return(0);
7558     }
7559
7560   sprintf(NewCn, "CN=%s", MachineName);
7561   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7562
7563   return(rc);
7564 }
7565
7566 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7567 {
7568   char    Name[128];
7569   char    *pPtr;
7570   int     rc;
7571   
7572   memset(Name, '\0', sizeof(Name));
7573   strcpy(Name, machine_name);
7574   pPtr = NULL;
7575   pPtr = strchr(Name, '.');
7576
7577   if (pPtr != NULL)
7578     (*pPtr) = '\0';
7579
7580   strcat(Name, "$");
7581   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7582 }
7583
7584 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7585                                 char *machine_name, char *container_name)
7586 {
7587   int     rc;
7588   char    *av[2];
7589   char    *call_args[2];
7590   
7591   av[0] = machine_name;
7592   call_args[0] = (char *)container_name;
7593   rc = mr_query("get_machine_to_container_map", 1, av, 
7594                 machine_GetMoiraContainer, call_args);
7595   return(rc);
7596 }
7597
7598 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7599 {
7600   char **call_args;
7601   
7602   call_args = ptr;
7603   strcpy(call_args[0], av[1]);
7604   return(0);
7605 }
7606
7607 int Moira_container_group_create(char **after)
7608 {
7609   long rc;
7610   char GroupName[64];
7611   char *argv[20];
7612   
7613   memset(GroupName, '\0', sizeof(GroupName));
7614   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7615                               after[CONTAINER_ROWID]);
7616   if (rc)
7617     return rc;
7618   
7619   argv[L_NAME] = GroupName;
7620   argv[L_ACTIVE] = "1";
7621   argv[L_PUBLIC] = "0";
7622   argv[L_HIDDEN] = "0";
7623   argv[L_MAILLIST] = "0";
7624   argv[L_GROUP] = "1";
7625   argv[L_GID] = UNIQUE_GID;
7626   argv[L_NFSGROUP] = "0";
7627   argv[L_MAILMAN] = "0";
7628   argv[L_MAILMAN_SERVER] = "[NONE]";
7629   argv[L_DESC] = "auto created container group";
7630   argv[L_ACE_TYPE] = "USER";
7631   argv[L_MEMACE_TYPE] = "USER";
7632   argv[L_ACE_NAME] = "sms";
7633   argv[L_MEMACE_NAME] = "sms";
7634
7635   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7636     {
7637       com_err(whoami, 0, 
7638               "Unable to create container group %s for container %s: %s",
7639               GroupName, after[CONTAINER_NAME], error_message(rc));
7640     }
7641
7642   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7643   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7644   
7645   return(rc);
7646 }
7647
7648 int Moira_container_group_update(char **before, char **after)
7649 {
7650   long rc;
7651   char BeforeGroupName[64];
7652   char AfterGroupName[64];
7653   char *argv[20];
7654   
7655   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7656     return(0);
7657
7658   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7659   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7660   if (strlen(BeforeGroupName) == 0)
7661     return(0);
7662
7663   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7664   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7665                               after[CONTAINER_ROWID]);
7666   if (rc)
7667     return rc;
7668
7669   if (strcasecmp(BeforeGroupName, AfterGroupName))
7670     {
7671       argv[L_NAME] = BeforeGroupName;
7672       argv[L_NAME + 1] = AfterGroupName;
7673       argv[L_ACTIVE + 1] = "1";
7674       argv[L_PUBLIC + 1] = "0";
7675       argv[L_HIDDEN + 1] = "0";
7676       argv[L_MAILLIST + 1] = "0";
7677       argv[L_GROUP + 1] = "1";
7678       argv[L_GID + 1] = UNIQUE_GID;
7679       argv[L_NFSGROUP + 1] = "0";
7680       argv[L_MAILMAN + 1] = "0";
7681       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7682       argv[L_DESC + 1] = "auto created container group";
7683       argv[L_ACE_TYPE + 1] = "USER";
7684       argv[L_MEMACE_TYPE + 1] = "USER";
7685       argv[L_ACE_NAME + 1] = "sms";
7686       argv[L_MEMACE_NAME + 1] = "sms";
7687       
7688       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7689         {
7690           com_err(whoami, 0, 
7691                   "Unable to rename container group from %s to %s: %s",
7692                   BeforeGroupName, AfterGroupName, error_message(rc));
7693         }
7694     }
7695   
7696   return(rc);
7697 }
7698
7699 int Moira_container_group_delete(char **before)
7700 {
7701   long rc = 0;
7702   char *argv[13];
7703   char GroupName[64];
7704   char ParentGroupName[64];
7705   
7706   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7707   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7708
7709   memset(GroupName, '\0', sizeof(GroupName));
7710
7711   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7712     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7713   
7714   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7715     {
7716       argv[0] = ParentGroupName;
7717       argv[1] = "LIST";
7718       argv[2] = GroupName;
7719
7720       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7721         {
7722           com_err(whoami, 0, 
7723                   "Unable to delete container group %s from list: %s",
7724                   GroupName, ParentGroupName, error_message(rc));
7725         }
7726     }
7727   
7728   if (strlen(GroupName) != 0)
7729     {
7730       argv[0] = GroupName;
7731
7732       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7733         {
7734           com_err(whoami, 0, "Unable to delete container group %s : %s",
7735                   GroupName, error_message(rc));
7736         }
7737     }
7738   
7739   return(rc);
7740 }
7741
7742 int Moira_groupname_create(char *GroupName, char *ContainerName,
7743                            char *ContainerRowID)
7744 {
7745   char *ptr;
7746   char *ptr1;
7747   char temp[64];
7748   char newGroupName[64];
7749   char tempGroupName[64];
7750   char tempgname[64];
7751   char *argv[1];
7752   int  i;
7753   long rc;
7754
7755   strcpy(temp, ContainerName);
7756   
7757   ptr1 = strrchr(temp, '/');
7758
7759   if (ptr1 != NULL)
7760   {
7761     *ptr1 = '\0';
7762     ptr = ++ptr1;
7763     ptr1 = strrchr(temp, '/');
7764
7765     if (ptr1 != NULL)
7766     {
7767         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7768     }
7769     else
7770         strcpy(tempgname, ptr);
7771   }
7772   else
7773     strcpy(tempgname, temp);
7774
7775   if (strlen(tempgname) > 25)
7776     tempgname[25] ='\0';
7777
7778   sprintf(newGroupName, "cnt-%s", tempgname);
7779
7780   /* change everything to lower case */
7781   ptr = newGroupName;
7782
7783   while (*ptr)
7784     {
7785       if (isupper(*ptr))
7786         *ptr = tolower(*ptr);
7787
7788       if (*ptr == ' ')
7789         *ptr = '-';
7790
7791       ptr++;
7792     }
7793
7794   strcpy(tempGroupName, newGroupName);
7795   i = (int)'0';
7796
7797   /* append 0-9 then a-z if a duplicate is found */
7798   while(1)
7799     {
7800       argv[0] = newGroupName;
7801
7802       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7803         {
7804           if (rc == MR_NO_MATCH)
7805             break;
7806           com_err(whoami, 0, "Moira error while creating group name for "
7807                   "container %s : %s", ContainerName, error_message(rc));
7808           return rc;
7809         }
7810
7811       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7812
7813       if (i == (int)'z')
7814         {
7815           com_err(whoami, 0, "Unable to find a unique group name for "
7816                   "container %s: too many duplicate container names",
7817                   ContainerName);
7818           return 1;
7819         }
7820
7821       if (i == '9')
7822         i = 'a';
7823       else
7824         i++;
7825     }
7826
7827   strcpy(GroupName, newGroupName);
7828   return(0);
7829 }
7830
7831 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7832 {
7833   long rc;
7834   char *argv[3];
7835   
7836   argv[0] = origContainerName;
7837   argv[1] = GroupName;
7838   
7839   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7840     {
7841       com_err(whoami, 0, 
7842               "Unable to set container group %s in container %s: %s",
7843               GroupName, origContainerName, error_message(rc));
7844     }
7845   
7846   return(0);
7847 }
7848
7849 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7850  {
7851    char ContainerName[64];
7852    char ParentGroupName[64];
7853    char *argv[3];
7854    long rc;
7855
7856    strcpy(ContainerName, origContainerName);
7857    
7858    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7859
7860    /* top-level container */
7861    if (strlen(ParentGroupName) == 0)
7862      return(0);
7863    
7864    argv[0] = ParentGroupName;
7865    argv[1] = "LIST";
7866    argv[2] = GroupName;
7867
7868    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7869      {
7870        com_err(whoami, 0, 
7871                "Unable to add container group %s to parent group %s: %s",
7872                GroupName, ParentGroupName, error_message(rc));
7873      }
7874    
7875    return(0);
7876  }
7877
7878 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7879 {
7880   char **call_args;
7881   
7882   call_args = ptr;
7883   strcpy(call_args[0], av[1]);
7884
7885   return(0);
7886 }
7887
7888 int Moira_getGroupName(char *origContainerName, char *GroupName,
7889                        int ParentFlag)
7890 {
7891   char ContainerName[64];
7892   char *argv[3];
7893   char *call_args[3];
7894   char *ptr;
7895   long rc;
7896
7897   strcpy(ContainerName, origContainerName);
7898
7899   if (ParentFlag)
7900     {
7901       ptr = strrchr(ContainerName, '/');
7902
7903       if (ptr != NULL)
7904         (*ptr) = '\0';
7905       else
7906         return(0);
7907     }
7908
7909   argv[0] = ContainerName;
7910   argv[1] = NULL;
7911   call_args[0] = GroupName;
7912   call_args[1] = NULL;
7913
7914   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7915                       call_args)))
7916     {
7917       if (strlen(GroupName) != 0)
7918         return(0);
7919     }
7920
7921   if (rc)
7922     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7923             ContainerName, error_message(rc));
7924   else
7925     com_err(whoami, 0, "Unable to get container group from container %s",
7926             ContainerName);
7927   
7928   return(0);
7929 }
7930
7931 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7932                                           int DeleteMachine)
7933 {
7934   char *argv[3];
7935   long rc;
7936   
7937   if (strcmp(GroupName, "[none]") == 0)
7938     return 0;
7939
7940   argv[0] = GroupName;
7941   argv[1] = "MACHINE";
7942   argv[2] = MachineName;
7943
7944   if (!DeleteMachine)
7945     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7946   else
7947     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7948
7949   if (rc)
7950     {
7951       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7952               MachineName, GroupName, error_message(rc));
7953     }
7954
7955   return(0);
7956 }
7957
7958 int GetMachineName(char *MachineName)
7959 {
7960   char    *args[2];
7961   char    NewMachineName[1024];
7962   char    *szDot;
7963   int     rc = 0;
7964   int     i;
7965   DWORD   dwLen = 0;
7966   char    *call_args[2];
7967   
7968   // If the address happens to be in the top-level MIT domain, great!
7969   strcpy(NewMachineName, MachineName);
7970
7971   for (i = 0; i < (int)strlen(NewMachineName); i++)
7972     NewMachineName[i] = toupper(NewMachineName[i]);
7973
7974   szDot = strchr(NewMachineName,'.');
7975
7976   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7977     {
7978       return(0);
7979     }
7980   
7981   // If not, see if it has a Moira alias in the top-level MIT domain.
7982   memset(NewMachineName, '\0', sizeof(NewMachineName));
7983   args[0] = "*";
7984   args[1] = MachineName;
7985   call_args[0] = NewMachineName;
7986   call_args[1] = NULL;
7987
7988   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7989     {
7990       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7991               MachineName, error_message(rc));
7992       strcpy(MachineName, "");
7993       return(0);
7994     }
7995   
7996   if (strlen(NewMachineName) != 0)
7997     strcpy(MachineName, NewMachineName);
7998   else
7999     strcpy(MachineName, "");
8000
8001   return(0);
8002 }
8003
8004 int ProcessMachineName(int ac, char **av, void *ptr)
8005 {
8006   char    **call_args;
8007   char    MachineName[1024];
8008   char    *szDot;
8009   int     i;
8010   
8011   call_args = ptr;
8012
8013   if (strlen(call_args[0]) == 0)
8014     {
8015       strcpy(MachineName, av[0]);
8016
8017       for (i = 0; i < (int)strlen(MachineName); i++)
8018         MachineName[i] = toupper(MachineName[i]);
8019
8020       szDot = strchr(MachineName,'.');
8021
8022         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
8023           {
8024             strcpy(call_args[0], MachineName);
8025           }
8026     }
8027
8028   return(0);
8029 }
8030
8031 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
8032 {
8033   int i;
8034   
8035   if (*UseSFU30)
8036     {
8037       for (i = 0; i < n; i++)
8038         {
8039           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
8040             mods[i]->mod_type = "uidNumber";
8041         }
8042
8043       (*UseSFU30) = 0;
8044     }
8045   else
8046     {
8047       for (i = 0; i < n; i++)
8048         {
8049           if (!strcmp(mods[i]->mod_type, "uidNumber"))
8050             mods[i]->mod_type = "msSFU30UidNumber";
8051         }
8052
8053       (*UseSFU30) = 1;
8054     }
8055 }
8056
8057 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8058                      char *DistinguishedName,
8059                      char *WinHomeDir, char *WinProfileDir,
8060                      char **homedir_v, char **winProfile_v,
8061                      char **drives_v, LDAPMod **mods, 
8062                      int OpType, int n)
8063 {
8064   char cWeight[3];
8065   char cPath[1024];
8066   char path[1024];
8067   char winPath[1024];
8068   char winProfile[1024];
8069   char homeDrive[8];
8070   char homedir[1024];
8071   char apple_homedir[1024];
8072   char *apple_homedir_v[] = {NULL, NULL};
8073   int  last_weight;
8074   int  i;
8075   int  rc;
8076   LDAPMod *DelMods[20];
8077   char *argv[3];
8078   char *save_argv[FS_END];
8079   char *fsgroup_save_argv[2];
8080
8081   memset(homeDrive, '\0', sizeof(homeDrive));
8082   memset(path, '\0', sizeof(path));
8083   memset(winPath, '\0', sizeof(winPath));
8084   memset(winProfile, '\0', sizeof(winProfile));
8085
8086   if(!ActiveDirectory) 
8087     {
8088       if (rc = moira_connect())
8089         {
8090           critical_alert("AD incremental",
8091                          "Error contacting Moira server : %s",
8092                          error_message(rc));
8093           return;
8094         }
8095       
8096       argv[0] = user_name;
8097
8098       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8099                           save_argv)))
8100         {
8101           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8102              !strcmp(save_argv[FS_TYPE], "MUL"))
8103             {
8104         
8105               argv[0] = save_argv[FS_NAME];
8106               fsgCount = 0;
8107               
8108               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8109                                   save_fsgroup_info, fsgroup_save_argv)))
8110                 {
8111                   if(fsgCount)
8112                     {
8113                       argv[0] = fsgroup_save_argv[0];
8114                       
8115                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8116                                           save_query_info, save_argv)))
8117                         {
8118                           strcpy(path, save_argv[FS_PACK]);
8119                         }
8120                     }
8121                 }
8122             }
8123           else
8124             {
8125               strcpy(path, save_argv[FS_PACK]);
8126             }
8127         }
8128       
8129       moira_disconnect();
8130
8131       if (strlen(path))
8132         {
8133           if (!strnicmp(path, AFS, strlen(AFS)))
8134             {
8135               sprintf(homedir, "%s", path);
8136               sprintf(apple_homedir, "%s/MacData", path);
8137               homedir_v[0] = homedir;
8138               apple_homedir_v[0] = apple_homedir;
8139               ADD_ATTR("homeDirectory", homedir_v, OpType);
8140               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8141                        OpType);
8142             }
8143         }
8144       else
8145         {
8146           homedir_v[0] = "NONE";
8147           apple_homedir_v[0] = "NONE";
8148           ADD_ATTR("homeDirectory", homedir_v, OpType);
8149           ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8150                    OpType);
8151         }
8152
8153       return(n);
8154     }
8155  
8156   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8157       (!strcasecmp(WinProfileDir, "[afs]")))
8158     {
8159       if (rc = moira_connect())
8160         {
8161           critical_alert("AD incremental",
8162                          "Error contacting Moira server : %s",
8163                          error_message(rc));
8164           return;
8165         }
8166       
8167       argv[0] = user_name;
8168
8169       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8170                           save_argv)))
8171         {
8172           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8173              !strcmp(save_argv[FS_TYPE], "MUL"))
8174             {
8175         
8176               argv[0] = save_argv[FS_NAME];
8177               fsgCount = 0;
8178               
8179               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8180                                   save_fsgroup_info, fsgroup_save_argv)))
8181                 {
8182                   if(fsgCount)
8183                     {
8184                       argv[0] = fsgroup_save_argv[0];
8185                       
8186                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8187                                           save_query_info, save_argv)))
8188                         {
8189                           strcpy(path, save_argv[FS_PACK]);
8190                         }
8191                     }
8192                 }
8193             }
8194           else
8195             {
8196               strcpy(path, save_argv[FS_PACK]);
8197             }
8198         }
8199      
8200       moira_disconnect();
8201
8202       if (strlen(path))
8203         {
8204           if (!strnicmp(path, AFS, strlen(AFS)))
8205             {
8206               AfsToWinAfs(path, winPath);
8207               strcpy(winProfile, winPath);
8208               strcat(winProfile, "\\.winprofile");
8209             }
8210         }
8211       else
8212         return(n);
8213     }
8214
8215     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8216         (!strcasecmp(WinProfileDir, "[dfs]")))
8217     {
8218       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8219               user_name[0], user_name);
8220
8221       if (!strcasecmp(WinProfileDir, "[dfs]"))
8222         {
8223           strcpy(winProfile, path);
8224           strcat(winProfile, "\\.winprofile");
8225         }
8226
8227       if (!strcasecmp(WinHomeDir, "[dfs]"))
8228         strcpy(winPath, path);
8229     }
8230     
8231     if (!strcasecmp(WinHomeDir, "[local]"))
8232       memset(winPath, '\0', sizeof(winPath));
8233     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8234              !strcasecmp(WinHomeDir, "[dfs]"))
8235       {
8236         strcpy(homeDrive, "H:");
8237       }
8238     else
8239       {
8240         strcpy(winPath, WinHomeDir);
8241         if (!strncmp(WinHomeDir, "\\\\", 2))
8242           {
8243             strcpy(homeDrive, "H:");
8244           }        
8245       }
8246     
8247     // nothing needs to be done if WinProfileDir is [afs].
8248     if (!strcasecmp(WinProfileDir, "[local]"))
8249       memset(winProfile, '\0', sizeof(winProfile));
8250     else if (strcasecmp(WinProfileDir, "[afs]") && 
8251              strcasecmp(WinProfileDir, "[dfs]"))
8252       {
8253         strcpy(winProfile, WinProfileDir);
8254       }
8255     
8256     if (strlen(winProfile) != 0)
8257       {
8258         if (winProfile[strlen(winProfile) - 1] == '\\')
8259           winProfile[strlen(winProfile) - 1] = '\0';
8260       }
8261
8262     if (strlen(winPath) != 0)
8263       {
8264         if (winPath[strlen(winPath) - 1] == '\\')
8265           winPath[strlen(winPath) - 1] = '\0';
8266       }
8267     
8268     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8269       strcat(winProfile, "\\");
8270
8271     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8272       strcat(winPath, "\\");
8273     
8274     if (strlen(winPath) == 0)
8275       {
8276         if (OpType == LDAP_MOD_REPLACE)
8277           {
8278             i = 0;
8279             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8280             DelMods[i] = NULL;
8281             //unset homeDirectory attribute for user.
8282             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8283             free(DelMods[0]);
8284           }
8285       }
8286     else
8287       {
8288         homedir_v[0] = strdup(winPath);
8289         ADD_ATTR("homeDirectory", homedir_v, OpType);
8290       }
8291     
8292     if (strlen(winProfile) == 0)
8293       {
8294         if (OpType == LDAP_MOD_REPLACE)
8295           {
8296             i = 0;
8297             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8298             DelMods[i] = NULL;
8299             //unset profilePate attribute for user.
8300             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8301             free(DelMods[0]);
8302           }
8303       }
8304     else
8305       {
8306         winProfile_v[0] = strdup(winProfile);
8307         ADD_ATTR("profilePath", winProfile_v, OpType);
8308       }
8309     
8310     if (strlen(homeDrive) == 0)
8311       {
8312         if (OpType == LDAP_MOD_REPLACE)
8313           {
8314             i = 0;
8315             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8316             DelMods[i] = NULL;
8317             //unset homeDrive attribute for user
8318             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8319             free(DelMods[0]);
8320           }
8321       }
8322     else
8323       {
8324         drives_v[0] = strdup(homeDrive);
8325         ADD_ATTR("homeDrive", drives_v, OpType);
8326       }
8327
8328     return(n);
8329 }
8330
8331 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8332                      char *attribute_value, char *attribute, char *user_name)
8333 {
8334   char      *mod_v[] = {NULL, NULL};
8335   LDAPMod   *DelMods[20];
8336   LDAPMod   *mods[20];
8337   int       n;
8338   int       i;
8339   int       rc;
8340   
8341   if (strlen(attribute_value) == 0)
8342     {
8343       i = 0;
8344       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8345       DelMods[i] = NULL;
8346       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8347       free(DelMods[0]);
8348     }
8349   else
8350     {
8351       n = 0;
8352       mod_v[0] = attribute_value;
8353       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8354       mods[n] = NULL;
8355
8356       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8357                               mods)) != LDAP_SUCCESS)
8358         {
8359           free(mods[0]);
8360           n = 0;
8361           mod_v[0] = attribute_value;
8362           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8363           mods[n] = NULL;
8364
8365           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8366                                   mods)) != LDAP_SUCCESS)
8367             {
8368               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8369                       "in the AD : %s",
8370                       attribute, user_name, ldap_err2string(rc));
8371             }
8372         }
8373
8374       free(mods[0]);
8375     }
8376   
8377   return(rc);
8378 }
8379
8380 void StringTrim(char *StringToTrim)
8381 {
8382   char *t, *s;
8383   char *save;
8384
8385   save = strdup(StringToTrim);
8386
8387   s = save;
8388
8389   while (isspace(*s))
8390     s++;
8391
8392   /* skip to end of string */
8393   if (*s == '\0')
8394     {
8395       if (*save)
8396         *save = '\0';
8397       strcpy(StringToTrim, save);
8398       return;
8399     }
8400   
8401   for (t = s; *t; t++)
8402     continue;
8403
8404   while (t > s)
8405     {
8406       --t;
8407       if (!isspace(*t))
8408         {
8409           t++;
8410           break;
8411         }
8412     }
8413
8414   if (*t)
8415     *t = '\0';
8416   
8417   strcpy(StringToTrim, s);
8418   return;
8419 }
8420
8421 int ReadConfigFile(char *DomainName)
8422 {
8423     int     Count;
8424     int     i;
8425     int     k;
8426     char    temp[256];
8427     char    temp1[256];
8428     FILE    *fptr;
8429
8430     Count = 0;
8431
8432     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8433
8434     if ((fptr = fopen(temp, "r")) != NULL)
8435       {
8436         while (fgets(temp, sizeof(temp), fptr) != 0)
8437           {
8438             for (i = 0; i < (int)strlen(temp); i++)
8439               temp[i] = toupper(temp[i]);
8440
8441             if (temp[strlen(temp) - 1] == '\n')
8442               temp[strlen(temp) - 1] = '\0';
8443
8444             StringTrim(temp);
8445
8446             if (strlen(temp) == 0)
8447               continue;
8448
8449             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8450               {
8451                 if (strlen(temp) > (strlen(DOMAIN)))
8452                   {
8453                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8454                     StringTrim(ldap_domain);
8455                   }
8456               }
8457             else if (!strncmp(temp, REALM, strlen(REALM)))
8458               {
8459                 if (strlen(temp) > (strlen(REALM)))
8460                   {
8461                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8462                     StringTrim(ldap_realm);
8463                   }
8464               }
8465             else if (!strncmp(temp, PORT, strlen(PORT)))
8466               {
8467                 if (strlen(temp) > (strlen(PORT)))
8468                   {
8469                     strcpy(ldap_port, &temp[strlen(PORT)]);
8470                     StringTrim(ldap_port);
8471                   }
8472               }
8473             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8474               {
8475                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8476                   {
8477                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8478                     StringTrim(PrincipalName);
8479                   }
8480               }
8481             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8482               {
8483                 if (strlen(temp) > (strlen(SERVER)))
8484                   {
8485                     ServerList[Count] = calloc(1, 256);
8486                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8487                     StringTrim(ServerList[Count]);
8488                     ++Count;
8489                   }
8490               }
8491             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8492               {
8493                 if (strlen(temp) > (strlen(MSSFU)))
8494                   {
8495                     strcpy(temp1, &temp[strlen(MSSFU)]);
8496                     StringTrim(temp1);
8497                     if (!strcmp(temp1, SFUTYPE))
8498                       UseSFU30 = 1;
8499                   }
8500               }
8501             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8502               {
8503                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8504                   {
8505                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8506                     StringTrim(temp1);
8507                     if (!strcasecmp(temp1, "NO")) 
8508                       {
8509                         UseGroupSuffix = 0;
8510                         memset(group_suffix, '\0', sizeof(group_suffix));
8511                       }
8512                   }
8513               }
8514             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8515               {
8516                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8517                   {
8518                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8519                     StringTrim(temp1);
8520                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8521                       UseGroupUniversal = 1;
8522                   }
8523               }
8524             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8525               {
8526                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8527                   {
8528                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8529                     StringTrim(temp1);
8530                     if (!strcasecmp(temp1, "NO"))
8531                       SetGroupAce = 0;
8532                   }
8533               }
8534             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8535               {
8536                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8537                   {
8538                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8539                     StringTrim(temp1);
8540                     if (!strcasecmp(temp1, "NO"))
8541                       SetPassword = 0;
8542                   }
8543               }
8544             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8545               {
8546                 if (strlen(temp) > (strlen(EXCHANGE)))
8547                   {
8548                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8549                     StringTrim(temp1);
8550                     if (!strcasecmp(temp1, "YES"))
8551                       Exchange = 1;
8552                   }
8553               }
8554             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8555                               strlen(PROCESS_MACHINE_CONTAINER)))
8556               {
8557                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8558                   {
8559                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8560                     StringTrim(temp1);
8561                     if (!strcasecmp(temp1, "NO"))
8562                       ProcessMachineContainer = 0;
8563                   }
8564               }
8565             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8566                               strlen(ACTIVE_DIRECTORY)))
8567               {
8568                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8569                   {
8570                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8571                     StringTrim(temp1);
8572                     if (!strcasecmp(temp1, "NO"))
8573                       ActiveDirectory = 0;
8574                   }
8575               }
8576             else if (!strncmp(temp, GROUP_POPULATE_MEMBERS, 
8577                               strlen(GROUP_POPULATE_MEMBERS)))
8578               {
8579                 if (strlen(temp) > (strlen(GROUP_POPULATE_MEMBERS)))
8580                   {
8581                     strcpy(temp1, &temp[strlen(GROUP_POPULATE_MEMBERS)]);
8582                     StringTrim(temp1);
8583                     if (!strcasecmp(temp1, "DELETE")) 
8584                       {
8585                         GroupPopulateDelete = 1;
8586                       }
8587                   }
8588               }
8589             else
8590               {
8591                 if (strlen(ldap_domain) != 0)
8592                   {
8593                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8594                     break;
8595                   }
8596
8597                 if (strlen(temp) != 0)
8598                   strcpy(ldap_domain, temp);
8599               }
8600           }
8601         fclose(fptr);
8602       }
8603     
8604     if (strlen(ldap_domain) == 0)
8605       {
8606       strcpy(ldap_domain, DomainName);
8607       }
8608
8609     if (Count == 0)
8610         return(0);
8611
8612     for (i = 0; i < Count; i++)
8613       {
8614         if (ServerList[i] != 0)
8615           {
8616             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8617               ServerList[i][k] = toupper(ServerList[i][k]);
8618           }
8619       }
8620     
8621     return(0);
8622 }
8623
8624 int ReadDomainList()
8625 {
8626   int     Count;
8627   int     i;
8628   char    temp[128];
8629   char    temp1[128];
8630   FILE    *fptr;
8631   unsigned char c[11];
8632   unsigned char stuff[256];
8633   int     rc;
8634   int     ok;
8635
8636   Count = 0;
8637   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8638
8639   if ((fptr = fopen(temp, "r")) != NULL)
8640     {
8641       while (fgets(temp, sizeof(temp), fptr) != 0)
8642         {
8643           for (i = 0; i < (int)strlen(temp); i++)
8644             temp[i] = toupper(temp[i]);
8645
8646           if (temp[strlen(temp) - 1] == '\n')
8647             temp[strlen(temp) - 1] = '\0';
8648
8649           StringTrim(temp);
8650
8651           if (strlen(temp) == 0)
8652             continue;
8653
8654           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8655             {
8656               if (strlen(temp) > (strlen(DOMAIN)))
8657                 {
8658                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8659                   StringTrim(temp1);
8660                   strcpy(temp, temp1);
8661                 }
8662             }
8663           
8664           strcpy(DomainNames[Count], temp);
8665           StringTrim(DomainNames[Count]);
8666           ++Count;
8667         }
8668
8669       fclose(fptr);
8670     }
8671
8672   if (Count == 0)
8673     {
8674       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8675                      "configuration error in ldap.cfg");
8676       return(1);
8677     }
8678   
8679   return(0);
8680 }
8681
8682 int email_isvalid(const char *address) {
8683   int        count = 0;
8684   const char *c, *domain;
8685   static char *rfc822_specials = "()<>@,;:\\\"[]";
8686
8687   if(address[strlen(address) - 1] == '.') 
8688     return 0;
8689     
8690   /* first we validate the name portion (name@domain) */
8691   for (c = address;  *c;  c++) {
8692     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8693                        '\"')) {
8694       while (*++c) {
8695         if (*c == '\"') 
8696           break;
8697         if (*c == '\\' && (*++c == ' ')) 
8698           continue;
8699         if (*c <= ' ' || *c >= 127) 
8700           return 0;
8701       }
8702
8703       if (!*c++) 
8704         return 0;
8705       if (*c == '@') 
8706         break;
8707       if (*c != '.') 
8708         return 0;
8709       continue;
8710     }
8711
8712     if (*c == '@') 
8713       break;
8714     if (*c <= ' ' || *c >= 127) 
8715       return 0;
8716     if (strchr(rfc822_specials, *c)) 
8717       return 0;
8718   }
8719
8720   if (c == address || *(c - 1) == '.') 
8721     return 0;
8722
8723   /* next we validate the domain portion (name@domain) */
8724   if (!*(domain = ++c)) return 0;
8725   do {
8726     if (*c == '.') {
8727       if (c == domain || *(c - 1) == '.') 
8728         return 0;
8729       count++;
8730     }
8731     if (*c <= ' ' || *c >= 127) 
8732       return 0;
8733     if (strchr(rfc822_specials, *c)) 
8734       return 0;
8735   } while (*++c);
8736
8737   return (count >= 1);
8738 }
8739
8740 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8741              char **homeServerName) 
8742 {
8743   LK_ENTRY *group_base;
8744   LK_ENTRY *sub_group_base;
8745   LK_ENTRY *gPtr;
8746   LK_ENTRY *sub_gPtr;
8747   int      group_count;
8748   int      sub_group_count;
8749   char     filter[1024];
8750   char     sub_filter[1024];
8751   char     search_path[1024];
8752   char     range[1024];
8753   char     *attr_array[3];
8754   char     *s;
8755   int      homeMDB_count = -1;
8756   int      rc;
8757   int      i;
8758   int      mdbbl_count;
8759   int      rangeStep = 1500;
8760   int      rangeLow = 0;
8761   int      rangeHigh = rangeLow + (rangeStep - 1);
8762   int      isLast = 0;
8763
8764   /* Grumble..... microsoft not making it searchable from the root *grr* */
8765
8766   memset(filter, '\0', sizeof(filter));
8767   memset(search_path, '\0', sizeof(search_path));
8768   
8769   sprintf(filter, "(objectClass=msExchMDB)");
8770   sprintf(search_path, "CN=Configuration,%s", dn_path);
8771   attr_array[0] = "distinguishedName";
8772   attr_array[1] = NULL;
8773   
8774   group_base = NULL;
8775   group_count = 0;
8776   
8777   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8778                            &group_base, &group_count, 
8779                            LDAP_SCOPE_SUBTREE)) != 0) 
8780     {
8781       com_err(whoami, 0, "Unable to find msExchMDB %s",
8782               ldap_err2string(rc));
8783       return(rc);
8784     }
8785   
8786   if (group_count) 
8787     {
8788       gPtr = group_base;
8789       
8790       while(gPtr) {
8791         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8792             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8793             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8794           {
8795             gPtr = gPtr->next;
8796             continue;
8797           }
8798
8799         /* 
8800          * Due to limits in active directory we need to use the LDAP
8801          * range semantics to query and return all the values in 
8802          * large lists, we will stop increasing the range when
8803          * the result count is 0.
8804          */
8805
8806         i = 0;  
8807         mdbbl_count = 0;
8808
8809         for(;;) 
8810           {
8811             memset(sub_filter, '\0', sizeof(sub_filter));
8812             memset(range, '\0', sizeof(range));
8813             sprintf(sub_filter, "(objectClass=msExchMDB)");
8814
8815             if(isLast)
8816               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8817             else 
8818               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8819
8820             attr_array[0] = range;
8821             attr_array[1] = NULL;
8822             
8823             sub_group_base = NULL;
8824             sub_group_count = 0;
8825             
8826             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8827                                      attr_array, &sub_group_base, 
8828                                      &sub_group_count, 
8829                                      LDAP_SCOPE_SUBTREE)) != 0) 
8830               {
8831                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8832                         ldap_err2string(rc));
8833                 return(rc);
8834               }
8835
8836             if(!sub_group_count)
8837               {
8838                 if(isLast) 
8839                   {
8840                     isLast = 0;
8841                     rangeLow = 0;
8842                     rangeHigh = rangeLow + (rangeStep - 1);
8843                     break;
8844                   }
8845                 else
8846                   isLast++;
8847               }
8848
8849             mdbbl_count += sub_group_count;
8850             rangeLow = rangeHigh + 1;
8851             rangeHigh = rangeLow + (rangeStep - 1);
8852           }
8853
8854         /* First time through, need to initialize or update the least used */
8855         
8856         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8857                 mdbbl_count);
8858
8859         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8860           {
8861             homeMDB_count = mdbbl_count; 
8862             *homeMDB = strdup(gPtr->dn);
8863           }
8864
8865         gPtr = gPtr->next;
8866         linklist_free(sub_group_base);
8867       }
8868     }
8869
8870   linklist_free(group_base);
8871   
8872   /* 
8873    * Ok found the server least allocated need to now query to get its
8874    * msExchHomeServerName so we can set it as a user attribute
8875    */
8876   
8877   attr_array[0] = "legacyExchangeDN";
8878   attr_array[1] = NULL; 
8879   
8880   group_count = 0;
8881   group_base = NULL;
8882   
8883   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8884                            attr_array, &group_base, 
8885                            &group_count, 
8886                            LDAP_SCOPE_SUBTREE)) != 0) 
8887     {
8888       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8889               ldap_err2string(rc));
8890       return(rc);
8891     }  
8892   
8893   if(group_count) 
8894     {
8895       *homeServerName = strdup(group_base->value);
8896       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8897         {
8898           *s = '\0';
8899         }
8900     } 
8901
8902   linklist_free(group_base);
8903   
8904   return(rc);
8905 }
8906       
8907 char *lowercase(char *s)
8908 {
8909   char *p;
8910
8911   for (p = s; *p; p++)
8912     {
8913       if (isupper(*p))
8914         *p = tolower(*p);
8915     }
8916   return s;
8917 }
8918
8919 char *uppercase(char *s)
8920 {
8921   char *p;
8922
8923   for (p = s; *p; p++)
8924     {
8925       if (islower(*p))
8926         *p = toupper(*p);
8927     }
8928   return s;
8929 }
8930
8931 char *escape_string(char *s)
8932 {
8933   char *p, *q;
8934   char string[1024];
8935   char temp[1024];
8936   int i = 0;
8937   int spaces = 0;
8938
8939   memset(string, '\0', sizeof(string));
8940
8941   q = s;
8942
8943   /* Replace leading spaces */
8944
8945   while(isspace(*q)) {
8946     string[i++] = '\\';
8947     string[i++] = '2';
8948     string[i++] = '0';
8949     q++;
8950   }
8951
8952   /* Escape any special characters */
8953
8954   for(; *q != '\0'; q++) {
8955     if(*q == ',')
8956       string[i++] = '\\';
8957     if(*q == '+') 
8958       string[i++] = '\\';
8959     if(*q == '"') 
8960       string[i++] = '\\';
8961     if(*q == '\\') 
8962       string[i++] = '\\';
8963     if(*q == '<') 
8964       string[i++] = '\\';
8965     if(*q == '>') 
8966       string[i++] = '\\';
8967     if(*q == ';')
8968       string[i++] = '\\';
8969     if(*q == '#')
8970       string[i++] = '\\';
8971     if(*q == '=')
8972       string[i++] = '\\';
8973
8974     string[i++] = *q;
8975   }
8976
8977   return strdup(string);
8978 }
8979
8980 int save_query_info(int argc, char **argv, void *hint)
8981 {
8982   int i;
8983   char **nargv = hint;
8984
8985   for(i = 0; i < argc; i++)
8986     nargv[i] = strdup(argv[i]);
8987
8988   return MR_CONT;
8989 }
8990
8991 int save_fsgroup_info(int argc, char **argv, void *hint)
8992 {
8993   int i;
8994   char **nargv = hint;
8995
8996   if(!fsgCount) 
8997     {
8998       for(i = 0; i < argc; i++)
8999         nargv[i] = strdup(argv[i]);
9000
9001       fsgCount++;
9002     }
9003
9004   return MR_CONT;
9005 }
This page took 0.779075 seconds and 5 git commands to generate.