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