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