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