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