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