]> andersk Git - moira.git/blob - incremental/winad/winad.c
8da0b4df74e8358ec31b00924b49549ddc04c4ec
[moira.git] / incremental / winad / winad.c
1 /* $Header$
2 /* winad.incr arguments example
3  *
4  * arguments when moira creates the account - ignored by winad.incr since the 
5  * account is unusable. users 0 11 #45198 45198 /bin/cmd cmd Last First Middle
6  * 0 950000001 2000 121049
7  *
8  * login, unix_uid, shell, winconsoleshell, last, 
9  * first, middle, status, mitid, type, moiraid
10  *
11  * arguments for creating or updating a user account 
12  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
13  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
14  * First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
15  * users 11 11 #45206 45206 /bin/cmd cmd Last First Middle 0 950000001 STAFF
16  * 121058  PathToHomeDir PathToProfileDir newuser 45206 /bin/cmd cmd Last
17  * First Middle 2 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
18  *
19  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
20  * mitid, type, moiraid
21  *
22  * arguments for deactivating/deleting a user account
23  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
24  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
25  * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
26  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF
27  * 121058  PathToHomeDir PathToProfileDir username 45206 /bin/cmd cmd Last
28  * First Middle 3 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
29  * 
30  * login, unix_uid, shell, winconsoleshell, last, first, middle, status,
31  * mitid, type, moiraid
32  *
33  * arguments for reactivating a user account
34  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
35  * 121058 username 45206 /bin/cmd cmd Last First Middle 1 950000001 STAFF
36  * 121058
37  * users 11 11 username 45206 /bin/cmd cmd Last First Middle 3 950000001 STAFF
38  * 121058 username 45206 /bin/cmd cmd Last First Middle 2 950000001 STAFF 12105
39  *
40  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
41  * mitid, type, moiraid
42  *
43  * arguments for changing user name
44  * users 11 11 oldusername 45206 /bin/cmd cmd Last First Middle 1 950000001 
45  * STAFF 121058 PathToHomeDir PathToProfileDir newusername 45206 /bin/cmd cmd 
46  * Last First Middle 1 950000001 STAFF 121058 PathToHomeDir PathToProfileDir
47  *
48  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
49  * mitid, type, moiraid
50  *
51  * arguments for expunging a user
52  * users 11 0 username 45198 /bin/cmd cmd Last First Middle 0 950000001 2000
53  * 121049
54  *
55  * login, unix_uid, shell, winconsoleshell, last, first, middle, status, 
56  * mitid, type, moiraid
57  *
58  * arguments for creating a "special" group/list
59  * list 0 11 listname 1 1 0 0 0 -1 NONE 0 description 92616
60  *
61  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
62  * acl_id, description, moiraid
63  * 
64  * arguments for creating a "mail" group/list
65  * list 0 11 listname 1 1 0 1 0 -1 NONE 0 description 92616
66  *
67  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
68  * acl_id, description, moiraid
69  *
70  * arguments for creating a "group" group/list
71  * list 0 11 listname 1 1 0 0 1 -1 NONE 0 description 92616
72  * 
73  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
74  * acl_id, description, moiraid
75  *
76  * arguments for creating a "group/mail" group/list
77  * list 0 11 listname 1 1 0 1 1 -1 NONE 0 description 92616
78  *
79  * listname, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
80  * acl_id, description, moiraid
81  *
82  * arguments to add a USER member to group/list
83  * imembers 0 12 listname USER userName 1 1 0 0 0 -1 1 92616 121047
84  *
85  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
86  * gid, userStatus, moiraListId, moiraUserId
87  *
88  * arguments to add a STRING or KERBEROS member to group/list
89  * imembers 0 10 listname STRING stringName 1 1 0 0 0 -1 92616
90  * imembers 0 10 listlistnameName KERBEROS kerberosName 1 1 0 0 0 -1 92616
91  *
92  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
93  * gid, moiraListId
94  *
95  * NOTE: group members of type LIST are ignored.
96  *
97  * arguments to remove a USER member to group/list
98  * imembers 12 0 listname USER userName 1 1 0 0 0 -1 1 92616 121047
99  * 
100  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
101  * gid, userStatus, moiraListId, moiraUserId
102  *
103  * arguments to remove a STRING or KERBEROS member to group/list
104  * imembers 10 0 listname STRING stringName 1 1 0 0 0 -1 92616
105  * imembers 10 0 listname KERBEROS kerberosName 1 1 0 0 0 -1 92616
106  *
107  * list_name, user_type, name, active, publicflg, hidden, maillist, grouplist,
108  * gid, moiraListId
109  *
110  * NOTE: group members of type LIST are ignored.
111  *
112  * arguments for renaming a group/list
113  * list 11 11 oldlistname 1 1 0 0 0 -1 NONE 0 description 92616 newlistname 1
114  * 1 0 0 0 -1 description 0 92616
115  * 
116  * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
117  * acl_id, description, moiraListId
118  *
119  * arguments for deleting a group/list
120  * list 11 0 listname 1 1 0 0 0 -1 NONE 0 description 92616
121  *
122  * name, active, publicflg, hidden, maillist, grouplist, gid, acl_type, 
123  * acl_id, description, moiraListId
124  *
125  * arguments for adding a file system
126  * filesys 0 12 username AFS ATHENA.MIT.EDU 
127  * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
128  * wheel 1 HOMEDIR 101727
129  *
130  * arguments for deleting a file system
131  * filesys 12 0 username AFS ATHENA.MIT.EDU 
132  * /afs/athena.mit.edu/user/n/e/username /mit/username w descripton username
133  * wheel 1 HOMEDIR 101727
134  *
135  * arguments when moira creates a container (OU).
136  * containers 0 8 machines/test/bottom description location contact USER
137  * 105316 2222 [none]
138  *
139  * arguments when moira deletes a container (OU).
140  * containers 8 0 machines/test/bottom description location contact USER 
141  * 105316 2222 groupname
142  *
143  * arguments when moira modifies a container information (OU).
144  * containers 8 8 machines/test/bottom description location contact USER 
145  * 105316 2222 groupname machines/test/bottom description1 location contact 
146  * USER 105316 2222 groupname
147  *
148  * arguments when moira adds a machine from an OU
149  * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
150  * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
151  *
152  * arguments when moira removes a machine from an OU
153  * table name, beforec, afterc, machine_name, container_name, mach_id, cnt_id
154  * mcntmap 0 5 DAVIDT.MIT.EDU dttest/dttest1 76767 46 groupname
155  *
156 */
157
158 #include <mit-copyright.h>
159
160 #ifdef _WIN32
161 #include <winsock2.h>
162 #include <windows.h>
163 #include <stdlib.h>
164 #include <malloc.h>
165 #include <lmaccess.h>
166 #endif
167
168 #include <hesiod.h>
169 #include <string.h>
170 #include <ldap.h>
171 #include <stdio.h>
172 #include <moira.h>
173 #include <moira_site.h>
174 #include <mrclient.h>
175 #include <krb5.h>
176 #include <gsssasl.h>
177 #include <gssldap.h> 
178 #include "kpasswd.h"
179
180 #ifdef _WIN32
181 #ifndef ECONNABORTED
182 #define ECONNABORTED WSAECONNABORTED
183 #endif
184 #ifndef ECONNREFUSED
185 #define ECONNREFUSED WSAECONNREFUSED
186 #endif
187 #ifndef EHOSTUNREACH
188 #define EHOSTUNREACH WSAEHOSTUNREACH
189 #endif
190 #define krb5_xfree free
191 #define F_OK 0
192 #define sleep(A) Sleep(A * 1000);
193 #endif /* _WIN32 */
194
195 #ifndef _WIN32
196 #include <sys/types.h>
197 #include <netinet/in.h>
198 #include <arpa/nameser.h>
199 #include <resolv.h>
200 #include <sys/utsname.h>
201 #include <unistd.h>
202
203 #define CFG_PATH "/moira/winad/"
204 #define WINADCFG "winad.cfg"
205 #define strnicmp(A,B,C) strncasecmp(A,B,C)
206 #define UCHAR unsigned char
207
208 #define UF_SCRIPT               0x0001
209 #define UF_ACCOUNTDISABLE       0x0002
210 #define UF_HOMEDIR_REQUIRED     0x0008
211 #define UF_LOCKOUT              0x0010
212 #define UF_PASSWD_NOTREQD       0x0020
213 #define UF_PASSWD_CANT_CHANGE   0x0040
214 #define UF_DONT_EXPIRE_PASSWD   0x10000
215
216 #define UF_TEMP_DUPLICATE_ACCOUNT       0x0100
217 #define UF_NORMAL_ACCOUNT               0x0200
218 #define UF_INTERDOMAIN_TRUST_ACCOUNT    0x0800
219 #define UF_WORKSTATION_TRUST_ACCOUNT    0x1000
220 #define UF_SERVER_TRUST_ACCOUNT         0x2000
221
222 #define OWNER_SECURITY_INFORMATION       (0x00000001L)
223 #define GROUP_SECURITY_INFORMATION       (0x00000002L)
224 #define DACL_SECURITY_INFORMATION        (0x00000004L)
225 #define SACL_SECURITY_INFORMATION        (0x00000008L)
226
227 #ifndef BYTE
228 #define BYTE unsigned char
229 #endif
230 typedef unsigned int DWORD;
231 typedef unsigned long ULONG;
232
233 typedef struct _GUID
234 {
235   unsigned long Data1;
236   unsigned short Data2;
237   unsigned short Data3;
238   unsigned char Data4[8];
239 } GUID;
240
241 typedef struct _SID_IDENTIFIER_AUTHORITY { 
242   BYTE Value[6]; 
243 } SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; 
244
245 typedef struct _SID {
246   BYTE  Revision;
247   BYTE  SubAuthorityCount;
248   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
249   DWORD SubAuthority[512];
250 } SID;
251 #endif/*!WIN32*/
252
253 #ifndef WINADCFG
254 #define WINADCFG "winad.cfg"
255 #endif
256
257 #ifndef CFG_PATH
258 #define CFG_PATH ""
259 #endif 
260
261 #define AFS "/afs/"
262 #define WINAFS "\\\\afs\\all\\"
263
264 #define ADS_GROUP_TYPE_GLOBAL_GROUP         0x00000002
265 #define ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP   0x00000004
266 #define ADS_GROUP_TYPE_LOCAL_GROUP          0x00000004
267 #define ADS_GROUP_TYPE_UNIVERSAL_GROUP      0x00000008
268 #define ADS_GROUP_TYPE_SECURITY_ENABLED     0x80000000
269
270 #define QUERY_VERSION   -1
271 #define PRIMARY_REALM   "ATHENA.MIT.EDU"
272 #define PRIMARY_DOMAIN  "win.mit.edu"
273 #define PRODUCTION_PRINCIPAL "sms"
274 #define TEST_PRINCIPAL       "smstest"
275
276 #define SUBSTITUTE  1
277 #define REPLACE     2
278
279 #define USERS         0
280 #define GROUPS        1
281
282 #define MEMBER_ADD          1
283 #define MEMBER_REMOVE       2
284 #define MEMBER_CHANGE_NAME  3
285 #define MEMBER_ACTIVATE     4
286 #define MEMBER_DEACTIVATE   5
287 #define MEMBER_CREATE       6
288
289 #define MOIRA_ALL       0x0
290 #define MOIRA_USERS     0x1
291 #define MOIRA_KERBEROS  0x2
292 #define MOIRA_STRINGS   0x4
293 #define MOIRA_LISTS     0x8
294
295 #define CHECK_GROUPS    1
296 #define CLEANUP_GROUPS  2
297
298 #define AD_NO_GROUPS_FOUND        -1
299 #define AD_WRONG_GROUP_DN_FOUND   -2
300 #define AD_MULTIPLE_GROUPS_FOUND  -3
301 #define AD_INVALID_NAME           -4
302 #define AD_LDAP_FAILURE           -5
303 #define AD_INVALID_FILESYS        -6
304 #define AD_NO_ATTRIBUTE_FOUND     -7
305 #define AD_NO_OU_FOUND            -8
306 #define AD_NO_USER_FOUND          -9
307
308 /* container arguments */
309 #define CONTAINER_NAME       0
310 #define CONTAINER_DESC       1
311 #define CONTAINER_LOCATION   2
312 #define CONTAINER_CONTACT    3
313 #define CONTAINER_TYPE       4
314 #define CONTAINER_ID         5
315 #define CONTAINER_ROWID      6
316 #define CONTAINER_GROUP_NAME 7
317
318 /*mcntmap arguments*/
319 #define OU_MACHINE_NAME        0
320 #define OU_CONTAINER_NAME      1
321 #define OU_MACHINE_ID          2
322 #define OU_CONTAINER_ID        3
323 #define OU_CONTAINER_GROUP     4
324
325 typedef struct lk_entry {
326   int     op;
327   int     length;
328   int     ber_value;
329   char    *dn;
330   char    *attribute;
331   char    *value;
332   char    *member;
333   char    *type;
334   char    *list;
335   struct  lk_entry *next;
336 } LK_ENTRY;
337
338 #define STOP_FILE "/moira/winad/nowinad"
339 #define file_exists(file) (access((file), F_OK) == 0)
340
341 #define N_SD_BER_BYTES   5
342 #define LDAP_BERVAL struct berval
343 #define MAX_SERVER_NAMES 32
344
345 #define HIDDEN_GROUP                "HiddenGroup.g"
346 #define HIDDEN_GROUP_WITH_ADMIN     "HiddenGroupWithAdmin.g"
347 #define NOT_HIDDEN_GROUP            "NotHiddenGroup.g"
348 #define NOT_HIDDEN_GROUP_WITH_ADMIN "NotHiddenGroupWithAdmin.g"
349
350 #define ADDRESS_LIST_PREFIX "CN=MIT Directory,CN=All Address Lists,\
351 CN=Address Lists Container,CN=Massachusetts Institute of Technology,\
352 CN=Microsoft Exchange,CN=Services,CN=Configuration,"
353
354 #define ADD_ATTR(t, v, o)               \
355   mods[n] = malloc(sizeof(LDAPMod));    \
356   mods[n]->mod_op = o;                  \
357   mods[n]->mod_type = t;                \
358   mods[n++]->mod_values = v
359
360 #define DEL_ATTR(t, o)                  \
361   DelMods[i] = malloc(sizeof(LDAPMod)); \
362   DelMods[i]->mod_op = o;               \
363   DelMods[i]->mod_type = t;             \
364   DelMods[i++]->mod_values = NULL
365
366 #define DOMAIN_SUFFIX   "MIT.EDU"
367 #define DOMAIN  "DOMAIN:"
368 #define PRINCIPALNAME  "PRINCIPAL:"
369 #define SERVER  "SERVER:"
370 #define MSSFU   "SFU:"
371 #define SFUTYPE "30"
372 #define GROUP_SUFFIX "GROUP_SUFFIX:"
373 #define GROUP_TYPE   "GROUP_TYPE:"
374 #define SET_GROUP_ACE    "SET_GROUP_ACE:"
375 #define SET_PASSWORD "SET_PASSWORD:"
376 #define EXCHANGE "EXCHANGE:"
377 #define PROCESS_MACHINE_CONTAINER "PROCESS_MACHINE_CONTAINER:"
378 #define MAX_DOMAINS 10
379 char DomainNames[MAX_DOMAINS][128];
380
381 LK_ENTRY *member_base = NULL;
382
383 char   PrincipalName[128];
384 static char tbl_buf[1024];
385 char  kerberos_ou[] = "OU=kerberos,OU=moira";
386 char  contact_ou[] = "OU=strings,OU=moira";
387 char  user_ou[] = "OU=users,OU=moira";
388 char  group_ou_distribution[] = "OU=mail,OU=lists,OU=moira";
389 char  group_ou_root[] = "OU=lists,OU=moira";
390 char  group_ou_security[] = "OU=group,OU=lists,OU=moira";
391 char  group_ou_neither[] = "OU=special,OU=lists,OU=moira";
392 char  group_ou_both[] = "OU=mail,OU=group,OU=lists,OU=moira";
393 char  orphans_machines_ou[] = "OU=Machines,OU=Orphans";
394 char  orphans_other_ou[] = "OU=Other,OU=Orphans";
395 char  security_template_ou[] = "OU=security_templates";
396 char *whoami;
397 char ldap_domain[256];
398 char *ServerList[MAX_SERVER_NAMES];
399 char default_server[256];
400 static char tbl_buf[1024];
401 char group_suffix[256];
402 char exchange_acl[256];
403 int  mr_connections = 0;
404 int  callback_rc;
405 int  UseSFU30 = 0;
406 int  UseGroupSuffix = 1;
407 int  UseGroupUniversal = 0;
408 int  SetGroupAce = 1;
409 int  SetPassword = 1;
410 int  Exchange = 0;
411 int  ProcessMachineContainer = 1;
412 int  UpdateDomainList;
413
414 extern int set_password(char *user, char *password, char *domain);
415
416 int ad_get_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
417                  char *group_membership, char *MoiraId, char *attribute,
418                  LK_ENTRY **linklist_base, int *linklist_count,
419                  char *rFilter);
420 void AfsToWinAfs(char* path, char* winPath);
421 int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, 
422                char *Win2kPassword, char *Win2kUser, char *default_server,
423                int connect_to_kdc, char **ServerList);
424 void ad_kdc_disconnect();
425 int ad_server_connect(char *connectedServer, char *domain);
426 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
427                      char *attribute_value, char *attribute, char *user_name);
428 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer);
429 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name);
430 int check_winad(void);
431 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, 
432                char *MoiraId);
433 /* containers */
434 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
435                        char *distinguishedName, int count, char **av);
436 void container_check(LDAP *ldap_handle, char *dn_path, char *name);
437 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av);
438 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av);
439 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
440                                     char *distinguishedName, int count, 
441                                     char **av);
442 void container_get_dn(char *src, char *dest);
443 void container_get_name(char *src, char *dest);
444 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName);
445 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
446                      char **before, int afterc, char **after);
447 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
448                      char **before, int afterc, char **after);
449
450 int GetAceInfo(int ac, char **av, void *ptr);
451 int get_group_membership(char *group_membership, char *group_ou, 
452                          int *security_flag, char **av);
453 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
454                    char *machine_ou, char *pPtr);
455 int Moira_container_group_create(char **after);
456 int Moira_container_group_delete(char **before);
457 int Moira_groupname_create(char *GroupName, char *ContainerName,
458                            char *ContainerRowID);
459 int Moira_container_group_update(char **before, char **after);
460 int Moira_process_machine_container_group(char *MachineName, char* groupName,
461                                           int DeleteMachine);
462 int Moira_addGroupToParent(char *origContainerName, char *GroupName);
463 int Moira_getContainerGroup(int ac, char **av, void *ptr);
464 int Moira_getGroupName(char *origContainerName, char *GroupName,
465                        int ParentFlag);
466 int Moira_setContainerGroup(char *ContainerName, char *GroupName);
467 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *group_name, char *Type,
468                int UpdateGroup, int *ProcessGroup, char *maillist);
469 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
470                   char *group_name, char *group_ou, char *group_membership, 
471                   int group_security_flag, int type, char *maillist);
472 int process_lists(int ac, char **av, void *ptr);
473 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
474                          char *TargetGroupName, int HiddenGroup, 
475                          char *AceType, char *AceName);
476 int ProcessMachineName(int ac, char **av, void *ptr);
477 int ReadConfigFile(char *DomainName);
478 int ReadDomainList();
479 void StringTrim(char *StringToTrim);
480 int save_query_info(int argc, char **argv, void *hint);
481 int user_create(int ac, char **av, void *ptr);
482 int user_change_status(LDAP *ldap_handle, char *dn_path, 
483                        char *user_name, char *MoiraId, int operation);
484 int user_delete(LDAP *ldap_handle, char *dn_path, 
485                 char *u_name, char *MoiraId);
486 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
487                 char *user_name);
488 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
489                 char *uid, char *MitId, char *MoiraId, int State,
490                 char *WinHomeDir, char *WinProfileDir, char *first,
491                 char *middle, char *last);
492 void change_to_lower_case(char *ptr);
493 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou);
494 int contact_remove_email(LDAP *ld, char *bind_path,
495                          LK_ENTRY **linklist_entry, int linklist_current);
496 int group_create(int ac, char **av, void *ptr);
497 int group_delete(LDAP *ldap_handle, char *dn_path, 
498                  char *group_name, char *group_membership, char *MoiraId);
499 int group_rename(LDAP *ldap_handle, char *dn_path, 
500                  char *before_group_name, char *before_group_membership, 
501                  char *before_group_ou, int before_security_flag, 
502                  char *before_desc, char *after_group_name, 
503                  char *after_group_membership, char *after_group_ou, 
504                  int after_security_flag, char *after_desc,
505                  char *MoiraId, char *filter, char *maillist);
506 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name);
507 int machine_GetMoiraContainer(int ac, char **av, void *ptr);
508 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
509                                 char *machine_name, char *container_name);
510 int machine_move_to_ou(LDAP *ldap_handle, char *dn_path, 
511                        char *MoiraMachineName, char *DestinationOu);
512 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
513                    char *group_name, char *group_ou, char *group_membership, 
514                    int group_security_flag, int updateGroup, char *maillist);
515 int member_list_build(int ac, char **av, void *ptr);
516 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
517                char *group_ou, char *group_membership, 
518                char *user_name, char *pUserOu, char *MoiraId);
519 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
520                   char *group_ou, char *group_membership, char *user_name,
521                   char *pUserOu, char *MoiraId);
522 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
523                    char *group_ou, char *group_membership, 
524                    int group_security_flag, char *MoiraId);
525 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
526                      char *DistinguishedName,
527                      char *WinHomeDir, char *WinProfileDir,
528                      char **homedir_v, char **winProfile_v,
529                      char **drives_v, LDAPMod **mods, 
530                      int OpType, int n);
531 int sid_update(LDAP *ldap_handle, char *dn_path);
532 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n);
533 int check_string(char *s);
534 int check_container_name(char* s);
535
536 int mr_connect_cl(char *server, char *client, int version, int auth);
537 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
538                   char **before, int beforec, char **after, int afterc);
539 void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
540                 char **before, int beforec, char **after, int afterc);
541 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
542              char **before, int beforec, char **after, int afterc);
543 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
544              char **before, int beforec, char **after, int afterc);
545 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
546                char **before, int beforec, char **after, int afterc);
547 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
548                 char **before, int beforec, char **after, int afterc);
549 int linklist_create_entry(char *attribute, char *value,
550                           LK_ENTRY **linklist_entry);
551 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
552                    char **attr_array, LK_ENTRY **linklist_base, 
553                    int *linklist_count, unsigned long ScopeType);
554 void linklist_free(LK_ENTRY *linklist_base);
555
556 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
557                         char *distinguished_name, LK_ENTRY **linklist_current);
558 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
559                      LK_ENTRY **linklist_base, int *linklist_count);
560 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
561                     char *Attribute, char *distinguished_name, 
562                     LK_ENTRY **linklist_current);
563
564 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
565                         char *oldValue, char *newValue,
566                         char ***modvalues, int type);
567 void free_values(char **modvalues);
568
569 int convert_domain_to_dn(char *domain, char **bind_path);
570 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
571                             char *distinguished_name);
572 int moira_disconnect(void);
573 int moira_connect(void);
574 void print_to_screen(const char *fmt, ...);
575 int GetMachineName(char *MachineName);
576 int tickets_get_k5();
577 int destroy_cache(void);
578 int dest_tkt(void);
579
580 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB,
581                  char **homeServerName);
582
583 int main(int argc, char **argv)
584 {
585   unsigned long   rc;
586   int             beforec;
587   int             afterc;
588   int             i;
589   int             j;
590   int             k;
591   int             OldUseSFU30;
592   char            *table;
593   char            **before;
594   char            **after;
595   LDAP            *ldap_handle;
596   char            dn_path[256];
597   char            *orig_argv[64];
598   
599   whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
600   
601   if (argc < 4)
602     {
603       com_err(whoami, 0, "Unable to process %s", "argc < 4");
604       exit(1);
605     }
606   
607   if (argc < (4 + atoi(argv[2]) + atoi(argv[3])))
608     {
609       com_err(whoami, 0, "Unable to process %s", 
610               "argc < (4 + beforec + afterc)");
611       exit(1);
612     }
613
614   if (!strcmp(argv[1], "filesys"))
615     exit(0);
616
617   for (i = 1; i < argc; i++)
618     {
619       strcat(tbl_buf, argv[i]);
620       strcat(tbl_buf, " ");
621     }
622
623   com_err(whoami, 0, "%s", tbl_buf);
624
625   if (check_winad())
626     {
627       com_err(whoami, 0, "%s failed", "check_winad()");
628       exit(1);
629     }
630
631   initialize_sms_error_table();
632   initialize_krb_error_table();
633
634   UpdateDomainList = 0;
635   memset(DomainNames, '\0', sizeof(DomainNames[0]) * MAX_DOMAINS);
636
637   if (ReadDomainList())
638     {
639       com_err(whoami, 0, "%s failed", "ReadDomainList()");
640       exit(1);
641     }
642
643   for (i = 0; i < argc; i++)
644      orig_argv[i] = NULL;
645
646   for (k = 0; k < MAX_DOMAINS; k++)
647     {
648       if (strlen(DomainNames[k]) == 0)
649         continue;
650       for (i = 0; i < argc; i++)
651         {
652           if (orig_argv[i] != NULL)
653             free(orig_argv[i]);
654           orig_argv[i] = strdup(argv[i]);
655         }
656
657       memset(PrincipalName, '\0', sizeof(PrincipalName));
658       memset(ldap_domain, '\0', sizeof(ldap_domain));
659       memset(ServerList, '\0', sizeof(ServerList[0]) * MAX_SERVER_NAMES);
660       memset(default_server, '\0', sizeof(default_server));
661       memset(dn_path, '\0', sizeof(dn_path));
662       memset(group_suffix, '\0', sizeof(group_suffix));
663       memset(exchange_acl, '\0', sizeof(exchange_acl));
664
665       UseSFU30 = 0;
666       UseGroupSuffix = 1;
667       UseGroupUniversal = 0;
668       SetGroupAce = 1;
669       SetPassword = 1;
670       Exchange = 0;
671       ProcessMachineContainer = 1;
672
673       sprintf(group_suffix, "%s", "_group");
674       sprintf(exchange_acl, "%s", "exchange-acl");
675
676       beforec = atoi(orig_argv[2]);
677       afterc = atoi(orig_argv[3]);
678       table = orig_argv[1];
679       before = &orig_argv[4];
680       after = &orig_argv[4 + beforec];
681
682       if (afterc == 0)
683         after = NULL;
684
685       if (beforec == 0)
686         before = NULL;
687
688       if (ReadConfigFile(DomainNames[k]))
689         continue;
690
691       OldUseSFU30 = UseSFU30;
692
693       for (i = 0; i < 5; i++)
694         {
695           ldap_handle = (LDAP *)NULL;
696           if (!(rc = ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", 
697                                 default_server, 1, ServerList)))
698             {
699               com_err(whoami, 0, "connected to domain %s", DomainNames[k]);
700               break;
701             }
702         }
703
704       if ((rc) || (ldap_handle == NULL))
705         {
706           critical_alert("incremental",
707                          "winad.incr cannot connect to any server in "
708                          "domain %s", DomainNames[k]);
709           continue;
710         }
711
712       for (i = 0; i < (int)strlen(table); i++)
713         table[i] = tolower(table[i]);
714
715       if (!strcmp(table, "users"))
716         do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after,
717                 afterc);
718       else if (!strcmp(table, "list"))
719         do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
720                 afterc);
721       else if (!strcmp(table, "imembers"))
722         do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
723                   afterc);
724       else if (!strcmp(table, "containers"))
725         do_container(ldap_handle, dn_path, ldap_domain, before, beforec, after,
726                      afterc);
727       else if (!strcmp(table, "mcntmap"))
728         do_mcntmap(ldap_handle, dn_path, ldap_domain, before, beforec, after,
729                    afterc);
730       
731       ad_kdc_disconnect();
732
733       for (i = 0; i < MAX_SERVER_NAMES; i++)
734         {
735           if (ServerList[i] != NULL)
736             {
737               free(ServerList[i]);
738               ServerList[i] = NULL;
739             }
740         }
741       
742       rc = ldap_unbind_s(ldap_handle);
743     }
744   
745   exit(0);
746 }
747
748 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
749                 char **before, int beforec, char **after, int afterc)
750 {
751   char    MoiraContainerName[128];
752   char    ADContainerName[128];
753   char    MachineName[1024];
754   char    OriginalMachineName[1024];
755   long    rc;
756   int     DeleteMachine;
757   char    MoiraContainerGroup[64];
758
759   if (!ProcessMachineContainer)
760     {
761       com_err(whoami, 0, "Process machines and containers disabled, skipping");
762       return;
763     }
764   
765   DeleteMachine = 0;
766   memset(ADContainerName, '\0', sizeof(ADContainerName));
767   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
768   
769   if ((beforec == 0) && (afterc == 0))
770     return;
771   
772   if (rc = moira_connect())
773     {
774       critical_alert("AD incremental",
775                      "Error contacting Moira server : %s",
776                      error_message(rc));
777       return;
778     }
779   
780   if ((beforec != 0) && (afterc == 0)) /*remove a machine*/
781     {
782       strcpy(OriginalMachineName, before[OU_MACHINE_NAME]);
783       strcpy(MachineName, before[OU_MACHINE_NAME]);
784       strcpy(MoiraContainerGroup, before[OU_CONTAINER_GROUP]);
785       DeleteMachine = 1;
786       com_err(whoami, 0, "removing machine %s from %s", 
787               OriginalMachineName, before[OU_CONTAINER_NAME]);
788     }
789   else if ((beforec == 0) && (afterc != 0)) /*add a machine*/
790     {
791       strcpy(OriginalMachineName, after[OU_MACHINE_NAME]);
792       strcpy(MachineName, after[OU_MACHINE_NAME]);
793       strcpy(MoiraContainerGroup, after[OU_CONTAINER_GROUP]);
794       com_err(whoami, 0, "adding machine %s to container %s", 
795               OriginalMachineName, after[OU_CONTAINER_NAME]);
796     }
797   else
798     {
799       moira_disconnect();
800       return;
801     }
802   
803   rc = GetMachineName(MachineName);
804
805   if (strlen(MachineName) == 0)
806     {
807       moira_disconnect();
808       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
809               OriginalMachineName);
810       return;
811     }
812
813   Moira_process_machine_container_group(MachineName, MoiraContainerGroup,
814                                         DeleteMachine);
815
816   if (machine_check(ldap_handle, dn_path, MachineName))
817     {
818       com_err(whoami, 0, "Unable to find machine %s (alias %s) in AD.", 
819               OriginalMachineName, MachineName);
820       moira_disconnect();
821       return;
822     }
823
824   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
825   machine_get_moira_container(ldap_handle, dn_path, MachineName, 
826                               MoiraContainerName);
827
828   if (strlen(MoiraContainerName) == 0)
829     {
830       com_err(whoami, 0, "Unable to fine machine %s (alias %s) container "
831               "in Moira - moving to orphans OU.",
832               OriginalMachineName, MachineName);
833       machine_move_to_ou(ldap_handle, dn_path, MachineName, 
834                          orphans_machines_ou);
835       moira_disconnect();
836       return;
837     }
838
839   container_get_dn(MoiraContainerName, ADContainerName);
840
841   if (MoiraContainerName[strlen(MoiraContainerName) - 1] != '/')
842     strcat(MoiraContainerName, "/");
843
844   container_check(ldap_handle, dn_path, MoiraContainerName);
845   machine_move_to_ou(ldap_handle, dn_path, MachineName, ADContainerName);
846   moira_disconnect();
847   return;
848 }
849
850 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
851                   char **before, int beforec, char **after, int afterc)
852 {
853   long rc;
854
855   if (!ProcessMachineContainer)
856     {
857       com_err(whoami, 0, "Process machines and containers disabled, skipping");
858       return;
859     }
860
861   if ((beforec == 0) && (afterc == 0))
862     return;
863
864   if (rc = moira_connect())
865     {
866       critical_alert("AD incremental", "Error contacting Moira server : %s",
867                      error_message(rc));
868       return;
869     }
870
871   if ((beforec != 0) && (afterc == 0)) /*delete a new container*/
872     {
873       com_err(whoami, 0, "deleting container %s", before[CONTAINER_NAME]);
874       container_delete(ldap_handle, dn_path, beforec, before);
875       Moira_container_group_delete(before);
876       moira_disconnect();
877       return;
878     }
879
880   if ((beforec == 0) && (afterc != 0)) /*create a container*/
881     {
882       com_err(whoami, 0, "creating container %s", after[CONTAINER_NAME]);
883       container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
884       container_create(ldap_handle, dn_path, afterc, after);
885       Moira_container_group_create(after);
886       moira_disconnect();
887       return;
888     }
889
890   if (strcasecmp(before[CONTAINER_NAME], after[CONTAINER_NAME]))
891     {
892       com_err(whoami, 0, "renaming container %s to %s", 
893               before[CONTAINER_NAME], after[CONTAINER_NAME]);
894       container_rename(ldap_handle, dn_path, beforec, before, afterc, after);
895       Moira_container_group_update(before, after);
896       moira_disconnect();
897       return;
898     }
899
900   com_err(whoami, 0, "updating container %s information", 
901           after[CONTAINER_NAME]);
902   container_update(ldap_handle, dn_path, beforec, before, afterc, after);
903   Moira_container_group_update(before, after);
904   moira_disconnect();
905   return;
906 }
907
908 #define L_LIST_DESC 9
909 #define L_LIST_ID   10
910
911 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
912              char **before, int beforec, char **after, int afterc)
913 {
914   int   updateGroup;
915   int   ProcessGroup;
916   long  rc;
917   char  group_membership[6];
918   char  list_id[32];
919   int   security_flag;
920   char  filter[128];
921   char  group_ou[256];
922   char  before_list_id[32];
923   char  before_group_membership[1];
924   int   before_security_flag;
925   char  before_group_ou[256];
926   LK_ENTRY *ptr = NULL;
927
928   if (beforec == 0 && afterc == 0)
929     return;
930
931   memset(list_id, '\0', sizeof(list_id));
932   memset(before_list_id, '\0', sizeof(before_list_id));
933   memset(before_group_ou, '\0', sizeof(before_group_ou));
934   memset(before_group_membership, '\0', sizeof(before_group_membership));
935   memset(group_ou, '\0', sizeof(group_ou));
936   memset(group_membership, '\0', sizeof(group_membership));
937   updateGroup = 0;
938
939   if (beforec > L_GID)
940     {
941       if (beforec < L_LIST_ID)
942         return;
943       if (beforec > L_LIST_DESC)
944         {
945           strcpy(before_list_id, before[L_LIST_ID]);
946         }
947       before_security_flag = 0;
948       get_group_membership(before_group_membership, before_group_ou, 
949                            &before_security_flag, before);
950     }
951
952   if (afterc > L_GID)
953     {
954       if (afterc < L_LIST_ID)
955         return;
956       if (afterc > L_LIST_DESC)
957         {
958           strcpy(list_id, after[L_LIST_ID]);
959         }
960       security_flag = 0;
961       get_group_membership(group_membership, group_ou, &security_flag, after);
962     }
963   
964   if ((beforec == 0) && (afterc == 0)) /*this case should never happen*/
965     return;
966
967   updateGroup = 0;
968   
969   if (beforec)
970     {
971       updateGroup = 1;
972
973       if ((rc = process_group(ldap_handle, dn_path, before_list_id, 
974                               before[L_NAME], before_group_ou, 
975                               before_group_membership, 
976                               before_security_flag, CHECK_GROUPS,
977                               before[L_MAILLIST])))
978         {
979           if (rc == AD_NO_GROUPS_FOUND)
980             updateGroup = 0;
981           else
982             {
983               if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
984                   (rc == AD_MULTIPLE_GROUPS_FOUND))
985                 {
986                   rc = process_group(ldap_handle, dn_path, before_list_id, 
987                                      before[L_NAME], before_group_ou, 
988                                      before_group_membership, 
989                                      before_security_flag, CLEANUP_GROUPS,
990                                      before[L_MAILLIST]);
991                 }
992               if ((rc != AD_NO_GROUPS_FOUND) && (rc != 0))
993                 {
994                   com_err(whoami, 0, "Unable to process list %s",
995                           before[L_NAME]);
996                   return;
997                 }
998               if (rc == AD_NO_GROUPS_FOUND)
999                 updateGroup = 0;
1000             }
1001         }
1002     }
1003   
1004   if ((beforec != 0) && (afterc != 0))
1005     {
1006       if (((strcmp(after[L_NAME], before[L_NAME])) || 
1007            ((!strcmp(after[L_NAME], before[L_NAME])) && 
1008             (strcmp(before_group_ou, group_ou)))) &&
1009           (updateGroup == 1))
1010         {
1011           com_err(whoami, 0, "Changing list name from %s to %s",
1012                   before[L_NAME], after[L_NAME]);
1013
1014           if ((strlen(before_group_ou) == 0) || 
1015               (strlen(before_group_membership) == 0) ||
1016               (strlen(group_ou) == 0) || (strlen(group_membership) == 0))
1017             {
1018               com_err(whoami, 0, "%s", "Unable to find the group OU's");
1019               return;
1020             }
1021
1022           memset(filter, '\0', sizeof(filter));
1023
1024           if ((rc = group_rename(ldap_handle, dn_path, 
1025                                  before[L_NAME], before_group_membership, 
1026                                  before_group_ou, before_security_flag, 
1027                                  before[L_LIST_DESC], after[L_NAME], 
1028                                  group_membership, group_ou, security_flag, 
1029                                  after[L_LIST_DESC],
1030                                  list_id, filter, after[L_MAILLIST])))
1031             {
1032               if (rc != AD_NO_GROUPS_FOUND)
1033                 {
1034                   com_err(whoami, 0, 
1035                           "Unable to change list name from %s to %s",
1036                           before[L_NAME], after[L_NAME]);
1037                   return;
1038                 }
1039               updateGroup = 0;
1040             }
1041           beforec = 0;
1042         }
1043       else
1044         beforec = 0;
1045     }
1046   
1047   if (beforec)
1048     {
1049       if ((strlen(before_group_ou) == 0) || 
1050           (strlen(before_group_membership) == 0))
1051         {
1052           com_err(whoami, 0, 
1053                   "Unable to find the group OU for group %s", before[L_NAME]);
1054           return;
1055         }
1056
1057       com_err(whoami, 0, "Deleting group %s", before[L_NAME]);
1058       rc = group_delete(ldap_handle, dn_path, before[L_NAME], 
1059                         before_group_membership, before_list_id);
1060       return;
1061     }
1062
1063   if (afterc)
1064     {
1065       if (!updateGroup)
1066         {
1067           com_err(whoami, 0, "Creating group %s", after[L_NAME]);
1068
1069           if (rc = process_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1070                                   group_ou, group_membership, 
1071                                   security_flag, CHECK_GROUPS,
1072                                  after[L_MAILLIST]))
1073             {
1074               if (rc != AD_NO_GROUPS_FOUND)
1075                 {
1076                   if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
1077                       (rc == AD_MULTIPLE_GROUPS_FOUND))
1078                     {
1079                       rc = process_group(ldap_handle, dn_path, list_id, 
1080                                          after[L_NAME], 
1081                                          group_ou, group_membership, 
1082                                          security_flag, CLEANUP_GROUPS,
1083                                          after[L_MAILLIST]);
1084                     }
1085
1086                   if (rc)
1087                     {
1088                       com_err(whoami, 0, 
1089                               "Unable to create list %s", after[L_NAME]);
1090                       return;
1091                     }
1092                 }
1093             }
1094         }
1095       else
1096         com_err(whoami, 0, "Updating group %s information", after[L_NAME]);
1097
1098       if (rc = moira_connect())
1099         {
1100           critical_alert("AD incremental",
1101                          "Error contacting Moira server : %s",
1102                          error_message(rc));
1103           return;
1104         }
1105
1106       ProcessGroup = 0;
1107
1108       if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 0, 
1109                      &ProcessGroup, after[L_MAILLIST]))
1110         return;
1111
1112       if (ProcessGroup)
1113         {
1114           if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 1, 
1115                          &ProcessGroup, after[L_MAILLIST]))
1116             return;
1117         }
1118
1119       if (make_new_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1120                          group_ou, group_membership, security_flag, 
1121                          updateGroup, after[L_MAILLIST]))
1122         {
1123           moira_disconnect();
1124           return;
1125         }
1126
1127       if (atoi(after[L_ACTIVE]))
1128         {
1129           populate_group(ldap_handle, dn_path, after[L_NAME], group_ou, 
1130                          group_membership, security_flag, list_id);
1131         }
1132
1133       moira_disconnect();
1134     }
1135   return;
1136 }
1137
1138 #define LM_EXTRA_ACTIVE   (LM_END)
1139 #define LM_EXTRA_PUBLIC   (LM_END+1)
1140 #define LM_EXTRA_HIDDEN   (LM_END+2)
1141 #define LM_EXTRA_MAILLIST (LM_END+3)
1142 #define LM_EXTRA_GROUP    (LM_END+4)
1143 #define LM_EXTRA_GID      (LM_END+5)
1144 #define LMN_LIST_ID       (LM_END+6)
1145 #define LM_LIST_ID        (LM_END+7)
1146 #define LM_USER_ID        (LM_END+8)
1147 #define LM_EXTRA_END      (LM_END+9)
1148
1149 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
1150                char **before, int beforec, char **after, int afterc)
1151 {
1152   LK_ENTRY *group_base;
1153   int group_count;
1154   char  filter[128];
1155   char *attr_array[3];
1156   char  group_name[128];
1157   char  user_name[128];
1158   char  user_type[128];
1159   char  moira_list_id[32];
1160   char  moira_user_id[32];
1161   char  group_membership[1];
1162   char  group_ou[256];
1163   char  machine_ou[256];
1164   char  member[256];
1165   char  *args[16];
1166   char  **ptr;
1167   char  *av[7];
1168   char  *call_args[7];
1169   char  *pUserOu;
1170   char  *s;
1171   char  NewMachineName[1024];
1172   int   security_flag;
1173   int   rc;
1174   int   ProcessGroup;
1175   char  *save_argv[U_END];
1176
1177   pUserOu = NULL;
1178   ptr = NULL;
1179   memset(moira_list_id, '\0', sizeof(moira_list_id));
1180   memset(moira_user_id, '\0', sizeof(moira_user_id));
1181
1182   if (afterc)
1183     {
1184       if (afterc < LM_EXTRA_GID)
1185         return;
1186
1187       if (!atoi(after[LM_EXTRA_ACTIVE]))
1188         {
1189           com_err(whoami, 0, 
1190                   "Unable to add %s to group %s : group not active", 
1191                   after[2], after[0]);
1192           return;
1193         }
1194
1195       ptr = after;
1196
1197       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1198         return;
1199
1200       strcpy(user_name, after[LM_MEMBER]);
1201       strcpy(group_name, after[LM_LIST]);
1202       strcpy(user_type, after[LM_TYPE]);
1203
1204       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1205         {
1206           if (afterc > LM_EXTRA_GROUP)
1207             {
1208               strcpy(moira_list_id, after[LMN_LIST_ID]);
1209               strcpy(moira_user_id, after[LM_LIST_ID]);
1210             }
1211         }
1212       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1213         {
1214           if (afterc > LMN_LIST_ID)
1215             {
1216               strcpy(moira_list_id, after[LM_LIST_ID]);
1217               strcpy(moira_user_id, after[LM_USER_ID]);
1218             }
1219         }
1220       else
1221         {
1222           if (afterc > LM_EXTRA_GID)
1223             strcpy(moira_list_id, after[LMN_LIST_ID]);
1224         }
1225     }
1226   else if (beforec)
1227     {
1228       if (beforec < LM_EXTRA_GID)
1229         return;
1230       if (!atoi(before[LM_EXTRA_ACTIVE]))
1231         {
1232           com_err(whoami, 0, 
1233                   "Unable to add %s to group %s : group not active", 
1234                   before[2], before[0]);
1235           return;
1236         }
1237
1238       ptr = before;
1239
1240       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1241         return;
1242
1243       strcpy(user_name, before[LM_MEMBER]);
1244       strcpy(group_name, before[LM_LIST]);
1245       strcpy(user_type, before[LM_TYPE]);
1246
1247       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1248         {
1249           if (beforec > LM_EXTRA_GROUP)
1250             {
1251               strcpy(moira_list_id, before[LMN_LIST_ID]);
1252               strcpy(moira_user_id, before[LM_LIST_ID]);
1253             }
1254         }
1255       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1256         {
1257           if (beforec > LMN_LIST_ID)
1258             {
1259               strcpy(moira_list_id, before[LM_LIST_ID]);
1260               strcpy(moira_user_id, before[LM_USER_ID]);
1261             }
1262         }
1263       else
1264         {
1265           if (beforec > LM_EXTRA_GID)
1266             strcpy(moira_list_id, before[LMN_LIST_ID]);
1267         }
1268     }
1269
1270   if (ptr == NULL)
1271     {
1272       com_err(whoami, 0, 
1273               "Unable to process group : beforec = %d, afterc = %d", 
1274               beforec, afterc);
1275       return;
1276     }
1277
1278   args[L_NAME] = ptr[LM_LIST];
1279   args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE];
1280   args[L_PUBLIC] = ptr[LM_EXTRA_PUBLIC];
1281   args[L_HIDDEN] = ptr[LM_EXTRA_HIDDEN];
1282   args[L_MAILLIST] = ptr[LM_EXTRA_MAILLIST];
1283   args[L_GROUP] = ptr[LM_EXTRA_GROUP];
1284   args[L_GID] = ptr[LM_EXTRA_GID];
1285
1286   security_flag = 0;
1287   memset(group_ou, '\0', sizeof(group_ou));
1288   get_group_membership(group_membership, group_ou, &security_flag, args);
1289
1290   if (strlen(group_ou) == 0)
1291     {
1292       com_err(whoami, 0, "Unable to find the group OU for group %s", 
1293               group_name);
1294       return;
1295     }
1296
1297   if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, 
1298                          group_ou, group_membership, security_flag, 
1299                          CHECK_GROUPS, args[L_MAILLIST]))
1300     {
1301       if (rc != AD_NO_GROUPS_FOUND)
1302         {
1303           if (rc = process_group(ldap_handle, dn_path, moira_list_id, 
1304                                  group_name, group_ou, group_membership, 
1305                                  security_flag, CLEANUP_GROUPS,
1306                                  args[L_MAILLIST]))
1307             {
1308               if (rc != AD_NO_GROUPS_FOUND)
1309                 {
1310                   if (afterc)
1311                     com_err(whoami, 0, "Unable to add %s to group %s - " 
1312                             "unable to process group", user_name, group_name);
1313                   else
1314                     com_err(whoami, 0, "Unable to remove %s from group %s - "
1315                             "unable to process group", user_name, group_name);
1316                   return;
1317                 }
1318             }
1319         }
1320     }
1321
1322   if (rc == AD_NO_GROUPS_FOUND)
1323     {
1324       if (rc = moira_connect())
1325         {
1326           critical_alert("AD incremental",
1327                          "Error contacting Moira server : %s",
1328                          error_message(rc));
1329           return;
1330         }
1331       
1332       com_err(whoami, 0, "creating group %s", group_name);
1333       ProcessGroup = 0;
1334
1335       if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 0, 
1336                      &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1337         return;
1338
1339       if (ProcessGroup)
1340         {
1341           if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 1, 
1342                          &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1343             return;
1344         }
1345
1346       if (make_new_group(ldap_handle, dn_path, moira_list_id, ptr[LM_LIST], 
1347                          group_ou, group_membership, security_flag, 0,
1348                          ptr[LM_EXTRA_MAILLIST]))
1349         {
1350           moira_disconnect();
1351           return;
1352         }
1353
1354       if (atoi(ptr[LM_EXTRA_ACTIVE]))
1355         {
1356           populate_group(ldap_handle, dn_path, ptr[LM_LIST], group_ou, 
1357                          group_membership, security_flag, moira_list_id);
1358         }
1359
1360       moira_disconnect();
1361     }
1362
1363   rc = 0;
1364
1365   if (beforec)
1366     {
1367       com_err(whoami, 0, "removing user %s from list %s", user_name, 
1368               group_name);
1369       pUserOu = user_ou;
1370
1371       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1372         {
1373           memset(machine_ou, '\0', sizeof(machine_ou));
1374           memset(NewMachineName, '\0', sizeof(NewMachineName));
1375           if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], 
1376                              machine_ou, NewMachineName))
1377             return;
1378           if (ptr[LM_MEMBER] != NULL)     
1379             free(ptr[LM_MEMBER]);
1380           ptr[LM_MEMBER] = strdup(NewMachineName);
1381           pUserOu = machine_ou;
1382         }
1383
1384       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1385         {
1386           strcpy(member, ptr[LM_MEMBER]);
1387
1388           if (Exchange) 
1389             {
1390               if((s = strchr(member, '@')) == (char *) NULL)
1391                 { 
1392                   strcat(member, "@mit.edu");
1393                   
1394                   if (ptr[LM_MEMBER] != NULL)
1395                     free(ptr[LM_MEMBER]);
1396                   ptr[LM_MEMBER] = strdup(member);
1397                 }
1398           
1399               if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1400                 {
1401                   s = strrchr(member, '.');
1402                   *s = '\0';
1403                   strcat(s, ".mit.edu");
1404                   
1405                   if (ptr[LM_MEMBER] != NULL)
1406                     free(ptr[LM_MEMBER]);
1407                   ptr[LM_MEMBER] = strdup(member);
1408                 }
1409             }
1410
1411           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], contact_ou))
1412             return;
1413
1414           pUserOu = contact_ou;
1415         }
1416       else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1417         {
1418           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1419                              kerberos_ou))
1420             return;
1421
1422           pUserOu = kerberos_ou;
1423         }
1424       if (rc = member_remove(ldap_handle, dn_path, group_name,
1425                              group_ou, group_membership, ptr[LM_MEMBER], 
1426                              pUserOu, moira_list_id))
1427         com_err(whoami, 0, "Unable to remove %s from group %s", user_name, 
1428                 group_name);
1429       
1430       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1431         {
1432           if (rc = moira_connect())
1433             {
1434               critical_alert("AD incremental",
1435                              "Error contacting Moira server : %s",
1436                              error_message(rc));
1437               return;
1438             }
1439           
1440           if (rc = populate_group(ldap_handle, dn_path, group_name,
1441                                   group_ou, group_membership, security_flag,
1442                                   moira_list_id))
1443             com_err(whoami, 0, "Unable to remove %s from group %s",
1444                     user_name, group_name);
1445           moira_disconnect();
1446         }
1447       return;
1448     }
1449   
1450   com_err(whoami, 0, "Adding %s to list %s", user_name, group_name);
1451   pUserOu = user_ou;
1452   
1453   if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1454     {
1455       memset(machine_ou, '\0', sizeof(machine_ou));
1456       memset(NewMachineName, '\0', sizeof(NewMachineName));
1457
1458       if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], machine_ou, 
1459                          NewMachineName))
1460         return;
1461
1462       if (ptr[LM_MEMBER] != NULL)
1463         free(ptr[LM_MEMBER]);
1464
1465       ptr[LM_MEMBER] = strdup(NewMachineName);
1466       pUserOu = machine_ou;
1467     }
1468   else if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1469     {
1470       strcpy(member, ptr[LM_MEMBER]);
1471
1472       if (Exchange) 
1473         {
1474           if((s = strchr(member, '@')) == (char *) NULL)
1475             { 
1476               strcat(member, "@mit.edu");
1477               
1478               if (ptr[LM_MEMBER] != NULL)
1479                 free(ptr[LM_MEMBER]);
1480               ptr[LM_MEMBER] = strdup(member);
1481             }
1482           
1483           if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1484             {
1485               s = strrchr(member, '.');
1486               *s = '\0';
1487               strcat(s, ".mit.edu");
1488               
1489               if (ptr[LM_MEMBER] != NULL)
1490                 free(ptr[LM_MEMBER]);
1491               ptr[LM_MEMBER] = strdup(member);
1492             }
1493         }
1494       
1495       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], contact_ou))
1496         return;
1497
1498       pUserOu = contact_ou;
1499     }
1500   else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1501     {
1502       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], kerberos_ou))
1503         return;
1504
1505       pUserOu = kerberos_ou;
1506     }
1507   else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1508     {
1509       if ((rc = check_user(ldap_handle, dn_path, ptr[LM_MEMBER], 
1510                            moira_user_id)) == AD_NO_USER_FOUND)
1511         {
1512           if (rc = moira_connect())
1513             {
1514               critical_alert("AD incremental", 
1515                              "Error connection to Moira : %s",
1516                              error_message(rc));
1517               return;
1518             }
1519
1520           com_err(whoami, 0, "creating user %s", ptr[LM_MEMBER]);
1521           av[0] = ptr[LM_MEMBER];
1522           call_args[0] = (char *)ldap_handle;
1523           call_args[1] = dn_path;
1524           call_args[2] = moira_user_id;
1525           call_args[3] = NULL;
1526           
1527           callback_rc = 0;
1528
1529           if (Exchange)
1530             {
1531               group_count = 0;
1532               group_base = NULL;
1533           
1534               sprintf(filter, "(&(objectClass=group)(cn=%s))", ptr[LM_MEMBER]);
1535               attr_array[0] = "cn";
1536               attr_array[1] = NULL;
1537               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
1538                                        attr_array, &group_base, &group_count,
1539                                        LDAP_SCOPE_SUBTREE)) != 0)
1540                 {
1541                   com_err(whoami, 0, "Unable to process user %s : %s",
1542                           ptr[LM_MEMBER], ldap_err2string(rc));
1543                   return;
1544                 }
1545               
1546               if (group_count)
1547                 {
1548                   com_err(whoami, 0, "Object already exists with name %s",
1549                           ptr[LM_MEMBER]);
1550                   return;
1551                 }
1552           
1553               linklist_free(group_base);
1554               group_count = 0;
1555               group_base = NULL;
1556             }
1557
1558           if (rc = mr_query("get_user_account_by_login", 1, av, 
1559                             save_query_info, save_argv))
1560             {
1561               moira_disconnect();
1562               com_err(whoami, 0, "Unable to create user %s : %s",
1563                       ptr[LM_MEMBER], error_message(rc));
1564               return;
1565             }
1566
1567           if (rc = user_create(U_END, save_argv, call_args)) 
1568             {
1569               moira_disconnect();
1570               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1571               return;
1572             }
1573
1574           if (callback_rc)
1575             {
1576               moira_disconnect();
1577               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1578               return;
1579             }
1580         }
1581       else
1582         {
1583           if (rc != 0)
1584             return;
1585         }
1586       pUserOu = user_ou;
1587     }
1588   
1589   if (rc = member_add(ldap_handle, dn_path, group_name,
1590                       group_ou, group_membership, ptr[LM_MEMBER],
1591                       pUserOu, moira_list_id))
1592     com_err(whoami, 0, "Unable to add %s to group %s", user_name, group_name);
1593   
1594   if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1595     {
1596       if (rc = moira_connect())
1597         {
1598           critical_alert("AD incremental",
1599                          "Error contacting Moira server : %s",
1600                          error_message(rc));
1601           return;
1602         }
1603       
1604       if (rc = populate_group(ldap_handle, dn_path, group_name,
1605                               group_ou, group_membership, security_flag,
1606                               moira_list_id))
1607         com_err(whoami, 0, "Unable to add %s to group %s",
1608                 user_name, group_name);
1609       
1610       moira_disconnect();
1611     }
1612
1613   return;
1614 }
1615
1616
1617 #define U_USER_ID    10
1618 #define U_HOMEDIR    11
1619 #define U_PROFILEDIR 12
1620
1621 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
1622              char **before, int beforec, char **after, 
1623              int afterc)
1624 {
1625   LK_ENTRY *group_base;
1626   int   group_count;
1627   char  filter[128];
1628   char  *attr_array[3];
1629   int   rc;
1630   char  *av[7];
1631   char  after_user_id[32];
1632   char  before_user_id[32];
1633   char  *call_args[7];
1634   char  *save_argv[U_END];
1635
1636   if ((beforec == 0) && (afterc == 0))
1637     return;
1638
1639   memset(after_user_id, '\0', sizeof(after_user_id));
1640   memset(before_user_id, '\0', sizeof(before_user_id));
1641
1642   if (beforec > U_USER_ID)
1643     strcpy(before_user_id, before[U_USER_ID]);
1644
1645   if (afterc > U_USER_ID)
1646     strcpy(after_user_id, after[U_USER_ID]);
1647
1648   if ((beforec == 0) && (afterc == 0)) /*this case should never happen */
1649     return;
1650
1651   if ((beforec == 0) && (afterc != 0)) 
1652     {
1653       /*this case only happens when the account*/
1654       /*account is first created but not usable*/
1655
1656       com_err(whoami, 0, "Unable to process user %s because the user account "
1657               "is not yet usable", after[U_NAME]);
1658       return;
1659     }
1660
1661   /*this case only happens when the account is expunged */
1662
1663   if ((beforec != 0) && (afterc == 0)) 
1664     {                                 
1665       if (atoi(before[U_STATE]) == 0)
1666         {
1667           com_err(whoami, 0, "expunging user %s from AD", before[U_NAME]);
1668           user_delete(ldap_handle, dn_path, before[U_NAME], before_user_id);
1669         }
1670       else
1671         {
1672           com_err(whoami, 0, "Unable to process because user %s has been "
1673                   "previously expungeded", before[U_NAME]);
1674         }
1675       return;
1676     }
1677
1678   /*process anything that gets here*/
1679
1680   if ((rc = check_user(ldap_handle, dn_path, before[U_NAME], 
1681                        before_user_id)) == AD_NO_USER_FOUND)
1682     {
1683       if (!check_string(after[U_NAME]))
1684         return;
1685
1686       if (rc = moira_connect())
1687         {
1688           critical_alert("AD incremental", 
1689                          "Error connection to Moira : %s",
1690                          error_message(rc));
1691           return;
1692         }
1693
1694       com_err(whoami, 0, "creating user %s", after[U_NAME]);
1695       
1696       av[0] = after[U_NAME];
1697       call_args[0] = (char *)ldap_handle;
1698       call_args[1] = dn_path;
1699       call_args[2] = after_user_id;
1700       call_args[3] = NULL;
1701       callback_rc = 0;
1702
1703       if (Exchange) 
1704         {
1705           group_count = 0;
1706           group_base = NULL;
1707           
1708           sprintf(filter, "(&(objectClass=group)(cn=%s))", after[U_NAME]);
1709           attr_array[0] = "cn";
1710           attr_array[1] = NULL;
1711           
1712           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
1713                                    &group_base, &group_count,
1714                                    LDAP_SCOPE_SUBTREE)) != 0)
1715             {
1716               com_err(whoami, 0, "Unable to process user %s : %s",
1717                       after[U_NAME], ldap_err2string(rc));
1718               return;
1719             }
1720           
1721           if (group_count >= 1)
1722             {
1723               com_err(whoami, 0, "Object already exists with name %s",
1724                       after[U_NAME]);
1725               return;
1726             }
1727       
1728           linklist_free(group_base);
1729           group_count = 0;
1730           group_base = NULL;
1731         }
1732
1733       if (rc = mr_query("get_user_account_by_login", 1, av,
1734                         save_query_info, save_argv))
1735         {
1736           moira_disconnect();
1737           com_err(whoami, 0, "Unable to create user %s : %s",
1738                   after[U_NAME], error_message(rc));
1739           return;
1740         }
1741
1742       if (rc = user_create(U_END, save_argv, call_args)) 
1743         {
1744           com_err(whoami, 0, "Unable to create user %s : %s",
1745                   after[U_NAME], error_message(rc));
1746           return;
1747         }
1748       
1749       if (callback_rc)
1750         {
1751           moira_disconnect();
1752           com_err(whoami, 0, "Unable to create user %s", after[U_NAME]);
1753           return;
1754         }
1755
1756       return;
1757     }
1758   else
1759     {
1760       if (rc != 0)
1761         return;
1762     }
1763
1764   if (strcmp(before[U_NAME], after[U_NAME]))
1765     {
1766       if ((check_string(before[U_NAME])) && (check_string(after[U_NAME])))
1767         {
1768           com_err(whoami, 0, "changing user %s to %s", 
1769                   before[U_NAME], after[U_NAME]);
1770
1771           if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], 
1772                                 after[U_NAME])) != LDAP_SUCCESS)
1773             {
1774               return;
1775             }
1776         }
1777     }
1778
1779   com_err(whoami, 0, "updating user %s information", after[U_NAME]);
1780   rc = user_update(ldap_handle, dn_path, after[U_NAME],
1781                    after[U_UID], after[U_MITID], 
1782                    after_user_id, atoi(after[U_STATE]),
1783                    after[U_HOMEDIR], after[U_PROFILEDIR],
1784                    after[U_FIRST], after[U_MIDDLE], after[U_LAST]);
1785
1786   return;
1787 }
1788
1789 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
1790                         char *oldValue, char *newValue,
1791                         char ***modvalues, int type)
1792 {
1793   LK_ENTRY    *linklist_ptr;
1794   int         i;
1795   char        *cPtr;
1796   
1797   if (((*modvalues) = calloc(1, 
1798                              (modvalue_count + 1) * sizeof(char *))) == NULL)
1799     {
1800       return(1);
1801     }
1802
1803   for (i = 0; i < (modvalue_count + 1); i++)
1804     (*modvalues)[i] = NULL;
1805
1806   if (modvalue_count != 0)
1807     {
1808       linklist_ptr = linklist_base;
1809       for (i = 0; i < modvalue_count; i++)
1810         {
1811           if ((oldValue != NULL) && (newValue != NULL))
1812             {
1813               if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue))
1814                   != (char *)NULL)
1815                 {
1816                   if (type == REPLACE)
1817                     {
1818                       if (((*modvalues)[i] = calloc(1, strlen(newValue) + 1))
1819                           == NULL)
1820                         return(1);
1821                       memset((*modvalues)[i], '\0', strlen(newValue) + 1);
1822                       strcpy((*modvalues)[i], newValue);
1823                     }
1824                   else
1825                     {
1826                       if (((*modvalues)[i] = calloc(1, 
1827                                         (int)(cPtr - linklist_ptr->value) + 
1828                                                (linklist_ptr->length - 
1829                                                strlen(oldValue)) + 
1830                                                strlen(newValue) + 1)) == NULL)
1831                         return(1);
1832                       memset((*modvalues)[i], '\0', 
1833                              (int)(cPtr - linklist_ptr->value) + 
1834                              (linklist_ptr->length - strlen(oldValue)) + 
1835                              strlen(newValue) + 1);
1836                       memcpy((*modvalues)[i], linklist_ptr->value, 
1837                              (int)(cPtr - linklist_ptr->value));
1838                       strcat((*modvalues)[i], newValue);
1839                       strcat((*modvalues)[i], 
1840                              &linklist_ptr->value[(int)(cPtr - 
1841                                      linklist_ptr->value) + strlen(oldValue)]);
1842                     }
1843                 }
1844               else
1845                 {
1846                   (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1847                   memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1848                   memcpy((*modvalues)[i], linklist_ptr->value,
1849                          linklist_ptr->length);
1850                 }
1851             }
1852         else
1853             {
1854               (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1855               memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1856               memcpy((*modvalues)[i], linklist_ptr->value,
1857                      linklist_ptr->length);
1858             }
1859           linklist_ptr = linklist_ptr->next;
1860         }
1861       (*modvalues)[i] = NULL;
1862     }
1863   return(0);
1864 }
1865
1866
1867 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
1868                    char **attr_array, LK_ENTRY **linklist_base,
1869                    int *linklist_count, unsigned long ScopeType)
1870 {
1871   ULONG       rc;
1872   LDAPMessage *ldap_entry;
1873
1874   rc = 0;
1875   ldap_entry = NULL;
1876   (*linklist_base) = NULL;
1877   (*linklist_count) = 0;
1878
1879   if ((rc = ldap_search_s(ldap_handle, dn_path, ScopeType, 
1880                           search_exp, attr_array, 0, 
1881                           &ldap_entry)) != LDAP_SUCCESS)
1882       {
1883         if (rc != LDAP_SIZELIMIT_EXCEEDED)
1884           return(0);
1885       }
1886
1887   rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, 
1888                         linklist_count);
1889
1890   ldap_msgfree(ldap_entry);
1891   return(rc);
1892 }
1893
1894 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
1895                      LK_ENTRY **linklist_base, int *linklist_count)
1896 {
1897   char        distinguished_name[1024];
1898   LK_ENTRY    *linklist_ptr;
1899   int         rc;
1900
1901   if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL)
1902     return(0);
1903   
1904   memset(distinguished_name, '\0', sizeof(distinguished_name));
1905   get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1906
1907   if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name,
1908                                 linklist_base)) != 0)
1909     return(rc);
1910
1911   while ((ldap_entry = ldap_next_entry(ldap_handle, ldap_entry)) != NULL)
1912     {
1913       memset(distinguished_name, '\0', sizeof(distinguished_name));
1914       get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1915       
1916       if ((rc = retrieve_attributes(ldap_handle, ldap_entry, 
1917                                     distinguished_name, linklist_base)) != 0)
1918         return(rc);
1919     }
1920
1921   linklist_ptr = (*linklist_base);
1922   (*linklist_count) = 0;
1923
1924   while (linklist_ptr != NULL)
1925     {
1926       ++(*linklist_count);
1927       linklist_ptr = linklist_ptr->next;
1928     }
1929
1930   return(0);
1931 }
1932
1933 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
1934                         char *distinguished_name, LK_ENTRY **linklist_current)
1935 {
1936   char        *Attribute;
1937   BerElement  *ptr;
1938
1939   ptr = NULL;
1940
1941   if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, 
1942                                         &ptr)) != NULL)
1943     {
1944       retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name,
1945                       linklist_current);
1946       ldap_memfree(Attribute);
1947       while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, 
1948                                               ptr)) != NULL)
1949         {
1950           retrieve_values(ldap_handle, ldap_entry, Attribute,
1951                           distinguished_name, linklist_current);
1952           ldap_memfree(Attribute);
1953         }
1954     }
1955
1956   ldap_ber_free(ptr, 0);
1957
1958   return(0);
1959 }
1960
1961 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
1962                     char *Attribute, char *distinguished_name,
1963                     LK_ENTRY **linklist_current)
1964 {
1965   char        **str_value;
1966   char        temp[256];
1967   void        **Ptr;
1968   int         use_bervalue;
1969   LK_ENTRY    *linklist_previous;
1970   LDAP_BERVAL **ber_value;
1971   DWORD       ber_length;
1972
1973 #ifdef LDAP_DEBUG
1974   SID         *sid;
1975   GUID        *guid;
1976   int         i;
1977   int         intValue;
1978   DWORD       *subauth;
1979   SID_IDENTIFIER_AUTHORITY    *sid_auth;
1980   unsigned char   *subauth_count;
1981 #endif /*LDAP_BEGUG*/
1982
1983   use_bervalue = 0;
1984   memset(temp, '\0', sizeof(temp));
1985
1986   if ((!strcmp(Attribute, "objectSid")) ||
1987       (!strcmp(Attribute, "objectGUID")))
1988     use_bervalue = 1;
1989   
1990   if (use_bervalue)
1991     {
1992       ber_value = ldap_get_values_len(ldap_handle, ldap_entry, Attribute);
1993       Ptr = (void **)ber_value;
1994       str_value = NULL;
1995     }
1996   else
1997     {
1998       str_value = ldap_get_values(ldap_handle, ldap_entry, Attribute);
1999       Ptr = (void **)str_value;
2000       ber_value = NULL;
2001     }
2002
2003   if (Ptr != NULL)
2004     {
2005       for (; *Ptr; Ptr++) 
2006         {
2007           if ((linklist_previous = calloc(1, sizeof(LK_ENTRY))) == NULL)
2008             return(1);
2009
2010           memset(linklist_previous, '\0', sizeof(LK_ENTRY));
2011           linklist_previous->next = (*linklist_current);
2012           (*linklist_current) = linklist_previous;
2013           
2014           if (((*linklist_current)->attribute = calloc(1, 
2015                                               strlen(Attribute) + 1)) == NULL)
2016             return(1);
2017
2018           memset((*linklist_current)->attribute, '\0', strlen(Attribute) + 1);
2019           strcpy((*linklist_current)->attribute, Attribute);
2020
2021           if (use_bervalue)
2022             {
2023               ber_length = (*(LDAP_BERVAL **)Ptr)->bv_len;
2024
2025               if (((*linklist_current)->value = calloc(1, ber_length)) == NULL)
2026                 return(1);
2027
2028               memset((*linklist_current)->value, '\0', ber_length);
2029               memcpy((*linklist_current)->value, 
2030                      (*(LDAP_BERVAL **)Ptr)->bv_val, ber_length);
2031               (*linklist_current)->length = ber_length;
2032             }
2033           else
2034             {
2035               if (((*linklist_current)->value = calloc(1, 
2036                                                     strlen(*Ptr) + 1)) == NULL)
2037                 return(1);
2038
2039               memset((*linklist_current)->value, '\0', strlen(*Ptr) + 1);
2040               (*linklist_current)->length = strlen(*Ptr);
2041               strcpy((*linklist_current)->value, *Ptr);
2042             }
2043
2044           (*linklist_current)->ber_value = use_bervalue;
2045
2046           if (((*linklist_current)->dn = calloc(1, 
2047                                       strlen(distinguished_name) + 1)) == NULL)
2048             return(1);
2049
2050           memset((*linklist_current)->dn, '\0', 
2051                  strlen(distinguished_name) + 1);
2052           strcpy((*linklist_current)->dn, distinguished_name);
2053
2054 #ifdef LDAP_DEBUG
2055           if (!strcmp(Attribute, "objectGUID"))
2056             {
2057               guid = (GUID *)((*linklist_current)->value);
2058               sprintf(temp, 
2059                       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
2060                       guid->Data1, guid->Data2, guid->Data3, 
2061                       guid->Data4[0], guid->Data4[1], guid->Data4[2], 
2062                       guid->Data4[3], guid->Data4[4], guid->Data4[5], 
2063                       guid->Data4[6], guid->Data4[7]);
2064               print_to_screen("     %20s : {%s}\n", Attribute, temp);
2065             }
2066           else if (!strcmp(Attribute, "objectSid"))
2067             {
2068               sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val);
2069
2070 #ifdef _WIN32
2071               print_to_screen("        Revision = %d\n", sid->Revision);
2072               print_to_screen("        SID Identifier Authority:\n");
2073               sid_auth = &sid->IdentifierAuthority;
2074               if (sid_auth->Value[0])
2075                 print_to_screen("            SECURITY_NULL_SID_AUTHORITY\n");
2076               else if (sid_auth->Value[1])
2077                 print_to_screen("            SECURITY_WORLD_SID_AUTHORITY\n");
2078               else if (sid_auth->Value[2])
2079                 print_to_screen("            SECURITY_LOCAL_SID_AUTHORITY\n");
2080               else if (sid_auth->Value[3])
2081                 print_to_screen("           SECURITY_CREATOR_SID_AUTHORITY\n");
2082               else if (sid_auth->Value[5])
2083                 print_to_screen("            SECURITY_NT_AUTHORITY\n");
2084               else
2085                 print_to_screen("            UNKNOWN SID AUTHORITY\n");
2086               subauth_count = GetSidSubAuthorityCount(sid);
2087               print_to_screen("        SidSubAuthorityCount = %d\n", 
2088                               *subauth_count);
2089               print_to_screen("        SidSubAuthority:\n");
2090               for (i = 0; i < *subauth_count; i++)
2091                 {
2092                   if ((subauth = GetSidSubAuthority(sid, i)) != NULL)
2093                     print_to_screen("            %u\n", *subauth);
2094                 }
2095 #endif
2096             }
2097           else if ((!memcmp(Attribute, "userAccountControl", 
2098                             strlen("userAccountControl"))) ||
2099                    (!memcmp(Attribute, "sAMAccountType", 
2100                             strlen("sAmAccountType"))))
2101             {
2102               intValue = atoi(*Ptr);
2103               print_to_screen("     %20s : %ld\n",Attribute, intValue);
2104
2105               if (!memcmp(Attribute, "userAccountControl", 
2106                           strlen("userAccountControl")))
2107                 {
2108                   if (intValue & UF_ACCOUNTDISABLE)
2109                     print_to_screen("     %20s :    %s\n", 
2110                                     "", "Account disabled");
2111                   else
2112                     print_to_screen("     %20s :    %s\n", 
2113                                     "", "Account active");
2114                   if (intValue & UF_HOMEDIR_REQUIRED)
2115                     print_to_screen("     %20s :    %s\n", 
2116                                     "", "Home directory required");
2117                   if (intValue & UF_LOCKOUT)
2118                     print_to_screen("     %20s :    %s\n", 
2119                                     "", "Account locked out");
2120                   if (intValue & UF_PASSWD_NOTREQD)
2121                     print_to_screen("     %20s :    %s\n", 
2122                                     "", "No password required");
2123                   if (intValue & UF_PASSWD_CANT_CHANGE)
2124                     print_to_screen("     %20s :    %s\n",
2125                                     "", "Cannot change password");
2126                   if (intValue & UF_TEMP_DUPLICATE_ACCOUNT)
2127                     print_to_screen("     %20s :    %s\n", 
2128                                     "", "Temp duplicate account");
2129                   if (intValue & UF_NORMAL_ACCOUNT)
2130                     print_to_screen("     %20s :    %s\n", 
2131                                     "", "Normal account");
2132                   if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT)
2133                     print_to_screen("     %20s :    %s\n", 
2134                                     "", "Interdomain trust account");
2135                   if (intValue & UF_WORKSTATION_TRUST_ACCOUNT)
2136                     print_to_screen("     %20s :    %s\n", 
2137                                     "", "Workstation trust account");
2138                   if (intValue & UF_SERVER_TRUST_ACCOUNT)
2139                     print_to_screen("     %20s :    %s\n", 
2140                                     "", "Server trust account");
2141                 }
2142             }
2143           else
2144             {
2145               print_to_screen("     %20s : %s\n",Attribute, *Ptr);
2146             }
2147 #endif /*LDAP_DEBUG*/
2148         }
2149
2150       if (str_value != NULL)
2151         ldap_value_free(str_value);
2152
2153       if (ber_value != NULL)
2154         ldap_value_free_len(ber_value);
2155     }
2156
2157   (*linklist_current) = linklist_previous;
2158
2159   return(0);
2160 }
2161
2162 int moira_connect(void)
2163 {
2164   long    rc;
2165   char    HostName[64];
2166
2167   if (!mr_connections++)
2168     {
2169
2170 #ifdef _WIN32
2171       memset(HostName, '\0', sizeof(HostName));
2172       strcpy(HostName, "ttsp");
2173       rc = mr_connect_cl(HostName, "winad.incr", QUERY_VERSION, 1);
2174 #else
2175       struct utsname uts;
2176       uname(&uts);
2177       rc = mr_connect_cl(uts.nodename, "winad.incr", QUERY_VERSION, 1);
2178 #endif /*WIN32*/
2179
2180       return rc;
2181     }
2182
2183   return 0;
2184 }
2185
2186 int check_winad(void)
2187 {
2188   int i;
2189   
2190   for (i = 0; file_exists(STOP_FILE); i++)
2191     {
2192       if (i > 30)
2193         {
2194           critical_alert("AD incremental",
2195                          "WINAD incremental failed (%s exists): %s",
2196                          STOP_FILE, tbl_buf);
2197           return(1);
2198         }
2199
2200       sleep(60);
2201     }
2202
2203   return(0);
2204 }
2205
2206 int moira_disconnect(void)
2207 {
2208
2209   if (!--mr_connections)
2210     {
2211       mr_disconnect();
2212     }
2213
2214   return 0;
2215 }
2216
2217 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
2218                             char *distinguished_name)
2219 {
2220   char    *CName;
2221   
2222   CName = ldap_get_dn(ldap_handle, ldap_entry);
2223
2224   if (CName == NULL)
2225     return;
2226
2227   strcpy(distinguished_name, CName);
2228   ldap_memfree(CName);
2229 }
2230
2231 int linklist_create_entry(char *attribute, char *value, 
2232                           LK_ENTRY **linklist_entry)
2233 {
2234   (*linklist_entry) = calloc(1, sizeof(LK_ENTRY));
2235
2236   if (!(*linklist_entry))
2237     {
2238       return(1);
2239     }
2240
2241   memset((*linklist_entry), '\0', sizeof(LK_ENTRY));
2242   (*linklist_entry)->attribute = calloc(1, strlen(attribute) + 1);
2243   memset((*linklist_entry)->attribute, '\0', strlen(attribute) + 1);
2244   strcpy((*linklist_entry)->attribute, attribute);
2245   (*linklist_entry)->value = calloc(1, strlen(value) + 1);
2246   memset((*linklist_entry)->value, '\0', strlen(value) + 1);
2247   strcpy((*linklist_entry)->value, value);
2248   (*linklist_entry)->length = strlen(value);
2249   (*linklist_entry)->next = NULL;
2250
2251   return(0);
2252 }
2253
2254 void print_to_screen(const char *fmt, ...)
2255 {
2256   va_list pvar;
2257
2258   va_start(pvar, fmt);
2259   vfprintf(stderr, fmt, pvar);
2260   fflush(stderr);
2261   va_end(pvar);
2262 }
2263
2264 int get_group_membership(char *group_membership, char *group_ou, 
2265                          int *security_flag, char **av)
2266 {
2267   int  maillist_flag;
2268   int  group_flag;
2269   
2270   maillist_flag = atoi(av[L_MAILLIST]);
2271   group_flag = atoi(av[L_GROUP]);
2272
2273   if (security_flag != NULL)
2274     (*security_flag) = 0;
2275   
2276   if ((maillist_flag) && (group_flag))
2277     {
2278       if (group_membership != NULL)
2279         group_membership[0] = 'B';
2280
2281       if (security_flag != NULL)
2282         (*security_flag) = 1;
2283
2284       if (group_ou != NULL)
2285         strcpy(group_ou, group_ou_both);
2286     }
2287   else if ((!maillist_flag) && (group_flag))
2288     {
2289       if (group_membership != NULL)
2290         group_membership[0] = 'S';
2291
2292       if (security_flag != NULL)
2293         (*security_flag) = 1;
2294
2295       if (group_ou != NULL)
2296         strcpy(group_ou, group_ou_security);
2297     }
2298   else if ((maillist_flag) && (!group_flag))
2299     {
2300       if (group_membership != NULL)
2301         group_membership[0] = 'D';
2302
2303       if (group_ou != NULL)
2304         strcpy(group_ou, group_ou_distribution);
2305     }
2306   else
2307     {
2308       if (group_membership != NULL)
2309         group_membership[0] = 'N';
2310
2311       if (group_ou != NULL)
2312         strcpy(group_ou, group_ou_neither);
2313     }
2314
2315   return(0);
2316 }
2317
2318 int group_rename(LDAP *ldap_handle, char *dn_path, 
2319                  char *before_group_name, char *before_group_membership, 
2320                  char *before_group_ou, int before_security_flag, 
2321                  char *before_desc, char *after_group_name, 
2322                  char *after_group_membership, char *after_group_ou, 
2323                  int after_security_flag, char *after_desc,
2324                  char *MoiraId, char *filter, char *maillist)
2325 {
2326   LDAPMod   *mods[20];
2327   char      old_dn[512];
2328   char      new_dn[512];
2329   char      new_dn_path[512];
2330   char      sam_name[256];
2331   char      mail[256];
2332   char      mail_nickname[256];
2333   char      proxy_address[256];
2334   char      address_book[256];
2335   char      *attr_array[3];
2336   char      *mitMoiraId_v[] = {NULL, NULL};
2337   char      *name_v[] = {NULL, NULL};
2338   char      *samAccountName_v[] = {NULL, NULL};
2339   char      *groupTypeControl_v[] = {NULL, NULL};
2340   char      *mail_v[] = {NULL, NULL};
2341   char      *proxy_address_v[] = {NULL, NULL};
2342   char      *mail_nickname_v[] = {NULL, NULL};
2343   char      *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("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   com_err(whoami, 0, "AD_GET_GROUP: samname is %s%s", group_name, group_suffix);
5740   attr_array[0] = attribute;
5741   attr_array[1] = NULL;
5742
5743   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5744                            linklist_base, linklist_count, 
5745                            LDAP_SCOPE_SUBTREE)) != 0)
5746     {
5747       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
5748               MoiraId, ldap_err2string(rc));
5749       return(rc);
5750     }
5751
5752   if ((*linklist_count) == 1)
5753     {
5754       strcpy(rFilter, filter);
5755       return(0);
5756     }
5757
5758   return(0);
5759 }
5760
5761 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
5762 {
5763   char filter[128];
5764   char *attr_array[3];
5765   char SamAccountName[64];
5766   int  group_count;
5767   int  rc;
5768   LK_ENTRY  *group_base;
5769   LK_ENTRY  *gPtr;
5770
5771   group_count = 0;
5772   group_base = NULL;
5773
5774   if (strlen(MoiraId) != 0)
5775     {
5776       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5777       attr_array[0] = "sAMAccountName";
5778       attr_array[1] = NULL;
5779       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5780                                &group_base, &group_count, 
5781                                LDAP_SCOPE_SUBTREE)) != 0)
5782         {
5783           com_err(whoami, 0, "Unable to process user %s : %s",
5784                   UserName, ldap_err2string(rc));
5785           return(rc);
5786         }
5787
5788       if (group_count > 1)
5789         {
5790           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
5791                   MoiraId);
5792           gPtr = group_base;
5793
5794           while (gPtr)
5795             {
5796               com_err(whoami, 0, "user %s exist with MoiraId = %s",
5797                       gPtr->value, MoiraId);
5798               gPtr = gPtr->next;
5799             }
5800         }
5801     }
5802
5803   if (group_count != 1)
5804     {
5805       linklist_free(group_base);
5806       group_count = 0;
5807       group_base = NULL;
5808       sprintf(filter, "(sAMAccountName=%s)", UserName);
5809       attr_array[0] = "sAMAccountName";
5810       attr_array[1] = NULL;
5811
5812       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5813                                &group_base, &group_count, 
5814                                LDAP_SCOPE_SUBTREE)) != 0)
5815         {
5816           com_err(whoami, 0, "Unable to process user %s : %s",
5817                   UserName, ldap_err2string(rc));
5818           return(rc);
5819         }
5820     }
5821
5822   if (group_count != 1)
5823     {
5824       linklist_free(group_base);
5825       return(AD_NO_USER_FOUND);
5826     }
5827
5828   strcpy(SamAccountName, group_base->value);
5829   linklist_free(group_base);
5830   group_count = 0;
5831   rc = 0;
5832
5833   if (strcmp(SamAccountName, UserName))
5834     {
5835       rc = user_rename(ldap_handle, dn_path, SamAccountName, 
5836                        UserName);
5837     }
5838
5839   return(0);
5840 }
5841
5842 void container_get_dn(char *src, char *dest)
5843 {
5844   char *sPtr;
5845   char *array[20];
5846   char name[256];
5847   int  n;
5848
5849   memset(array, '\0', 20 * sizeof(array[0]));
5850
5851   if (strlen(src) == 0)
5852     return;
5853
5854   strcpy(name, src);
5855   sPtr = name;
5856   n = 0;
5857   array[n] = name;
5858   ++n;
5859
5860   while (*sPtr)
5861     {
5862       if ((*sPtr) == '/')
5863         {
5864           (*sPtr) = '\0';
5865           ++sPtr;
5866           array[n] = sPtr;
5867           ++n;
5868         }
5869       else
5870         ++sPtr;
5871     }
5872
5873   strcpy(dest, "OU=");
5874
5875   while (n != 0)
5876     {
5877       strcat(dest, array[n-1]);
5878       --n;
5879       if (n > 0)
5880         {
5881           strcat(dest, ",OU=");
5882         }
5883     }
5884
5885   return;
5886 }
5887
5888 void container_get_name(char *src, char *dest)
5889 {
5890   char *sPtr;
5891   char *dPtr;
5892
5893   if (strlen(src) == 0)
5894     return;
5895
5896   sPtr = src;
5897   dPtr = src;
5898
5899   while (*sPtr)
5900     {
5901       if ((*sPtr) == '/')
5902         {
5903           dPtr = sPtr;
5904           ++dPtr;
5905         }
5906       ++sPtr;
5907     }
5908
5909   strcpy(dest, dPtr);
5910   return;
5911 }
5912
5913 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
5914 {
5915   char cName[256];
5916   char *av[7];
5917   int  i;
5918   int  rc;
5919
5920   strcpy(cName, name);
5921
5922   for (i = 0; i < (int)strlen(cName); i++)
5923     {
5924       if (cName[i] == '/')
5925         {
5926           cName[i] = '\0';
5927           av[CONTAINER_NAME] = cName;
5928           av[CONTAINER_DESC] = "";
5929           av[CONTAINER_LOCATION] = "";
5930           av[CONTAINER_CONTACT] = "";
5931           av[CONTAINER_TYPE] = "";
5932           av[CONTAINER_ID] = "";
5933           av[CONTAINER_ROWID] = "";
5934           rc = container_create(ldap_handle, dn_path, 7, av);
5935
5936           if (rc == LDAP_SUCCESS)
5937             {
5938               com_err(whoami, 0, "container %s created without a mitMoiraId", 
5939                       cName);
5940             }
5941
5942           cName[i] = '/';
5943         }
5944     }
5945 }
5946
5947 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
5948                      char **before, int afterc, char **after)
5949 {
5950   char      dName[256];
5951   char      cName[256];
5952   char      new_cn[128];
5953   char      new_dn_path[256];
5954   char      temp[256];
5955   char      distinguishedName[256];
5956   char      *pPtr;
5957   int       rc;
5958   int       i;
5959
5960   memset(cName, '\0', sizeof(cName));
5961   container_get_name(after[CONTAINER_NAME], cName);
5962
5963   if (!check_container_name(cName))
5964     {
5965       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
5966               cName);
5967       return(AD_INVALID_NAME);
5968     }
5969
5970   memset(distinguishedName, '\0', sizeof(distinguishedName));
5971
5972   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
5973                                            distinguishedName, beforec, before))
5974     return(rc);
5975
5976   if (strlen(distinguishedName) == 0)
5977     {
5978       rc = container_create(ldap_handle, dn_path, afterc, after);
5979       return(rc);
5980     }
5981
5982   strcpy(temp, after[CONTAINER_NAME]);
5983   pPtr = temp;
5984
5985   for (i = 0; i < (int)strlen(temp); i++)
5986     {
5987       if (temp[i] == '/')
5988         {
5989           pPtr = &temp[i];
5990         }
5991     }
5992
5993   (*pPtr) = '\0';
5994
5995   container_get_dn(temp, dName);
5996
5997   if (strlen(temp) != 0)
5998     sprintf(new_dn_path, "%s,%s", dName, dn_path);
5999   else
6000     sprintf(new_dn_path, "%s", dn_path);
6001
6002   sprintf(new_cn, "OU=%s", cName);
6003
6004   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6005
6006   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6007                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6008     {
6009       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6010               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6011               ldap_err2string(rc));
6012       return(rc);
6013     }
6014
6015   memset(dName, '\0', sizeof(dName));
6016   container_get_dn(after[CONTAINER_NAME], dName);
6017   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6018
6019   return(rc);
6020 }
6021
6022 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6023 {
6024   char      distinguishedName[256];
6025   int       rc;
6026
6027   memset(distinguishedName, '\0', sizeof(distinguishedName));
6028
6029   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6030                                            distinguishedName, count, av))
6031     return(rc);
6032
6033   if (strlen(distinguishedName) == 0)
6034     return(0);
6035
6036   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6037     {
6038       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6039         container_move_objects(ldap_handle, dn_path, distinguishedName);
6040       else
6041         com_err(whoami, 0, "Unable to delete container %s from AD : %s",
6042                 av[CONTAINER_NAME], ldap_err2string(rc));
6043     }
6044
6045   return(rc);
6046 }
6047
6048 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6049 {
6050   char      *attr_array[3];
6051   LK_ENTRY  *group_base;
6052   int       group_count;
6053   LDAPMod   *mods[20];
6054   char      *objectClass_v[] = {"top", 
6055                            "organizationalUnit", 
6056                            NULL};
6057
6058   char *ou_v[] = {NULL, NULL};
6059   char *name_v[] = {NULL, NULL};
6060   char *moiraId_v[] = {NULL, NULL};
6061   char *desc_v[] = {NULL, NULL};
6062   char *managedBy_v[] = {NULL, NULL};
6063   char dName[256];
6064   char cName[256];
6065   char managedByDN[256];
6066   char filter[256];
6067   char temp[256];
6068   int  n;
6069   int  i;
6070   int  rc;
6071
6072   memset(filter, '\0', sizeof(filter));
6073   memset(dName, '\0', sizeof(dName));
6074   memset(cName, '\0', sizeof(cName));
6075   memset(managedByDN, '\0', sizeof(managedByDN));
6076   container_get_dn(av[CONTAINER_NAME], dName);
6077   container_get_name(av[CONTAINER_NAME], cName);
6078
6079   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6080     {
6081       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6082               cName);
6083       return(AD_INVALID_NAME);
6084     }
6085
6086   if (!check_container_name(cName))
6087     {
6088       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6089               cName);
6090       return(AD_INVALID_NAME);
6091     }
6092
6093   n = 0;
6094   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6095   name_v[0] = cName;
6096   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6097   ou_v[0] = cName;
6098   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6099
6100   if (strlen(av[CONTAINER_ROWID]) != 0)
6101     {
6102       moiraId_v[0] = av[CONTAINER_ROWID];
6103       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6104     }
6105
6106   if (strlen(av[CONTAINER_DESC]) != 0)
6107     {
6108       desc_v[0] = av[CONTAINER_DESC];
6109       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6110     }
6111
6112   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6113     {
6114       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6115         {
6116           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6117                               kerberos_ou))
6118             {
6119               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6120                       kerberos_ou, dn_path);
6121               managedBy_v[0] = managedByDN;
6122               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6123             }
6124         }
6125       else
6126         {
6127           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6128             {
6129               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6130                       "(objectClass=user)))", av[CONTAINER_ID]);
6131             }
6132
6133           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6134             {
6135               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6136                       av[CONTAINER_ID]);
6137             }
6138
6139           if (strlen(filter) != 0)
6140             {
6141               attr_array[0] = "distinguishedName";
6142               attr_array[1] = NULL;
6143               group_count = 0;
6144               group_base = NULL;
6145               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6146                                        attr_array, 
6147                                        &group_base, &group_count, 
6148                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6149                 {
6150                   if (group_count == 1)
6151                     {
6152                       strcpy(managedByDN, group_base->value);
6153                       managedBy_v[0] = managedByDN;
6154                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6155                     }
6156                   linklist_free(group_base);
6157                   group_base = NULL;
6158                   group_count = 0;
6159                 }
6160             }
6161         }
6162     }
6163   
6164   mods[n] = NULL;
6165
6166   sprintf(temp, "%s,%s", dName, dn_path);
6167   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
6168   
6169   for (i = 0; i < n; i++)
6170     free(mods[i]);
6171   
6172   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
6173     {
6174       com_err(whoami, 0, "Unable to create container %s : %s",
6175               cName, ldap_err2string(rc));
6176       return(rc);
6177     }
6178
6179   if (rc == LDAP_ALREADY_EXISTS)
6180     {
6181       if (strlen(av[CONTAINER_ROWID]) != 0)
6182         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
6183     }
6184
6185   return(rc);
6186 }
6187
6188 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
6189                      char **before, int afterc, char **after)
6190 {
6191   char distinguishedName[256];
6192   int  rc;
6193
6194   memset(distinguishedName, '\0', sizeof(distinguishedName));
6195
6196   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6197                                            distinguishedName, afterc, after))
6198     return(rc);
6199
6200   if (strlen(distinguishedName) == 0)
6201     {
6202       rc = container_create(ldap_handle, dn_path, afterc, after);
6203       return(rc);
6204     }
6205   
6206   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6207   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
6208                           after);
6209
6210   return(rc);
6211 }
6212
6213 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
6214                                     char *distinguishedName, int count, 
6215                                     char **av)
6216 {
6217   char      *attr_array[3];
6218   LK_ENTRY  *group_base;
6219   int       group_count;
6220   char      dName[256];
6221   char      cName[256];
6222   char      filter[512];
6223   int       rc;
6224
6225   memset(filter, '\0', sizeof(filter));
6226   memset(dName, '\0', sizeof(dName));
6227   memset(cName, '\0', sizeof(cName));
6228   container_get_dn(av[CONTAINER_NAME], dName);
6229   container_get_name(av[CONTAINER_NAME], cName);
6230
6231   if (strlen(dName) == 0)
6232     {
6233       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6234               av[CONTAINER_NAME]);
6235       return(AD_INVALID_NAME);
6236     }
6237
6238   if (!check_container_name(cName))
6239     {
6240       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6241               cName);
6242       return(AD_INVALID_NAME);
6243     }
6244   
6245   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
6246           av[CONTAINER_ROWID]);
6247   attr_array[0] = "distinguishedName";
6248   attr_array[1] = NULL;
6249   group_count = 0;
6250   group_base = NULL;
6251
6252   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6253                            &group_base, &group_count, 
6254                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6255     {
6256       if (group_count == 1)
6257         {
6258           strcpy(distinguishedName, group_base->value);
6259         }
6260
6261       linklist_free(group_base);
6262       group_base = NULL;
6263       group_count = 0;
6264     }
6265
6266   if (strlen(distinguishedName) == 0)
6267     {
6268       sprintf(filter, "(&(objectClass=organizationalUnit)"
6269               "(distinguishedName=%s,%s))", dName, dn_path);
6270       attr_array[0] = "distinguishedName";
6271       attr_array[1] = NULL;
6272       group_count = 0;
6273       group_base = NULL;
6274
6275       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6276                                &group_base, &group_count, 
6277                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6278         {
6279           if (group_count == 1)
6280             {
6281               strcpy(distinguishedName, group_base->value);
6282             }
6283
6284           linklist_free(group_base);
6285           group_base = NULL;
6286           group_count = 0;
6287         }
6288     }
6289
6290   return(0);
6291 }
6292
6293 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
6294                        char *distinguishedName, int count, char **av)
6295 {
6296   char      *attr_array[5];
6297   LK_ENTRY  *group_base;
6298   LK_ENTRY  *pPtr;
6299   LDAPMod   *mods[20];
6300   int       group_count;
6301   char      filter[512];
6302   char      *moiraId_v[] = {NULL, NULL};
6303   char      *desc_v[] = {NULL, NULL};
6304   char      *managedBy_v[] = {NULL, NULL};
6305   char      managedByDN[256];
6306   char      moiraId[64];
6307   char      desc[256];
6308   char      ad_path[512];
6309   int       rc;
6310   int       i;
6311   int       n;
6312
6313
6314   strcpy(ad_path, distinguishedName);
6315
6316   if (strlen(dName) != 0)
6317     sprintf(ad_path, "%s,%s", dName, dn_path);
6318
6319   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
6320           ad_path);
6321
6322   if (strlen(av[CONTAINER_ID]) != 0)
6323     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
6324             av[CONTAINER_ROWID]);
6325
6326   attr_array[0] = "mitMoiraId";
6327   attr_array[1] = "description";
6328   attr_array[2] = "managedBy";
6329   attr_array[3] = NULL;
6330   group_count = 0;
6331   group_base = NULL;
6332
6333   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6334                            &group_base, &group_count, 
6335                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
6336     {
6337       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
6338               av[CONTAINER_NAME], ldap_err2string(rc));
6339       return(rc);
6340     }
6341
6342   memset(managedByDN, '\0', sizeof(managedByDN));
6343   memset(moiraId, '\0', sizeof(moiraId));
6344   memset(desc, '\0', sizeof(desc));
6345   pPtr = group_base;
6346
6347   while (pPtr)
6348     {
6349       if (!strcasecmp(pPtr->attribute, "description"))
6350         strcpy(desc, pPtr->value);
6351       else if (!strcasecmp(pPtr->attribute, "managedBy"))
6352         strcpy(managedByDN, pPtr->value);
6353       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
6354         strcpy(moiraId, pPtr->value);
6355       pPtr = pPtr->next;
6356     }
6357
6358   linklist_free(group_base);
6359   group_base = NULL;
6360   group_count = 0;
6361
6362   n = 0;
6363   if (strlen(av[CONTAINER_ROWID]) != 0)
6364     {
6365       moiraId_v[0] = av[CONTAINER_ROWID];
6366       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
6367     }
6368
6369   if (strlen(av[CONTAINER_DESC]) != 0)
6370     {
6371       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
6372                        dName);
6373     }
6374   else
6375     {
6376       if (strlen(desc) != 0)
6377         {
6378           attribute_update(ldap_handle, ad_path, "", "description", dName);
6379         }
6380     }
6381
6382   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6383     {
6384       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6385         {
6386           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6387                               kerberos_ou))
6388             {
6389               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6390                       kerberos_ou, dn_path);
6391               managedBy_v[0] = managedByDN;
6392               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
6393             }
6394           else
6395             {
6396               if (strlen(managedByDN) != 0)
6397                 {
6398                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
6399                                    dName);
6400                 }
6401             }
6402         }
6403       else
6404         {
6405           memset(filter, '\0', sizeof(filter));
6406
6407           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6408             {
6409               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6410                       "(objectClass=user)))", av[CONTAINER_ID]);
6411             }
6412
6413           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6414             {
6415               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6416                       av[CONTAINER_ID]);
6417             }
6418
6419           if (strlen(filter) != 0)
6420             {
6421               attr_array[0] = "distinguishedName";
6422               attr_array[1] = NULL;
6423               group_count = 0;
6424               group_base = NULL;
6425               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6426                                        attr_array, &group_base, &group_count, 
6427                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6428                 {
6429                   if (group_count == 1)
6430                     {
6431                       strcpy(managedByDN, group_base->value);
6432                       managedBy_v[0] = managedByDN;
6433                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
6434                     }
6435                   else
6436                     {
6437                       if (strlen(managedByDN) != 0)
6438                         {
6439                           attribute_update(ldap_handle, ad_path, "", 
6440                                            "managedBy", dName);
6441                         }
6442                     }
6443
6444                   linklist_free(group_base);
6445                   group_base = NULL;
6446                   group_count = 0;
6447                 }
6448             }
6449           else
6450             {
6451               if (strlen(managedByDN) != 0)
6452                 {
6453                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
6454                                    dName);
6455                 }
6456             }
6457         }
6458     }
6459
6460   mods[n] = NULL;
6461
6462   if (n == 0)
6463     return(LDAP_SUCCESS);
6464
6465   rc = ldap_modify_s(ldap_handle, ad_path, mods);
6466
6467   for (i = 0; i < n; i++)
6468     free(mods[i]);
6469
6470   if (rc != LDAP_SUCCESS)
6471     {
6472       com_err(whoami, 0, "Unable to modify container info for %s : %s",
6473               av[CONTAINER_NAME], ldap_err2string(rc));
6474       return(rc);
6475     }
6476   
6477   return(rc);
6478 }
6479
6480 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
6481 {
6482   char      *attr_array[3];
6483   LK_ENTRY  *group_base;
6484   LK_ENTRY  *pPtr;
6485   int       group_count;
6486   char      filter[512];
6487   char      new_cn[128];
6488   char      temp[256];
6489   int       rc;
6490   int       NumberOfEntries = 10;
6491   int       i;
6492   int       count;
6493
6494   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
6495
6496   for (i = 0; i < 3; i++)
6497     {
6498       memset(filter, '\0', sizeof(filter));
6499
6500       if (i == 0)
6501         {
6502           strcpy(filter, "(!(|(objectClass=computer)"
6503                  "(objectClass=organizationalUnit)))");
6504           attr_array[0] = "cn";
6505           attr_array[1] = NULL;
6506         }
6507       else if (i == 1)
6508         {
6509           strcpy(filter, "(objectClass=computer)");
6510           attr_array[0] = "cn";
6511           attr_array[1] = NULL;
6512         }
6513       else
6514         {
6515           strcpy(filter, "(objectClass=organizationalUnit)");
6516           attr_array[0] = "ou";
6517           attr_array[1] = NULL;
6518         }
6519
6520       while (1)
6521         {
6522           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
6523                                    &group_base, &group_count, 
6524                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
6525             {
6526               break;
6527             }
6528
6529           if (group_count == 0)
6530             break;
6531
6532           pPtr = group_base;
6533
6534           while(pPtr)
6535             {
6536               if (!strcasecmp(pPtr->attribute, "cn"))
6537                 {
6538                   sprintf(new_cn, "cn=%s", pPtr->value);
6539                   if (i == 0)
6540                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
6541                   if (i == 1)
6542                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
6543                   count = 1;
6544
6545                   while (1)
6546                     {
6547                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
6548                                          TRUE, NULL, NULL);
6549                       if (rc == LDAP_ALREADY_EXISTS)
6550                         {
6551                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
6552                           ++count;
6553                         }
6554                       else
6555                         break;
6556                     }
6557                 }
6558               else if (!strcasecmp(pPtr->attribute, "ou"))
6559                 {
6560                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
6561                 }
6562
6563               pPtr = pPtr->next;
6564             }
6565
6566           linklist_free(group_base);
6567           group_base = NULL;
6568           group_count = 0;
6569         }
6570     }
6571
6572   return(0);
6573 }
6574
6575 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
6576                    char *machine_ou, char *NewMachineName)
6577 {
6578   LK_ENTRY  *group_base;
6579   int  group_count;
6580   int  i;
6581   char filter[128];
6582   char *attr_array[3];
6583   char cn[256];
6584   char dn[256];
6585   char temp[256];
6586   char *pPtr;
6587   int   rc;
6588
6589   strcpy(NewMachineName, member);
6590   rc = moira_connect();
6591   rc = GetMachineName(NewMachineName);
6592   moira_disconnect();
6593
6594   if (strlen(NewMachineName) == 0)
6595     {
6596       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
6597               member);
6598       return(1);
6599     }
6600
6601   pPtr = NULL;
6602   pPtr = strchr(NewMachineName, '.');
6603
6604   if (pPtr != NULL)
6605     (*pPtr) = '\0';
6606
6607   group_base = NULL;
6608   group_count = 0;
6609   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
6610   attr_array[0] = "cn";
6611   attr_array[1] = NULL;
6612   sprintf(temp, "%s", dn_path);
6613
6614   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
6615                            &group_base, &group_count, 
6616                            LDAP_SCOPE_SUBTREE)) != 0)
6617     {
6618       com_err(whoami, 0, "Unable to process machine %s : %s",
6619               member, ldap_err2string(rc));
6620       return(1);
6621     }
6622
6623   if (group_count != 1)
6624     {
6625       com_err(whoami, 0, 
6626               "Unable to process machine %s : machine not found in AD",
6627               NewMachineName);
6628       return(1);
6629     }
6630
6631   strcpy(dn, group_base->dn);
6632   strcpy(cn, group_base->value);
6633
6634   for (i = 0; i < (int)strlen(dn); i++)
6635     dn[i] = tolower(dn[i]);
6636
6637   for (i = 0; i < (int)strlen(cn); i++)
6638     cn[i] = tolower(cn[i]);
6639
6640   linklist_free(group_base);
6641   pPtr = NULL;
6642   pPtr = strstr(dn, cn);
6643
6644   if (pPtr == NULL)
6645     {
6646       com_err(whoami, 0, "Unable to process machine %s",
6647               member);
6648       return(1);
6649     }
6650
6651   pPtr += strlen(cn) + 1;
6652   strcpy(machine_ou, pPtr);
6653   pPtr = NULL;
6654   pPtr = strstr(machine_ou, "dc=");
6655
6656   if (pPtr == NULL)
6657     {
6658       com_err(whoami, 0, "Unable to process machine %s",
6659               member);
6660       return(1);
6661     }
6662
6663   --pPtr;
6664   (*pPtr) = '\0';
6665
6666   return(0);
6667 }
6668
6669 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
6670                        char *MoiraMachineName, char *DestinationOu)
6671 {
6672   char        NewCn[128];
6673   char        OldDn[512];
6674   char        MachineName[128];
6675   char        filter[128];
6676   char        *attr_array[3];
6677   char        NewOu[256];
6678   char        *cPtr = NULL;
6679   int         group_count;
6680   long        rc;
6681   LK_ENTRY    *group_base;
6682
6683   group_count = 0;
6684   group_base = NULL;
6685   
6686   strcpy(MachineName, MoiraMachineName);
6687   rc = GetMachineName(MachineName);
6688
6689   if (strlen(MachineName) == 0)
6690     {
6691       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
6692               MoiraMachineName);
6693       return(1);
6694     }
6695   
6696   cPtr = strchr(MachineName, '.');
6697
6698   if (cPtr != NULL)
6699     (*cPtr) = '\0';
6700
6701   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
6702   attr_array[0] = "sAMAccountName";
6703   attr_array[1] = NULL;
6704
6705   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6706                            &group_base, 
6707                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
6708     {
6709       com_err(whoami, 0, "Unable to process machine %s : %s",
6710               MoiraMachineName, ldap_err2string(rc));
6711       return(1);
6712     }
6713   
6714   if (group_count == 1)
6715     strcpy(OldDn, group_base->dn);
6716
6717   linklist_free(group_base);
6718   group_base = NULL;
6719
6720   if (group_count != 1)
6721     {
6722       com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
6723               MoiraMachineName);
6724       return(1);
6725     }
6726
6727   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
6728   cPtr = strchr(OldDn, ',');
6729
6730   if (cPtr != NULL)
6731     {
6732       ++cPtr;
6733       if (!strcasecmp(cPtr, NewOu))
6734         return(0);
6735     }
6736
6737   sprintf(NewCn, "CN=%s", MachineName);
6738   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
6739
6740   return(rc);
6741 }
6742
6743 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
6744 {
6745   char    Name[128];
6746   char    *pPtr;
6747   int     rc;
6748   
6749   memset(Name, '\0', sizeof(Name));
6750   strcpy(Name, machine_name);
6751   pPtr = NULL;
6752   pPtr = strchr(Name, '.');
6753
6754   if (pPtr != NULL)
6755     (*pPtr) = '\0';
6756
6757   strcat(Name, "$");
6758   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
6759 }
6760
6761 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
6762                                 char *machine_name, char *container_name)
6763 {
6764   int     rc;
6765   char    *av[2];
6766   char    *call_args[2];
6767   
6768   av[0] = machine_name;
6769   call_args[0] = (char *)container_name;
6770   rc = mr_query("get_machine_to_container_map", 1, av, 
6771                 machine_GetMoiraContainer, call_args);
6772   return(rc);
6773 }
6774
6775 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
6776 {
6777   char **call_args;
6778   
6779   call_args = ptr;
6780   strcpy(call_args[0], av[1]);
6781   return(0);
6782 }
6783
6784 int Moira_container_group_create(char **after)
6785 {
6786   long rc;
6787   char GroupName[64];
6788   char *argv[20];
6789   
6790   memset(GroupName, '\0', sizeof(GroupName));
6791   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
6792                               after[CONTAINER_ROWID]);
6793   if (rc)
6794     return rc;
6795   
6796   argv[L_NAME] = GroupName;
6797   argv[L_ACTIVE] = "1";
6798   argv[L_PUBLIC] = "0";
6799   argv[L_HIDDEN] = "0";
6800   argv[L_MAILLIST] = "0";
6801   argv[L_GROUP] = "1";
6802   argv[L_GID] = UNIQUE_GID;
6803   argv[L_NFSGROUP] = "0";
6804   argv[L_MAILMAN] = "0";
6805   argv[L_MAILMAN_SERVER] = "[NONE]";
6806   argv[L_DESC] = "auto created container group";
6807   argv[L_ACE_TYPE] = "USER";
6808   argv[L_MEMACE_TYPE] = "USER";
6809   argv[L_ACE_NAME] = "sms";
6810   argv[L_MEMACE_NAME] = "sms";
6811
6812   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
6813     {
6814       com_err(whoami, 0, 
6815               "Unable to create container group %s for container %s: %s",
6816               GroupName, after[CONTAINER_NAME], error_message(rc));
6817     }
6818
6819   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
6820   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
6821   
6822   return(rc);
6823 }
6824
6825 int Moira_container_group_update(char **before, char **after)
6826 {
6827   long rc;
6828   char BeforeGroupName[64];
6829   char AfterGroupName[64];
6830   char *argv[20];
6831   
6832   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
6833     return(0);
6834
6835   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
6836   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
6837   if (strlen(BeforeGroupName) == 0)
6838     return(0);
6839
6840   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
6841   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
6842                               after[CONTAINER_ROWID]);
6843   if (rc)
6844     return rc;
6845
6846   if (strcasecmp(BeforeGroupName, AfterGroupName))
6847     {
6848       argv[L_NAME] = BeforeGroupName;
6849       argv[L_NAME + 1] = AfterGroupName;
6850       argv[L_ACTIVE + 1] = "1";
6851       argv[L_PUBLIC + 1] = "0";
6852       argv[L_HIDDEN + 1] = "0";
6853       argv[L_MAILLIST + 1] = "0";
6854       argv[L_GROUP + 1] = "1";
6855       argv[L_GID + 1] = UNIQUE_GID;
6856       argv[L_NFSGROUP + 1] = "0";
6857       argv[L_MAILMAN + 1] = "0";
6858       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
6859       argv[L_DESC + 1] = "auto created container group";
6860       argv[L_ACE_TYPE + 1] = "USER";
6861       argv[L_MEMACE_TYPE + 1] = "USER";
6862       argv[L_ACE_NAME + 1] = "sms";
6863       argv[L_MEMACE_NAME + 1] = "sms";
6864       
6865       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
6866         {
6867           com_err(whoami, 0, 
6868                   "Unable to rename container group from %s to %s: %s",
6869                   BeforeGroupName, AfterGroupName, error_message(rc));
6870         }
6871     }
6872   
6873   return(rc);
6874 }
6875
6876 int Moira_container_group_delete(char **before)
6877 {
6878   long rc = 0;
6879   char *argv[13];
6880   char GroupName[64];
6881   char ParentGroupName[64];
6882   
6883   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
6884   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
6885
6886   memset(GroupName, '\0', sizeof(GroupName));
6887
6888   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
6889     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
6890   
6891   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
6892     {
6893       argv[0] = ParentGroupName;
6894       argv[1] = "LIST";
6895       argv[2] = GroupName;
6896
6897       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
6898         {
6899           com_err(whoami, 0, 
6900                   "Unable to delete container group %s from list: %s",
6901                   GroupName, ParentGroupName, error_message(rc));
6902         }
6903     }
6904   
6905   if (strlen(GroupName) != 0)
6906     {
6907       argv[0] = GroupName;
6908
6909       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
6910         {
6911           com_err(whoami, 0, "Unable to delete container group %s : %s",
6912                   GroupName, error_message(rc));
6913         }
6914     }
6915   
6916   return(rc);
6917 }
6918
6919 int Moira_groupname_create(char *GroupName, char *ContainerName,
6920                            char *ContainerRowID)
6921 {
6922   char *ptr;
6923   char *ptr1;
6924   char temp[64];
6925   char newGroupName[64];
6926   char tempGroupName[64];
6927   char tempgname[64];
6928   char *argv[1];
6929   int  i;
6930   long rc;
6931
6932   strcpy(temp, ContainerName);
6933   
6934   ptr1 = strrchr(temp, '/');
6935
6936   if (ptr1 != NULL)
6937   {
6938     *ptr1 = '\0';
6939     ptr = ++ptr1;
6940     ptr1 = strrchr(temp, '/');
6941
6942     if (ptr1 != NULL)
6943     {
6944         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
6945     }
6946     else
6947         strcpy(tempgname, ptr);
6948   }
6949   else
6950     strcpy(tempgname, temp);
6951
6952   if (strlen(tempgname) > 25)
6953     tempgname[25] ='\0';
6954
6955   sprintf(newGroupName, "cnt-%s", tempgname);
6956
6957   /* change everything to lower case */
6958   ptr = newGroupName;
6959
6960   while (*ptr)
6961     {
6962       if (isupper(*ptr))
6963         *ptr = tolower(*ptr);
6964
6965       if (*ptr == ' ')
6966         *ptr = '-';
6967
6968       ptr++;
6969     }
6970
6971   strcpy(tempGroupName, newGroupName);
6972   i = (int)'0';
6973
6974   /* append 0-9 then a-z if a duplicate is found */
6975   while(1)
6976     {
6977       argv[0] = newGroupName;
6978
6979       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
6980         {
6981           if (rc == MR_NO_MATCH)
6982             break;
6983           com_err(whoami, 0, "Moira error while creating group name for "
6984                   "container %s : %s", ContainerName, error_message(rc));
6985           return rc;
6986         }
6987
6988       sprintf(newGroupName, "%s-%c", tempGroupName, i);
6989
6990       if (i == (int)'z')
6991         {
6992           com_err(whoami, 0, "Unable to find a unique group name for "
6993                   "container %s: too many duplicate container names",
6994                   ContainerName);
6995           return 1;
6996         }
6997
6998       if (i == '9')
6999         i = 'a';
7000       else
7001         i++;
7002     }
7003
7004   strcpy(GroupName, newGroupName);
7005   return(0);
7006 }
7007
7008 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7009 {
7010   long rc;
7011   char *argv[3];
7012   
7013   argv[0] = origContainerName;
7014   argv[1] = GroupName;
7015   
7016   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7017     {
7018       com_err(whoami, 0, 
7019               "Unable to set container group %s in container %s: %s",
7020               GroupName, origContainerName, error_message(rc));
7021     }
7022   
7023   return(0);
7024 }
7025
7026 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7027  {
7028    char ContainerName[64];
7029    char ParentGroupName[64];
7030    char *argv[3];
7031    long rc;
7032
7033    strcpy(ContainerName, origContainerName);
7034    
7035    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7036
7037    /* top-level container */
7038    if (strlen(ParentGroupName) == 0)
7039      return(0);
7040    
7041    argv[0] = ParentGroupName;
7042    argv[1] = "LIST";
7043    argv[2] = GroupName;
7044
7045    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7046      {
7047        com_err(whoami, 0, 
7048                "Unable to add container group %s to parent group %s: %s",
7049                GroupName, ParentGroupName, error_message(rc));
7050      }
7051    
7052    return(0);
7053  }
7054
7055 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7056 {
7057   char **call_args;
7058   
7059   call_args = ptr;
7060   strcpy(call_args[0], av[1]);
7061
7062   return(0);
7063 }
7064
7065 int Moira_getGroupName(char *origContainerName, char *GroupName,
7066                        int ParentFlag)
7067 {
7068   char ContainerName[64];
7069   char *argv[3];
7070   char *call_args[3];
7071   char *ptr;
7072   long rc;
7073
7074   strcpy(ContainerName, origContainerName);
7075
7076   if (ParentFlag)
7077     {
7078       ptr = strrchr(ContainerName, '/');
7079
7080       if (ptr != NULL)
7081         (*ptr) = '\0';
7082       else
7083         return(0);
7084     }
7085
7086   argv[0] = ContainerName;
7087   argv[1] = NULL;
7088   call_args[0] = GroupName;
7089   call_args[1] = NULL;
7090
7091   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7092                       call_args)))
7093     {
7094       if (strlen(GroupName) != 0)
7095         return(0);
7096     }
7097
7098   if (rc)
7099     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7100             ContainerName, error_message(rc));
7101   else
7102     com_err(whoami, 0, "Unable to get container group from container %s",
7103             ContainerName);
7104   
7105   return(0);
7106 }
7107
7108 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7109                                           int DeleteMachine)
7110 {
7111   char *argv[3];
7112   long rc;
7113   
7114   if (strcmp(GroupName, "[none]") == 0)
7115     return 0;
7116
7117   argv[0] = GroupName;
7118   argv[1] = "MACHINE";
7119   argv[2] = MachineName;
7120
7121   if (!DeleteMachine)
7122     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7123   else
7124     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7125
7126   if (rc)
7127     {
7128       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7129               MachineName, GroupName, error_message(rc));
7130     }
7131
7132   return(0);
7133 }
7134
7135 int GetMachineName(char *MachineName)
7136 {
7137   char    *args[2];
7138   char    NewMachineName[1024];
7139   char    *szDot;
7140   int     rc = 0;
7141   int     i;
7142   DWORD   dwLen = 0;
7143   char    *call_args[2];
7144   
7145   // If the address happens to be in the top-level MIT domain, great!
7146   strcpy(NewMachineName, MachineName);
7147
7148   for (i = 0; i < (int)strlen(NewMachineName); i++)
7149     NewMachineName[i] = toupper(NewMachineName[i]);
7150
7151   szDot = strchr(NewMachineName,'.');
7152
7153   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7154     {
7155       return(0);
7156     }
7157   
7158   // If not, see if it has a Moira alias in the top-level MIT domain.
7159   memset(NewMachineName, '\0', sizeof(NewMachineName));
7160   args[0] = "*";
7161   args[1] = MachineName;
7162   call_args[0] = NewMachineName;
7163   call_args[1] = NULL;
7164
7165   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7166     {
7167       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7168               MachineName, error_message(rc));
7169       strcpy(MachineName, "");
7170       return(0);
7171     }
7172   
7173   if (strlen(NewMachineName) != 0)
7174     strcpy(MachineName, NewMachineName);
7175   else
7176     strcpy(MachineName, "");
7177
7178   return(0);
7179 }
7180
7181 int ProcessMachineName(int ac, char **av, void *ptr)
7182 {
7183   char    **call_args;
7184   char    MachineName[1024];
7185   char    *szDot;
7186   int     i;
7187   
7188   call_args = ptr;
7189
7190   if (strlen(call_args[0]) == 0)
7191     {
7192       strcpy(MachineName, av[0]);
7193
7194       for (i = 0; i < (int)strlen(MachineName); i++)
7195         MachineName[i] = toupper(MachineName[i]);
7196
7197       szDot = strchr(MachineName,'.');
7198
7199         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
7200           {
7201             strcpy(call_args[0], MachineName);
7202           }
7203     }
7204
7205   return(0);
7206 }
7207
7208 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
7209 {
7210   int i;
7211   
7212   if (*UseSFU30)
7213     {
7214       for (i = 0; i < n; i++)
7215         {
7216           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
7217             mods[i]->mod_type = "uidNumber";
7218         }
7219
7220       (*UseSFU30) = 0;
7221     }
7222   else
7223     {
7224       for (i = 0; i < n; i++)
7225         {
7226           if (!strcmp(mods[i]->mod_type, "uidNumber"))
7227             mods[i]->mod_type = "msSFU30UidNumber";
7228         }
7229
7230       (*UseSFU30) = 1;
7231     }
7232 }
7233
7234 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
7235                      char *DistinguishedName,
7236                      char *WinHomeDir, char *WinProfileDir,
7237                      char **homedir_v, char **winProfile_v,
7238                      char **drives_v, LDAPMod **mods, 
7239                      int OpType, int n)
7240 {
7241   char **hp;
7242   char cWeight[3];
7243   char cPath[1024];
7244   char path[1024];
7245   char winPath[1024];
7246   char winProfile[1024];
7247   char homeDrive[8];
7248   int  last_weight;
7249   int  i;
7250   int  rc;
7251   LDAPMod *DelMods[20];
7252   
7253   memset(homeDrive, '\0', sizeof(homeDrive));
7254   memset(path, '\0', sizeof(path));
7255   memset(winPath, '\0', sizeof(winPath));
7256   memset(winProfile, '\0', sizeof(winProfile));
7257   hp = NULL;
7258
7259   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
7260       (!strcasecmp(WinProfileDir, "[afs]")))
7261     {
7262       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
7263         {
7264           memset(cWeight, 0, sizeof(cWeight));
7265           memset(cPath, 0, sizeof(cPath));
7266           last_weight = 1000;
7267           i = 0;
7268
7269           while (hp[i] != NULL)
7270             {
7271               if (sscanf(hp[i], "%*s %s", cPath))
7272                 {
7273                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
7274                     {
7275                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
7276                         {
7277                           if (atoi(cWeight) < last_weight)
7278                             {
7279                               strcpy(path, cPath);
7280                               last_weight = (int)atoi(cWeight);
7281                             }
7282                         }
7283                       else 
7284                         strcpy(path, cPath);
7285                     }
7286                 }
7287               ++i;
7288             }
7289
7290           if (strlen(path))
7291             {
7292               if (!strnicmp(path, AFS, strlen(AFS)))
7293                 {
7294                   AfsToWinAfs(path, winPath);
7295                   strcpy(winProfile, winPath);
7296                   strcat(winProfile, "\\.winprofile");
7297                 }
7298             }
7299         }
7300       else
7301         return(n);
7302     }
7303
7304     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
7305         (!strcasecmp(WinProfileDir, "[dfs]")))
7306     {
7307       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
7308               user_name[0], user_name);
7309
7310       if (!strcasecmp(WinProfileDir, "[dfs]"))
7311         {
7312           strcpy(winProfile, path);
7313           strcat(winProfile, "\\.winprofile");
7314         }
7315
7316       if (!strcasecmp(WinHomeDir, "[dfs]"))
7317         strcpy(winPath, path);
7318     }
7319     
7320     if (hp != NULL)
7321       {
7322         i = 0;
7323         while (hp[i])
7324           {
7325             free(hp[i]);
7326             i++;
7327           }
7328       }
7329     
7330     if (!strcasecmp(WinHomeDir, "[local]"))
7331       memset(winPath, '\0', sizeof(winPath));
7332     else if (!strcasecmp(WinHomeDir, "[afs]") || 
7333              !strcasecmp(WinHomeDir, "[dfs]"))
7334       {
7335         strcpy(homeDrive, "H:");
7336       }
7337     else
7338       {
7339         strcpy(winPath, WinHomeDir);
7340         if (!strncmp(WinHomeDir, "\\\\", 2))
7341           {
7342             strcpy(homeDrive, "H:");
7343           }        
7344       }
7345     
7346     // nothing needs to be done if WinProfileDir is [afs].
7347     if (!strcasecmp(WinProfileDir, "[local]"))
7348       memset(winProfile, '\0', sizeof(winProfile));
7349     else if (strcasecmp(WinProfileDir, "[afs]") && 
7350              strcasecmp(WinProfileDir, "[dfs]"))
7351       {
7352         strcpy(winProfile, WinProfileDir);
7353       }
7354     
7355     if (strlen(winProfile) != 0)
7356       {
7357         if (winProfile[strlen(winProfile) - 1] == '\\')
7358           winProfile[strlen(winProfile) - 1] = '\0';
7359       }
7360
7361     if (strlen(winPath) != 0)
7362       {
7363         if (winPath[strlen(winPath) - 1] == '\\')
7364           winPath[strlen(winPath) - 1] = '\0';
7365       }
7366     
7367     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
7368       strcat(winProfile, "\\");
7369
7370     if ((winPath[1] == ':') && (strlen(winPath) == 2))
7371       strcat(winPath, "\\");
7372     
7373     if (strlen(winPath) == 0)
7374       {
7375         if (OpType == LDAP_MOD_REPLACE)
7376           {
7377             i = 0;
7378             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
7379             DelMods[i] = NULL;
7380             //unset homeDirectory attribute for user.
7381             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7382             free(DelMods[0]);
7383           }
7384       }
7385     else
7386       {
7387         homedir_v[0] = strdup(winPath);
7388         ADD_ATTR("homeDirectory", homedir_v, OpType);
7389       }
7390     
7391     if (strlen(winProfile) == 0)
7392       {
7393         if (OpType == LDAP_MOD_REPLACE)
7394           {
7395             i = 0;
7396             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
7397             DelMods[i] = NULL;
7398             //unset profilePate attribute for user.
7399             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7400             free(DelMods[0]);
7401           }
7402       }
7403     else
7404       {
7405         winProfile_v[0] = strdup(winProfile);
7406         ADD_ATTR("profilePath", winProfile_v, OpType);
7407       }
7408     
7409     if (strlen(homeDrive) == 0)
7410       {
7411         if (OpType == LDAP_MOD_REPLACE)
7412           {
7413             i = 0;
7414             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
7415             DelMods[i] = NULL;
7416             //unset homeDrive attribute for user
7417             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7418             free(DelMods[0]);
7419           }
7420       }
7421     else
7422       {
7423         drives_v[0] = strdup(homeDrive);
7424         ADD_ATTR("homeDrive", drives_v, OpType);
7425       }
7426
7427     return(n);
7428 }
7429
7430 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
7431                      char *attribute_value, char *attribute, char *user_name)
7432 {
7433   char      *mod_v[] = {NULL, NULL};
7434   LDAPMod   *DelMods[20];
7435   LDAPMod   *mods[20];
7436   int       n;
7437   int       i;
7438   int       rc;
7439   
7440   if (strlen(attribute_value) == 0)
7441     {
7442       i = 0;
7443       DEL_ATTR(attribute, LDAP_MOD_DELETE);
7444       DelMods[i] = NULL;
7445       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
7446       free(DelMods[0]);
7447     }
7448   else
7449     {
7450       n = 0;
7451       mod_v[0] = attribute_value;
7452       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
7453       mods[n] = NULL;
7454
7455       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
7456                               mods)) != LDAP_SUCCESS)
7457         {
7458           free(mods[0]);
7459           n = 0;
7460           mod_v[0] = attribute_value;
7461           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
7462           mods[n] = NULL;
7463
7464           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
7465                                   mods)) != LDAP_SUCCESS)
7466             {
7467               com_err(whoami, 0, "Unable to change the %s attribute for %s "
7468                       "in the AD : %s",
7469                       attribute, user_name, ldap_err2string(rc));
7470             }
7471         }
7472
7473       free(mods[0]);
7474     }
7475   
7476   return(rc);
7477 }
7478
7479 void StringTrim(char *StringToTrim)
7480 {
7481   char *t, *s;
7482   char *save;
7483
7484   save = strdup(StringToTrim);
7485
7486   s = save;
7487
7488   while (isspace(*s))
7489     s++;
7490
7491   /* skip to end of string */
7492   if (*s == '\0')
7493     {
7494       if (*save)
7495         *save = '\0';
7496       strcpy(StringToTrim, save);
7497       return;
7498     }
7499   
7500   for (t = s; *t; t++)
7501     continue;
7502
7503   while (t > s)
7504     {
7505       --t;
7506       if (!isspace(*t))
7507         {
7508           t++;
7509           break;
7510         }
7511     }
7512
7513   if (*t)
7514     *t = '\0';
7515   
7516   strcpy(StringToTrim, s);
7517   return;
7518 }
7519
7520 int ReadConfigFile(char *DomainName)
7521 {
7522     int     Count;
7523     int     i;
7524     int     k;
7525     char    temp[256];
7526     char    temp1[256];
7527     FILE    *fptr;
7528
7529     Count = 0;
7530
7531     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
7532
7533     if ((fptr = fopen(temp, "r")) != NULL)
7534       {
7535         while (fgets(temp, sizeof(temp), fptr) != 0)
7536           {
7537             for (i = 0; i < (int)strlen(temp); i++)
7538               temp[i] = toupper(temp[i]);
7539
7540             if (temp[strlen(temp) - 1] == '\n')
7541               temp[strlen(temp) - 1] = '\0';
7542
7543             StringTrim(temp);
7544
7545             if (strlen(temp) == 0)
7546               continue;
7547
7548             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
7549               {
7550                 if (strlen(temp) > (strlen(DOMAIN)))
7551                   {
7552                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
7553                     StringTrim(ldap_domain);
7554                   }
7555               }
7556             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
7557               {
7558                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
7559                   {
7560                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
7561                     StringTrim(PrincipalName);
7562                   }
7563               }
7564             else if (!strncmp(temp, SERVER, strlen(SERVER)))
7565               {
7566                 if (strlen(temp) > (strlen(SERVER)))
7567                   {
7568                     ServerList[Count] = calloc(1, 256);
7569                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
7570                     StringTrim(ServerList[Count]);
7571                     ++Count;
7572                   }
7573               }
7574             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
7575               {
7576                 if (strlen(temp) > (strlen(MSSFU)))
7577                   {
7578                     strcpy(temp1, &temp[strlen(MSSFU)]);
7579                     StringTrim(temp1);
7580                     if (!strcmp(temp1, SFUTYPE))
7581                       UseSFU30 = 1;
7582                   }
7583               }
7584             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
7585               {
7586                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
7587                   {
7588                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
7589                     StringTrim(temp1);
7590                     if (!strcasecmp(temp1, "NO")) 
7591                       {
7592                         UseGroupSuffix = 0;
7593                         memset(group_suffix, '\0', sizeof(group_suffix));
7594                       }
7595                   }
7596               }
7597             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
7598               {
7599                 if (strlen(temp) > (strlen(GROUP_TYPE)))
7600                   {
7601                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
7602                     StringTrim(temp1);
7603                     if (!strcasecmp(temp1, "UNIVERSAL")) 
7604                       UseGroupUniversal = 1;
7605                   }
7606               }
7607             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
7608               {
7609                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
7610                   {
7611                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
7612                     StringTrim(temp1);
7613                     if (!strcasecmp(temp1, "NO"))
7614                       SetGroupAce = 0;
7615                   }
7616               }
7617             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
7618               {
7619                 if (strlen(temp) > (strlen(SET_PASSWORD)))
7620                   {
7621                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
7622                     StringTrim(temp1);
7623                     if (!strcasecmp(temp1, "NO"))
7624                       SetPassword = 0;
7625                   }
7626               }
7627             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
7628               {
7629                 if (strlen(temp) > (strlen(EXCHANGE)))
7630                   {
7631                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
7632                     StringTrim(temp1);
7633                     if (!strcasecmp(temp1, "YES"))
7634                       Exchange = 1;
7635                   }
7636               }
7637             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
7638                               strlen(PROCESS_MACHINE_CONTAINER)))
7639               {
7640                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
7641                   {
7642                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
7643                     StringTrim(temp1);
7644                     if (!strcasecmp(temp1, "NO"))
7645                       ProcessMachineContainer = 0;
7646                   }
7647               }
7648             else
7649               {
7650                 if (strlen(ldap_domain) != 0)
7651                   {
7652                     memset(ldap_domain, '\0', sizeof(ldap_domain));
7653                     break;
7654                   }
7655
7656                 if (strlen(temp) != 0)
7657                   strcpy(ldap_domain, temp);
7658               }
7659           }
7660         fclose(fptr);
7661       }
7662     
7663     if (strlen(ldap_domain) == 0)
7664       {
7665       strcpy(ldap_domain, DomainName);
7666       }
7667
7668     if (Count == 0)
7669         return(0);
7670
7671     for (i = 0; i < Count; i++)
7672       {
7673         if (ServerList[i] != 0)
7674           {
7675             strcat(ServerList[i], ".");
7676             strcat(ServerList[i], ldap_domain);
7677             for (k = 0; k < (int)strlen(ServerList[i]); k++)
7678               ServerList[i][k] = toupper(ServerList[i][k]);
7679           }
7680       }
7681     
7682     return(0);
7683 }
7684
7685 int ReadDomainList()
7686 {
7687   int     Count;
7688   int     i;
7689   char    temp[128];
7690   char    temp1[128];
7691   FILE    *fptr;
7692   unsigned char c[11];
7693   unsigned char stuff[256];
7694   int     rc;
7695   int     ok;
7696
7697   Count = 0;
7698   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
7699
7700   if ((fptr = fopen(temp, "r")) != NULL)
7701     {
7702       while (fgets(temp, sizeof(temp), fptr) != 0)
7703         {
7704           for (i = 0; i < (int)strlen(temp); i++)
7705             temp[i] = toupper(temp[i]);
7706
7707           if (temp[strlen(temp) - 1] == '\n')
7708             temp[strlen(temp) - 1] = '\0';
7709
7710           StringTrim(temp);
7711
7712           if (strlen(temp) == 0)
7713             continue;
7714
7715           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
7716             {
7717               if (strlen(temp) > (strlen(DOMAIN)))
7718                 {
7719                   strcpy(temp1, &temp[strlen(DOMAIN)]);
7720                   StringTrim(temp1);
7721                   strcpy(temp, temp1);
7722                 }
7723             }
7724           
7725           strcpy(DomainNames[Count], temp);
7726           StringTrim(DomainNames[Count]);
7727           ++Count;
7728         }
7729
7730       fclose(fptr);
7731     }
7732
7733   if (Count == 0)
7734     {
7735       critical_alert("incremental", "%s", "winad.incr cannot run due to a "
7736                      "configuration error in winad.cfg");
7737       return(1);
7738     }
7739   
7740   return(0);
7741 }
7742
7743 int email_isvalid(const char *address) {
7744   int        count = 0;
7745   const char *c, *domain;
7746   static char *rfc822_specials = "()<>@,;:\\\"[]";
7747
7748   if(address[strlen(address) - 1] == '.') 
7749     return 0;
7750     
7751   /* first we validate the name portion (name@domain) */
7752   for (c = address;  *c;  c++) {
7753     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
7754                        '\"')) {
7755       while (*++c) {
7756         if (*c == '\"') 
7757           break;
7758         if (*c == '\\' && (*++c == ' ')) 
7759           continue;
7760         if (*c <= ' ' || *c >= 127) 
7761           return 0;
7762       }
7763
7764       if (!*c++) 
7765         return 0;
7766       if (*c == '@') 
7767         break;
7768       if (*c != '.') 
7769         return 0;
7770       continue;
7771     }
7772
7773     if (*c == '@') 
7774       break;
7775     if (*c <= ' ' || *c >= 127) 
7776       return 0;
7777     if (strchr(rfc822_specials, *c)) 
7778       return 0;
7779   }
7780
7781   if (c == address || *(c - 1) == '.') 
7782     return 0;
7783
7784   /* next we validate the domain portion (name@domain) */
7785   if (!*(domain = ++c)) return 0;
7786   do {
7787     if (*c == '.') {
7788       if (c == domain || *(c - 1) == '.') 
7789         return 0;
7790       count++;
7791     }
7792     if (*c <= ' ' || *c >= 127) 
7793       return 0;
7794     if (strchr(rfc822_specials, *c)) 
7795       return 0;
7796   } while (*++c);
7797
7798   return (count >= 1);
7799 }
7800
7801 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
7802              char **homeServerName) 
7803 {
7804   LK_ENTRY *group_base;
7805   LK_ENTRY *sub_group_base;
7806   LK_ENTRY *gPtr;
7807   LK_ENTRY *sub_gPtr;
7808   int      group_count;
7809   int      sub_group_count;
7810   char     filter[1024];
7811   char     sub_filter[1024];
7812   char     search_path[1024];
7813   char     range[1024];
7814   char     *attr_array[3];
7815   char     *s;
7816   int      homeMDB_count = -1;
7817   int      rc;
7818   int      i;
7819   int      mdbbl_count;
7820   int      rangeStep = 1500;
7821   int      rangeLow = 0;
7822   int      rangeHigh = rangeLow + (rangeStep - 1);
7823   int      isLast = 0;
7824
7825   /* Grumble..... microsoft not making it searchable from the root *grr* */
7826
7827   memset(filter, '\0', sizeof(filter));
7828   memset(search_path, '\0', sizeof(search_path));
7829   
7830   sprintf(filter, "(objectClass=msExchMDB)");
7831   sprintf(search_path, "CN=Configuration,%s", dn_path);
7832   attr_array[0] = "distinguishedName";
7833   attr_array[1] = NULL;
7834   
7835   group_base = NULL;
7836   group_count = 0;
7837   
7838   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
7839                            &group_base, &group_count, 
7840                            LDAP_SCOPE_SUBTREE)) != 0) 
7841     {
7842       com_err(whoami, 0, "Unable to find msExchMDB %s",
7843               ldap_err2string(rc));
7844       return(rc);
7845     }
7846   
7847   if (group_count) 
7848     {
7849       gPtr = group_base;
7850       
7851       while(gPtr) {
7852         if (((s = strstr(gPtr->dn, "Public")) != (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.680116 seconds and 3 git commands to generate.