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