]> andersk Git - moira.git/blob - incremental/ldap/winad.c
4e31c7a61f4bcf3729b3c273ce28ed8f7eff0b06
[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   char      *null_v[] = {NULL, NULL};
2413   u_int     groupTypeControl;
2414   char      groupTypeControlStr[80];
2415   char      contact_mail[256];
2416   int       n;
2417   int       i;
2418   int       rc;
2419   LK_ENTRY  *group_base;
2420   int       group_count;
2421   int       MailDisabled = 0;
2422   char      search_filter[1024];
2423
2424   if(UseGroupUniversal)
2425     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2426   else
2427     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2428      
2429   if (!check_string(before_group_name))
2430     {
2431       com_err(whoami, 0, 
2432               "Unable to process invalid LDAP list name %s", 
2433               before_group_name);
2434       return(AD_INVALID_NAME);
2435     }
2436
2437   if (!check_string(after_group_name))
2438     {
2439       com_err(whoami, 0, 
2440               "Unable to process invalid LDAP list name %s", after_group_name);
2441       return(AD_INVALID_NAME);
2442     }
2443
2444   if (Exchange) 
2445     {
2446       if(atoi(maillist)) 
2447         {
2448           group_count = 0;
2449           group_base = NULL;
2450           
2451           sprintf(search_filter, "(&(objectClass=user)(cn=%s))", 
2452                   after_group_name);
2453           attr_array[0] = "cn";
2454           attr_array[1] = NULL;
2455
2456           if ((rc = linklist_build(ldap_handle, dn_path, search_filter, 
2457                                    attr_array, &group_base, &group_count,
2458                                    LDAP_SCOPE_SUBTREE)) != 0)
2459           {
2460             com_err(whoami, 0, "Unable to process group %s : %s",
2461                     after_group_name, ldap_err2string(rc));
2462             return(rc);
2463           }
2464           
2465           if (group_count)
2466             {
2467               com_err(whoami, 0, "Object already exists with name %s",
2468                       after_group_name);
2469               MailDisabled++;
2470             }
2471         
2472           linklist_free(group_base);
2473           group_base = NULL;
2474           group_count = 0;
2475         }
2476     }
2477
2478   group_count = 0;
2479   group_base = NULL;
2480
2481   if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, 
2482                         before_group_membership, 
2483                         MoiraId, "samAccountName", &group_base, 
2484                         &group_count, filter))
2485     return(rc);
2486
2487   if (group_count == 0)
2488     {
2489       return(AD_NO_GROUPS_FOUND);
2490     }
2491
2492   if (group_count != 1)
2493     {
2494       com_err(whoami, 0, "Unable to process multiple groups with "
2495               "MoiraId = %s exist in the directory", MoiraId);
2496       return(AD_MULTIPLE_GROUPS_FOUND);
2497     }
2498
2499   strcpy(old_dn, group_base->dn);
2500
2501   linklist_free(group_base);
2502   group_base = NULL;
2503   group_count = 0;
2504   attr_array[0] = "sAMAccountName";
2505   attr_array[1] = NULL;
2506
2507   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
2508                            &group_base, &group_count, 
2509                            LDAP_SCOPE_SUBTREE)) != 0)
2510     {
2511       com_err(whoami, 0, "Unable to get list %s dn : %s",
2512               after_group_name, ldap_err2string(rc));
2513       return(rc);
2514     }
2515
2516   if (group_count != 1)
2517     {
2518       com_err(whoami, 0,
2519               "Unable to get sAMAccountName for group %s", 
2520               before_group_name);
2521       return(AD_LDAP_FAILURE);
2522     }
2523   
2524   strcpy(sam_name, group_base->value);
2525   linklist_free(group_base);
2526   group_base = NULL;
2527   group_count = 0;
2528   
2529   sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path);
2530   sprintf(new_dn, "cn=%s", after_group_name);
2531   sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain));
2532   sprintf(contact_mail, "%s@mit.edu", after_group_name); 
2533   sprintf(proxy_address, "SMTP:%s@%s", after_group_name, 
2534           lowercase(ldap_domain));
2535   sprintf(mail_nickname, "%s", after_group_name);
2536
2537   com_err(whoami, 0, "Old %s New %s,%s", old_dn, new_dn, new_dn_path);
2538
2539   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path,
2540                               TRUE, NULL, NULL)) != LDAP_SUCCESS)
2541     {
2542       com_err(whoami, 0, "Unable to rename list from %s to %s : %s",
2543               before_group_name, after_group_name, ldap_err2string(rc));
2544       return(rc);
2545     }
2546   
2547   name_v[0] = after_group_name;
2548
2549   if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], 
2550                group_suffix, strlen(group_suffix)))
2551     {
2552       sprintf(sam_name, "%s%s", after_group_name, group_suffix);
2553     }
2554   else
2555     {
2556       com_err(whoami, 0, 
2557               "Unable to rename list from %s to %s : sAMAccountName not found",
2558               before_group_name, after_group_name);
2559       return(rc);
2560     }
2561
2562   samAccountName_v[0] = sam_name;
2563
2564   if (after_security_flag)
2565     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2566
2567   sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2568   groupTypeControl_v[0] = groupTypeControlStr;
2569   mitMoiraId_v[0] = MoiraId;
2570
2571   sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
2572   rc = attribute_update(ldap_handle, new_dn, after_desc, "description", 
2573                         after_group_name);
2574   n = 0;
2575   ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE);
2576   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
2577   ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2578   ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE);
2579
2580   if (Exchange)
2581     {
2582       if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) 
2583         {
2584           mail_nickname_v[0] = mail_nickname;
2585           proxy_address_v[0] = proxy_address;
2586           mail_v[0] = mail;
2587           report_to_originator_v[0] = "TRUE";
2588
2589           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2590           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2591           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2592           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2593                    LDAP_MOD_REPLACE);
2594         } 
2595       else 
2596         {
2597           mail_nickname_v[0] = NULL;
2598           proxy_address_v[0] = NULL;
2599           mail_v[0] = NULL;
2600           legacy_exchange_dn_v[0] = NULL;
2601           address_book_v[0] = NULL;
2602           report_to_originator_v[0] = NULL;
2603
2604           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2605           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2606           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2607           ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE);
2608           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2609           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2610                    LDAP_MOD_REPLACE);
2611         }
2612     }
2613   else
2614     {
2615       if(atoi(maillist) && email_isvalid(contact_mail)) 
2616         {
2617           mail_v[0] = contact_mail;
2618           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2619
2620           if(!ActiveDirectory)
2621             {
2622               null_v[0] = "/dev/null";
2623               ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2624             }
2625         }
2626     }
2627
2628   mods[n] = NULL;
2629
2630   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
2631     {
2632       com_err(whoami, 0, 
2633               "Unable to modify list data for %s after renaming: %s",
2634               after_group_name, ldap_err2string(rc));
2635     }
2636
2637   for (i = 0; i < n; i++)
2638     free(mods[i]);
2639
2640   return(rc);
2641 }
2642
2643 int group_create(int ac, char **av, void *ptr)
2644 {
2645   LDAPMod *mods[20];
2646   char new_dn[256];
2647   char group_ou[256];
2648   char new_group_name[256];
2649   char sam_group_name[256];
2650   char cn_group_name[256];
2651   char mail[256];
2652   char contact_mail[256];
2653   char mail_nickname[256];
2654   char proxy_address[256];
2655   char address_book[256];
2656   char *cn_v[] = {NULL, NULL};
2657   char *objectClass_v[] = {"top", "group", NULL};
2658   char *objectClass_ldap_v[] = {"top", "microsoftComTop", "securityPrincipal",
2659                                 "group", "mailRecipient", NULL};
2660   char info[256];
2661   char *samAccountName_v[] = {NULL, NULL};
2662   char *altSecurityIdentities_v[] = {NULL, NULL};
2663   char *member_v[] = {NULL, NULL};
2664   char *name_v[] = {NULL, NULL};
2665   char *desc_v[] = {NULL, NULL};
2666   char *info_v[] = {NULL, NULL};
2667   char *mitMoiraId_v[] = {NULL, NULL};
2668   char *mitMoiraPublic_v[] = {NULL, NULL};
2669   char *mitMoiraHidden_v[] = {NULL, NULL};
2670   char *groupTypeControl_v[] = {NULL, NULL};
2671   char *mail_v[] = {NULL, NULL};
2672   char *proxy_address_v[] = {NULL, NULL};
2673   char *mail_nickname_v[] = {NULL, NULL};
2674   char *report_to_originator_v[] = {NULL, NULL};
2675   char *address_book_v[] = {NULL, NULL};
2676   char *legacy_exchange_dn_v[] = {NULL, NULL};
2677   char *gidNumber_v[] = {NULL, NULL};
2678   char *null_v[] = {NULL, NULL};
2679   char groupTypeControlStr[80];
2680   char group_membership[1];
2681   int  i;
2682   int  security_flag;
2683   u_int groupTypeControl;
2684   int  n;
2685   int  rc;
2686   int  updateGroup;
2687   int  MailDisabled = 0;
2688   char **call_args;
2689   LK_ENTRY *group_base;
2690   int  group_count;
2691   char filter[1024];
2692   char *attr_array[3];
2693   
2694   call_args = ptr;
2695
2696   if(UseGroupUniversal)
2697     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2698   else 
2699     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2700
2701   if (!check_string(av[L_NAME]))
2702     {
2703       com_err(whoami, 0, "Unable to process invalid LDAP list name %s", 
2704               av[L_NAME]);
2705       return(AD_INVALID_NAME);
2706     }
2707
2708   updateGroup = (int)call_args[4];
2709   memset(group_ou, 0, sizeof(group_ou));
2710   memset(group_membership, 0, sizeof(group_membership));
2711   security_flag = 0;
2712
2713   get_group_membership(group_membership, group_ou, &security_flag, av);
2714
2715   strcpy(new_group_name, av[L_NAME]);
2716   sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
2717   sprintf(contact_mail, "%s@mit.edu", av[L_NAME]);
2718   sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain));
2719   sprintf(mail_nickname, "%s", av[L_NAME]);
2720
2721   if (security_flag)
2722     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2723   
2724   sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix);
2725
2726   if (!updateGroup)
2727     {
2728       sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2729       groupTypeControl_v[0] = groupTypeControlStr;
2730
2731       strcpy(cn_group_name, av[L_NAME]);
2732       
2733       samAccountName_v[0] = sam_group_name;
2734       name_v[0] = new_group_name;
2735       cn_v[0] = new_group_name;
2736
2737       n = 0;
2738       ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
2739
2740       if(ActiveDirectory)
2741         {
2742           ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
2743         } 
2744       else
2745         {
2746           mitMoiraPublic_v[0] = av[L_PUBLIC];
2747           mitMoiraHidden_v[0] = av[L_HIDDEN];
2748           ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
2749           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_ADD);
2750           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_ADD);
2751           
2752           if(atoi(av[L_GROUP])) 
2753             {
2754               gidNumber_v[0] = av[L_GID];
2755               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_ADD);
2756             }
2757         }
2758
2759       ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
2760       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
2761       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
2762
2763       if (Exchange)
2764         {
2765           if(atoi(av[L_MAILLIST])) 
2766             {
2767               group_count = 0;
2768               group_base = NULL;
2769               
2770               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2771               attr_array[0] = "cn";
2772               attr_array[1] = NULL;
2773               
2774               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2775                                        filter, attr_array, &group_base, 
2776                                        &group_count,
2777                                        LDAP_SCOPE_SUBTREE)) != 0)
2778                 {
2779                   com_err(whoami, 0, "Unable to process group %s : %s",
2780                           av[L_NAME], ldap_err2string(rc));
2781                   return(rc);
2782                 }
2783               
2784               if (group_count)
2785                 {
2786                   com_err(whoami, 0, "Object already exists with name %s",
2787                           av[L_NAME]);
2788                   MailDisabled++;
2789                 }
2790         
2791               linklist_free(group_base);
2792               group_base = NULL;
2793               group_count = 0;
2794             }
2795           
2796           if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2797             {
2798               mail_nickname_v[0] = mail_nickname;
2799               report_to_originator_v[0] = "TRUE";
2800
2801               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
2802               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2803                        LDAP_MOD_ADD);
2804             }
2805         }
2806       else
2807         {
2808           if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2809             {
2810               mail_v[0] = contact_mail;
2811               ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
2812
2813               if(!ActiveDirectory)
2814                 {
2815                   null_v[0] = "/dev/null";
2816                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_ADD);
2817                 }
2818             }
2819         }
2820       
2821       if (strlen(av[L_DESC]) != 0)
2822         {
2823           desc_v[0] = av[L_DESC];
2824           ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
2825         }
2826       
2827       ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
2828
2829       if (strlen(av[L_ACE_NAME]) != 0)
2830         {
2831           sprintf(info, "The Administrator of this list is: %s", 
2832                   av[L_ACE_NAME]);
2833           info_v[0] = info;
2834           ADD_ATTR("info", info_v, LDAP_MOD_ADD);
2835         }
2836
2837       if (strlen(call_args[5]) != 0)
2838         {
2839           mitMoiraId_v[0] = call_args[5];
2840           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD);
2841         }
2842           
2843       mods[n] = NULL;
2844       
2845       rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
2846       
2847       for (i = 0; i < n; i++)
2848         free(mods[i]);
2849
2850       if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
2851         {
2852           com_err(whoami, 0, "Unable to create list %s in directory : %s",
2853                   av[L_NAME], ldap_err2string(rc));
2854           callback_rc = rc;
2855           return(rc);
2856         }
2857     }
2858
2859   if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup))
2860     {
2861       rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], 
2862                             "description", av[L_NAME]);
2863       sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]);
2864
2865       rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", 
2866                                 av[L_NAME]);
2867
2868       n = 0;
2869
2870       if (strlen(call_args[5]) != 0)
2871         {
2872           mitMoiraId_v[0] = call_args[5];
2873           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2874         }
2875
2876       if (!(atoi(av[L_ACTIVE])))
2877         {
2878           member_v[0] = NULL;
2879           ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
2880         }
2881    
2882       if (!ActiveDirectory) 
2883         {
2884           mitMoiraPublic_v[0] = av[L_PUBLIC];
2885           mitMoiraHidden_v[0] = av[L_HIDDEN];
2886           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_REPLACE);
2887           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_REPLACE);
2888
2889           if(atoi(av[L_GROUP])) 
2890             {
2891               gidNumber_v[0] = av[L_GID];
2892               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2893             }
2894           else
2895             {
2896               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2897             }
2898         }
2899
2900       if (Exchange)
2901         {
2902           if(atoi(av[L_MAILLIST])) 
2903             {
2904               group_count = 0;
2905               group_base = NULL;
2906               
2907               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2908               attr_array[0] = "cn";
2909               attr_array[1] = NULL;
2910               
2911               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2912                                        filter, attr_array, &group_base, 
2913                                        &group_count,
2914                                        LDAP_SCOPE_SUBTREE)) != 0)
2915                 {
2916                   com_err(whoami, 0, "Unable to process group %s : %s",
2917                           av[L_NAME], ldap_err2string(rc));
2918                   return(rc);
2919                 }
2920               
2921               if (group_count)
2922                 {
2923                   com_err(whoami, 0, "Object already exists with name %s",
2924                           av[L_NAME]);
2925                   MailDisabled++;
2926                 }
2927               
2928               linklist_free(group_base);
2929               group_base = NULL;
2930               group_count = 0;
2931             }
2932
2933           if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2934             {
2935               mail_nickname_v[0] = mail_nickname;
2936               report_to_originator_v[0] = "TRUE";
2937
2938               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2939               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2940                        LDAP_MOD_REPLACE);
2941             }
2942           else 
2943             {
2944               mail_v[0] = NULL;
2945               mail_nickname_v[0] = NULL;
2946               proxy_address_v[0] = NULL;
2947               legacy_exchange_dn_v[0] = NULL;
2948               address_book_v[0] = NULL;
2949               report_to_originator_v[0] = NULL;
2950
2951               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2952               ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2953               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2954               ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, 
2955                        LDAP_MOD_REPLACE);
2956               ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2957               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2958                        LDAP_MOD_REPLACE);
2959             }
2960         }
2961       else
2962         {
2963           if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2964             {
2965               mail_v[0] = contact_mail;
2966               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2967
2968               if(!ActiveDirectory)
2969                 {
2970                   null_v[0] = "/dev/null";
2971                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2972                 }
2973             }
2974           else
2975             {
2976               mail_v[0] = NULL;
2977               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2978
2979               if(!ActiveDirectory)
2980                 {
2981                   null_v[0] = NULL;
2982                   ADD_ATTR("mailRoutingAddress", null_v, LDAP_MOD_REPLACE);
2983                 }
2984             }
2985         }
2986    
2987       mods[n] = NULL;
2988       rc = LDAP_SUCCESS;
2989
2990       if (n != 0)
2991         {
2992           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
2993
2994           for (i = 0; i < n; i++)
2995               free(mods[i]);
2996
2997           if (rc != LDAP_SUCCESS)
2998             {
2999               com_err(whoami, 0, "Unable to update list %s in directory : %s",
3000                       av[L_NAME], ldap_err2string(rc));
3001               callback_rc = rc;
3002               return(rc);
3003             }
3004         }
3005     }
3006
3007   ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], 
3008                        atoi(av[L_HIDDEN]),  av[L_ACE_TYPE], av[L_ACE_NAME]);
3009
3010   return(LDAP_SUCCESS);
3011 }
3012
3013 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
3014                          char *TargetGroupName, int HiddenGroup, 
3015                          char *AceType, char *AceName)
3016 {
3017   char          filter_exp[1024];
3018   char          *attr_array[5];
3019   char          search_path[512];
3020   char          root_ou[128];
3021   char          TemplateDn[512];
3022   char          TemplateSamName[128];
3023   char          TargetDn[512];
3024   char          TargetSamName[128];
3025   char          AceSamAccountName[128];
3026   char          AceDn[256];
3027   unsigned char AceSid[128];
3028   unsigned char UserTemplateSid[128];
3029   char          acBERBuf[N_SD_BER_BYTES];
3030   char          GroupSecurityTemplate[256];
3031   char          hide_addres_lists[256];
3032   char          address_book[256];
3033   char          *hide_address_lists_v[] = {NULL, NULL};
3034   char          *address_book_v[] = {NULL, NULL};
3035   char          *owner_v[] = {NULL, NULL};
3036   int           AceSidCount;
3037   int           UserTemplateSidCount;
3038   int           group_count;
3039   int           n;
3040   int           i;
3041   int           rc;
3042   int           nVal;
3043   ULONG         dwInfo;
3044   int           array_count = 0;
3045   LDAPMod       *mods[20];
3046   LK_ENTRY      *group_base;
3047   LDAP_BERVAL   **ppsValues;
3048   LDAPControl sControl = {"1.2.840.113556.1.4.801",
3049                           { N_SD_BER_BYTES, acBERBuf },
3050                           TRUE
3051                          };
3052   LDAPControl *apsServerControls[] = {&sControl, NULL};
3053   LDAPMessage *psMsg;
3054
3055   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
3056     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
3057   BEREncodeSecurityBits(dwInfo, acBERBuf);
3058
3059   sprintf(search_path, "%s,%s", group_ou_root, dn_path);
3060   sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix);
3061   attr_array[0] = "sAMAccountName";
3062   attr_array[1] = NULL;
3063   group_count = 0;
3064   group_base = NULL;
3065
3066   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3067                            &group_base, &group_count, 
3068                            LDAP_SCOPE_SUBTREE) != 0))
3069     return(1);
3070
3071   if (group_count != 1)
3072     {
3073       linklist_free(group_base);
3074       return(1);
3075     }
3076
3077   strcpy(TargetDn, group_base->dn);
3078   strcpy(TargetSamName, group_base->value);
3079   linklist_free(group_base);
3080   group_base = NULL;
3081   group_count = 0;
3082
3083   UserTemplateSidCount = 0;
3084   memset(UserTemplateSid, '\0', sizeof(UserTemplateSid));
3085   memset(AceSamAccountName, '\0', sizeof(AceSamAccountName));
3086   memset(AceSid, '\0', sizeof(AceSid));
3087   AceSidCount = 0;
3088   group_base = NULL;
3089   group_count = 0;
3090
3091   if (strlen(AceName) != 0)
3092     {
3093       if (!strcmp(AceType, "LIST"))
3094         {
3095           sprintf(AceSamAccountName, "%s%s", AceName, group_suffix);
3096           strcpy(root_ou, group_ou_root);
3097         }
3098       else if (!strcmp(AceType, "USER"))
3099         {
3100           sprintf(AceSamAccountName, "%s", AceName);
3101           strcpy(root_ou, user_ou);
3102         }
3103
3104       if (ActiveDirectory)
3105         {
3106           if (strlen(AceSamAccountName) != 0)
3107             {
3108               sprintf(search_path, "%s", dn_path);
3109               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3110               attr_array[0] = "objectSid";
3111               attr_array[1] = NULL;
3112               group_count = 0;
3113               group_base = NULL;
3114               
3115               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3116                                        attr_array, &group_base, &group_count, 
3117                                        LDAP_SCOPE_SUBTREE) != 0))
3118                 return(1);
3119               if (group_count == 1)
3120                 {
3121                   strcpy(AceDn, group_base->dn);
3122                   AceSidCount = group_base->length;
3123                   memcpy(AceSid, group_base->value, AceSidCount);
3124                 }
3125               linklist_free(group_base);
3126               group_base = NULL;
3127               group_count = 0;
3128             }
3129         }
3130       else
3131         {
3132           if (strlen(AceSamAccountName) != 0)
3133             {
3134               sprintf(search_path, "%s", dn_path);
3135               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3136               attr_array[0] = "samAccountName";
3137               attr_array[1] = NULL;
3138               group_count = 0;
3139               group_base = NULL;
3140               
3141               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3142                                        attr_array, &group_base, &group_count, 
3143                                        LDAP_SCOPE_SUBTREE) != 0))
3144                 return(1);
3145               if (group_count == 1)
3146                 {
3147                   strcpy(AceDn, group_base->dn);
3148                 }
3149               linklist_free(group_base);
3150               group_base = NULL;
3151               group_count = 0;
3152             }
3153         }
3154     }
3155
3156   if (!ActiveDirectory) 
3157     {
3158       if (strlen(AceDn) != 0) 
3159         {
3160           owner_v[0] = strdup(AceDn);
3161           n = 0;
3162           ADD_ATTR("owner", owner_v, LDAP_MOD_REPLACE);
3163
3164           mods[n] = NULL;
3165
3166           rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3167           
3168           for (i = 0; i < n; i++)
3169             free(mods[i]);
3170
3171           if (rc != LDAP_SUCCESS)
3172             com_err(whoami, 0, "Unable to set owner for group %s : %s",
3173               TargetGroupName, ldap_err2string(rc));
3174         }
3175
3176       return(rc);
3177     }
3178   
3179   if (AceSidCount == 0)
3180     {
3181       com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not "
3182               "have a directory SID.", TargetGroupName, AceName, AceType);
3183       com_err(whoami, 0, "   Non-admin security group template will be used.");
3184     }
3185   else
3186     {
3187       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3188       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
3189       attr_array[0] = "objectSid";
3190       attr_array[1] = NULL;
3191
3192       group_count = 0;
3193       group_base = NULL;
3194
3195       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3196                                attr_array, &group_base, &group_count, 
3197                                LDAP_SCOPE_SUBTREE) != 0))
3198         return(1);
3199
3200       if ((rc != 0) || (group_count != 1))
3201         {
3202           com_err(whoami, 0, "Unable to process user security template: %s", 
3203                   "UserTemplate");
3204           AceSidCount = 0;
3205         }
3206       else
3207         {
3208           UserTemplateSidCount = group_base->length;
3209           memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount);
3210         }
3211       linklist_free(group_base);
3212       group_base = NULL;
3213       group_count = 0;
3214     }
3215
3216   if (HiddenGroup)
3217     {
3218       if (AceSidCount == 0)
3219         {
3220           strcpy(GroupSecurityTemplate, HIDDEN_GROUP);
3221           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP);
3222         }
3223       else
3224         {
3225           strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN);
3226           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN);
3227         }
3228     }
3229   else
3230     {
3231       if (AceSidCount == 0)
3232         {
3233           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP);
3234           sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP);
3235         }
3236       else
3237         {
3238           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN);
3239           sprintf(filter_exp, "(sAMAccountName=%s)", 
3240                   NOT_HIDDEN_GROUP_WITH_ADMIN);
3241         }
3242     }
3243
3244   sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3245   attr_array[0] = "sAMAccountName";
3246   attr_array[1] = NULL;
3247   group_count = 0;
3248   group_base = NULL;
3249
3250   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3251                            &group_base, &group_count, 
3252                            LDAP_SCOPE_SUBTREE) != 0))
3253     return(1);
3254
3255   if (group_count != 1)
3256     {
3257       linklist_free(group_base);
3258       com_err(whoami, 0, "Unable to process group security template: %s - "
3259               "security not set", GroupSecurityTemplate);
3260       return(1);
3261     }
3262
3263   strcpy(TemplateDn, group_base->dn);
3264   strcpy(TemplateSamName, group_base->value);
3265   linklist_free(group_base);
3266   group_base = NULL;
3267   group_count = 0;
3268   
3269   sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName);
3270   rc = ldap_search_ext_s(ldap_handle,
3271                          TemplateDn,
3272                          LDAP_SCOPE_SUBTREE,
3273                          filter_exp,
3274                          NULL,
3275                          0,
3276                          apsServerControls,
3277                          NULL,
3278                          NULL,
3279                          0,
3280                          &psMsg);
3281
3282   if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
3283     {
3284       com_err(whoami, 0, "Unable to find group security template: %s - "
3285               "security not set", GroupSecurityTemplate);
3286       return(1);
3287     }
3288
3289   ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
3290
3291   if (ppsValues == NULL)
3292     {
3293       com_err(whoami, 0, "Unable to find group security descriptor for group "
3294               "%s - security not set", GroupSecurityTemplate);
3295       return(1);
3296     }
3297   
3298   if (AceSidCount != 0)
3299     {
3300       for (nVal = 0; ppsValues[nVal] != NULL; nVal++)
3301         {
3302           for (i = 0; 
3303                i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++)
3304             {
3305               if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, 
3306                           UserTemplateSidCount))
3307                 {
3308                   memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount);
3309                   break;
3310                 }
3311             }
3312         }
3313     }
3314
3315   n = 0;
3316   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, 
3317            LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
3318
3319   if (Exchange)
3320     {
3321       if(HiddenGroup) 
3322         {
3323           hide_address_lists_v[0] = "TRUE";
3324           address_book_v[0] = NULL;
3325           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3326                    LDAP_MOD_REPLACE);
3327           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
3328         } else {
3329           hide_address_lists_v[0] = NULL;
3330           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3331                    LDAP_MOD_REPLACE);
3332         }
3333     }
3334
3335   mods[n] = NULL;
3336
3337   rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3338
3339   for (i = 0; i < n; i++)
3340     free(mods[i]);
3341
3342   ldap_value_free_len(ppsValues);
3343   ldap_msgfree(psMsg);
3344
3345   if (rc != LDAP_SUCCESS)
3346     {
3347       com_err(whoami, 0, "Unable to set security settings for group %s : %s",
3348               TargetGroupName, ldap_err2string(rc));
3349
3350       if (AceSidCount != 0)
3351         {
3352           com_err(whoami, 0, 
3353                   "Trying to set security for group %s without admin.",
3354                   TargetGroupName);
3355
3356           if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, 
3357                                         HiddenGroup, "", ""))
3358             {
3359               com_err(whoami, 0, "Unable to set security for group %s.",
3360                       TargetGroupName);
3361               return(rc);
3362             }
3363         }
3364       return(rc);
3365     }
3366
3367   return(rc);
3368 }
3369
3370 int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, 
3371                  char *group_membership, char *MoiraId)
3372 {
3373   LK_ENTRY  *group_base;
3374   char      temp[512];
3375   char      filter[128];
3376   int       group_count;
3377   int       rc;
3378
3379   if (!check_string(group_name))
3380     {
3381       com_err(whoami, 0, 
3382               "Unable to process invalid LDAP list name %s", group_name);
3383       return(AD_INVALID_NAME);
3384     }
3385
3386   memset(filter, '\0', sizeof(filter));
3387   group_count = 0;
3388   group_base = NULL;
3389   sprintf(temp, "%s,%s", group_ou_root, dn_path);
3390
3391   if (rc = ad_get_group(ldap_handle, temp, group_name, 
3392                         group_membership, MoiraId, 
3393                         "samAccountName", &group_base, 
3394                         &group_count, filter))
3395     return(rc);
3396
3397   if (group_count == 1)
3398     {
3399       if ((rc = ldap_delete_s(ldap_handle, group_base->dn)) != LDAP_SUCCESS)
3400         {
3401           linklist_free(group_base);
3402           com_err(whoami, 0, "Unable to delete list %s from directory : %s",
3403                   group_name, ldap_err2string(rc));
3404           return(rc);
3405         }
3406       linklist_free(group_base);
3407     }
3408   else
3409     {
3410       linklist_free(group_base);
3411       com_err(whoami, 0, "Unable to find list %s in directory.", group_name);
3412       return(AD_NO_GROUPS_FOUND);
3413     }
3414   
3415   return(0);
3416 }
3417
3418 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer)
3419 {
3420     *pBuffer++ = 0x30;
3421     *pBuffer++ = 0x03;
3422     *pBuffer++ = 0x02;
3423     *pBuffer++ = 0x00;
3424     return(N_SD_BER_BYTES);
3425 }
3426
3427 int process_lists(int ac, char **av, void *ptr)
3428 {
3429   int   rc;
3430   int   security_flag;
3431   char  group_ou[256];
3432   char  group_membership[2];
3433   char  **call_args;
3434
3435   call_args = ptr;
3436
3437   security_flag = 0;
3438   memset(group_ou, '\0', sizeof(group_ou));
3439   memset(group_membership, '\0', sizeof(group_membership));
3440   get_group_membership(group_membership, group_ou, &security_flag, av);
3441   rc = populate_group((LDAP *)call_args[0], (char *)call_args[1], 
3442                       av[L_NAME], group_ou, group_membership, 
3443                       security_flag, "");
3444
3445   return(0);
3446 }
3447
3448 int member_list_build(int ac, char **av, void *ptr)
3449 {
3450   LK_ENTRY  *linklist;
3451   char      temp[1024];
3452   char      **call_args;
3453   char      *s;
3454   call_args = ptr;
3455
3456   strcpy(temp, av[ACE_NAME]);
3457   StringTrim(temp);
3458   
3459   if (!check_string(temp))
3460     return(0);
3461
3462   if (!strcmp(av[ACE_TYPE], "USER"))
3463     {
3464       if (!((int)call_args[3] & MOIRA_USERS))
3465         return(0);
3466     }
3467   else if (!strcmp(av[ACE_TYPE], "STRING"))
3468     {
3469       if (Exchange)
3470         {
3471           if((s = strchr(temp, '@')) == (char *) NULL) 
3472             {
3473               strcat(temp, "@mit.edu");
3474             }
3475           
3476           if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6))
3477             {
3478               s = strrchr(temp, '.');
3479               *s = '\0';
3480               strcat(s, ".mit.edu");
3481             }
3482         }
3483
3484       if (!((int)call_args[3] & MOIRA_STRINGS))
3485         return(0);
3486         
3487       if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou))
3488         return(0);
3489     }
3490   else if (!strcmp(av[ACE_TYPE], "LIST"))
3491     {
3492       if (!((int)call_args[3] & MOIRA_LISTS))
3493         return(0);
3494     }
3495   else if (!strcmp(av[ACE_TYPE], "KERBEROS"))
3496     {
3497       if (!((int)call_args[3] & MOIRA_KERBEROS))
3498         return(0);
3499
3500       if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
3501                          kerberos_ou))
3502         return(0);
3503
3504     }
3505   else if (!strcmp(av[ACE_TYPE], "MACHINE"))
3506     {
3507       if (!((int)call_args[3] & MOIRA_MACHINE))
3508         return(0);
3509     }
3510   else
3511     return(0);
3512
3513   linklist = member_base;
3514
3515   while (linklist)
3516     {
3517     if (!strcasecmp(temp, linklist->member) &&
3518         !strcasecmp(av[ACE_TYPE], linklist->type))
3519       return(0);
3520
3521     linklist = linklist->next;
3522     }
3523
3524   linklist = calloc(1, sizeof(LK_ENTRY));
3525   linklist->op = 1;
3526   linklist->dn = NULL;
3527   linklist->list = calloc(1, strlen(call_args[2]) + 1);
3528   strcpy(linklist->list, call_args[2]);
3529   linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1);
3530   strcpy(linklist->type, av[ACE_TYPE]);
3531   linklist->member = calloc(1, strlen(temp) + 1);
3532   strcpy(linklist->member, temp);
3533   linklist->next = member_base;
3534   member_base = linklist;
3535
3536   return(0);
3537 }
3538
3539 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
3540                   char *group_ou, char *group_membership, char *user_name,
3541                   char *UserOu, char *MoiraId)
3542 {
3543   char        distinguished_name[1024];
3544   char        *modvalues[2];
3545   char        temp[256];
3546   char        filter[128];
3547   char        *attr_array[3];
3548   int         group_count;
3549   int         i;
3550   int         n;
3551   LDAPMod     *mods[20];
3552   LK_ENTRY    *group_base;
3553   ULONG       rc;
3554   char        *s;
3555
3556   if (!check_string(group_name))
3557     return(AD_INVALID_NAME);
3558
3559   memset(filter, '\0', sizeof(filter));
3560   group_base = NULL;
3561   group_count = 0;
3562
3563   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3564                         group_membership, MoiraId, 
3565                         "samAccountName", &group_base, 
3566                         &group_count, filter))
3567     return(rc);
3568
3569   if (group_count != 1)
3570     {
3571       com_err(whoami, 0, "Unable to find list %s in directory",
3572               group_name);
3573       linklist_free(group_base);
3574       group_base = NULL;
3575       group_count = 0;
3576       goto cleanup;
3577     }
3578
3579   strcpy(distinguished_name, group_base->dn);
3580   linklist_free(group_base);
3581   group_base = NULL;
3582   group_count = 0;
3583
3584   if(ActiveDirectory)
3585     {
3586       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3587     }
3588   else
3589     {
3590       if(!strcmp(UserOu, user_ou))
3591         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3592       else
3593         sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3594     }
3595
3596   modvalues[0] = temp;
3597   modvalues[1] = NULL;
3598
3599   n = 0;
3600   ADD_ATTR("member", modvalues, LDAP_MOD_DELETE);
3601   mods[n] = NULL;
3602   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3603
3604   for (i = 0; i < n; i++)
3605     free(mods[i]);
3606
3607   if (rc == LDAP_UNWILLING_TO_PERFORM)
3608     rc = LDAP_SUCCESS;
3609
3610   if (rc != LDAP_SUCCESS)
3611     {
3612       com_err(whoami, 0, "Unable to modify list %s members : %s",
3613               group_name, ldap_err2string(rc));
3614       goto cleanup;
3615     }
3616
3617   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) 
3618     {
3619       if (Exchange)
3620         {
3621           if(!strcmp(UserOu, contact_ou) && 
3622              ((s = strstr(user_name, "@mit.edu")) != (char *) NULL))
3623             {
3624               memset(temp, '\0', sizeof(temp));
3625               strcpy(temp, user_name);
3626               s = strchr(temp, '@');
3627               *s = '\0';
3628               
3629               sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp);
3630           
3631               if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL,
3632                                        &group_base, &group_count, 
3633                                        LDAP_SCOPE_SUBTREE) != 0))
3634                 return(rc);       
3635               
3636               if(group_count)
3637                 goto cleanup;
3638               
3639               linklist_free(group_base);
3640               group_base = NULL;
3641               group_count = 0;
3642             }
3643           
3644           sprintf(filter, "(distinguishedName=%s)", temp);
3645           attr_array[0] = "memberOf";
3646           attr_array[1] = NULL;
3647           
3648           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
3649                                    &group_base, &group_count, 
3650                                    LDAP_SCOPE_SUBTREE) != 0))
3651             return(rc);
3652           
3653
3654           if(!group_count) 
3655             {
3656               com_err(whoami, 0, "Removing unreferenced object %s", temp);
3657           
3658               if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) 
3659                 return(rc);
3660             }
3661         }
3662     }
3663
3664  cleanup:
3665   return(rc);
3666 }
3667
3668 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
3669                char *group_ou, char *group_membership, char *user_name, 
3670                char *UserOu, char *MoiraId)
3671 {
3672   char        distinguished_name[1024];
3673   char        *modvalues[2];
3674   char        temp[256];
3675   char        filter[128];
3676   int         group_count;
3677   int         n;
3678   int         i;
3679   LDAPMod     *mods[20];
3680   LK_ENTRY    *group_base;
3681   ULONG       rc;
3682
3683   if (!check_string(group_name))
3684     return(AD_INVALID_NAME);
3685
3686   rc = 0;
3687   memset(filter, '\0', sizeof(filter));
3688   group_base = NULL;
3689   group_count = 0;
3690
3691   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3692                         group_membership, MoiraId, 
3693                         "samAccountName", &group_base, 
3694                         &group_count, filter))
3695     return(rc);
3696
3697   if (group_count != 1)
3698     {
3699       linklist_free(group_base);
3700       group_base = NULL;
3701       group_count = 0;
3702       com_err(whoami, 0, "Unable to find list %s %d in directory",
3703               group_name, group_count);
3704       return(AD_MULTIPLE_GROUPS_FOUND);
3705     }
3706
3707   strcpy(distinguished_name, group_base->dn);
3708   linklist_free(group_base);
3709   group_base = NULL;
3710   group_count = 0;
3711
3712   if(ActiveDirectory)
3713     {
3714       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3715     }
3716   else 
3717     {
3718       if(!strcmp(UserOu, user_ou))
3719         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3720       else
3721         sprintf(temp, "cn=%s,%s,%s", user_name, UserOu, dn_path);
3722     }
3723
3724   modvalues[0] = temp;
3725   modvalues[1] = NULL;
3726
3727   n = 0;
3728   ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
3729   mods[n] = NULL;
3730   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3731
3732   if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
3733     rc = LDAP_SUCCESS;
3734
3735   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou)))
3736     {
3737       if (rc == LDAP_UNWILLING_TO_PERFORM)
3738         rc = LDAP_SUCCESS;
3739     }
3740
3741   for (i = 0; i < n; i++)
3742     free(mods[i]);
3743
3744   if (rc != LDAP_SUCCESS)
3745     {
3746       com_err(whoami, 0, "Unable to add %s to list %s as a member : %s",
3747               user_name, group_name, ldap_err2string(rc));
3748     }
3749
3750   return(rc);
3751 }
3752
3753 int contact_remove_email(LDAP *ld, char *bind_path,
3754                          LK_ENTRY **linklist_base, int linklist_current)
3755 {
3756   LK_ENTRY  *gPtr;
3757   int       rc;
3758   char      *mail_v[] = {NULL, NULL};
3759   LDAPMod   *mods[20];
3760   int n;
3761   int i;
3762
3763   mail_v[0] = NULL;
3764
3765   n = 0;
3766   ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
3767   ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE);
3768   ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE);
3769   ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE);
3770   mods[n] = NULL;
3771
3772   gPtr = (*linklist_base);
3773   
3774   while(gPtr) {
3775     rc = ldap_modify_s(ld, gPtr->dn, mods);
3776     
3777     if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3778       {
3779         com_err(whoami, 0, "Unable to modify contact %s in directory : %s",
3780                 gPtr->dn, ldap_err2string(rc));
3781         return(rc);
3782       }
3783
3784     gPtr = gPtr->next;
3785   }
3786
3787   for (i = 0; i < n; i++)
3788     free(mods[i]);
3789   
3790     return(rc);
3791 }
3792
3793 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
3794 {
3795   LDAPMod *mods[20];
3796   LK_ENTRY  *group_base;
3797   int  group_count;
3798   char new_dn[256];
3799   char cn_user_name[256];
3800   char contact_name[256];
3801   char mail_nickname[256];
3802   char proxy_address_internal[256];
3803   char proxy_address_external[256];
3804   char target_address[256];
3805   char internal_contact_name[256];
3806   char filter[128];
3807   char mail[256];
3808   char principal[256];
3809   char mit_address_book[256];
3810   char default_address_book[256];
3811   char contact_address_book[256];
3812   char uid[256];
3813   char *email_v[] = {NULL, NULL};
3814   char *cn_v[] = {NULL, NULL};
3815   char *contact_v[] = {NULL, NULL};
3816   char *uid_v[] = {NULL, NULL};
3817   char *mail_nickname_v[] = {NULL, NULL};
3818   char *proxy_address_internal_v[] = {NULL, NULL};
3819   char *proxy_address_external_v[] = {NULL, NULL};
3820   char *target_address_v[] = {NULL, NULL};
3821   char *mit_address_book_v[] = {NULL, NULL};
3822   char *default_address_book_v[] = {NULL, NULL};
3823   char *contact_address_book_v[] = {NULL, NULL};
3824   char *hide_address_lists_v[] = {NULL, NULL};
3825   char *attr_array[3];
3826   char *objectClass_v[] = {"top", "person", 
3827                            "organizationalPerson", 
3828                            "contact", NULL};
3829   char *objectClass_ldap_v[] = {"top", "person", "microsoftComTop", 
3830                                 "inetOrgPerson", "organizationalPerson",
3831                                 "contact", "mailRecipient", "eduPerson",
3832                                 NULL};
3833   char *name_v[] = {NULL, NULL};
3834   char *desc_v[] = {NULL, NULL};
3835   char *s;
3836   int  n;
3837   int  rc;
3838   int  i;
3839   char temp[256];
3840   char *c;
3841   char *mail_routing_v[] = {NULL, NULL};
3842   char *principal_v[] = {NULL, NULL};
3843
3844   if (!check_string(user))
3845     {
3846       com_err(whoami, 0, "Unable to process invalid LDAP name %s", user);
3847       return(AD_INVALID_NAME);
3848     }
3849
3850   strcpy(mail, user);
3851   strcpy(contact_name, mail);
3852   strcpy(internal_contact_name, mail);
3853   
3854   if((s = strchr(internal_contact_name, '@')) != NULL) {
3855     *s = '?';
3856   }
3857
3858   sprintf(cn_user_name,"CN=%s,%s,%s", escape_string(contact_name), group_ou, 
3859           bind_path);
3860
3861   sprintf(target_address, "SMTP:%s", contact_name);
3862   sprintf(proxy_address_external, "SMTP:%s", contact_name);
3863   sprintf(mail_nickname, "%s", internal_contact_name);
3864  
3865   cn_v[0] = cn_user_name;
3866   contact_v[0] = contact_name;
3867   uid_v[0] = uid;
3868   name_v[0] = user;
3869   desc_v[0] = "Auto account created by Moira";
3870   email_v[0] = mail;
3871   proxy_address_internal_v[0] = proxy_address_internal;
3872   proxy_address_external_v[0] = proxy_address_external;
3873   mail_nickname_v[0] = mail_nickname;
3874   target_address_v[0] = target_address;
3875   mit_address_book_v[0] = mit_address_book;
3876   default_address_book_v[0] = default_address_book;
3877   contact_address_book_v[0] = contact_address_book;
3878   strcpy(new_dn, cn_user_name);
3879   n = 0;
3880
3881   ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
3882
3883   if(!ActiveDirectory)
3884     {
3885       if(!strcmp(group_ou, contact_ou))
3886         sprintf(uid, "%s%s", contact_name, "_strings");
3887       
3888       if(!strcmp(group_ou, kerberos_ou))
3889         sprintf(uid, "%s%s", contact_name, "_kerberos");
3890
3891       uid_v[0] = uid;
3892
3893       ADD_ATTR("sn", contact_v, LDAP_MOD_ADD);
3894       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
3895     }
3896
3897   if(ActiveDirectory)
3898     {
3899       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
3900     }
3901   else
3902     {
3903       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
3904     }
3905
3906   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
3907   ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
3908   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
3909
3910   if (Exchange)
3911     {
3912       if (!strcmp(group_ou, contact_ou) && email_isvalid(mail))
3913         {
3914           group_count = 0;
3915           group_base = NULL;
3916           
3917           sprintf(filter, "(&(objectClass=user)(cn=%s))", mail);
3918           attr_array[0] = "cn";
3919           attr_array[1] = NULL;
3920
3921           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3922                                    &group_base, &group_count, 
3923                                    LDAP_SCOPE_SUBTREE)) != 0) 
3924             {
3925               com_err(whoami, 0, "Unable to process contact %s : %s", 
3926                       user, ldap_err2string(rc));
3927               return(rc);
3928             }
3929       
3930           if (group_count) 
3931             {
3932               com_err(whoami, 0, "Object already exists with name %s",
3933                       user);
3934               return(1);
3935             }
3936
3937           linklist_free(group_base);
3938           group_base = NULL;
3939           group_count = 0;
3940       
3941           sprintf(filter, "(&(objectClass=group)(cn=%s))", mail);
3942           attr_array[0] = "cn";
3943           attr_array[1] = NULL;
3944
3945           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3946                                    &group_base, &group_count, 
3947                                    LDAP_SCOPE_SUBTREE)) != 0) 
3948             {
3949               com_err(whoami, 0, "Unable to process contact %s : %s", 
3950                       user, ldap_err2string(rc));
3951               return(rc);
3952             }
3953           
3954           if (group_count) 
3955             {
3956               com_err(whoami, 0, "Object already exists with name %s",
3957                       user);
3958               return(1);
3959             }
3960   
3961           linklist_free(group_base);
3962           group_count = 0;
3963           group_base = NULL;
3964           
3965           sprintf(filter, "(&(objectClass=user)(mail=%s))", mail);
3966           attr_array[0] = "cn";
3967           attr_array[1] = NULL;
3968
3969           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3970                                    &group_base, &group_count, 
3971                                    LDAP_SCOPE_SUBTREE)) != 0) 
3972             {
3973               com_err(whoami, 0, "Unable to process contact %s : %s", 
3974                       user, ldap_err2string(rc));
3975               return(rc);
3976             }
3977           
3978           if (group_count) 
3979             {
3980               com_err(whoami, 0, "Object already exists with name %s",
3981                       user);
3982               return(1);
3983             }
3984
3985           linklist_free(group_base);
3986           group_base = NULL;
3987           group_count = 0;
3988
3989           sprintf(filter, "(&(objectClass=group)(mail=%s))", mail);
3990           attr_array[0] = "cn";
3991           attr_array[1] = NULL;
3992
3993           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3994                                    &group_base, &group_count, 
3995                                    LDAP_SCOPE_SUBTREE)) != 0) 
3996             {
3997               com_err(whoami, 0, "Unable to process contact %s : %s", 
3998                       user, ldap_err2string(rc));
3999               return(rc);
4000             }
4001       
4002           if (group_count) 
4003             {
4004               com_err(whoami, 0, "Object already exists with name %s",
4005                       user);
4006               return(1);
4007             }
4008           
4009           linklist_free(group_base);
4010           group_base = NULL;
4011           group_count = 0;
4012           
4013           ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
4014           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
4015           ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD);
4016           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD);
4017           
4018           hide_address_lists_v[0] = "TRUE";
4019           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4020                    LDAP_MOD_ADD);
4021         }
4022     }
4023
4024   if(!ActiveDirectory) 
4025     {
4026       if((c = strchr(mail, '@')) == NULL)
4027           sprintf(temp, "%s@mit.edu", mail);
4028       else
4029           sprintf(temp, "%s", mail);
4030
4031       mail_routing_v[0] = temp;
4032       email_v[0] = temp;
4033       principal_v[0] = principal;
4034
4035       if(!strcmp(group_ou, contact_ou))
4036         {
4037           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4038           ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD);
4039         }
4040     }
4041
4042   mods[n] = NULL;
4043
4044   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4045
4046   for (i = 0; i < n; i++)
4047     free(mods[i]);
4048   
4049   if (Exchange)
4050     {
4051       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
4052           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
4053         {
4054           n = 0;
4055           
4056           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
4057           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
4058           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
4059                    LDAP_MOD_REPLACE);
4060           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
4061
4062           hide_address_lists_v[0] = "TRUE";
4063           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4064                    LDAP_MOD_REPLACE);
4065     
4066           mods[n] = NULL;
4067           rc = ldap_modify_s(ld, new_dn, mods);
4068       
4069           if (rc) 
4070             {
4071               com_err(whoami, 0, "Unable to update contact %s", mail);
4072             }
4073       
4074           for (i = 0; i < n; i++)
4075             free(mods[i]);
4076         }
4077     }
4078
4079   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4080     {
4081       com_err(whoami, 0, "Unable to create contact %s : %s",
4082               user, ldap_err2string(rc));
4083       return(rc);
4084     }
4085
4086   return(0);
4087 }
4088
4089 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
4090                 char *Uid, char *MitId, char *MoiraId, int State,
4091                 char *WinHomeDir, char *WinProfileDir, char *first,
4092                 char *middle, char *last, char *shell, char *class)
4093 {
4094   LDAPMod   *mods[20];
4095   LK_ENTRY  *group_base;
4096   int  group_count;
4097   char distinguished_name[512];
4098   char displayName[256];
4099   char *mitMoiraId_v[] = {NULL, NULL};
4100   char *mitMoiraClass_v[] = {NULL, NULL};
4101   char *mitMoiraStatus_v[] = {NULL, NULL};
4102   char *uid_v[] = {NULL, NULL};
4103   char *mitid_v[] = {NULL, NULL};
4104   char *homedir_v[] = {NULL, NULL};
4105   char *winProfile_v[] = {NULL, NULL};
4106   char *drives_v[] = {NULL, NULL};
4107   char *userAccountControl_v[] = {NULL, NULL};
4108   char *alt_recipient_v[] = {NULL, NULL};
4109   char *hide_address_lists_v[] = {NULL, NULL};
4110   char *mail_v[] = {NULL, NULL};
4111   char *gid_v[] = {NULL, NULL};
4112   char *loginshell_v[] = {NULL, NULL};
4113   char *principal_v[] = {NULL, NULL};
4114   char userAccountControlStr[80];
4115   int  n;
4116   int  rc;
4117   int  i;
4118   int  OldUseSFU30;
4119   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4120     UF_PASSWD_CANT_CHANGE;
4121   char filter[128];
4122   char *attr_array[3];
4123   char temp[1024];
4124   char mail[256];
4125   char contact_mail[256];
4126   char filter_exp[1024];
4127   char search_path[512];
4128   char TemplateDn[512];
4129   char TemplateSamName[128];
4130   char alt_recipient[256];
4131   char principal[256];
4132   char status[256];
4133   char acBERBuf[N_SD_BER_BYTES];
4134   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4135                           { N_SD_BER_BYTES, acBERBuf },
4136                           TRUE};
4137   LDAPControl *apsServerControls[] = {&sControl, NULL};
4138   LDAPMessage *psMsg;
4139   LDAP_BERVAL   **ppsValues;
4140   ULONG dwInfo;
4141   char *argv[3];
4142   char *homeMDB;
4143   char *homeServerName;
4144   char *save_argv[7];
4145   char search_string[256];
4146   char *p, *q;
4147   char *mail_routing_v[] = {NULL, NULL};
4148   char *c;
4149
4150   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4151     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4152   BEREncodeSecurityBits(dwInfo, acBERBuf);
4153
4154   if (!check_string(user_name))
4155     {
4156       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4157               user_name);
4158       return(AD_INVALID_NAME);
4159     }
4160   
4161   memset(contact_mail, '\0', sizeof(contact_mail));
4162   sprintf(contact_mail, "%s@mit.edu", user_name);
4163   memset(mail, '\0', sizeof(mail));
4164   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4165   memset(alt_recipient, '\0', sizeof(alt_recipient));
4166   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4167           dn_path);
4168   sprintf(search_string, "@%s", uppercase(ldap_domain));
4169
4170   if (Exchange)
4171     {
4172       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4173         {
4174           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4175         }
4176     }
4177
4178   group_count = 0;
4179   group_base = NULL;
4180
4181   memset(displayName, '\0', sizeof(displayName));
4182
4183   if (strlen(MoiraId) != 0)
4184     {
4185       if(ActiveDirectory)
4186         {
4187           sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4188         }
4189       else
4190         {
4191           sprintf(filter, 
4192                   "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId);
4193         }
4194
4195       attr_array[0] = "cn";
4196       attr_array[1] = NULL;
4197       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4198                                &group_base, &group_count, 
4199                                LDAP_SCOPE_SUBTREE)) != 0)
4200         {
4201           com_err(whoami, 0, "Unable to process user %s : %s",
4202                   user_name, ldap_err2string(rc));
4203           return(rc);
4204         }
4205     }
4206
4207   if (group_count != 1)
4208     {
4209       linklist_free(group_base);
4210       group_base = NULL;
4211       group_count = 0;
4212       sprintf(filter, "(sAMAccountName=%s)", user_name);
4213       attr_array[0] = "cn";
4214       attr_array[1] = NULL;
4215       sprintf(temp, "%s,%s", user_ou, dn_path);
4216       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
4217                                &group_base, &group_count, 
4218                                LDAP_SCOPE_SUBTREE)) != 0)
4219         {
4220           com_err(whoami, 0, "Unable to process user %s : %s",
4221                   user_name, ldap_err2string(rc));
4222           return(rc);
4223         }
4224     }
4225
4226   if (group_count != 1)
4227     {
4228       com_err(whoami, 0, "Unable to find user %s in directory",
4229               user_name);
4230       linklist_free(group_base);
4231       return(AD_NO_USER_FOUND);
4232     }
4233
4234   strcpy(distinguished_name, group_base->dn);
4235
4236   linklist_free(group_base);
4237   group_count = 0;
4238
4239   if(!ActiveDirectory) 
4240     {
4241       if (rc = moira_connect())
4242         {
4243           critical_alert("Ldap incremental", 
4244                          "Error contacting Moira server : %s",
4245                          error_message(rc));
4246           return;
4247         }
4248   
4249       argv[0] = user_name;
4250       
4251       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4252         {
4253           n = 0;
4254           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
4255           mods[n] = NULL;
4256           rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4257           
4258           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
4259             rc = LDAP_SUCCESS;
4260
4261           if(rc)
4262             com_err(whoami, 0, 
4263                     "Unable to set the mailRoutingAddress for %s : %s",
4264                     user_name, ldap_err2string(rc));
4265           
4266           p = strdup(save_argv[3]);
4267           
4268           if((c = strchr(p, ',')) != NULL) 
4269             {
4270               q = strtok(p, ",");
4271               StringTrim(q);
4272
4273               if ((c = strchr(q, '@')) == NULL)
4274                 sprintf(temp, "%s@mit.edu", q);
4275               else
4276                 sprintf(temp, "%s", q);
4277               
4278               if(email_isvalid(temp) && State != US_DELETED) 
4279                 {
4280                   mail_routing_v[0]  = temp;
4281                   
4282                   n = 0;
4283                   ADD_ATTR("mailRoutingAddress", mail_routing_v, 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 %s : %s",
4294                             user_name, ldap_err2string(rc));
4295                 }
4296
4297               while((q = strtok(NULL, ",")) != NULL) {
4298                 StringTrim(q);
4299                 
4300                 if((c = strchr(q, '@')) == NULL) 
4301                   sprintf(temp, "%s@mit.edu", q);
4302                 else
4303                   sprintf(temp, "%s", q);
4304
4305                 if(email_isvalid(temp) && State != US_DELETED) 
4306                   {
4307                     mail_routing_v[0]  = temp;
4308                 
4309                     n = 0;
4310                     ADD_ATTR("mailRoutingAddress", mail_routing_v, 
4311                              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 " 
4322                               "%s : %s",
4323                               user_name, ldap_err2string(rc));
4324                   }
4325               }
4326             } else {
4327               StringTrim(p);
4328
4329             if((c = strchr(p, '@')) == NULL)
4330               sprintf(temp, "%s@mit.edu", p);
4331             else
4332               sprintf(temp, "%s", p);
4333             
4334             if(email_isvalid(temp) && State != US_DELETED) 
4335               {
4336                 mail_routing_v[0]  = temp;
4337                 
4338                 n = 0;
4339                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4340                 mods[n] = NULL;
4341                 rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4342                 
4343                 if (rc == LDAP_ALREADY_EXISTS || 
4344                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
4345                   rc = LDAP_SUCCESS;
4346                 
4347                 if(rc)
4348                   com_err(whoami, 0, 
4349                           "Unable to set the mailRoutingAddress for %s : %s",
4350                           user_name, ldap_err2string(rc));
4351               }
4352             }
4353         }
4354       moira_disconnect();
4355     }
4356
4357   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
4358     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
4359                           "employeeID", user_name);
4360   else
4361     rc = attribute_update(ldap_handle, distinguished_name, "none", 
4362                           "employeeID", user_name);
4363
4364   if(strlen(first)) {
4365     strcat(displayName, first);
4366   }
4367
4368   if(strlen(middle)) {
4369     if(strlen(first)) 
4370       strcat(displayName, " ");
4371
4372     strcat(displayName, middle);
4373   }
4374
4375   if(strlen(last)) {
4376     if(strlen(middle) || strlen(first))
4377       strcat(displayName, " ");
4378
4379     strcat(displayName, last);
4380   }
4381
4382   if(strlen(displayName))
4383     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4384                           "displayName", user_name);
4385   else
4386     rc = attribute_update(ldap_handle, distinguished_name, user_name,
4387                           "displayName", user_name);
4388
4389   if(!ActiveDirectory)
4390     {
4391       if(strlen(displayName))
4392         rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4393                               "cn", user_name);
4394       else
4395         rc = attribute_update(ldap_handle, distinguished_name, user_name,
4396                               "cn", user_name);
4397     }
4398
4399   if(!ActiveDirectory)
4400     {
4401       rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4402                             "eduPersonNickname", user_name);
4403     }
4404
4405   if(strlen(first))
4406     rc = attribute_update(ldap_handle, distinguished_name, first, 
4407                           "givenName", user_name);
4408   else
4409     rc = attribute_update(ldap_handle, distinguished_name, "",
4410                           "givenName", user_name);
4411
4412   if(strlen(middle) == 1) 
4413     rc = attribute_update(ldap_handle, distinguished_name, middle,
4414                           "initials", user_name);
4415   else 
4416     rc = attribute_update(ldap_handle, distinguished_name, "",
4417                           "initials", user_name);
4418   
4419   if(strlen(last))
4420     rc = attribute_update(ldap_handle, distinguished_name, last,
4421                           "sn", user_name);
4422   else 
4423     rc = attribute_update(ldap_handle, distinguished_name, "",
4424                           "sn", user_name);
4425
4426   if(ActiveDirectory)
4427     {
4428       rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4429                             user_name);
4430     }
4431   else
4432     {
4433       rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", 
4434                             user_name);
4435     }
4436     
4437   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4438                         "mitMoiraId", user_name);
4439
4440   n = 0;
4441   uid_v[0] = Uid;
4442
4443   if(ActiveDirectory)
4444     {
4445       if (!UseSFU30)
4446         {
4447           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4448         }
4449       else
4450         {
4451           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4452         }
4453     }
4454   else
4455     {
4456       sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4457       sprintf(status, "%d", State);
4458       principal_v[0] = principal;
4459       loginshell_v[0] = shell;
4460       mitMoiraClass_v[0] = class;
4461       mitMoiraStatus_v[0] = status;
4462       gid_v[0] = "101";
4463       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4464       ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE);
4465       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE);
4466       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4467       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE);
4468       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE);
4469     }
4470
4471   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4472     {
4473       userAccountControl |= UF_ACCOUNTDISABLE;
4474
4475       if (Exchange)
4476         {
4477           hide_address_lists_v[0] = "TRUE";
4478           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4479                    LDAP_MOD_REPLACE);
4480         }
4481     }
4482   else
4483     {
4484       if (Exchange)
4485         {
4486           hide_address_lists_v[0] = NULL;
4487           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4488                    LDAP_MOD_REPLACE);
4489         }
4490     }
4491
4492   sprintf(userAccountControlStr, "%ld", userAccountControl);
4493   userAccountControl_v[0] = userAccountControlStr;
4494   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4495
4496   if (Exchange)
4497     {
4498       if (rc = moira_connect())
4499         {
4500           critical_alert("Ldap incremental", 
4501                          "Error contacting Moira server : %s",
4502                          error_message(rc));
4503           return;
4504         }
4505  
4506       argv[0] = user_name;
4507
4508       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4509         {
4510           if(!strcmp(save_argv[1], "EXCHANGE") || 
4511              (strstr(save_argv[3], search_string) != NULL))
4512             {
4513               alt_recipient_v[0] = NULL;
4514               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4515
4516               argv[0] = exchange_acl;
4517               argv[1] = "USER";
4518               argv[2] = user_name;
4519               
4520               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4521               
4522               if ((rc) && (rc != MR_EXISTS))
4523                 {
4524                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4525                           user_name, exchange_acl, error_message(rc));
4526                 }
4527             }
4528           else 
4529             {
4530               alt_recipient_v[0] = alt_recipient;
4531               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4532               
4533               argv[0] = exchange_acl;
4534               argv[1] = "USER";
4535               argv[2] = user_name;
4536               
4537               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4538               
4539               if ((rc) && (rc != MR_NO_MATCH))
4540                 {  
4541                   com_err(whoami, 0,
4542                           "Unable to remove user %s from %s: %s, %d",
4543                           user_name, exchange_acl, error_message(rc), rc);
4544                 }  
4545             }
4546         }
4547       else
4548         {
4549           alt_recipient_v[0] = alt_recipient;
4550           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4551           
4552           argv[0] = exchange_acl;
4553           argv[1] = "USER";
4554           argv[2] = user_name;
4555           
4556           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4557           
4558           if ((rc) && (rc != MR_NO_MATCH))
4559             {  
4560               com_err(whoami, 0,
4561                       "Unable to remove user %s from %s: %s, %d",
4562                       user_name, exchange_acl, error_message(rc), rc);
4563             }  
4564         }
4565       
4566       moira_disconnect();
4567     }
4568   else
4569     {
4570       mail_v[0] = contact_mail;
4571       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4572
4573       if(!ActiveDirectory)
4574         {
4575           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_REPLACE);
4576         }
4577     }
4578
4579   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4580                        WinProfileDir, homedir_v, winProfile_v,
4581                        drives_v, mods, LDAP_MOD_REPLACE, n);
4582
4583   if(ActiveDirectory)
4584     {
4585       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4586       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4587       attr_array[0] = "sAMAccountName";
4588       attr_array[1] = NULL;
4589       group_count = 0;
4590       group_base = NULL;
4591     
4592       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
4593                                attr_array,
4594                                &group_base, &group_count, 
4595                                LDAP_SCOPE_SUBTREE) != 0))
4596         return(1);
4597       
4598       if (group_count != 1)
4599         {
4600           com_err(whoami, 0, "Unable to process user security template: %s - "
4601                   "security not set", "UserTemplate.u");
4602           return(1);
4603         }
4604
4605       strcpy(TemplateDn, group_base->dn);
4606       strcpy(TemplateSamName, group_base->value);
4607       linklist_free(group_base);
4608       group_base = NULL;
4609       group_count = 0;
4610       
4611       rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4612                              filter_exp, NULL, 0, apsServerControls, NULL,
4613                              NULL, 0, &psMsg);
4614
4615       if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4616         {
4617           com_err(whoami, 0, "Unable to find user security template: %s - "
4618                   "security not set", "UserTemplate.u");
4619           return(1);
4620         }
4621       
4622       ppsValues = ldap_get_values_len(ldap_handle, psMsg, 
4623                                       "ntSecurityDescriptor");
4624
4625       if (ppsValues == NULL)
4626         {
4627           com_err(whoami, 0, "Unable to find user security template: %s - "
4628                   "security not set", "UserTemplate.u");
4629           return(1);
4630         }
4631       
4632       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4633                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4634     }
4635
4636   mods[n] = NULL;
4637
4638   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4639                           mods)) != LDAP_SUCCESS)
4640     {
4641       OldUseSFU30 = UseSFU30;
4642       SwitchSFU(mods, &UseSFU30, n);
4643       if (OldUseSFU30 != UseSFU30)
4644         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4645       if (rc)
4646         {
4647           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4648                   user_name, ldap_err2string(rc));
4649         }
4650     }
4651   
4652   for (i = 0; i < n; i++)
4653     free(mods[i]);
4654
4655   return(rc);
4656 }
4657
4658 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4659                 char *user_name)
4660 {
4661   LDAPMod *mods[20];
4662   char new_dn[256];
4663   char old_dn[256];
4664   char upn[256];
4665   char mail[256];
4666   char contact_mail[256];
4667   char proxy_address[256];
4668   char query_base_dn[256];
4669   char temp[256];
4670   char *userPrincipalName_v[] = {NULL, NULL};
4671   char *altSecurityIdentities_v[] = {NULL, NULL};
4672   char *name_v[] = {NULL, NULL};
4673   char *samAccountName_v[] = {NULL, NULL};
4674   char *mail_v[] = {NULL, NULL};
4675   char *mail_nickname_v[] = {NULL, NULL};
4676   char *proxy_address_v[] = {NULL, NULL};
4677   char *query_base_dn_v[] = {NULL, NULL};
4678   char *principal_v[] = {NULL, NULL};
4679   char principal[256];
4680   int  n;
4681   int  rc;
4682   int  i;
4683
4684   if (!check_string(before_user_name))
4685     {
4686       com_err(whoami, 0, 
4687               "Unable to process invalid LDAP user name %s", before_user_name);
4688       return(AD_INVALID_NAME);
4689     }
4690
4691   if (!check_string(user_name))
4692     {
4693       com_err(whoami, 0, 
4694               "Unable to process invalid LDAP user name %s", user_name);
4695       return(AD_INVALID_NAME);
4696     }
4697
4698   strcpy(user_name, user_name);
4699  
4700   if(ActiveDirectory)
4701     sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4702   else
4703     sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path);
4704
4705   if(ActiveDirectory)
4706     sprintf(new_dn, "cn=%s", user_name);
4707   else
4708     sprintf(new_dn, "uid=%s", user_name);
4709
4710   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4711   sprintf(contact_mail, "%s@mit.edu", user_name);
4712   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4713   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4714
4715   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4716                            NULL, NULL)) != LDAP_SUCCESS)
4717     {
4718       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4719               before_user_name, user_name, ldap_err2string(rc));
4720       return(rc);
4721     }
4722
4723   if (Exchange)
4724     {
4725       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4726               dn_path);
4727
4728       if(rc = ldap_delete_s(ldap_handle, temp))
4729         {
4730           com_err(whoami, 0, "Unable to delete user contact for %s",
4731                   user_name);
4732         }
4733       
4734       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4735         {
4736           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4737         }
4738     }
4739
4740   name_v[0] = user_name;
4741   sprintf(upn, "%s@%s", user_name, ldap_domain);
4742   userPrincipalName_v[0] = upn;
4743   principal_v[0] = principal;
4744   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4745   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4746   altSecurityIdentities_v[0] = temp;
4747   samAccountName_v[0] = user_name;
4748   mail_v[0] = mail;
4749   mail_nickname_v[0] = user_name;
4750   proxy_address_v[0] = proxy_address; 
4751   query_base_dn_v[0] = query_base_dn;
4752
4753   n = 0;
4754   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4755   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4756   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4757   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4758
4759   if(!ActiveDirectory)
4760     {
4761       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE);
4762       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4763       ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4764       ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE);
4765     }
4766
4767   if (Exchange)
4768     {
4769       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4770       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4771       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4772       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4773     }
4774   else
4775     {
4776       mail_v[0] = contact_mail;
4777       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4778
4779       if(!ActiveDirectory)
4780         {
4781           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_REPLACE);
4782         }
4783     }
4784
4785   mods[n] = NULL;
4786   
4787   if(ActiveDirectory)
4788     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4789   else
4790     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path);
4791
4792   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4793     {
4794       com_err(whoami, 0, 
4795               "Unable to modify user data for %s after renaming : %s",
4796               user_name, ldap_err2string(rc));
4797     }
4798   
4799   for (i = 0; i < n; i++)
4800     free(mods[i]);
4801
4802   return(rc);
4803 }
4804
4805 int user_create(int ac, char **av, void *ptr)
4806 {
4807   LDAPMod *mods[20];
4808   char new_dn[256];
4809   char user_name[256];
4810   char sam_name[256];
4811   char upn[256];
4812   char mail[256];
4813   char contact_mail[256];
4814   char proxy_address[256];
4815   char mail_nickname[256];
4816   char query_base_dn[256];
4817   char displayName[256];
4818   char address_book[256];
4819   char alt_recipient[256];
4820   char *cn_v[] = {NULL, NULL};
4821   char *objectClass_v[] = {"top", "person", "organizationalPerson",
4822                            "user", NULL};
4823   char *objectClass_ldap_v[] = {"top", 
4824                                 "eduPerson", "posixAccount", 
4825                                 "apple-user", "shadowAccount",
4826                                 "microsoftComTop", "securityPrincipal",
4827                                 "inetOrgPerson", "user", 
4828                                 "organizationalPerson", "person",
4829                                 "mailRecipient", NULL};
4830
4831   char *samAccountName_v[] = {NULL, NULL};
4832   char *altSecurityIdentities_v[] = {NULL, NULL};
4833   char *mitMoiraId_v[] = {NULL, NULL};
4834   char *mitMoiraClass_v[] = {NULL, NULL};
4835   char *mitMoiraStatus_v[] = {NULL, NULL};
4836   char *name_v[] = {NULL, NULL};
4837   char *desc_v[] = {NULL, NULL};
4838   char *userPrincipalName_v[] = {NULL, NULL};
4839   char *userAccountControl_v[] = {NULL, NULL};
4840   char *uid_v[] = {NULL, NULL};
4841   char *gid_v[] = {NULL, NULL};
4842   char *mitid_v[] = {NULL, NULL};
4843   char *homedir_v[] = {NULL, NULL};
4844   char *winProfile_v[] = {NULL, NULL};
4845   char *drives_v[] = {NULL, NULL};
4846   char *mail_v[] = {NULL, NULL};
4847   char *givenName_v[] = {NULL, NULL};
4848   char *sn_v[] = {NULL, NULL};
4849   char *initials_v[] = {NULL, NULL};
4850   char *displayName_v[] = {NULL, NULL};
4851   char *proxy_address_v[] = {NULL, NULL};
4852   char *mail_nickname_v[] = {NULL, NULL};
4853   char *query_base_dn_v[] = {NULL, NULL};
4854   char *address_book_v[] = {NULL, NULL};
4855   char *homeMDB_v[] = {NULL, NULL};
4856   char *homeServerName_v[] = {NULL, NULL};
4857   char *mdbUseDefaults_v[] = {NULL, NULL};
4858   char *mailbox_guid_v[] = {NULL, NULL};
4859   char *user_culture_v[] = {NULL, NULL};
4860   char *user_account_control_v[] = {NULL, NULL};
4861   char *msexch_version_v[] = {NULL, NULL};
4862   char *alt_recipient_v[] = {NULL, NULL};
4863   char *hide_address_lists_v[] = {NULL, NULL};
4864   char *principal_v[] = {NULL, NULL};
4865   char *loginshell_v[] = {NULL, NULL};
4866   char userAccountControlStr[80];
4867   char temp[1024];
4868   char principal[256];
4869   char filter_exp[1024];
4870   char search_path[512];
4871   char *attr_array[3];
4872   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4873     UF_PASSWD_CANT_CHANGE; 
4874   int  n;
4875   int  rc;
4876   int  i;
4877   int  OldUseSFU30;
4878   char **call_args;
4879   char WinHomeDir[1024];
4880   char WinProfileDir[1024];
4881   char *homeMDB;
4882   char *homeServerName;
4883   ULONG dwInfo;
4884   char acBERBuf[N_SD_BER_BYTES];
4885   LK_ENTRY  *group_base;
4886   int    group_count;
4887   char TemplateDn[512];
4888   char TemplateSamName[128];
4889   LDAP_BERVAL **ppsValues;
4890   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4891                           { N_SD_BER_BYTES, acBERBuf },
4892                           TRUE};
4893   LDAPControl *apsServerControls[] = {&sControl, NULL};
4894   LDAPMessage *psMsg;
4895   char *argv[3];
4896   char *save_argv[7];
4897   char search_string[256];
4898   char *o_v[] = {NULL, NULL};
4899   char *p, *q;
4900   char *mail_routing_v[] = {NULL, NULL};
4901   char *c;
4902
4903   call_args = ptr;
4904
4905   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4906     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4907   BEREncodeSecurityBits(dwInfo, acBERBuf);
4908
4909   if (!check_string(av[U_NAME]))
4910     {
4911       callback_rc = AD_INVALID_NAME;
4912       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4913               av[U_NAME]);
4914       return(AD_INVALID_NAME);
4915     }
4916
4917   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4918   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4919   memset(displayName, '\0', sizeof(displayName));
4920   memset(query_base_dn, '\0', sizeof(query_base_dn));
4921   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4922   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4923   strcpy(user_name, av[U_NAME]);
4924   sprintf(upn, "%s@%s", user_name, ldap_domain);
4925   sprintf(sam_name, "%s", av[U_NAME]);
4926
4927   if(strlen(av[U_FIRST])) {
4928     strcat(displayName, av[U_FIRST]);
4929   }
4930
4931   if(strlen(av[U_MIDDLE])) {
4932     if(strlen(av[U_FIRST]))
4933        strcat(displayName, " "); 
4934   
4935     strcat(displayName, av[U_MIDDLE]);
4936   }
4937
4938   if(strlen(av[U_LAST])) {
4939     if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]))
4940       strcat(displayName, " ");
4941
4942     strcat(displayName, av[U_LAST]);
4943   }
4944
4945   samAccountName_v[0] = sam_name;
4946   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4947       (atoi(av[U_STATE]) != US_REGISTERED))
4948     {
4949       userAccountControl |= UF_ACCOUNTDISABLE;
4950
4951       if (Exchange)
4952         {
4953           hide_address_lists_v[0] = "TRUE";
4954           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4955                    LDAP_MOD_ADD);
4956         }
4957     }
4958
4959   sprintf(userAccountControlStr, "%ld", userAccountControl);
4960   userAccountControl_v[0] = userAccountControlStr;
4961   userPrincipalName_v[0] = upn;
4962   
4963   if(ActiveDirectory)
4964     cn_v[0] = user_name;
4965   else
4966     cn_v[0] = displayName;
4967     
4968   name_v[0] = user_name;
4969   desc_v[0] = "Auto account created by Moira";
4970   mail_v[0] = mail;
4971   givenName_v[0] = av[U_FIRST];
4972
4973   if(ActiveDirectory)
4974     sn_v[0] = av[U_LAST];
4975   else
4976     if(strlen(av[U_LAST]))
4977       sn_v[0] = av[U_LAST];
4978     else
4979       sn_v[0] = av[U_NAME];
4980
4981   displayName_v[0] = displayName;
4982   mail_nickname_v[0] = user_name;
4983   o_v[0] = "Massachusetts Institute of Technology";
4984
4985   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4986   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4987   altSecurityIdentities_v[0] = temp;    
4988   principal_v[0] = principal;
4989
4990   if(ActiveDirectory)
4991     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4992   else
4993     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]);
4994
4995   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4996   sprintf(contact_mail, "%s@mit.edu", user_name);
4997   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4998   query_base_dn_v[0] = query_base_dn;
4999   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
5000           call_args[1]);
5001   sprintf(search_string, "@%s", uppercase(ldap_domain));
5002
5003   if (Exchange)
5004     {
5005       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
5006                         contact_ou))
5007         {
5008           com_err(whoami, 0, "Unable to create user contact %s", 
5009                   contact_mail);
5010         }
5011       
5012       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
5013                       &homeServerName)) 
5014         {
5015           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
5016           return(1);
5017         }
5018       
5019       com_err(whoami, 0, "homeMDB:%s", homeMDB);
5020       com_err(whoami, 0, "homeServerName:%s", homeServerName);
5021   
5022       homeMDB_v[0] = homeMDB;
5023       homeServerName_v[0] = homeServerName; 
5024     }
5025
5026   n = 0;
5027
5028   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
5029   
5030   if(ActiveDirectory) 
5031     {
5032       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
5033     }
5034   else
5035     {
5036       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
5037     }
5038
5039   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
5040   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
5041   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
5042   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
5043   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
5044
5045   if (Exchange)
5046     {
5047       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
5048       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
5049       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
5050       mdbUseDefaults_v[0] = "TRUE";
5051       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
5052       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
5053       
5054       argv[0] = user_name;
5055     
5056       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5057         {
5058           if(!strcmp(save_argv[1], "EXCHANGE") || 
5059              (strstr(save_argv[3], search_string) != NULL))
5060             {
5061               argv[0] = exchange_acl;
5062               argv[1] = "USER";
5063               argv[2] = user_name;
5064               
5065               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
5066               
5067               if ((rc) && (rc != MR_EXISTS))
5068                 {
5069                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
5070                           user_name, exchange_acl, error_message(rc));
5071                 }
5072             } 
5073           else 
5074             {
5075               alt_recipient_v[0] = alt_recipient;
5076               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5077             }
5078         }
5079       else
5080         {
5081           alt_recipient_v[0] = alt_recipient;
5082           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5083           
5084           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
5085         }
5086     }
5087   else
5088     {
5089       mail_v[0] = contact_mail;
5090       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
5091
5092       if(!ActiveDirectory)
5093         {
5094           ADD_ATTR("mitMoiraMail", mail_v, LDAP_MOD_ADD);
5095         }
5096     }
5097
5098   if(strlen(av[U_FIRST])) {
5099     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
5100   }
5101
5102   if(strlen(av[U_LAST]) || strlen(av[U_NAME])) {
5103     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
5104   }
5105
5106   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
5107     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
5108
5109     if(!ActiveDirectory)
5110       {
5111         ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD);      
5112       }
5113   } else {
5114     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
5115
5116     if(!ActiveDirectory)
5117       {
5118         ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD);            
5119       }
5120   }
5121
5122   if (strlen(av[U_MIDDLE]) == 1) {
5123     initials_v[0] = av[U_MIDDLE];
5124     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
5125   }
5126
5127   if (strlen(call_args[2]) != 0)    
5128     {
5129       mitMoiraId_v[0] = call_args[2];
5130       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
5131     }
5132
5133   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
5134
5135   if(!ActiveDirectory)
5136     {
5137       loginshell_v[0] = av[U_SHELL];
5138       mitMoiraClass_v[0] = av[U_CLASS];
5139       mitMoiraStatus_v[0] = av[U_STATE];
5140       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD);
5141       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD);
5142       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD);
5143       ADD_ATTR("o", o_v, LDAP_MOD_ADD);
5144       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD);
5145       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD);
5146     }
5147
5148   if (strlen(av[U_UID]) != 0)
5149     {
5150       uid_v[0] = av[U_UID];
5151
5152       if(ActiveDirectory) 
5153         {
5154           ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
5155         }
5156       else
5157         {
5158           gid_v[0] = "101";
5159           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5160           ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD);
5161         }
5162
5163       if(ActiveDirectory)
5164         {
5165           if (!UseSFU30)
5166             {
5167               ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5168             }
5169           else
5170             {
5171               ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
5172             }
5173         }
5174     }
5175
5176   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
5177       mitid_v[0] = av[U_MITID];
5178   else
5179       mitid_v[0] = "none";
5180
5181   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
5182
5183   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, 
5184                        WinHomeDir, WinProfileDir, homedir_v, winProfile_v,
5185                        drives_v, mods, LDAP_MOD_ADD, n);
5186   
5187   if(ActiveDirectory) 
5188     {
5189       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
5190       sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
5191       attr_array[0] = "sAMAccountName";
5192       attr_array[1] = NULL;
5193       group_count = 0;
5194       group_base = NULL;
5195       
5196       if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
5197                                attr_array, &group_base, &group_count, 
5198                                LDAP_SCOPE_SUBTREE) != 0))
5199         return(1);
5200       
5201       if (group_count != 1)
5202         {
5203           com_err(whoami, 0, "Unable to process user security template: %s - "
5204                   "security not set", "UserTemplate.u");
5205           return(1);
5206         }
5207       
5208       strcpy(TemplateDn, group_base->dn);
5209       strcpy(TemplateSamName, group_base->value);
5210       linklist_free(group_base);
5211       group_base = NULL;
5212       group_count = 0;
5213       
5214       rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, 
5215                              LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, 
5216                              apsServerControls, NULL,
5217                              NULL, 0, &psMsg);
5218       
5219       if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
5220         {
5221           com_err(whoami, 0, "Unable to find user security template: %s - "
5222                   "security not set", "UserTemplate.u");
5223           return(1);
5224         }
5225       
5226       ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
5227                                       "ntSecurityDescriptor");
5228       if (ppsValues == NULL)
5229         {
5230           com_err(whoami, 0, "Unable to find user security template: %s - "
5231                   "security not set", "UserTemplate.u");
5232           return(1);
5233         }
5234       
5235       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
5236                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
5237     }
5238
5239   mods[n] = NULL;
5240
5241   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5242
5243   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5244     {
5245       OldUseSFU30 = UseSFU30;
5246       SwitchSFU(mods, &UseSFU30, n);
5247       if (OldUseSFU30 != UseSFU30)
5248         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5249     }
5250
5251   for (i = 0; i < n; i++)
5252     free(mods[i]);
5253
5254   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5255     {
5256       com_err(whoami, 0, "Unable to create user %s : %s",
5257               user_name, ldap_err2string(rc));
5258       callback_rc = rc;
5259       return(rc);
5260     }
5261
5262   if ((rc == LDAP_SUCCESS) && (SetPassword))
5263     {
5264       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5265         {
5266           ad_kdc_disconnect();
5267           if (!ad_server_connect(default_server, ldap_domain))
5268             {
5269               com_err(whoami, 0, "Unable to set password for user %s : %s",
5270                       user_name, 
5271                       "cannot get changepw ticket from windows domain");
5272             }
5273           else
5274             {
5275               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5276                 {
5277                   com_err(whoami, 0, "Unable to set password for user %s "
5278                           ": %ld", user_name, rc);
5279                 }
5280             }
5281         }
5282     }
5283
5284   if(!ActiveDirectory) 
5285     {
5286       if (rc = moira_connect())
5287         {
5288           critical_alert("Ldap incremental", 
5289                          "Error contacting Moira server : %s",
5290                          error_message(rc));
5291           return;
5292         }
5293   
5294       argv[0] = user_name;
5295       
5296       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5297         {
5298           n = 0;
5299           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
5300           mods[n] = NULL;
5301           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5302            
5303           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
5304             rc = LDAP_SUCCESS;
5305
5306           if(rc)
5307             com_err(whoami, 0,
5308                     "Unable to set the mailRoutingAddress for %s : %s",
5309                     user_name, ldap_err2string(rc));
5310
5311           p = strdup(save_argv[3]);
5312           
5313           if((c = strchr(p, ',')) != NULL) {
5314             q = strtok(p, ",");
5315             StringTrim(q);
5316
5317             if ((c = strchr(q, '@')) == NULL)
5318               sprintf(temp, "%s@mit.edu", q);
5319             else
5320               sprintf(temp, "%s", q);
5321
5322             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5323               {
5324                 mail_routing_v[0]  = temp;
5325
5326                 n = 0;
5327                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5328                 mods[n] = NULL;
5329                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5330                 
5331                 if (rc == LDAP_ALREADY_EXISTS || 
5332                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5333                   rc = LDAP_SUCCESS;
5334                 
5335                 if(rc)
5336                   com_err(whoami, 0, 
5337                           "Unable to set the mailRoutingAddress for %s : %s",
5338                           user_name, ldap_err2string(rc));
5339               }
5340
5341             while((q = strtok(NULL, ",")) != NULL) {
5342               StringTrim(q);
5343
5344               if((c = strchr(q, '@')) == NULL)
5345                 sprintf(temp, "%s@mit.edu", q);
5346               else
5347                 sprintf(temp, "%s", q);
5348
5349               if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED)
5350                 {
5351                   mail_routing_v[0]  = temp;
5352                   
5353                   n = 0;
5354                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5355                   mods[n] = NULL;
5356                   rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5357                   
5358                   if (rc == LDAP_ALREADY_EXISTS || 
5359                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
5360                     rc = LDAP_SUCCESS;
5361                   
5362                   if(rc)
5363                     com_err(whoami, 0, 
5364                             "Unable to set the mailRoutingAddress for %s : %s",
5365                             user_name, ldap_err2string(rc));
5366                 }
5367             }
5368           } else {
5369             StringTrim(p);
5370
5371             if((c = strchr(p, '@')) == NULL)
5372               sprintf(temp, "%s@mit.edu", p);
5373             else
5374               sprintf(temp, "%s", p);
5375
5376             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5377               {
5378                 mail_routing_v[0]  = temp;
5379                 
5380                 n = 0;
5381                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5382                 mods[n] = NULL;
5383                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5384                 
5385                 if (rc == LDAP_ALREADY_EXISTS || 
5386                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5387                   rc = LDAP_SUCCESS;
5388                 
5389                 if(rc)
5390                   com_err(whoami, 0, 
5391                           "Unable to set the mailRoutingAddress for %s : %s",
5392                           user_name, ldap_err2string(rc));
5393               }
5394           }
5395         }
5396       moira_disconnect();
5397     }
5398
5399   return(0);
5400 }
5401
5402 int user_change_status(LDAP *ldap_handle, char *dn_path, 
5403                        char *user_name, char *MoiraId,
5404                        int operation)
5405 {
5406   char      filter[128];
5407   char      *attr_array[3];
5408   char      temp[256];
5409   char      distinguished_name[1024];
5410   char      **modvalues;
5411   char      *mitMoiraId_v[] = {NULL, NULL};
5412   LDAPMod   *mods[20];
5413   LK_ENTRY  *group_base;
5414   int       group_count;
5415   int       rc;
5416   int       i;
5417   int       n;
5418   ULONG     ulongValue;
5419
5420   if (!check_string(user_name))
5421     {
5422       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
5423               user_name);
5424       return(AD_INVALID_NAME);
5425     }
5426
5427   group_count = 0;
5428   group_base = NULL;
5429
5430   if (strlen(MoiraId) != 0)
5431     {
5432       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5433       attr_array[0] = "UserAccountControl";
5434       attr_array[1] = NULL;
5435       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5436                                &group_base, &group_count, 
5437                                LDAP_SCOPE_SUBTREE)) != 0)
5438         {
5439           com_err(whoami, 0, "Unable to process user %s : %s",
5440                   user_name, ldap_err2string(rc));
5441           return(rc);
5442         }
5443     }
5444
5445   if (group_count != 1)
5446     {
5447       linklist_free(group_base);
5448       group_count = 0;
5449       group_base = NULL;
5450       sprintf(filter, "(sAMAccountName=%s)", user_name);
5451       attr_array[0] = "UserAccountControl";
5452       attr_array[1] = NULL;
5453       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5454                                &group_base, &group_count, 
5455                                LDAP_SCOPE_SUBTREE)) != 0)
5456         {
5457           com_err(whoami, 0, "Unable to process user %s : %s",
5458                   user_name, ldap_err2string(rc));
5459           return(rc);
5460         }
5461     }
5462   
5463   if (group_count != 1)
5464     {
5465       linklist_free(group_base);
5466       com_err(whoami, 0, "Unable to find user %s in directory",
5467               user_name);
5468       return(LDAP_NO_SUCH_OBJECT);
5469     }
5470
5471   strcpy(distinguished_name, group_base->dn);
5472   ulongValue = atoi((*group_base).value);
5473
5474   if (operation == MEMBER_DEACTIVATE)
5475     ulongValue |= UF_ACCOUNTDISABLE;
5476   else    
5477     ulongValue &= ~UF_ACCOUNTDISABLE;
5478
5479   sprintf(temp, "%ld", ulongValue);
5480
5481   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
5482                                 temp, &modvalues, REPLACE)) == 1)
5483     goto cleanup;
5484
5485   linklist_free(group_base);
5486   group_base = NULL;
5487   group_count = 0;
5488   n = 0;
5489   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
5490
5491   if (strlen(MoiraId) != 0)
5492     {
5493     mitMoiraId_v[0] = MoiraId;
5494     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
5495     }
5496
5497   mods[n] = NULL;
5498   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
5499
5500   for (i = 0; i < n; i++)
5501     free(mods[i]);
5502
5503   free_values(modvalues);
5504
5505   if (rc != LDAP_SUCCESS)
5506     {
5507       com_err(whoami, 0, "Unable to change status of user %s : %s",
5508               user_name, ldap_err2string(rc));
5509     }
5510   
5511  cleanup:
5512   return(rc);
5513 }
5514
5515 int user_delete(LDAP *ldap_handle, char *dn_path, 
5516                 char *u_name, char *MoiraId)
5517 {
5518   char      filter[128];
5519   char      *attr_array[3];
5520   char      distinguished_name[1024];
5521   char      user_name[512];
5522   LK_ENTRY  *group_base;
5523   int       group_count;
5524   int       rc;
5525   char      temp[256];
5526
5527   if (!check_string(u_name))
5528     return(AD_INVALID_NAME);
5529
5530   strcpy(user_name, u_name);
5531   group_count = 0;
5532   group_base = NULL;
5533
5534   if (strlen(MoiraId) != 0)
5535     {
5536       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5537       attr_array[0] = "name";
5538       attr_array[1] = NULL;
5539       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5540                                &group_base, &group_count, 
5541                                LDAP_SCOPE_SUBTREE)) != 0)
5542         {
5543           com_err(whoami, 0, "Unable to process user %s : %s",
5544                   user_name, ldap_err2string(rc));
5545           goto cleanup;
5546         }
5547     }
5548   
5549   if (group_count != 1)
5550     {
5551       linklist_free(group_base);
5552       group_count = 0;
5553       group_base = NULL;
5554       sprintf(filter, "(sAMAccountName=%s)", user_name);
5555       attr_array[0] = "name";
5556       attr_array[1] = NULL;
5557       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5558                                &group_base, &group_count, 
5559                                LDAP_SCOPE_SUBTREE)) != 0)
5560         {
5561           com_err(whoami, 0, "Unable to process user %s : %s",
5562                   user_name, ldap_err2string(rc));
5563           goto cleanup;
5564         }
5565     }
5566
5567   if (group_count != 1)
5568     {
5569       goto cleanup;
5570     }
5571   
5572   strcpy(distinguished_name, group_base->dn);
5573
5574   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
5575     {
5576       com_err(whoami, 0, "Unable to process user %s : %s",
5577               user_name, ldap_err2string(rc));
5578     }
5579
5580   /* Need to add code to delete mit.edu contact */
5581   
5582   if (Exchange)
5583     {
5584       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
5585
5586       if(rc = ldap_delete_s(ldap_handle, temp))
5587         {
5588           com_err(whoami, 0, "Unable to delete user contact for %s",
5589                   user_name);
5590         }
5591     }
5592
5593  cleanup:
5594   linklist_free(group_base);
5595
5596   return(0);
5597 }
5598
5599 void linklist_free(LK_ENTRY *linklist_base)
5600 {
5601   LK_ENTRY *linklist_previous;
5602
5603   while (linklist_base != NULL)
5604     {
5605       if (linklist_base->dn != NULL)
5606         free(linklist_base->dn);
5607
5608       if (linklist_base->attribute != NULL)
5609         free(linklist_base->attribute);
5610
5611       if (linklist_base->value != NULL)
5612         free(linklist_base->value);
5613
5614       if (linklist_base->member != NULL)
5615         free(linklist_base->member);
5616
5617       if (linklist_base->type != NULL)
5618         free(linklist_base->type);
5619
5620       if (linklist_base->list != NULL)
5621         free(linklist_base->list);
5622
5623       linklist_previous = linklist_base;
5624       linklist_base = linklist_previous->next;
5625       free(linklist_previous);
5626     }
5627 }
5628
5629 void free_values(char **modvalues)
5630 {
5631   int i;
5632
5633   i = 0;
5634
5635   if (modvalues != NULL)
5636     {
5637     while (modvalues[i] != NULL)
5638       {
5639         free(modvalues[i]);
5640         modvalues[i] = NULL;
5641         ++i;
5642       }
5643     free(modvalues);
5644   }
5645 }
5646
5647 static int illegalchars[] = {
5648   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5649   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5650   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
5651   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5652   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5653   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5654   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5655   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5656   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5657   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5658   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5659   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5660   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5661   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5662   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5663   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5664 };
5665
5666 static int illegalchars_ldap[] = {
5667   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5668   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5669   0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* SPACE - / */
5670   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
5671   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5672   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */
5673   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5674   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5675   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5676   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5677   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5678   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5679   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5680   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5681   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5682   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5683 };
5684
5685 int check_string(char *s)
5686 {
5687   char  character;
5688   char  *string;
5689
5690   string = s;
5691
5692   for (; *s; s++)
5693     {
5694       character = *s;
5695
5696       if (isupper(character))
5697         character = tolower(character);
5698
5699       if(ActiveDirectory)
5700         {
5701           if (illegalchars[(unsigned) character])
5702             {
5703               com_err(whoami, 0, "Found illegal char '%c' (%d) in string %s",
5704                       character, (unsigned) character, string);
5705               return 0;
5706             }
5707         }
5708       else
5709         {
5710           if (illegalchars_ldap[(unsigned) character])
5711             {
5712               com_err(whoami, 0, "Found illegal char '%c' (%d) in string %s",
5713                       character, (unsigned) character, string);
5714               return 0;
5715             }
5716         }
5717     }
5718
5719   return(1);
5720 }
5721
5722 int check_container_name(char *s)
5723 {
5724   char  character;
5725
5726   for (; *s; s++)
5727     {
5728       character = *s;
5729
5730       if (isupper(character))
5731         character = tolower(character);
5732
5733       if (character == ' ')
5734         continue;
5735
5736       if (illegalchars[(unsigned) character])
5737         return 0;
5738     }
5739
5740   return(1);
5741 }
5742
5743 int mr_connect_cl(char *server, char *client, int version, int auth)
5744 {
5745   int   status;
5746   char  *motd;
5747   char  temp[128];
5748
5749   status = mr_connect(server);
5750
5751   if (status)
5752     {
5753       com_err(whoami, status, "while connecting to Moira");
5754       return status;
5755     }
5756
5757   status = mr_motd(&motd);
5758
5759   if (status)
5760     {
5761       mr_disconnect();
5762       com_err(whoami, status, "while checking server status");
5763       return status;
5764     }
5765
5766   if (motd)
5767     {
5768       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5769       com_err(whoami, status, temp);
5770       mr_disconnect();
5771       return status;
5772     }
5773
5774   status = mr_version(version);
5775
5776   if (status)
5777     {
5778       if (status == MR_UNKNOWN_PROC)
5779         {
5780           if (version > 2)
5781             status = MR_VERSION_HIGH;
5782           else
5783             status = MR_SUCCESS;
5784         }
5785
5786       if (status == MR_VERSION_HIGH)
5787         {
5788           com_err(whoami, 0, "Warning: This client is running newer code "
5789                   "than the server.");
5790                   com_err(whoami, 0, "Some operations may not work.");
5791         }
5792       else if (status && status != MR_VERSION_LOW)
5793         {
5794           com_err(whoami, status, "while setting query version number.");
5795           mr_disconnect();
5796           return status;
5797         }
5798     }
5799
5800   if (auth)
5801     {
5802       status = mr_krb5_auth(client);
5803       if (status)
5804         {
5805           com_err(whoami, status, "while authenticating to Moira.");
5806           mr_disconnect();
5807           return status;
5808         }
5809     }
5810   
5811   return MR_SUCCESS;
5812 }
5813
5814 void AfsToWinAfs(char* path, char* winPath)
5815 {
5816   char* pathPtr;
5817   char* winPathPtr;
5818   strcpy(winPath, WINAFS);
5819   pathPtr = path + strlen(AFS);
5820   winPathPtr = winPath + strlen(WINAFS);
5821   
5822   while (*pathPtr)
5823     {
5824       if (*pathPtr == '/')
5825         *winPathPtr = '\\';
5826       else
5827         *winPathPtr = *pathPtr;
5828       
5829       pathPtr++;
5830       winPathPtr++;
5831     }
5832 }
5833
5834 int GetAceInfo(int ac, char **av, void *ptr)
5835 {
5836   char **call_args;
5837   int   security_flag;
5838
5839   call_args = ptr;
5840   
5841   strcpy(call_args[0], av[L_ACE_TYPE]);
5842   strcpy(call_args[1], av[L_ACE_NAME]);
5843   security_flag = 0;
5844   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5845   return(LDAP_SUCCESS);  
5846 }
5847
5848 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5849 {
5850   char filter[128];
5851   char *attr_array[3];
5852   int  group_count;
5853   int  rc;
5854   LK_ENTRY  *group_base;
5855   
5856   group_count = 0;
5857   group_base = NULL;
5858   
5859   sprintf(filter, "(sAMAccountName=%s)", Name);
5860   attr_array[0] = "sAMAccountName";
5861   attr_array[1] = NULL;
5862
5863   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5864                            &group_base, &group_count, 
5865                            LDAP_SCOPE_SUBTREE)) != 0)
5866     {
5867       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5868               Name, ldap_err2string(rc));
5869       return(1);
5870     }
5871
5872   linklist_free(group_base);
5873   group_base = NULL;
5874
5875   if (group_count == 0)
5876     return(0);
5877   
5878   return(1);
5879 }
5880
5881 #define MAX_ACE 7
5882
5883 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5884                int UpdateGroup, int *ProcessGroup, char *maillist)
5885 {
5886   char  *av[2];
5887   char  GroupName[256];
5888   char  *call_args[7];
5889   int   rc;
5890   char  *AceInfo[4];
5891   char  AceType[32];
5892   char  AceName[128];
5893   char  AceMembership[2];
5894   char  AceOu[256];
5895   char  temp[128];
5896   char  *save_argv[U_END];
5897
5898   if (!SetGroupAce)
5899     {
5900       com_err(whoami, 0, "ProcessAce disabled, skipping");
5901       return(0);
5902     }
5903
5904   strcpy(GroupName, Name);
5905   
5906   if (strcasecmp(Type, "LIST"))
5907     return(1);
5908
5909   while (1)
5910     {
5911       av[0] = GroupName;
5912       AceInfo[0] = AceType;
5913       AceInfo[1] = AceName;
5914       AceInfo[2] = AceMembership;
5915       AceInfo[3] = AceOu;
5916       memset(AceType, '\0', sizeof(AceType));
5917       memset(AceName, '\0', sizeof(AceName));
5918       memset(AceMembership, '\0', sizeof(AceMembership));
5919       memset(AceOu, '\0', sizeof(AceOu));
5920       callback_rc = 0;
5921     
5922       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5923         { 
5924           if(rc != MR_NO_MATCH)
5925             com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5926                     GroupName, error_message(rc));
5927
5928           return(1);
5929         }
5930
5931       if (callback_rc)
5932         {
5933           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5934           return(1);
5935         }
5936
5937       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5938         return(0);
5939
5940       strcpy(temp, AceName);
5941
5942       if (!strcasecmp(AceType, "LIST"))
5943         sprintf(temp, "%s%s", AceName, group_suffix);
5944
5945       if (!UpdateGroup)
5946         {
5947           if (checkADname(ldap_handle, dn_path, temp))
5948               return(0);
5949
5950           (*ProcessGroup) = 1;
5951         }
5952
5953       if (!strcasecmp(AceInfo[0], "LIST"))
5954         {
5955           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5956                              AceMembership, 0, UpdateGroup, maillist))
5957             return(1);
5958
5959           populate_group(ldap_handle, dn_path, AceName, AceOu, AceMembership,
5960                          0, "");
5961         }
5962       else if (!strcasecmp(AceInfo[0], "USER"))
5963         {
5964           av[0] = AceName;
5965           call_args[0] = (char *)ldap_handle;
5966           call_args[1] = dn_path;
5967           call_args[2] = "";
5968           call_args[3] = NULL;
5969           callback_rc = 0;
5970
5971           if(!strcasecmp(AceName, PRODUCTION_PRINCIPAL) ||
5972              !strcasecmp(AceName, TEST_PRINCIPAL))
5973             {
5974               return(1);
5975             }
5976
5977           if (rc = mr_query("get_user_account_by_login", 1, av, 
5978                             save_query_info, save_argv))
5979             {
5980               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5981                       AceName, Name);
5982               return(1);
5983             }
5984
5985           if (rc = user_create(U_END, save_argv, call_args)) 
5986             {
5987               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5988                       AceName, Name);
5989               return(1);
5990             }
5991           
5992           if (callback_rc)
5993             {
5994               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5995                       AceName, Name);
5996               return(1);
5997             }
5998
5999           return(0);
6000         }
6001       else
6002         return(1);
6003
6004       if (!strcasecmp(AceType, "LIST"))
6005         {
6006           if (!strcasecmp(GroupName, AceName))
6007             return(0);
6008         }
6009
6010       strcpy(GroupName, AceName);
6011     }
6012   
6013   return(1);
6014 }
6015
6016 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6017                    char *group_name, char *group_ou, char *group_membership, 
6018                    int group_security_flag, int updateGroup, char *maillist)
6019 {
6020   char  *av[3];
6021   char  *call_args[8];
6022   int   rc;
6023   LK_ENTRY  *group_base;
6024   int  group_count;
6025   char filter[128];
6026   char *attr_array[3];
6027
6028   av[0] = group_name;
6029   call_args[0] = (char *)ldap_handle;
6030   call_args[1] = dn_path;
6031   call_args[2] = group_name;
6032   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
6033   call_args[4] = (char *)updateGroup;
6034   call_args[5] = MoiraId;
6035   call_args[6] = "0";
6036   call_args[7] = NULL;
6037   callback_rc = 0;
6038
6039   group_count = 0;
6040   group_base = NULL;
6041
6042   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
6043     {
6044       moira_disconnect();
6045       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
6046               error_message(rc));
6047       return(rc);
6048     }
6049
6050   if (callback_rc)
6051     {
6052       moira_disconnect();
6053       com_err(whoami, 0, "Unable to create list %s", group_name);
6054       return(callback_rc);
6055     }
6056
6057   return(0);
6058 }
6059
6060 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
6061                    char *group_ou, char *group_membership, 
6062                    int group_security_flag, char *MoiraId)
6063 {
6064   char      *av[3];
6065   char      *call_args[7];
6066   char      *pUserOu;
6067   LK_ENTRY  *ptr;
6068   int       rc;
6069   char      member[512];
6070   char      *s;
6071   char      **members;
6072   int       i = 0;
6073   int       j = 0;
6074   int       n = 0;
6075   char      group_dn[512];
6076   LDAPMod   *mods[20];
6077   char      *member_v[] = {NULL, NULL};
6078   char      *save_argv[U_END];
6079   char      machine_ou[256];
6080   char      NewMachineName[1024];
6081
6082   com_err(whoami, 0, "Populating group %s", group_name);
6083   av[0] = group_name;
6084   call_args[0] = (char *)ldap_handle;
6085   call_args[1] = dn_path;
6086   call_args[2] = group_name;
6087   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS | 
6088                           MOIRA_MACHINE);
6089   call_args[4] = NULL;
6090   member_base = NULL;
6091
6092   if (rc = mr_query("get_end_members_of_list", 1, av,
6093                     member_list_build, call_args))
6094     {
6095       if(rc == MR_LIST)
6096         return(0);
6097       
6098       com_err(whoami, 0, "Unable to populate list %s : %s", 
6099               group_name, error_message(rc));
6100       return(3);
6101     }
6102
6103   members = (char **)malloc(sizeof(char *) * 2);
6104
6105   if (member_base != NULL)
6106     {
6107       ptr = member_base;
6108
6109       while (ptr != NULL)
6110         {
6111           if (!strcasecmp(ptr->type, "LIST"))
6112             {
6113               ptr = ptr->next;
6114               continue;
6115             }
6116           
6117           if (!strcasecmp(ptr->type, "MACHINE") && !ProcessMachineContainer)
6118             {
6119               ptr = ptr->next;
6120               continue;
6121             }
6122             
6123           if(!strcasecmp(ptr->type, "USER"))
6124             {
6125               if(!strcasecmp(ptr->member, PRODUCTION_PRINCIPAL) ||
6126                  !strcasecmp(ptr->member, TEST_PRINCIPAL))
6127                 {
6128                   ptr = ptr->next;
6129                   continue;
6130                 }
6131
6132               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6133                                    "")) == AD_NO_USER_FOUND)
6134                 {
6135                   com_err(whoami, 0, "creating user %s", ptr->member);
6136
6137                   av[0] = ptr->member;
6138                   call_args[0] = (char *)ldap_handle;
6139                   call_args[1] = dn_path;
6140                   call_args[2] = "";
6141                   call_args[3] = NULL;
6142                   callback_rc = 0;
6143                   
6144                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6145                                     save_query_info, save_argv))
6146                     {
6147                       com_err(whoami, 0, "Unable to create user %s " 
6148                               "while populating group %s.", ptr->member,
6149                               group_name);
6150
6151                       return(3);
6152                     }
6153
6154                   if (rc = user_create(U_END, save_argv, call_args)) 
6155                     {
6156                       com_err(whoami, 0, "Unable to create user %s "
6157                               "while populating group %s.", ptr->member,
6158                               group_name);
6159                       
6160                       return(3);
6161                     }
6162           
6163                   if (callback_rc)
6164                     {
6165                       com_err(whoami, 0, "Unable to create user %s "
6166                               "while populating group %s", ptr->member, 
6167                               group_name);
6168
6169                       return(3);
6170                     }
6171                 }
6172
6173               pUserOu = user_ou;
6174                   
6175               if(ActiveDirectory) 
6176                 {
6177                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6178                           dn_path);
6179                 }
6180               else 
6181                 {
6182                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6183                           dn_path);
6184                 }
6185             }
6186           else if (!strcasecmp(ptr->type, "STRING"))
6187             {
6188               if (contact_create(ldap_handle, dn_path, ptr->member,
6189                                  contact_ou))
6190                 return(3);
6191
6192               pUserOu = contact_ou;
6193               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6194                       pUserOu, dn_path);
6195             }
6196           else if (!strcasecmp(ptr->type, "KERBEROS"))
6197             {
6198               if (contact_create(ldap_handle, dn_path, ptr->member, 
6199                                  kerberos_ou))
6200                 return(3);
6201
6202               pUserOu = kerberos_ou;
6203               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6204                       pUserOu, dn_path);
6205             }
6206           else if (!strcasecmp(ptr->type, "MACHINE"))
6207             {
6208               memset(machine_ou, '\0', sizeof(machine_ou));
6209               memset(NewMachineName, '\0', sizeof(NewMachineName));
6210
6211               if (!get_machine_ou(ldap_handle, dn_path, ptr->member,
6212                                  machine_ou, NewMachineName))
6213                 {
6214                   pUserOu = machine_ou;
6215                   sprintf(member, "cn=%s,%s,%s", NewMachineName, pUserOu,
6216                           dn_path);
6217                 }
6218               else
6219                 {
6220                   ptr = ptr->next;                  
6221                   continue;
6222                 }
6223             }
6224
6225           if(i > 1) 
6226             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6227           members[i++] = strdup(member);
6228
6229           ptr = ptr->next;
6230         }
6231     
6232       linklist_free(member_base);
6233       member_base = NULL;
6234     }
6235
6236   members[i] = NULL;
6237
6238   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6239
6240   if(GroupPopulateDelete)
6241     {
6242       n = 0;
6243       ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
6244       mods[n] = NULL;
6245       
6246       if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6247                               mods)) != LDAP_SUCCESS)
6248         {
6249           com_err(whoami, 0,
6250                   "Unable to populate group membership for %s: %s",
6251                   group_dn, ldap_err2string(rc));
6252         }
6253   
6254       for (i = 0; i < n; i++)
6255         free(mods[i]);
6256     }
6257
6258   n = 0;
6259   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6260   mods[n] = NULL;
6261
6262   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6263                           mods)) != LDAP_SUCCESS)
6264     {
6265       com_err(whoami, 0,
6266               "Unable to populate group membership for %s: %s",
6267               group_dn, ldap_err2string(rc));
6268     }
6269   
6270   for (i = 0; i < n; i++)
6271     free(mods[i]);
6272     
6273   free(members);
6274
6275   return(0);
6276 }
6277
6278 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6279                   char *group_name, char *group_ou, char *group_membership, 
6280                   int group_security_flag, int type, char *maillist)
6281 {
6282   char      before_desc[512];
6283   char      before_name[256];
6284   char      before_group_ou[256];
6285   char      before_group_membership[2];
6286   char      distinguishedName[256];
6287   char      ad_distinguishedName[256];
6288   char      filter[128];
6289   char      *attr_array[3];
6290   int       before_security_flag;
6291   int       group_count;
6292   int       rc;
6293   LK_ENTRY  *group_base;
6294   LK_ENTRY  *ptr;
6295   char      ou_both[512];
6296   char      ou_security[512];
6297   char      ou_distribution[512];
6298   char      ou_neither[512];
6299   char      group_dn[512];
6300
6301   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6302   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6303
6304   memset(filter, '\0', sizeof(filter));
6305   group_base = NULL;
6306   group_count = 0;
6307
6308   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6309                         "*", MoiraId, 
6310                         "samAccountName", &group_base, 
6311                         &group_count, filter))
6312     return(rc);
6313
6314   if (type == CHECK_GROUPS)
6315     {
6316       if (group_count == 1)
6317         {
6318           strcpy(group_dn, group_base->dn);
6319
6320           if (!strcasecmp(group_dn, distinguishedName))
6321             {
6322               linklist_free(group_base);
6323               return(0);
6324             }
6325         }
6326
6327       linklist_free(group_base);
6328
6329       if (group_count == 0)
6330         return(AD_NO_GROUPS_FOUND);
6331
6332       if (group_count == 1)
6333         return(AD_WRONG_GROUP_DN_FOUND);
6334
6335       return(AD_MULTIPLE_GROUPS_FOUND);
6336     }
6337
6338   if (group_count == 0)
6339     {
6340       return(AD_NO_GROUPS_FOUND);
6341     }
6342
6343   if (group_count > 1)
6344     {
6345       ptr = group_base;
6346
6347       strcpy(group_dn, ptr->dn);
6348
6349       while (ptr != NULL)
6350         {
6351           if (!strcasecmp(group_dn, ptr->value))
6352             break;
6353
6354           ptr = ptr->next;
6355         }
6356
6357       if (ptr == NULL)
6358         {
6359           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6360                   MoiraId);
6361           ptr = group_base;
6362
6363           while (ptr != NULL)
6364             {
6365               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6366               ptr = ptr->next;
6367             }
6368
6369           linklist_free(group_base);
6370           return(AD_MULTIPLE_GROUPS_FOUND);
6371         }
6372
6373       ptr = group_base;
6374
6375       while (ptr != NULL)
6376         {
6377           strcpy(group_dn, ptr->dn);
6378
6379           if (strcasecmp(group_dn, ptr->value))
6380             rc = ldap_delete_s(ldap_handle, ptr->value);
6381
6382           ptr = ptr->next;
6383         }
6384
6385       linklist_free(group_base);
6386       memset(filter, '\0', sizeof(filter));
6387       group_base = NULL;
6388       group_count = 0;
6389
6390       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6391                             "*", MoiraId, 
6392                             "samAccountName", &group_base, 
6393                             &group_count, filter))
6394         return(rc);
6395
6396       if (group_count == 0)
6397         return(AD_NO_GROUPS_FOUND);
6398
6399       if (group_count > 1)
6400         return(AD_MULTIPLE_GROUPS_FOUND);
6401     }
6402
6403   strcpy(ad_distinguishedName, group_base->dn);
6404   linklist_free(group_base);
6405   group_base = NULL;
6406   group_count = 0;
6407
6408   attr_array[0] = "sAMAccountName";
6409   attr_array[1] = NULL;
6410   
6411   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6412                            &group_base, &group_count, 
6413                            LDAP_SCOPE_SUBTREE)) != 0)
6414     {
6415       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6416               MoiraId, ldap_err2string(rc));
6417       return(rc);
6418     }
6419   
6420   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6421
6422   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6423     {
6424       linklist_free(group_base);
6425       group_base = NULL;
6426       group_count = 0;
6427       return(0);
6428     }
6429
6430   linklist_free(group_base);
6431   group_base = NULL;
6432   group_count = 0;
6433   memset(ou_both, '\0', sizeof(ou_both));
6434   memset(ou_security, '\0', sizeof(ou_security));
6435   memset(ou_distribution, '\0', sizeof(ou_distribution));
6436   memset(ou_neither, '\0', sizeof(ou_neither));
6437   memset(before_name, '\0', sizeof(before_name));
6438   memset(before_desc, '\0', sizeof(before_desc));
6439   memset(before_group_membership, '\0', sizeof(before_group_membership));
6440   
6441   attr_array[0] = "name";
6442   attr_array[1] = NULL;
6443
6444   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6445                            &group_base, &group_count, 
6446                            LDAP_SCOPE_SUBTREE)) != 0)
6447     {
6448       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6449               MoiraId, ldap_err2string(rc));
6450       return(rc);
6451     }
6452
6453   strcpy(before_name, group_base->value);
6454   linklist_free(group_base);
6455   group_base = NULL;
6456   group_count = 0;
6457
6458   attr_array[0] = "description";
6459   attr_array[1] = NULL;
6460   
6461   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6462                            &group_base, &group_count, 
6463                            LDAP_SCOPE_SUBTREE)) != 0)
6464     {
6465       com_err(whoami, 0, 
6466               "Unable to get list description with MoiraId = %s: %s",
6467               MoiraId, ldap_err2string(rc));
6468       return(rc);
6469     }
6470
6471   if (group_count != 0)
6472     {
6473       strcpy(before_desc, group_base->value);
6474       linklist_free(group_base);
6475       group_base = NULL;
6476       group_count = 0;
6477     }
6478  
6479   change_to_lower_case(ad_distinguishedName);  
6480   strcpy(ou_both, group_ou_both);
6481   change_to_lower_case(ou_both);
6482   strcpy(ou_security, group_ou_security);
6483   change_to_lower_case(ou_security);
6484   strcpy(ou_distribution, group_ou_distribution);
6485   change_to_lower_case(ou_distribution);
6486   strcpy(ou_neither, group_ou_neither);
6487   change_to_lower_case(ou_neither);
6488
6489   if (strstr(ad_distinguishedName, ou_both))
6490     {
6491       strcpy(before_group_ou, group_ou_both);
6492       before_group_membership[0] = 'B';
6493       before_security_flag = 1;
6494     }
6495   else if (strstr(ad_distinguishedName, ou_security))
6496     {
6497       strcpy(before_group_ou, group_ou_security);
6498       before_group_membership[0] = 'S';
6499       before_security_flag = 1;
6500     }
6501   else if (strstr(ad_distinguishedName, ou_distribution))
6502     {
6503       strcpy(before_group_ou, group_ou_distribution);
6504       before_group_membership[0] = 'D';
6505       before_security_flag = 0;
6506     }
6507   else if (strstr(ad_distinguishedName, ou_neither))
6508     {
6509       strcpy(before_group_ou, group_ou_neither);
6510       before_group_membership[0] = 'N';
6511       before_security_flag = 0;
6512     }
6513   else
6514     return(AD_NO_OU_FOUND);
6515
6516   rc = group_rename(ldap_handle, dn_path, before_name, 
6517                     before_group_membership, 
6518                     before_group_ou, before_security_flag, before_desc,
6519                     group_name, group_membership, group_ou, 
6520                     group_security_flag,
6521                     before_desc, MoiraId, filter, maillist);
6522
6523   return(rc);
6524 }
6525
6526 void change_to_lower_case(char *ptr)
6527 {
6528   int i;
6529
6530   for (i = 0; i < (int)strlen(ptr); i++)
6531     {
6532       ptr[i] = tolower(ptr[i]);
6533     }
6534 }
6535
6536 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6537                  char *group_name, char *group_membership, 
6538                  char *MoiraId, char *attribute,
6539                  LK_ENTRY **linklist_base, int *linklist_count,
6540                  char *rFilter)
6541 {
6542   LK_ENTRY  *pPtr;
6543   char  filter[128];
6544   char  *attr_array[3];
6545   char  *dn;
6546   int   rc;
6547
6548   (*linklist_base) = NULL;
6549   (*linklist_count) = 0;
6550
6551   if (strlen(rFilter) != 0)
6552     {
6553       strcpy(filter, rFilter);
6554       attr_array[0] = attribute;
6555       attr_array[1] = NULL;
6556       
6557       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6558                                linklist_base, linklist_count, 
6559                                LDAP_SCOPE_SUBTREE)) != 0)
6560         {
6561           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6562                   MoiraId, ldap_err2string(rc));
6563          return(rc);
6564        }
6565
6566     if ((*linklist_count) == 1)
6567       {
6568         strcpy(rFilter, filter);
6569         return(0);
6570       }
6571     }
6572
6573   linklist_free((*linklist_base));
6574   (*linklist_base) = NULL;
6575   (*linklist_count) = 0;
6576
6577   if (strlen(MoiraId) != 0)
6578     {
6579       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6580
6581       attr_array[0] = attribute;
6582       attr_array[1] = NULL;
6583
6584       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6585                                linklist_base, linklist_count, 
6586                                LDAP_SCOPE_SUBTREE)) != 0)
6587         {
6588           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6589                   MoiraId, ldap_err2string(rc));
6590          return(rc);
6591        }
6592     }
6593
6594   if ((*linklist_count) > 1)
6595     {
6596       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6597       pPtr = (*linklist_base);
6598
6599       while (pPtr)
6600         {
6601           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6602                   MoiraId);
6603           pPtr = pPtr->next;
6604         }
6605
6606       linklist_free((*linklist_base));
6607       (*linklist_base) = NULL;
6608       (*linklist_count) = 0;
6609     }
6610
6611   if ((*linklist_count) == 1)
6612     {
6613
6614       pPtr = (*linklist_base);
6615       dn = strdup(pPtr->dn);
6616       dn += 3;
6617
6618       if (!memcmp(dn, group_name, strlen(group_name)))
6619         {
6620           strcpy(rFilter, filter);
6621           return(0);
6622         }
6623     }
6624
6625   linklist_free((*linklist_base));
6626   (*linklist_base) = NULL;
6627   (*linklist_count) = 0;
6628   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6629
6630   attr_array[0] = attribute;
6631   attr_array[1] = NULL;
6632
6633   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6634                            linklist_base, linklist_count, 
6635                            LDAP_SCOPE_SUBTREE)) != 0)
6636     {
6637       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6638               MoiraId, ldap_err2string(rc));
6639       return(rc);
6640     }
6641
6642   if ((*linklist_count) == 1)
6643     {
6644       strcpy(rFilter, filter);
6645       return(0);
6646     }
6647
6648   return(0);
6649 }
6650
6651 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6652 {
6653   char filter[128];
6654   char *attr_array[3];
6655   char SamAccountName[64];
6656   int  group_count;
6657   int  rc;
6658   LK_ENTRY  *group_base;
6659   LK_ENTRY  *gPtr;
6660
6661   group_count = 0;
6662   group_base = NULL;
6663
6664   if (strlen(MoiraId) != 0)
6665     {
6666       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6667
6668       attr_array[0] = "sAMAccountName";
6669       attr_array[1] = NULL;
6670       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6671                                &group_base, &group_count, 
6672                                LDAP_SCOPE_SUBTREE)) != 0)
6673         {
6674           com_err(whoami, 0, "Unable to process user %s : %s",
6675                   UserName, ldap_err2string(rc));
6676           return(rc);
6677         }
6678
6679       if (group_count > 1)
6680         {
6681           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6682                   MoiraId);
6683           gPtr = group_base;
6684
6685           while (gPtr)
6686             {
6687               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6688                       gPtr->value, MoiraId);
6689               gPtr = gPtr->next;
6690             }
6691         }
6692     }
6693
6694   if (group_count != 1)
6695     {
6696       linklist_free(group_base);
6697       group_count = 0;
6698       group_base = NULL;
6699       sprintf(filter, "(sAMAccountName=%s)", UserName);
6700       attr_array[0] = "sAMAccountName";
6701       attr_array[1] = NULL;
6702
6703       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6704                                &group_base, &group_count, 
6705                                LDAP_SCOPE_SUBTREE)) != 0)
6706         {
6707           com_err(whoami, 0, "Unable to process user %s : %s",
6708                   UserName, ldap_err2string(rc));
6709           return(rc);
6710         }
6711     }
6712
6713   if (group_count != 1)
6714     {
6715       linklist_free(group_base);
6716       return(AD_NO_USER_FOUND);
6717     }
6718
6719   strcpy(SamAccountName, group_base->value);
6720   linklist_free(group_base);
6721   group_count = 0;
6722   rc = 0;
6723
6724   if (strcmp(SamAccountName, UserName))
6725     {
6726       com_err(whoami, 0, 
6727               "User object %s with MoiraId %s has mismatched usernames " 
6728               "(LDAP username %s, Moira username %s)", SamAccountName,
6729               MoiraId, SamAccountName, UserName);
6730     }
6731
6732   return(0);
6733 }
6734
6735 void container_get_dn(char *src, char *dest)
6736 {
6737   char *sPtr;
6738   char *array[20];
6739   char name[256];
6740   int  n;
6741
6742   memset(array, '\0', 20 * sizeof(array[0]));
6743
6744   if (strlen(src) == 0)
6745     return;
6746
6747   strcpy(name, src);
6748   sPtr = name;
6749   n = 0;
6750   array[n] = name;
6751   ++n;
6752
6753   while (*sPtr)
6754     {
6755       if ((*sPtr) == '/')
6756         {
6757           (*sPtr) = '\0';
6758           ++sPtr;
6759           array[n] = sPtr;
6760           ++n;
6761         }
6762       else
6763         ++sPtr;
6764     }
6765
6766   strcpy(dest, "OU=");
6767
6768   while (n != 0)
6769     {
6770       strcat(dest, array[n-1]);
6771       --n;
6772       if (n > 0)
6773         {
6774           strcat(dest, ",OU=");
6775         }
6776     }
6777
6778   return;
6779 }
6780
6781 void container_get_name(char *src, char *dest)
6782 {
6783   char *sPtr;
6784   char *dPtr;
6785
6786   if (strlen(src) == 0)
6787     return;
6788
6789   sPtr = src;
6790   dPtr = src;
6791
6792   while (*sPtr)
6793     {
6794       if ((*sPtr) == '/')
6795         {
6796           dPtr = sPtr;
6797           ++dPtr;
6798         }
6799       ++sPtr;
6800     }
6801
6802   strcpy(dest, dPtr);
6803   return;
6804 }
6805
6806 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6807 {
6808   char cName[256];
6809   char *av[7];
6810   int  i;
6811   int  rc;
6812
6813   strcpy(cName, name);
6814
6815   for (i = 0; i < (int)strlen(cName); i++)
6816     {
6817       if (cName[i] == '/')
6818         {
6819           cName[i] = '\0';
6820           av[CONTAINER_NAME] = cName;
6821           av[CONTAINER_DESC] = "";
6822           av[CONTAINER_LOCATION] = "";
6823           av[CONTAINER_CONTACT] = "";
6824           av[CONTAINER_TYPE] = "";
6825           av[CONTAINER_ID] = "";
6826           av[CONTAINER_ROWID] = "";
6827           rc = container_create(ldap_handle, dn_path, 7, av);
6828
6829           if (rc == LDAP_SUCCESS)
6830             {
6831               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6832                       cName);
6833             }
6834
6835           cName[i] = '/';
6836         }
6837     }
6838 }
6839
6840 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6841                      char **before, int afterc, char **after)
6842 {
6843   char      dName[256];
6844   char      cName[256];
6845   char      new_cn[128];
6846   char      new_dn_path[256];
6847   char      temp[256];
6848   char      distinguishedName[256];
6849   char      *pPtr;
6850   int       rc;
6851   int       i;
6852
6853   memset(cName, '\0', sizeof(cName));
6854   container_get_name(after[CONTAINER_NAME], cName);
6855
6856   if (!check_container_name(cName))
6857     {
6858       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6859               cName);
6860       return(AD_INVALID_NAME);
6861     }
6862
6863   memset(distinguishedName, '\0', sizeof(distinguishedName));
6864
6865   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6866                                            distinguishedName, beforec, before))
6867     return(rc);
6868
6869   if (strlen(distinguishedName) == 0)
6870     {
6871       rc = container_create(ldap_handle, dn_path, afterc, after);
6872       return(rc);
6873     }
6874
6875   strcpy(temp, after[CONTAINER_NAME]);
6876   pPtr = temp;
6877
6878   for (i = 0; i < (int)strlen(temp); i++)
6879     {
6880       if (temp[i] == '/')
6881         {
6882           pPtr = &temp[i];
6883         }
6884     }
6885
6886   (*pPtr) = '\0';
6887
6888   container_get_dn(temp, dName);
6889
6890   if (strlen(temp) != 0)
6891     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6892   else
6893     sprintf(new_dn_path, "%s", dn_path);
6894
6895   sprintf(new_cn, "OU=%s", cName);
6896
6897   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6898
6899   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6900                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6901     {
6902       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6903               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6904               ldap_err2string(rc));
6905       return(rc);
6906     }
6907
6908   memset(dName, '\0', sizeof(dName));
6909   container_get_dn(after[CONTAINER_NAME], dName);
6910   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6911
6912   return(rc);
6913 }
6914
6915 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6916 {
6917   char      distinguishedName[256];
6918   int       rc;
6919
6920   memset(distinguishedName, '\0', sizeof(distinguishedName));
6921
6922   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6923                                            distinguishedName, count, av))
6924     return(rc);
6925
6926   if (strlen(distinguishedName) == 0)
6927     return(0);
6928
6929   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6930     {
6931       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6932         container_move_objects(ldap_handle, dn_path, distinguishedName);
6933       else
6934         com_err(whoami, 0, "Unable to delete container %s from directory : %s",
6935                 av[CONTAINER_NAME], ldap_err2string(rc));
6936     }
6937
6938   return(rc);
6939 }
6940
6941 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6942 {
6943   char      *attr_array[3];
6944   LK_ENTRY  *group_base;
6945   int       group_count;
6946   LDAPMod   *mods[20];
6947   char      *objectClass_v[] = {"top", 
6948                            "organizationalUnit", 
6949                            NULL};
6950
6951   char *ou_v[] = {NULL, NULL};
6952   char *name_v[] = {NULL, NULL};
6953   char *moiraId_v[] = {NULL, NULL};
6954   char *desc_v[] = {NULL, NULL};
6955   char *managedBy_v[] = {NULL, NULL};
6956   char dName[256];
6957   char cName[256];
6958   char managedByDN[256];
6959   char filter[256];
6960   char temp[256];
6961   int  n;
6962   int  i;
6963   int  rc;
6964     
6965   memset(filter, '\0', sizeof(filter));
6966   memset(dName, '\0', sizeof(dName));
6967   memset(cName, '\0', sizeof(cName));
6968   memset(managedByDN, '\0', sizeof(managedByDN));
6969   container_get_dn(av[CONTAINER_NAME], dName);
6970   container_get_name(av[CONTAINER_NAME], cName);
6971
6972   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6973     {
6974       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6975               cName);
6976       return(AD_INVALID_NAME);
6977     }
6978
6979   if (!check_container_name(cName))
6980     {
6981       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6982               cName);
6983       return(AD_INVALID_NAME);
6984     }
6985
6986   n = 0;
6987   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6988   name_v[0] = cName;
6989   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6990   ou_v[0] = cName;
6991   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6992
6993   if (strlen(av[CONTAINER_ROWID]) != 0)
6994     {
6995       moiraId_v[0] = av[CONTAINER_ROWID];
6996       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6997     }
6998
6999   if (strlen(av[CONTAINER_DESC]) != 0)
7000     {
7001       desc_v[0] = av[CONTAINER_DESC];
7002       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
7003     }
7004
7005   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7006     {
7007       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7008         {
7009           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7010                               kerberos_ou))
7011             {
7012               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7013                       kerberos_ou, dn_path);
7014               managedBy_v[0] = managedByDN;
7015               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
7016             }
7017         }
7018       else
7019         {
7020           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7021             {
7022               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7023                       "(objectClass=user)))", av[CONTAINER_ID]);
7024             }
7025
7026           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7027             {
7028               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7029                       av[CONTAINER_ID]);
7030             }
7031
7032           if (strlen(filter) != 0)
7033             {
7034               attr_array[0] = "distinguishedName";
7035               attr_array[1] = NULL;
7036               group_count = 0;
7037               group_base = NULL;
7038               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7039                                        attr_array, 
7040                                        &group_base, &group_count, 
7041                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7042                 {
7043                   if (group_count == 1)
7044                     {
7045                       strcpy(managedByDN, group_base->value);
7046                       managedBy_v[0] = managedByDN;
7047                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
7048                     }
7049                   linklist_free(group_base);
7050                   group_base = NULL;
7051                   group_count = 0;
7052                 }
7053             }
7054         }
7055     }
7056   
7057   mods[n] = NULL;
7058
7059   sprintf(temp, "%s,%s", dName, dn_path);
7060   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
7061   
7062   for (i = 0; i < n; i++)
7063     free(mods[i]);
7064   
7065   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
7066     {
7067       com_err(whoami, 0, "Unable to create container %s : %s",
7068               cName, ldap_err2string(rc));
7069       return(rc);
7070     }
7071
7072   if (rc == LDAP_ALREADY_EXISTS)
7073     {
7074       if (strlen(av[CONTAINER_ROWID]) != 0)
7075         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
7076     }
7077
7078   return(rc);
7079 }
7080
7081 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
7082                      char **before, int afterc, char **after)
7083 {
7084   char distinguishedName[256];
7085   int  rc;
7086
7087   memset(distinguishedName, '\0', sizeof(distinguishedName));
7088
7089   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
7090                                            distinguishedName, afterc, after))
7091     return(rc);
7092
7093   if (strlen(distinguishedName) == 0)
7094     {
7095       rc = container_create(ldap_handle, dn_path, afterc, after);
7096       return(rc);
7097     }
7098   
7099   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
7100   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
7101                           after);
7102
7103   return(rc);
7104 }
7105
7106 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
7107                                     char *distinguishedName, int count, 
7108                                     char **av)
7109 {
7110   char      *attr_array[3];
7111   LK_ENTRY  *group_base;
7112   int       group_count;
7113   char      dName[256];
7114   char      cName[256];
7115   char      filter[512];
7116   int       rc;
7117
7118   memset(filter, '\0', sizeof(filter));
7119   memset(dName, '\0', sizeof(dName));
7120   memset(cName, '\0', sizeof(cName));
7121   container_get_dn(av[CONTAINER_NAME], dName);
7122   container_get_name(av[CONTAINER_NAME], cName);
7123
7124   if (strlen(dName) == 0)
7125     {
7126       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7127               av[CONTAINER_NAME]);
7128       return(AD_INVALID_NAME);
7129     }
7130
7131   if (!check_container_name(cName))
7132     {
7133       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7134               cName);
7135       return(AD_INVALID_NAME);
7136     }
7137   
7138   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7139           av[CONTAINER_ROWID]);
7140   attr_array[0] = "distinguishedName";
7141   attr_array[1] = NULL;
7142   group_count = 0;
7143   group_base = NULL;
7144
7145   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7146                            &group_base, &group_count, 
7147                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7148     {
7149       if (group_count == 1)
7150         {
7151           strcpy(distinguishedName, group_base->value);
7152         }
7153
7154       linklist_free(group_base);
7155       group_base = NULL;
7156       group_count = 0;
7157     }
7158
7159   if (strlen(distinguishedName) == 0)
7160     {
7161       sprintf(filter, "(&(objectClass=organizationalUnit)"
7162               "(distinguishedName=%s,%s))", dName, dn_path);
7163       attr_array[0] = "distinguishedName";
7164       attr_array[1] = NULL;
7165       group_count = 0;
7166       group_base = NULL;
7167
7168       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7169                                &group_base, &group_count, 
7170                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7171         {
7172           if (group_count == 1)
7173             {
7174               strcpy(distinguishedName, group_base->value);
7175             }
7176
7177           linklist_free(group_base);
7178           group_base = NULL;
7179           group_count = 0;
7180         }
7181     }
7182
7183   return(0);
7184 }
7185
7186 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7187                        char *distinguishedName, int count, char **av)
7188 {
7189   char      *attr_array[5];
7190   LK_ENTRY  *group_base;
7191   LK_ENTRY  *pPtr;
7192   LDAPMod   *mods[20];
7193   int       group_count;
7194   char      filter[512];
7195   char      *moiraId_v[] = {NULL, NULL};
7196   char      *desc_v[] = {NULL, NULL};
7197   char      *managedBy_v[] = {NULL, NULL};
7198   char      managedByDN[256];
7199   char      moiraId[64];
7200   char      desc[256];
7201   char      ad_path[512];
7202   int       rc;
7203   int       i;
7204   int       n;
7205
7206
7207   strcpy(ad_path, distinguishedName);
7208
7209   if (strlen(dName) != 0)
7210     sprintf(ad_path, "%s,%s", dName, dn_path);
7211
7212   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7213           ad_path);
7214
7215   if (strlen(av[CONTAINER_ID]) != 0)
7216     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7217             av[CONTAINER_ROWID]);
7218
7219   attr_array[0] = "mitMoiraId";
7220   attr_array[1] = "description";
7221   attr_array[2] = "managedBy";
7222   attr_array[3] = NULL;
7223   group_count = 0;
7224   group_base = NULL;
7225
7226   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7227                            &group_base, &group_count, 
7228                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7229     {
7230       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7231               av[CONTAINER_NAME], ldap_err2string(rc));
7232       return(rc);
7233     }
7234
7235   memset(managedByDN, '\0', sizeof(managedByDN));
7236   memset(moiraId, '\0', sizeof(moiraId));
7237   memset(desc, '\0', sizeof(desc));
7238   pPtr = group_base;
7239
7240   while (pPtr)
7241     {
7242       if (!strcasecmp(pPtr->attribute, "description"))
7243         strcpy(desc, pPtr->value);
7244       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7245         strcpy(managedByDN, pPtr->value);
7246       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7247         strcpy(moiraId, pPtr->value);
7248       pPtr = pPtr->next;
7249     }
7250
7251   linklist_free(group_base);
7252   group_base = NULL;
7253   group_count = 0;
7254
7255   n = 0;
7256   if (strlen(av[CONTAINER_ROWID]) != 0)
7257     {
7258       moiraId_v[0] = av[CONTAINER_ROWID];
7259       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7260     }
7261
7262   if (strlen(av[CONTAINER_DESC]) != 0)
7263     {
7264       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7265                        dName);
7266     }
7267   else
7268     {
7269       if (strlen(desc) != 0)
7270         {
7271           attribute_update(ldap_handle, ad_path, "", "description", dName);
7272         }
7273     }
7274
7275   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7276     {
7277       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7278         {
7279           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7280                               kerberos_ou))
7281             {
7282               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7283                       kerberos_ou, dn_path);
7284               managedBy_v[0] = managedByDN;
7285               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7286             }
7287           else
7288             {
7289               if (strlen(managedByDN) != 0)
7290                 {
7291                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7292                                    dName);
7293                 }
7294             }
7295         }
7296       else
7297         {
7298           memset(filter, '\0', sizeof(filter));
7299
7300           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7301             {
7302               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7303                       "(objectClass=user)))", av[CONTAINER_ID]);
7304             }
7305
7306           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7307             {
7308               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7309                       av[CONTAINER_ID]);
7310             }
7311
7312           if (strlen(filter) != 0)
7313             {
7314               attr_array[0] = "distinguishedName";
7315               attr_array[1] = NULL;
7316               group_count = 0;
7317               group_base = NULL;
7318               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7319                                        attr_array, &group_base, &group_count, 
7320                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7321                 {
7322                   if (group_count == 1)
7323                     {
7324                       strcpy(managedByDN, group_base->value);
7325                       managedBy_v[0] = managedByDN;
7326                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7327                     }
7328                   else
7329                     {
7330                       if (strlen(managedByDN) != 0)
7331                         {
7332                           attribute_update(ldap_handle, ad_path, "", 
7333                                            "managedBy", dName);
7334                         }
7335                     }
7336
7337                   linklist_free(group_base);
7338                   group_base = NULL;
7339                   group_count = 0;
7340                 }
7341             }
7342           else
7343             {
7344               if (strlen(managedByDN) != 0)
7345                 {
7346                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7347                                    dName);
7348                 }
7349             }
7350         }
7351     }
7352
7353   mods[n] = NULL;
7354
7355   if (n == 0)
7356     return(LDAP_SUCCESS);
7357
7358   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7359
7360   for (i = 0; i < n; i++)
7361     free(mods[i]);
7362
7363   if (rc != LDAP_SUCCESS)
7364     {
7365       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7366               av[CONTAINER_NAME], ldap_err2string(rc));
7367       return(rc);
7368     }
7369   
7370   return(rc);
7371 }
7372
7373 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7374 {
7375   char      *attr_array[3];
7376   LK_ENTRY  *group_base;
7377   LK_ENTRY  *pPtr;
7378   int       group_count;
7379   char      filter[512];
7380   char      new_cn[128];
7381   char      temp[256];
7382   int       rc;
7383   int       NumberOfEntries = 10;
7384   int       i;
7385   int       count;
7386
7387   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7388
7389   for (i = 0; i < 3; i++)
7390     {
7391       memset(filter, '\0', sizeof(filter));
7392
7393       if (i == 0)
7394         {
7395           strcpy(filter, "(!(|(objectClass=computer)"
7396                  "(objectClass=organizationalUnit)))");
7397           attr_array[0] = "cn";
7398           attr_array[1] = NULL;
7399         }
7400       else if (i == 1)
7401         {
7402           strcpy(filter, "(objectClass=computer)");
7403           attr_array[0] = "cn";
7404           attr_array[1] = NULL;
7405         }
7406       else
7407         {
7408           strcpy(filter, "(objectClass=organizationalUnit)");
7409           attr_array[0] = "ou";
7410           attr_array[1] = NULL;
7411         }
7412
7413       while (1)
7414         {
7415           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7416                                    &group_base, &group_count, 
7417                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7418             {
7419               break;
7420             }
7421
7422           if (group_count == 0)
7423             break;
7424
7425           pPtr = group_base;
7426
7427           while(pPtr)
7428             {
7429               if (!strcasecmp(pPtr->attribute, "cn"))
7430                 {
7431                   sprintf(new_cn, "cn=%s", pPtr->value);
7432                   if (i == 0)
7433                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7434                   if (i == 1)
7435                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7436                   count = 1;
7437
7438                   while (1)
7439                     {
7440                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7441                                          TRUE, NULL, NULL);
7442                       if (rc == LDAP_ALREADY_EXISTS)
7443                         {
7444                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7445                           ++count;
7446                         }
7447                       else
7448                         break;
7449                     }
7450                 }
7451               else if (!strcasecmp(pPtr->attribute, "ou"))
7452                 {
7453                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7454                 }
7455
7456               pPtr = pPtr->next;
7457             }
7458
7459           linklist_free(group_base);
7460           group_base = NULL;
7461           group_count = 0;
7462         }
7463     }
7464
7465   return(0);
7466 }
7467
7468 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7469                    char *machine_ou, char *NewMachineName)
7470 {
7471   LK_ENTRY  *group_base;
7472   int  group_count;
7473   int  i;
7474   char filter[128];
7475   char *attr_array[3];
7476   char cn[256];
7477   char dn[256];
7478   char temp[256];
7479   char *pPtr;
7480   int   rc;
7481
7482   strcpy(NewMachineName, member);
7483   rc = moira_connect();
7484   rc = GetMachineName(NewMachineName);
7485   moira_disconnect();
7486
7487   if (strlen(NewMachineName) == 0)
7488     {
7489       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7490               member);
7491       return(1);
7492     }
7493
7494   pPtr = NULL;
7495   pPtr = strchr(NewMachineName, '.');
7496
7497   if (pPtr != NULL)
7498     (*pPtr) = '\0';
7499
7500   group_base = NULL;
7501   group_count = 0;
7502   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7503   attr_array[0] = "cn";
7504   attr_array[1] = NULL;
7505   sprintf(temp, "%s", dn_path);
7506
7507   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7508                            &group_base, &group_count, 
7509                            LDAP_SCOPE_SUBTREE)) != 0)
7510     {
7511       com_err(whoami, 0, "Unable to process machine %s : %s",
7512               member, ldap_err2string(rc));
7513       return(1);
7514     }
7515
7516   if (group_count != 1)
7517     {
7518       return(1);
7519     }
7520
7521   strcpy(dn, group_base->dn);
7522   strcpy(cn, group_base->value);
7523
7524   for (i = 0; i < (int)strlen(dn); i++)
7525     dn[i] = tolower(dn[i]);
7526
7527   for (i = 0; i < (int)strlen(cn); i++)
7528     cn[i] = tolower(cn[i]);
7529
7530   linklist_free(group_base);
7531   pPtr = NULL;
7532   pPtr = strstr(dn, cn);
7533
7534   if (pPtr == NULL)
7535     {
7536       com_err(whoami, 0, "Unable to process machine %s",
7537               member);
7538       return(1);
7539     }
7540
7541   pPtr += strlen(cn) + 1;
7542   strcpy(machine_ou, pPtr);
7543   pPtr = NULL;
7544   pPtr = strstr(machine_ou, "dc=");
7545
7546   if (pPtr == NULL)
7547     {
7548       com_err(whoami, 0, "Unable to process machine %s",
7549               member);
7550       return(1);
7551     }
7552
7553   --pPtr;
7554   (*pPtr) = '\0';
7555
7556   return(0);
7557 }
7558
7559 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7560                        char *MoiraMachineName, char *DestinationOu)
7561 {
7562   char        NewCn[128];
7563   char        OldDn[512];
7564   char        MachineName[128];
7565   char        filter[128];
7566   char        *attr_array[3];
7567   char        NewOu[256];
7568   char        *cPtr = NULL;
7569   int         group_count;
7570   long        rc;
7571   LK_ENTRY    *group_base;
7572
7573   group_count = 0;
7574   group_base = NULL;
7575   
7576   strcpy(MachineName, MoiraMachineName);
7577   rc = GetMachineName(MachineName);
7578
7579   if (strlen(MachineName) == 0)
7580     {
7581       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7582               MoiraMachineName);
7583       return(1);
7584     }
7585   
7586   cPtr = strchr(MachineName, '.');
7587
7588   if (cPtr != NULL)
7589     (*cPtr) = '\0';
7590
7591   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7592   attr_array[0] = "sAMAccountName";
7593   attr_array[1] = NULL;
7594
7595   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7596                            &group_base, 
7597                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7598     {
7599       com_err(whoami, 0, "Unable to process machine %s : %s",
7600               MoiraMachineName, ldap_err2string(rc));
7601       return(1);
7602     }
7603   
7604   if (group_count == 1)
7605     strcpy(OldDn, group_base->dn);
7606
7607   linklist_free(group_base);
7608   group_base = NULL;
7609
7610   if (group_count != 1)
7611     {
7612       com_err(whoami, 0, "Unable to find machine %s in directory: %s", 
7613               MoiraMachineName);
7614       return(1);
7615     }
7616
7617   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7618   cPtr = strchr(OldDn, ',');
7619
7620   if (cPtr != NULL)
7621     {
7622       ++cPtr;
7623       if (!strcasecmp(cPtr, NewOu))
7624         return(0);
7625     }
7626
7627   sprintf(NewCn, "CN=%s", MachineName);
7628   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7629
7630   return(rc);
7631 }
7632
7633 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7634 {
7635   char    Name[128];
7636   char    *pPtr;
7637   int     rc;
7638   
7639   memset(Name, '\0', sizeof(Name));
7640   strcpy(Name, machine_name);
7641   pPtr = NULL;
7642   pPtr = strchr(Name, '.');
7643
7644   if (pPtr != NULL)
7645     (*pPtr) = '\0';
7646
7647   strcat(Name, "$");
7648   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7649 }
7650
7651 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7652                                 char *machine_name, char *container_name)
7653 {
7654   int     rc;
7655   char    *av[2];
7656   char    *call_args[2];
7657   
7658   av[0] = machine_name;
7659   call_args[0] = (char *)container_name;
7660   rc = mr_query("get_machine_to_container_map", 1, av, 
7661                 machine_GetMoiraContainer, call_args);
7662   return(rc);
7663 }
7664
7665 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7666 {
7667   char **call_args;
7668   
7669   call_args = ptr;
7670   strcpy(call_args[0], av[1]);
7671   return(0);
7672 }
7673
7674 int Moira_container_group_create(char **after)
7675 {
7676   long rc;
7677   char GroupName[64];
7678   char *argv[20];
7679   
7680   memset(GroupName, '\0', sizeof(GroupName));
7681   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7682                               after[CONTAINER_ROWID]);
7683   if (rc)
7684     return rc;
7685   
7686   argv[L_NAME] = GroupName;
7687   argv[L_ACTIVE] = "1";
7688   argv[L_PUBLIC] = "0";
7689   argv[L_HIDDEN] = "0";
7690   argv[L_MAILLIST] = "0";
7691   argv[L_GROUP] = "1";
7692   argv[L_GID] = UNIQUE_GID;
7693   argv[L_NFSGROUP] = "0";
7694   argv[L_MAILMAN] = "0";
7695   argv[L_MAILMAN_SERVER] = "[NONE]";
7696   argv[L_DESC] = "auto created container group";
7697   argv[L_ACE_TYPE] = "USER";
7698   argv[L_MEMACE_TYPE] = "USER";
7699   argv[L_ACE_NAME] = "sms";
7700   argv[L_MEMACE_NAME] = "sms";
7701
7702   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7703     {
7704       com_err(whoami, 0, 
7705               "Unable to create container group %s for container %s: %s",
7706               GroupName, after[CONTAINER_NAME], error_message(rc));
7707     }
7708
7709   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7710   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7711   
7712   return(rc);
7713 }
7714
7715 int Moira_container_group_update(char **before, char **after)
7716 {
7717   long rc;
7718   char BeforeGroupName[64];
7719   char AfterGroupName[64];
7720   char *argv[20];
7721   
7722   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7723     return(0);
7724
7725   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7726   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7727   if (strlen(BeforeGroupName) == 0)
7728     return(0);
7729
7730   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7731   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7732                               after[CONTAINER_ROWID]);
7733   if (rc)
7734     return rc;
7735
7736   if (strcasecmp(BeforeGroupName, AfterGroupName))
7737     {
7738       argv[L_NAME] = BeforeGroupName;
7739       argv[L_NAME + 1] = AfterGroupName;
7740       argv[L_ACTIVE + 1] = "1";
7741       argv[L_PUBLIC + 1] = "0";
7742       argv[L_HIDDEN + 1] = "0";
7743       argv[L_MAILLIST + 1] = "0";
7744       argv[L_GROUP + 1] = "1";
7745       argv[L_GID + 1] = UNIQUE_GID;
7746       argv[L_NFSGROUP + 1] = "0";
7747       argv[L_MAILMAN + 1] = "0";
7748       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7749       argv[L_DESC + 1] = "auto created container group";
7750       argv[L_ACE_TYPE + 1] = "USER";
7751       argv[L_MEMACE_TYPE + 1] = "USER";
7752       argv[L_ACE_NAME + 1] = "sms";
7753       argv[L_MEMACE_NAME + 1] = "sms";
7754       
7755       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7756         {
7757           com_err(whoami, 0, 
7758                   "Unable to rename container group from %s to %s: %s",
7759                   BeforeGroupName, AfterGroupName, error_message(rc));
7760         }
7761     }
7762   
7763   return(rc);
7764 }
7765
7766 int Moira_container_group_delete(char **before)
7767 {
7768   long rc = 0;
7769   char *argv[13];
7770   char GroupName[64];
7771   char ParentGroupName[64];
7772   
7773   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7774   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7775
7776   memset(GroupName, '\0', sizeof(GroupName));
7777
7778   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7779     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7780   
7781   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7782     {
7783       argv[0] = ParentGroupName;
7784       argv[1] = "LIST";
7785       argv[2] = GroupName;
7786
7787       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7788         {
7789           com_err(whoami, 0, 
7790                   "Unable to delete container group %s from list: %s",
7791                   GroupName, ParentGroupName, error_message(rc));
7792         }
7793     }
7794   
7795   if (strlen(GroupName) != 0)
7796     {
7797       argv[0] = GroupName;
7798
7799       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7800         {
7801           com_err(whoami, 0, "Unable to delete container group %s : %s",
7802                   GroupName, error_message(rc));
7803         }
7804     }
7805   
7806   return(rc);
7807 }
7808
7809 int Moira_groupname_create(char *GroupName, char *ContainerName,
7810                            char *ContainerRowID)
7811 {
7812   char *ptr;
7813   char *ptr1;
7814   char temp[64];
7815   char newGroupName[64];
7816   char tempGroupName[64];
7817   char tempgname[64];
7818   char *argv[1];
7819   int  i;
7820   long rc;
7821
7822   strcpy(temp, ContainerName);
7823   
7824   ptr1 = strrchr(temp, '/');
7825
7826   if (ptr1 != NULL)
7827   {
7828     *ptr1 = '\0';
7829     ptr = ++ptr1;
7830     ptr1 = strrchr(temp, '/');
7831
7832     if (ptr1 != NULL)
7833     {
7834         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7835     }
7836     else
7837         strcpy(tempgname, ptr);
7838   }
7839   else
7840     strcpy(tempgname, temp);
7841
7842   if (strlen(tempgname) > 25)
7843     tempgname[25] ='\0';
7844
7845   sprintf(newGroupName, "cnt-%s", tempgname);
7846
7847   /* change everything to lower case */
7848   ptr = newGroupName;
7849
7850   while (*ptr)
7851     {
7852       if (isupper(*ptr))
7853         *ptr = tolower(*ptr);
7854
7855       if (*ptr == ' ')
7856         *ptr = '-';
7857
7858       ptr++;
7859     }
7860
7861   strcpy(tempGroupName, newGroupName);
7862   i = (int)'0';
7863
7864   /* append 0-9 then a-z if a duplicate is found */
7865   while(1)
7866     {
7867       argv[0] = newGroupName;
7868
7869       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7870         {
7871           if (rc == MR_NO_MATCH)
7872             break;
7873           com_err(whoami, 0, "Moira error while creating group name for "
7874                   "container %s : %s", ContainerName, error_message(rc));
7875           return rc;
7876         }
7877
7878       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7879
7880       if (i == (int)'z')
7881         {
7882           com_err(whoami, 0, "Unable to find a unique group name for "
7883                   "container %s: too many duplicate container names",
7884                   ContainerName);
7885           return 1;
7886         }
7887
7888       if (i == '9')
7889         i = 'a';
7890       else
7891         i++;
7892     }
7893
7894   strcpy(GroupName, newGroupName);
7895   return(0);
7896 }
7897
7898 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7899 {
7900   long rc;
7901   char *argv[3];
7902   
7903   argv[0] = origContainerName;
7904   argv[1] = GroupName;
7905   
7906   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7907     {
7908       com_err(whoami, 0, 
7909               "Unable to set container group %s in container %s: %s",
7910               GroupName, origContainerName, error_message(rc));
7911     }
7912   
7913   return(0);
7914 }
7915
7916 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7917  {
7918    char ContainerName[64];
7919    char ParentGroupName[64];
7920    char *argv[3];
7921    long rc;
7922
7923    strcpy(ContainerName, origContainerName);
7924    
7925    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7926
7927    /* top-level container */
7928    if (strlen(ParentGroupName) == 0)
7929      return(0);
7930    
7931    argv[0] = ParentGroupName;
7932    argv[1] = "LIST";
7933    argv[2] = GroupName;
7934
7935    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7936      {
7937        com_err(whoami, 0, 
7938                "Unable to add container group %s to parent group %s: %s",
7939                GroupName, ParentGroupName, error_message(rc));
7940      }
7941    
7942    return(0);
7943  }
7944
7945 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7946 {
7947   char **call_args;
7948   
7949   call_args = ptr;
7950   strcpy(call_args[0], av[1]);
7951
7952   return(0);
7953 }
7954
7955 int Moira_getGroupName(char *origContainerName, char *GroupName,
7956                        int ParentFlag)
7957 {
7958   char ContainerName[64];
7959   char *argv[3];
7960   char *call_args[3];
7961   char *ptr;
7962   long rc;
7963
7964   strcpy(ContainerName, origContainerName);
7965
7966   if (ParentFlag)
7967     {
7968       ptr = strrchr(ContainerName, '/');
7969
7970       if (ptr != NULL)
7971         (*ptr) = '\0';
7972       else
7973         return(0);
7974     }
7975
7976   argv[0] = ContainerName;
7977   argv[1] = NULL;
7978   call_args[0] = GroupName;
7979   call_args[1] = NULL;
7980
7981   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7982                       call_args)))
7983     {
7984       if (strlen(GroupName) != 0)
7985         return(0);
7986     }
7987
7988   if (rc)
7989     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7990             ContainerName, error_message(rc));
7991   else
7992     com_err(whoami, 0, "Unable to get container group from container %s",
7993             ContainerName);
7994   
7995   return(0);
7996 }
7997
7998 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7999                                           int DeleteMachine)
8000 {
8001   char *argv[3];
8002   long rc;
8003   
8004   if (strcmp(GroupName, "[none]") == 0)
8005     return 0;
8006
8007   argv[0] = GroupName;
8008   argv[1] = "MACHINE";
8009   argv[2] = MachineName;
8010
8011   if (!DeleteMachine)
8012     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
8013   else
8014     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
8015
8016   if (rc)
8017     {
8018       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
8019               MachineName, GroupName, error_message(rc));
8020     }
8021
8022   return(0);
8023 }
8024
8025 int GetMachineName(char *MachineName)
8026 {
8027   char    *args[2];
8028   char    NewMachineName[1024];
8029   char    *szDot;
8030   int     rc = 0;
8031   int     i;
8032   DWORD   dwLen = 0;
8033   char    *call_args[2];
8034   
8035   // If the address happens to be in the top-level MIT domain, great!
8036   strcpy(NewMachineName, MachineName);
8037
8038   for (i = 0; i < (int)strlen(NewMachineName); i++)
8039     NewMachineName[i] = toupper(NewMachineName[i]);
8040
8041   szDot = strchr(NewMachineName,'.');
8042
8043   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
8044     {
8045       return(0);
8046     }
8047   
8048   // If not, see if it has a Moira alias in the top-level MIT domain.
8049   memset(NewMachineName, '\0', sizeof(NewMachineName));
8050   args[0] = "*";
8051   args[1] = MachineName;
8052   call_args[0] = NewMachineName;
8053   call_args[1] = NULL;
8054
8055   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
8056     {
8057       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
8058               MachineName, error_message(rc));
8059       strcpy(MachineName, "");
8060       return(0);
8061     }
8062   
8063   if (strlen(NewMachineName) != 0)
8064     strcpy(MachineName, NewMachineName);
8065   else
8066     strcpy(MachineName, "");
8067
8068   return(0);
8069 }
8070
8071 int ProcessMachineName(int ac, char **av, void *ptr)
8072 {
8073   char    **call_args;
8074   char    MachineName[1024];
8075   char    *szDot;
8076   int     i;
8077   
8078   call_args = ptr;
8079
8080   if (strlen(call_args[0]) == 0)
8081     {
8082       strcpy(MachineName, av[0]);
8083
8084       for (i = 0; i < (int)strlen(MachineName); i++)
8085         MachineName[i] = toupper(MachineName[i]);
8086
8087       szDot = strchr(MachineName,'.');
8088
8089         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
8090           {
8091             strcpy(call_args[0], MachineName);
8092           }
8093     }
8094
8095   return(0);
8096 }
8097
8098 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
8099 {
8100   int i;
8101   
8102   if (*UseSFU30)
8103     {
8104       for (i = 0; i < n; i++)
8105         {
8106           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
8107             mods[i]->mod_type = "uidNumber";
8108         }
8109
8110       (*UseSFU30) = 0;
8111     }
8112   else
8113     {
8114       for (i = 0; i < n; i++)
8115         {
8116           if (!strcmp(mods[i]->mod_type, "uidNumber"))
8117             mods[i]->mod_type = "msSFU30UidNumber";
8118         }
8119
8120       (*UseSFU30) = 1;
8121     }
8122 }
8123
8124 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8125                      char *DistinguishedName,
8126                      char *WinHomeDir, char *WinProfileDir,
8127                      char **homedir_v, char **winProfile_v,
8128                      char **drives_v, LDAPMod **mods, 
8129                      int OpType, int n)
8130 {
8131   char cWeight[3];
8132   char cPath[1024];
8133   char path[1024];
8134   char winPath[1024];
8135   char winProfile[1024];
8136   char homeDrive[8];
8137   char homedir[1024];
8138   char apple_homedir[1024];
8139   char *apple_homedir_v[] = {NULL, NULL};
8140   int  last_weight;
8141   int  i;
8142   int  rc;
8143   LDAPMod *DelMods[20];
8144   char *argv[3];
8145   char *save_argv[FS_END];
8146   char *fsgroup_save_argv[2];
8147
8148   memset(homeDrive, '\0', sizeof(homeDrive));
8149   memset(path, '\0', sizeof(path));
8150   memset(winPath, '\0', sizeof(winPath));
8151   memset(winProfile, '\0', sizeof(winProfile));
8152
8153   if(!ActiveDirectory) 
8154     {
8155       if (rc = moira_connect())
8156         {
8157           critical_alert("Ldap incremental",
8158                          "Error contacting Moira server : %s",
8159                          error_message(rc));
8160           return;
8161         }
8162       
8163       argv[0] = user_name;
8164
8165       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8166                           save_argv)))
8167         {
8168           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8169              !strcmp(save_argv[FS_TYPE], "MUL"))
8170             {
8171         
8172               argv[0] = save_argv[FS_NAME];
8173               fsgCount = 0;
8174               
8175               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8176                                   save_fsgroup_info, fsgroup_save_argv)))
8177                 {
8178                   if(fsgCount)
8179                     {
8180                       argv[0] = fsgroup_save_argv[0];
8181                       
8182                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8183                                           save_query_info, save_argv)))
8184                         {
8185                           strcpy(path, save_argv[FS_PACK]);
8186                         }
8187                     }
8188                 }
8189             }
8190           else
8191             {
8192               strcpy(path, save_argv[FS_PACK]);
8193             }
8194         }
8195       
8196       moira_disconnect();
8197
8198       if (strlen(path))
8199         {
8200           if (!strnicmp(path, AFS, strlen(AFS)))
8201             {
8202               sprintf(homedir, "%s", path);
8203               sprintf(apple_homedir, "%s/MacData", path);
8204               homedir_v[0] = homedir;
8205               apple_homedir_v[0] = apple_homedir;
8206               ADD_ATTR("homeDirectory", homedir_v, OpType);
8207               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8208                        OpType);
8209             }
8210         }
8211       else
8212         {
8213           homedir_v[0] = "NONE";
8214           apple_homedir_v[0] = "NONE";
8215           ADD_ATTR("homeDirectory", homedir_v, OpType);
8216           ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8217                    OpType);
8218         }
8219
8220       return(n);
8221     }
8222  
8223   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8224       (!strcasecmp(WinProfileDir, "[afs]")))
8225     {
8226       if (rc = moira_connect())
8227         {
8228           critical_alert("Ldap incremental",
8229                          "Error contacting Moira server : %s",
8230                          error_message(rc));
8231           return;
8232         }
8233       
8234       argv[0] = user_name;
8235
8236       if (!(rc = mr_query("get_filesys_by_label", 1, argv, save_query_info, 
8237                           save_argv)))
8238         {
8239           if(!strcmp(save_argv[FS_TYPE], "FSGROUP") ||
8240              !strcmp(save_argv[FS_TYPE], "MUL"))
8241             {
8242         
8243               argv[0] = save_argv[FS_NAME];
8244               fsgCount = 0;
8245               
8246               if (!(rc = mr_query("get_fsgroup_members", 1, argv, 
8247                                   save_fsgroup_info, fsgroup_save_argv)))
8248                 {
8249                   if(fsgCount)
8250                     {
8251                       argv[0] = fsgroup_save_argv[0];
8252                       
8253                       if (!(rc = mr_query("get_filesys_by_label", 1, argv, 
8254                                           save_query_info, save_argv)))
8255                         {
8256                           strcpy(path, save_argv[FS_PACK]);
8257                         }
8258                     }
8259                 }
8260             }
8261           else
8262             {
8263               strcpy(path, save_argv[FS_PACK]);
8264             }
8265         }
8266      
8267       moira_disconnect();
8268
8269       if (strlen(path))
8270         {
8271           if (!strnicmp(path, AFS, strlen(AFS)))
8272             {
8273               AfsToWinAfs(path, winPath);
8274               strcpy(winProfile, winPath);
8275               strcat(winProfile, "\\.winprofile");
8276             }
8277         }
8278       else
8279         return(n);
8280     }
8281
8282     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8283         (!strcasecmp(WinProfileDir, "[dfs]")))
8284     {
8285       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8286               user_name[0], user_name);
8287
8288       if (!strcasecmp(WinProfileDir, "[dfs]"))
8289         {
8290           strcpy(winProfile, path);
8291           strcat(winProfile, "\\.winprofile");
8292         }
8293
8294       if (!strcasecmp(WinHomeDir, "[dfs]"))
8295         strcpy(winPath, path);
8296     }
8297     
8298     if (!strcasecmp(WinHomeDir, "[local]"))
8299       memset(winPath, '\0', sizeof(winPath));
8300     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8301              !strcasecmp(WinHomeDir, "[dfs]"))
8302       {
8303         strcpy(homeDrive, "H:");
8304       }
8305     else
8306       {
8307         strcpy(winPath, WinHomeDir);
8308         if (!strncmp(WinHomeDir, "\\\\", 2))
8309           {
8310             strcpy(homeDrive, "H:");
8311           }        
8312       }
8313     
8314     // nothing needs to be done if WinProfileDir is [afs].
8315     if (!strcasecmp(WinProfileDir, "[local]"))
8316       memset(winProfile, '\0', sizeof(winProfile));
8317     else if (strcasecmp(WinProfileDir, "[afs]") && 
8318              strcasecmp(WinProfileDir, "[dfs]"))
8319       {
8320         strcpy(winProfile, WinProfileDir);
8321       }
8322     
8323     if (strlen(winProfile) != 0)
8324       {
8325         if (winProfile[strlen(winProfile) - 1] == '\\')
8326           winProfile[strlen(winProfile) - 1] = '\0';
8327       }
8328
8329     if (strlen(winPath) != 0)
8330       {
8331         if (winPath[strlen(winPath) - 1] == '\\')
8332           winPath[strlen(winPath) - 1] = '\0';
8333       }
8334     
8335     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8336       strcat(winProfile, "\\");
8337
8338     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8339       strcat(winPath, "\\");
8340     
8341     if (strlen(winPath) == 0)
8342       {
8343         if (OpType == LDAP_MOD_REPLACE)
8344           {
8345             i = 0;
8346             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8347             DelMods[i] = NULL;
8348             //unset homeDirectory attribute for user.
8349             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8350             free(DelMods[0]);
8351           }
8352       }
8353     else
8354       {
8355         homedir_v[0] = strdup(winPath);
8356         ADD_ATTR("homeDirectory", homedir_v, OpType);
8357       }
8358     
8359     if (strlen(winProfile) == 0)
8360       {
8361         if (OpType == LDAP_MOD_REPLACE)
8362           {
8363             i = 0;
8364             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8365             DelMods[i] = NULL;
8366             //unset profilePate attribute for user.
8367             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8368             free(DelMods[0]);
8369           }
8370       }
8371     else
8372       {
8373         winProfile_v[0] = strdup(winProfile);
8374         ADD_ATTR("profilePath", winProfile_v, OpType);
8375       }
8376     
8377     if (strlen(homeDrive) == 0)
8378       {
8379         if (OpType == LDAP_MOD_REPLACE)
8380           {
8381             i = 0;
8382             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8383             DelMods[i] = NULL;
8384             //unset homeDrive attribute for user
8385             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8386             free(DelMods[0]);
8387           }
8388       }
8389     else
8390       {
8391         drives_v[0] = strdup(homeDrive);
8392         ADD_ATTR("homeDrive", drives_v, OpType);
8393       }
8394
8395     return(n);
8396 }
8397
8398 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8399                      char *attribute_value, char *attribute, char *user_name)
8400 {
8401   char      *mod_v[] = {NULL, NULL};
8402   LDAPMod   *DelMods[20];
8403   LDAPMod   *mods[20];
8404   int       n;
8405   int       i;
8406   int       rc;
8407   
8408   if (strlen(attribute_value) == 0)
8409     {
8410       i = 0;
8411       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8412       DelMods[i] = NULL;
8413       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8414       free(DelMods[0]);
8415     }
8416   else
8417     {
8418       n = 0;
8419       mod_v[0] = attribute_value;
8420       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8421       mods[n] = NULL;
8422
8423       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8424                               mods)) != LDAP_SUCCESS)
8425         {
8426           free(mods[0]);
8427           n = 0;
8428           mod_v[0] = attribute_value;
8429           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8430           mods[n] = NULL;
8431
8432           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8433                                   mods)) != LDAP_SUCCESS)
8434             {
8435               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8436                       "in the directory : %s",
8437                       attribute, user_name, ldap_err2string(rc));
8438             }
8439         }
8440
8441       free(mods[0]);
8442     }
8443   
8444   return(rc);
8445 }
8446
8447 void StringTrim(char *StringToTrim)
8448 {
8449   char *t, *s;
8450   char *save;
8451
8452   save = strdup(StringToTrim);
8453
8454   s = save;
8455
8456   while (isspace(*s))
8457     s++;
8458
8459   /* skip to end of string */
8460   if (*s == '\0')
8461     {
8462       if (*save)
8463         *save = '\0';
8464       strcpy(StringToTrim, save);
8465       return;
8466     }
8467   
8468   for (t = s; *t; t++)
8469     continue;
8470
8471   while (t > s)
8472     {
8473       --t;
8474       if (!isspace(*t))
8475         {
8476           t++;
8477           break;
8478         }
8479     }
8480
8481   if (*t)
8482     *t = '\0';
8483   
8484   strcpy(StringToTrim, s);
8485   return;
8486 }
8487
8488 int ReadConfigFile(char *DomainName)
8489 {
8490     int     Count;
8491     int     i;
8492     int     k;
8493     char    temp[256];
8494     char    temp1[256];
8495     FILE    *fptr;
8496
8497     Count = 0;
8498
8499     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8500
8501     if ((fptr = fopen(temp, "r")) != NULL)
8502       {
8503         while (fgets(temp, sizeof(temp), fptr) != 0)
8504           {
8505             for (i = 0; i < (int)strlen(temp); i++)
8506               temp[i] = toupper(temp[i]);
8507
8508             if (temp[strlen(temp) - 1] == '\n')
8509               temp[strlen(temp) - 1] = '\0';
8510
8511             StringTrim(temp);
8512
8513             if (strlen(temp) == 0)
8514               continue;
8515
8516             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8517               {
8518                 if (strlen(temp) > (strlen(DOMAIN)))
8519                   {
8520                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8521                     StringTrim(ldap_domain);
8522                   }
8523               }
8524             else if (!strncmp(temp, REALM, strlen(REALM)))
8525               {
8526                 if (strlen(temp) > (strlen(REALM)))
8527                   {
8528                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8529                     StringTrim(ldap_realm);
8530                   }
8531               }
8532             else if (!strncmp(temp, PORT, strlen(PORT)))
8533               {
8534                 if (strlen(temp) > (strlen(PORT)))
8535                   {
8536                     strcpy(ldap_port, &temp[strlen(PORT)]);
8537                     StringTrim(ldap_port);
8538                   }
8539               }
8540             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8541               {
8542                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8543                   {
8544                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8545                     StringTrim(PrincipalName);
8546                   }
8547               }
8548             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8549               {
8550                 if (strlen(temp) > (strlen(SERVER)))
8551                   {
8552                     ServerList[Count] = calloc(1, 256);
8553                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8554                     StringTrim(ServerList[Count]);
8555                     ++Count;
8556                   }
8557               }
8558             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8559               {
8560                 if (strlen(temp) > (strlen(MSSFU)))
8561                   {
8562                     strcpy(temp1, &temp[strlen(MSSFU)]);
8563                     StringTrim(temp1);
8564                     if (!strcmp(temp1, SFUTYPE))
8565                       UseSFU30 = 1;
8566                   }
8567               }
8568             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8569               {
8570                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8571                   {
8572                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8573                     StringTrim(temp1);
8574                     if (!strcasecmp(temp1, "NO")) 
8575                       {
8576                         UseGroupSuffix = 0;
8577                         memset(group_suffix, '\0', sizeof(group_suffix));
8578                       }
8579                   }
8580               }
8581             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8582               {
8583                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8584                   {
8585                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8586                     StringTrim(temp1);
8587                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8588                       UseGroupUniversal = 1;
8589                   }
8590               }
8591             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8592               {
8593                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8594                   {
8595                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8596                     StringTrim(temp1);
8597                     if (!strcasecmp(temp1, "NO"))
8598                       SetGroupAce = 0;
8599                   }
8600               }
8601             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8602               {
8603                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8604                   {
8605                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8606                     StringTrim(temp1);
8607                     if (!strcasecmp(temp1, "NO"))
8608                       SetPassword = 0;
8609                   }
8610               }
8611             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8612               {
8613                 if (strlen(temp) > (strlen(EXCHANGE)))
8614                   {
8615                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8616                     StringTrim(temp1);
8617                     if (!strcasecmp(temp1, "YES"))
8618                       Exchange = 1;
8619                   }
8620               }
8621             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8622                               strlen(PROCESS_MACHINE_CONTAINER)))
8623               {
8624                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8625                   {
8626                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8627                     StringTrim(temp1);
8628                     if (!strcasecmp(temp1, "NO"))
8629                       ProcessMachineContainer = 0;
8630                   }
8631               }
8632             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8633                               strlen(ACTIVE_DIRECTORY)))
8634               {
8635                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8636                   {
8637                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8638                     StringTrim(temp1);
8639                     if (!strcasecmp(temp1, "NO"))
8640                       ActiveDirectory = 0;
8641                   }
8642               }
8643             else if (!strncmp(temp, GROUP_POPULATE_MEMBERS, 
8644                               strlen(GROUP_POPULATE_MEMBERS)))
8645               {
8646                 if (strlen(temp) > (strlen(GROUP_POPULATE_MEMBERS)))
8647                   {
8648                     strcpy(temp1, &temp[strlen(GROUP_POPULATE_MEMBERS)]);
8649                     StringTrim(temp1);
8650                     if (!strcasecmp(temp1, "DELETE")) 
8651                       {
8652                         GroupPopulateDelete = 1;
8653                       }
8654                   }
8655               }
8656             else
8657               {
8658                 if (strlen(ldap_domain) != 0)
8659                   {
8660                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8661                     break;
8662                   }
8663
8664                 if (strlen(temp) != 0)
8665                   strcpy(ldap_domain, temp);
8666               }
8667           }
8668         fclose(fptr);
8669       }
8670     
8671     if (strlen(ldap_domain) == 0)
8672       {
8673       strcpy(ldap_domain, DomainName);
8674       }
8675
8676     if (Count == 0)
8677         return(0);
8678
8679     for (i = 0; i < Count; i++)
8680       {
8681         if (ServerList[i] != 0)
8682           {
8683             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8684               ServerList[i][k] = toupper(ServerList[i][k]);
8685           }
8686       }
8687     
8688     return(0);
8689 }
8690
8691 int ReadDomainList()
8692 {
8693   int     Count;
8694   int     i;
8695   char    temp[128];
8696   char    temp1[128];
8697   FILE    *fptr;
8698   unsigned char c[11];
8699   unsigned char stuff[256];
8700   int     rc;
8701   int     ok;
8702
8703   Count = 0;
8704   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8705
8706   if ((fptr = fopen(temp, "r")) != NULL)
8707     {
8708       while (fgets(temp, sizeof(temp), fptr) != 0)
8709         {
8710           for (i = 0; i < (int)strlen(temp); i++)
8711             temp[i] = toupper(temp[i]);
8712
8713           if (temp[strlen(temp) - 1] == '\n')
8714             temp[strlen(temp) - 1] = '\0';
8715
8716           StringTrim(temp);
8717
8718           if (strlen(temp) == 0)
8719             continue;
8720
8721           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8722             {
8723               if (strlen(temp) > (strlen(DOMAIN)))
8724                 {
8725                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8726                   StringTrim(temp1);
8727                   strcpy(temp, temp1);
8728                 }
8729             }
8730           
8731           strcpy(DomainNames[Count], temp);
8732           StringTrim(DomainNames[Count]);
8733           ++Count;
8734         }
8735
8736       fclose(fptr);
8737     }
8738
8739   if (Count == 0)
8740     {
8741       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8742                      "configuration error in ldap.cfg");
8743       return(1);
8744     }
8745   
8746   return(0);
8747 }
8748
8749 int email_isvalid(const char *address) {
8750   int        count = 0;
8751   const char *c, *domain;
8752   static char *rfc822_specials = "()<>@,;:\\\"[]";
8753
8754   if(address[strlen(address) - 1] == '.') 
8755     return 0;
8756     
8757   /* first we validate the name portion (name@domain) */
8758   for (c = address;  *c;  c++) {
8759     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8760                        '\"')) {
8761       while (*++c) {
8762         if (*c == '\"') 
8763           break;
8764         if (*c == '\\' && (*++c == ' ')) 
8765           continue;
8766         if (*c <= ' ' || *c >= 127) 
8767           return 0;
8768       }
8769
8770       if (!*c++) 
8771         return 0;
8772       if (*c == '@') 
8773         break;
8774       if (*c != '.') 
8775         return 0;
8776       continue;
8777     }
8778
8779     if (*c == '@') 
8780       break;
8781     if (*c <= ' ' || *c >= 127) 
8782       return 0;
8783     if (strchr(rfc822_specials, *c)) 
8784       return 0;
8785   }
8786
8787   if (c == address || *(c - 1) == '.') 
8788     return 0;
8789
8790   /* next we validate the domain portion (name@domain) */
8791   if (!*(domain = ++c)) return 0;
8792   do {
8793     if (*c == '.') {
8794       if (c == domain || *(c - 1) == '.') 
8795         return 0;
8796       count++;
8797     }
8798     if (*c <= ' ' || *c >= 127) 
8799       return 0;
8800     if (strchr(rfc822_specials, *c)) 
8801       return 0;
8802   } while (*++c);
8803
8804   return (count >= 1);
8805 }
8806
8807 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8808              char **homeServerName) 
8809 {
8810   LK_ENTRY *group_base;
8811   LK_ENTRY *sub_group_base;
8812   LK_ENTRY *gPtr;
8813   LK_ENTRY *sub_gPtr;
8814   int      group_count;
8815   int      sub_group_count;
8816   char     filter[1024];
8817   char     sub_filter[1024];
8818   char     search_path[1024];
8819   char     range[1024];
8820   char     *attr_array[3];
8821   char     *s;
8822   int      homeMDB_count = -1;
8823   int      rc;
8824   int      i;
8825   int      mdbbl_count;
8826   int      rangeStep = 1500;
8827   int      rangeLow = 0;
8828   int      rangeHigh = rangeLow + (rangeStep - 1);
8829   int      isLast = 0;
8830
8831   /* Grumble..... microsoft not making it searchable from the root *grr* */
8832
8833   memset(filter, '\0', sizeof(filter));
8834   memset(search_path, '\0', sizeof(search_path));
8835   
8836   sprintf(filter, "(objectClass=msExchMDB)");
8837   sprintf(search_path, "CN=Configuration,%s", dn_path);
8838   attr_array[0] = "distinguishedName";
8839   attr_array[1] = NULL;
8840   
8841   group_base = NULL;
8842   group_count = 0;
8843   
8844   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8845                            &group_base, &group_count, 
8846                            LDAP_SCOPE_SUBTREE)) != 0) 
8847     {
8848       com_err(whoami, 0, "Unable to find msExchMDB %s",
8849               ldap_err2string(rc));
8850       return(rc);
8851     }
8852   
8853   if (group_count) 
8854     {
8855       gPtr = group_base;
8856       
8857       while(gPtr) {
8858         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8859             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8860             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8861           {
8862             gPtr = gPtr->next;
8863             continue;
8864           }
8865
8866         /* 
8867          * Due to limits in active directory we need to use the LDAP
8868          * range semantics to query and return all the values in 
8869          * large lists, we will stop increasing the range when
8870          * the result count is 0.
8871          */
8872
8873         i = 0;  
8874         mdbbl_count = 0;
8875
8876         for(;;) 
8877           {
8878             memset(sub_filter, '\0', sizeof(sub_filter));
8879             memset(range, '\0', sizeof(range));
8880             sprintf(sub_filter, "(objectClass=msExchMDB)");
8881
8882             if(isLast)
8883               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8884             else 
8885               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8886
8887             attr_array[0] = range;
8888             attr_array[1] = NULL;
8889             
8890             sub_group_base = NULL;
8891             sub_group_count = 0;
8892             
8893             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8894                                      attr_array, &sub_group_base, 
8895                                      &sub_group_count, 
8896                                      LDAP_SCOPE_SUBTREE)) != 0) 
8897               {
8898                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8899                         ldap_err2string(rc));
8900                 return(rc);
8901               }
8902
8903             if(!sub_group_count)
8904               {
8905                 if(isLast) 
8906                   {
8907                     isLast = 0;
8908                     rangeLow = 0;
8909                     rangeHigh = rangeLow + (rangeStep - 1);
8910                     break;
8911                   }
8912                 else
8913                   isLast++;
8914               }
8915
8916             mdbbl_count += sub_group_count;
8917             rangeLow = rangeHigh + 1;
8918             rangeHigh = rangeLow + (rangeStep - 1);
8919           }
8920
8921         /* First time through, need to initialize or update the least used */
8922         
8923         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8924                 mdbbl_count);
8925
8926         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8927           {
8928             homeMDB_count = mdbbl_count; 
8929             *homeMDB = strdup(gPtr->dn);
8930           }
8931
8932         gPtr = gPtr->next;
8933         linklist_free(sub_group_base);
8934       }
8935     }
8936
8937   linklist_free(group_base);
8938   
8939   /* 
8940    * Ok found the server least allocated need to now query to get its
8941    * msExchHomeServerName so we can set it as a user attribute
8942    */
8943   
8944   attr_array[0] = "legacyExchangeDN";
8945   attr_array[1] = NULL; 
8946   
8947   group_count = 0;
8948   group_base = NULL;
8949   
8950   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8951                            attr_array, &group_base, 
8952                            &group_count, 
8953                            LDAP_SCOPE_SUBTREE)) != 0) 
8954     {
8955       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8956               ldap_err2string(rc));
8957       return(rc);
8958     }  
8959   
8960   if(group_count) 
8961     {
8962       *homeServerName = strdup(group_base->value);
8963       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8964         {
8965           *s = '\0';
8966         }
8967     } 
8968
8969   linklist_free(group_base);
8970   
8971   return(rc);
8972 }
8973       
8974 char *lowercase(char *s)
8975 {
8976   char *p;
8977
8978   for (p = s; *p; p++)
8979     {
8980       if (isupper(*p))
8981         *p = tolower(*p);
8982     }
8983   return s;
8984 }
8985
8986 char *uppercase(char *s)
8987 {
8988   char *p;
8989
8990   for (p = s; *p; p++)
8991     {
8992       if (islower(*p))
8993         *p = toupper(*p);
8994     }
8995   return s;
8996 }
8997
8998 char *escape_string(char *s)
8999 {
9000   char *p, *q;
9001   char string[1024];
9002   char temp[1024];
9003   int i = 0;
9004   int spaces = 0;
9005
9006   memset(string, '\0', sizeof(string));
9007
9008   q = s;
9009
9010   /* Escape any special characters */
9011
9012   for(; *q != '\0'; q++) {
9013     if(*q == ',')
9014       string[i++] = '\\';
9015     if(*q == '+') 
9016       string[i++] = '\\';
9017     if(*q == '"') 
9018       string[i++] = '\\';
9019     if(*q == '\\') 
9020       string[i++] = '\\';
9021     if(*q == '<') 
9022       string[i++] = '\\';
9023     if(*q == '>') 
9024       string[i++] = '\\';
9025     if(*q == ';')
9026       string[i++] = '\\';
9027     if(*q == '#')
9028       string[i++] = '\\';
9029     if(*q == '=')
9030       string[i++] = '\\';
9031
9032     string[i++] = *q;
9033   }
9034
9035   return strdup(string);
9036 }
9037
9038 int save_query_info(int argc, char **argv, void *hint)
9039 {
9040   int i;
9041   char **nargv = hint;
9042
9043   for(i = 0; i < argc; i++)
9044     nargv[i] = strdup(argv[i]);
9045
9046   return MR_CONT;
9047 }
9048
9049 int save_fsgroup_info(int argc, char **argv, void *hint)
9050 {
9051   int i;
9052   char **nargv = hint;
9053
9054   if(!fsgCount) 
9055     {
9056       for(i = 0; i < argc; i++)
9057         nargv[i] = strdup(argv[i]);
9058
9059       fsgCount++;
9060     }
9061
9062   return MR_CONT;
9063 }
This page took 0.825847 seconds and 3 git commands to generate.