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