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