]> andersk Git - moira.git/blob - incremental/winad/winad.c
36aa5ca099734d2adec2ad593316340314065a7e
[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
3779       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
3780           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
3781         {
3782           n = 0;
3783           
3784           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
3785           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
3786           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
3787                    LDAP_MOD_REPLACE);
3788           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
3789
3790           hide_address_lists_v[0] = "TRUE";
3791           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
3792                    LDAP_MOD_REPLACE);
3793     
3794           mods[n] = NULL;
3795           rc = ldap_modify_s(ld, new_dn, mods);
3796       
3797           if (rc) 
3798             {
3799               com_err(whoami, 0, "Unable to update contact %s", mail);
3800             }
3801       
3802           for (i = 0; i < n; i++)
3803             free(mods[i]);
3804         }
3805     }
3806
3807   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3808     {
3809       n = 0;
3810       ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
3811       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
3812       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
3813       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
3814       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
3815       mods[n] = NULL;
3816       rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
3817
3818       for (i = 0; i < n; i++)
3819         free(mods[i]);
3820     }
3821
3822   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3823     {
3824       com_err(whoami, 0, "Unable to create contact %s : %s",
3825               user, ldap_err2string(rc));
3826       return(rc);
3827     }
3828
3829   return(0);
3830 }
3831
3832 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
3833                 char *Uid, char *MitId, char *MoiraId, int State,
3834                 char *WinHomeDir, char *WinProfileDir, char *first,
3835                 char *middle, char *last)
3836 {
3837   LDAPMod   *mods[20];
3838   LK_ENTRY  *group_base;
3839   int  group_count;
3840   char distinguished_name[512];
3841   char displayName[256];
3842   char *mitMoiraId_v[] = {NULL, NULL};
3843   char *uid_v[] = {NULL, NULL};
3844   char *mitid_v[] = {NULL, NULL};
3845   char *homedir_v[] = {NULL, NULL};
3846   char *winProfile_v[] = {NULL, NULL};
3847   char *drives_v[] = {NULL, NULL};
3848   char *userAccountControl_v[] = {NULL, NULL};
3849   char *alt_recipient_v[] = {NULL, NULL};
3850   char *hide_address_lists_v[] = {NULL, NULL};
3851   char *mail_v[] = {NULL, NULL};
3852   char userAccountControlStr[80];
3853   int  n;
3854   int  rc;
3855   int  i;
3856   int  OldUseSFU30;
3857   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
3858     UF_PASSWD_CANT_CHANGE;
3859   char filter[128];
3860   char *attr_array[3];
3861   char temp[256];
3862   char mail[256];
3863   char contact_mail[256];
3864   char filter_exp[1024];
3865   char search_path[512];
3866   char TemplateDn[512];
3867   char TemplateSamName[128];
3868   char alt_recipient[256];
3869   char acBERBuf[N_SD_BER_BYTES];
3870   LDAPControl sControl = {"1.2.840.113556.1.4.801",
3871                           { N_SD_BER_BYTES, acBERBuf },
3872                           TRUE};
3873   LDAPControl *apsServerControls[] = {&sControl, NULL};
3874   LDAPMessage *psMsg;
3875   LDAP_BERVAL   **ppsValues;
3876   ULONG dwInfo;
3877   char *argv[3];
3878   char *homeMDB;
3879   char *homeServerName;
3880   char *save_argv[7];
3881   char search_string[256];
3882
3883   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
3884     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
3885   BEREncodeSecurityBits(dwInfo, acBERBuf);
3886
3887   if (!check_string(user_name))
3888     {
3889       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
3890               user_name);
3891       return(AD_INVALID_NAME);
3892     }
3893   
3894   memset(contact_mail, '\0', sizeof(contact_mail));
3895   sprintf(contact_mail, "%s@mit.edu", user_name);
3896   memset(mail, '\0', sizeof(mail));
3897   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
3898   memset(alt_recipient, '\0', sizeof(alt_recipient));
3899   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
3900           dn_path);
3901   sprintf(search_string, "@%s", uppercase(ldap_domain));
3902
3903   if (Exchange)
3904     {
3905       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
3906         {
3907           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
3908         }
3909     }
3910
3911   group_count = 0;
3912   group_base = NULL;
3913
3914   memset(displayName, '\0', sizeof(displayName));
3915
3916   if (strlen(MoiraId) != 0)
3917     {
3918       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
3919       attr_array[0] = "cn";
3920       attr_array[1] = NULL;
3921       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
3922                                &group_base, &group_count, 
3923                                LDAP_SCOPE_SUBTREE)) != 0)
3924         {
3925           com_err(whoami, 0, "Unable to process user %s : %s",
3926                   user_name, ldap_err2string(rc));
3927           return(rc);
3928         }
3929     }
3930
3931   if (group_count != 1)
3932     {
3933       linklist_free(group_base);
3934       group_base = NULL;
3935       group_count = 0;
3936       sprintf(filter, "(sAMAccountName=%s)", user_name);
3937       attr_array[0] = "cn";
3938       attr_array[1] = NULL;
3939       sprintf(temp, "%s,%s", user_ou, dn_path);
3940       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
3941                                &group_base, &group_count, 
3942                                LDAP_SCOPE_SUBTREE)) != 0)
3943         {
3944           com_err(whoami, 0, "Unable to process user %s : %s",
3945                   user_name, ldap_err2string(rc));
3946           return(rc);
3947         }
3948     }
3949
3950   if (group_count != 1)
3951     {
3952       com_err(whoami, 0, "Unable to find user %s in AD",
3953               user_name);
3954       linklist_free(group_base);
3955       return(AD_NO_USER_FOUND);
3956     }
3957
3958   strcpy(distinguished_name, group_base->dn);
3959
3960   linklist_free(group_base);
3961   group_count = 0;
3962
3963   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
3964     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
3965                           "employeeID", user_name);
3966   else
3967     rc = attribute_update(ldap_handle, distinguished_name, "none", 
3968                           "employeeID", user_name);
3969
3970   if(strlen(first)) {
3971     strcat(displayName, first);
3972   }
3973
3974   if(strlen(middle)) {
3975     if(strlen(first)) 
3976       strcat(displayName, " ");
3977
3978     strcat(displayName, middle);
3979   }
3980
3981   if(strlen(last)) {
3982     if(strlen(middle) || strlen(first))
3983       strcat(displayName, " ");
3984
3985     strcat(displayName, last);
3986   }
3987
3988   if(strlen(displayName)) 
3989     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
3990                           "displayName", user_name);
3991   else
3992     rc = attribute_update(ldap_handle, distinguished_name, user_name,
3993                           "displayName", user_name);
3994   
3995   if(strlen(first))
3996     rc = attribute_update(ldap_handle, distinguished_name, first, 
3997                           "givenName", user_name);
3998   else
3999     rc = attribute_update(ldap_handle, distinguished_name, "",
4000                           "givenName", user_name);
4001
4002   if(strlen(middle) == 1) 
4003     rc = attribute_update(ldap_handle, distinguished_name, middle,
4004                           "initials", user_name);
4005   else 
4006     rc = attribute_update(ldap_handle, distinguished_name, "",
4007                           "initials", user_name);
4008   
4009   if(strlen(last))
4010     rc = attribute_update(ldap_handle, distinguished_name, last,
4011                           "sn", user_name);
4012   else 
4013     rc = attribute_update(ldap_handle, distinguished_name, "",
4014                           "sn", user_name);
4015   
4016   rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4017                         user_name);
4018   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4019                         "mitMoiraId", user_name);
4020
4021   n = 0;
4022   uid_v[0] = Uid;
4023
4024   if (!UseSFU30)
4025     {
4026       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4027     }
4028   else
4029     {
4030       ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4031     }
4032
4033   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4034     {
4035       userAccountControl |= UF_ACCOUNTDISABLE;
4036
4037       if (Exchange)
4038         {
4039           hide_address_lists_v[0] = "TRUE";
4040           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4041                    LDAP_MOD_REPLACE);
4042         }
4043     }
4044   else
4045     {
4046       if (Exchange)
4047         {
4048           hide_address_lists_v[0] = NULL;
4049           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4050                    LDAP_MOD_REPLACE);
4051         }
4052     }
4053
4054   sprintf(userAccountControlStr, "%ld", userAccountControl);
4055   userAccountControl_v[0] = userAccountControlStr;
4056   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4057
4058   if (Exchange)
4059     {
4060       if (rc = moira_connect())
4061         {
4062           critical_alert("AD incremental", 
4063                          "Error contacting Moira server : %s",
4064                          error_message(rc));
4065           return;
4066         }
4067  
4068       argv[0] = user_name;
4069
4070       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4071         {
4072           if(!strcmp(save_argv[1], "EXCHANGE") || 
4073              (strstr(save_argv[3], search_string) != NULL))
4074             {
4075               alt_recipient_v[0] = NULL;
4076               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4077
4078               argv[0] = exchange_acl;
4079               argv[1] = "USER";
4080               argv[2] = user_name;
4081               
4082               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4083               
4084               if ((rc) && (rc != MR_EXISTS))
4085                 {
4086                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4087                           user_name, exchange_acl, error_message(rc));
4088                 }
4089             }
4090           else 
4091             {
4092               alt_recipient_v[0] = alt_recipient;
4093               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4094               
4095               argv[0] = exchange_acl;
4096               argv[1] = "USER";
4097               argv[2] = user_name;
4098               
4099               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4100               
4101               if ((rc) && (rc != MR_NO_MATCH))
4102                 {  
4103                   com_err(whoami, 0,
4104                           "Unable to remove user %s from %s: %s, %d",
4105                           user_name, exchange_acl, error_message(rc), rc);
4106                 }  
4107             }
4108         }
4109       else
4110         {
4111           alt_recipient_v[0] = alt_recipient;
4112           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4113           
4114           argv[0] = exchange_acl;
4115           argv[1] = "USER";
4116           argv[2] = user_name;
4117           
4118           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4119           
4120           if ((rc) && (rc != MR_NO_MATCH))
4121             {  
4122               com_err(whoami, 0,
4123                       "Unable to remove user %s from %s: %s, %d",
4124                       user_name, exchange_acl, error_message(rc), rc);
4125             }  
4126         }
4127       
4128       moira_disconnect();
4129     }
4130   else
4131     {
4132       mail_v[0] = contact_mail;
4133       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4134     }
4135
4136   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4137                        WinProfileDir, homedir_v, winProfile_v,
4138                        drives_v, mods, LDAP_MOD_REPLACE, n);
4139
4140   sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4141   sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4142   attr_array[0] = "sAMAccountName";
4143   attr_array[1] = NULL;
4144   group_count = 0;
4145   group_base = NULL;
4146
4147   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array,
4148                            &group_base, &group_count, 
4149                            LDAP_SCOPE_SUBTREE) != 0))
4150     return(1);
4151
4152   if (group_count != 1)
4153     {
4154       com_err(whoami, 0, "Unable to process user security template: %s - "
4155               "security not set", "UserTemplate.u");
4156       return(1);
4157     }
4158
4159   strcpy(TemplateDn, group_base->dn);
4160   strcpy(TemplateSamName, group_base->value);
4161   linklist_free(group_base);
4162   group_base = NULL;
4163   group_count = 0;
4164
4165   rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4166                          filter_exp, NULL, 0, apsServerControls, NULL,
4167                          NULL, 0, &psMsg);
4168
4169   if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4170     {
4171       com_err(whoami, 0, "Unable to find user security template: %s - "
4172               "security not set", "UserTemplate.u");
4173       return(1);
4174     }
4175
4176   ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
4177
4178   if (ppsValues == NULL)
4179     {
4180       com_err(whoami, 0, "Unable to find user security template: %s - "
4181               "security not set", "UserTemplate.u");
4182       return(1);
4183     }
4184   
4185   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4186            LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4187   
4188   mods[n] = NULL;
4189
4190   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4191                           mods)) != LDAP_SUCCESS)
4192     {
4193       OldUseSFU30 = UseSFU30;
4194       SwitchSFU(mods, &UseSFU30, n);
4195       if (OldUseSFU30 != UseSFU30)
4196         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4197       if (rc)
4198         {
4199           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4200                   user_name, ldap_err2string(rc));
4201         }
4202     }
4203   
4204   for (i = 0; i < n; i++)
4205     free(mods[i]);
4206
4207   return(rc);
4208 }
4209
4210 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4211                 char *user_name)
4212 {
4213   LDAPMod *mods[20];
4214   char new_dn[256];
4215   char old_dn[256];
4216   char upn[256];
4217   char mail[256];
4218   char contact_mail[256];
4219   char proxy_address[256];
4220   char query_base_dn[256];
4221   char temp[256];
4222   char *userPrincipalName_v[] = {NULL, NULL};
4223   char *altSecurityIdentities_v[] = {NULL, NULL};
4224   char *name_v[] = {NULL, NULL};
4225   char *samAccountName_v[] = {NULL, NULL};
4226   char *mail_v[] = {NULL, NULL};
4227   char *mail_nickname_v[] = {NULL, NULL};
4228   char *proxy_address_v[] = {NULL, NULL};
4229   char *query_base_dn_v[] = {NULL, NULL};
4230   int  n;
4231   int  rc;
4232   int  i;
4233
4234   if (!check_string(before_user_name))
4235     {
4236       com_err(whoami, 0, 
4237               "Unable to process invalid LDAP user name %s", before_user_name);
4238       return(AD_INVALID_NAME);
4239     }
4240
4241   if (!check_string(user_name))
4242     {
4243       com_err(whoami, 0, 
4244               "Unable to process invalid LDAP user name %s", user_name);
4245       return(AD_INVALID_NAME);
4246     }
4247
4248   strcpy(user_name, user_name);
4249   sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4250   sprintf(new_dn, "cn=%s", user_name);
4251   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4252   sprintf(contact_mail, "%s@mit.edu", user_name);
4253   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4254
4255   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4256                            NULL, NULL)) != LDAP_SUCCESS)
4257     {
4258       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4259               before_user_name, user_name, ldap_err2string(rc));
4260       return(rc);
4261     }
4262
4263   if (Exchange)
4264     {
4265       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4266               dn_path);
4267
4268       if(rc = ldap_delete_s(ldap_handle, temp))
4269         {
4270           com_err(whoami, 0, "Unable to delete user contact for %s",
4271                   user_name);
4272         }
4273       
4274       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4275         {
4276           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4277         }
4278     }
4279
4280   name_v[0] = user_name;
4281   sprintf(upn, "%s@%s", user_name, ldap_domain);
4282   userPrincipalName_v[0] = upn;
4283   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4284   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4285   altSecurityIdentities_v[0] = temp;
4286   samAccountName_v[0] = user_name;
4287   mail_v[0] = mail;
4288   mail_nickname_v[0] = user_name;
4289   proxy_address_v[0] = proxy_address; 
4290   query_base_dn_v[0] = query_base_dn;
4291
4292   n = 0;
4293   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4294   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4295   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4296   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4297
4298   if (Exchange)
4299     {
4300       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4301       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4302       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4303       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4304     }
4305   else
4306     {
4307       mail_v[0] = contact_mail;
4308       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4309     }
4310
4311   mods[n] = NULL;
4312   
4313   sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4314
4315   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4316     {
4317       com_err(whoami, 0, 
4318               "Unable to modify user data for %s after renaming : %s",
4319               user_name, ldap_err2string(rc));
4320     }
4321   
4322   for (i = 0; i < n; i++)
4323     free(mods[i]);
4324
4325   return(rc);
4326 }
4327
4328 int user_create(int ac, char **av, void *ptr)
4329 {
4330   LDAPMod *mods[20];
4331   char new_dn[256];
4332   char user_name[256];
4333   char sam_name[256];
4334   char upn[256];
4335   char mail[256];
4336   char contact_mail[256];
4337   char proxy_address[256];
4338   char mail_nickname[256];
4339   char query_base_dn[256];
4340   char displayName[256];
4341   char address_book[256];
4342   char alt_recipient[256];
4343   char *cn_v[] = {NULL, NULL};
4344   char *objectClass_v[] = {"top", "person", 
4345                            "organizationalPerson", 
4346                            "user", NULL};
4347
4348   char *samAccountName_v[] = {NULL, NULL};
4349   char *altSecurityIdentities_v[] = {NULL, NULL};
4350   char *mitMoiraId_v[] = {NULL, NULL};
4351   char *name_v[] = {NULL, NULL};
4352   char *desc_v[] = {NULL, NULL};
4353   char *userPrincipalName_v[] = {NULL, NULL};
4354   char *userAccountControl_v[] = {NULL, NULL};
4355   char *uid_v[] = {NULL, NULL};
4356   char *mitid_v[] = {NULL, NULL};
4357   char *homedir_v[] = {NULL, NULL};
4358   char *winProfile_v[] = {NULL, NULL};
4359   char *drives_v[] = {NULL, NULL};
4360   char *mail_v[] = {NULL, NULL};
4361   char *givenName_v[] = {NULL, NULL};
4362   char *sn_v[] = {NULL, NULL};
4363   char *initials_v[] = {NULL, NULL};
4364   char *displayName_v[] = {NULL, NULL};
4365   char *proxy_address_v[] = {NULL, NULL};
4366   char *mail_nickname_v[] = {NULL, NULL};
4367   char *query_base_dn_v[] = {NULL, NULL};
4368   char *address_book_v[] = {NULL, NULL};
4369   char *homeMDB_v[] = {NULL, NULL};
4370   char *homeServerName_v[] = {NULL, NULL};
4371   char *mdbUseDefaults_v[] = {NULL, NULL};
4372   char *mailbox_guid_v[] = {NULL, NULL};
4373   char *user_culture_v[] = {NULL, NULL};
4374   char *user_account_control_v[] = {NULL, NULL};
4375   char *msexch_version_v[] = {NULL, NULL};
4376   char *alt_recipient_v[] = {NULL, NULL};
4377   char *hide_address_lists_v[] = {NULL, NULL};
4378   char userAccountControlStr[80];
4379   char temp[128];
4380   char filter_exp[1024];
4381   char search_path[512];
4382   char *attr_array[3];
4383   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4384     UF_PASSWD_CANT_CHANGE; 
4385   int  n;
4386   int  rc;
4387   int  i;
4388   int  OldUseSFU30;
4389   char **call_args;
4390   char WinHomeDir[1024];
4391   char WinProfileDir[1024];
4392   char *homeMDB;
4393   char *homeServerName;
4394   ULONG dwInfo;
4395   char acBERBuf[N_SD_BER_BYTES];
4396   LK_ENTRY  *group_base;
4397   int    group_count;
4398   char TemplateDn[512];
4399   char TemplateSamName[128];
4400   LDAP_BERVAL **ppsValues;
4401   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4402                           { N_SD_BER_BYTES, acBERBuf },
4403                           TRUE};
4404   LDAPControl *apsServerControls[] = {&sControl, NULL};
4405   LDAPMessage *psMsg;
4406   char *argv[3];
4407   char *save_argv[7];
4408   char search_string[256];
4409
4410   call_args = ptr;
4411
4412   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4413     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4414   BEREncodeSecurityBits(dwInfo, acBERBuf);
4415
4416   if (!check_string(av[U_NAME]))
4417     {
4418       callback_rc = AD_INVALID_NAME;
4419       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4420               av[U_NAME]);
4421       return(AD_INVALID_NAME);
4422     }
4423
4424   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4425   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4426   memset(displayName, '\0', sizeof(displayName));
4427   memset(query_base_dn, '\0', sizeof(query_base_dn));
4428   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4429   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4430   strcpy(user_name, av[U_NAME]);
4431   sprintf(upn, "%s@%s", user_name, ldap_domain);
4432   sprintf(sam_name, "%s", av[U_NAME]);
4433
4434   if(strlen(av[U_FIRST])) {
4435     strcat(displayName, av[U_FIRST]);
4436   }
4437
4438   if(strlen(av[U_MIDDLE])) {
4439     if(strlen(av[U_FIRST]))
4440        strcat(displayName, " "); 
4441
4442     strcat(displayName, av[U_MIDDLE]);
4443   }
4444
4445   if(strlen(av[U_LAST])) {
4446     if(strlen(av[U_FIRST]) || strlen(av[U_LAST]))
4447       strcat(displayName, " ");
4448
4449     strcat(displayName, av[U_LAST]);
4450   }
4451
4452   samAccountName_v[0] = sam_name;
4453   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4454       (atoi(av[U_STATE]) != US_REGISTERED))
4455     {
4456       userAccountControl |= UF_ACCOUNTDISABLE;
4457
4458       if (Exchange)
4459         {
4460           hide_address_lists_v[0] = "TRUE";
4461           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4462                    LDAP_MOD_ADD);
4463         }
4464     }
4465
4466   sprintf(userAccountControlStr, "%ld", userAccountControl);
4467   userAccountControl_v[0] = userAccountControlStr;
4468   userPrincipalName_v[0] = upn;
4469   cn_v[0] = user_name;
4470   name_v[0] = user_name;
4471   desc_v[0] = "Auto account created by Moira";
4472   mail_v[0] = mail;
4473   givenName_v[0] = av[U_FIRST];
4474   sn_v[0] = av[U_LAST];
4475   displayName_v[0] = displayName;
4476   mail_nickname_v[0] = user_name;
4477   
4478   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4479   altSecurityIdentities_v[0] = temp;    
4480   sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4481   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4482   sprintf(contact_mail, "%s@mit.edu", user_name);
4483   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4484   query_base_dn_v[0] = query_base_dn;
4485   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4486           call_args[1]);
4487   sprintf(search_string, "@%s", uppercase(ldap_domain));
4488
4489
4490   if (Exchange)
4491     {
4492       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
4493                         contact_ou))
4494         {
4495           com_err(whoami, 0, "Unable to create user contact %s", 
4496                   contact_mail);
4497         }
4498       
4499       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
4500                       &homeServerName)) 
4501         {
4502           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
4503           return(1);
4504         }
4505       
4506       com_err(whoami, 0, "homeMDB:%s", homeMDB);
4507       com_err(whoami, 0, "homeServerName:%s", homeServerName);
4508   
4509       homeMDB_v[0] = homeMDB;
4510       homeServerName_v[0] = homeServerName; 
4511     }
4512
4513   n = 0;
4514   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
4515   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
4516   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
4517   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
4518   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
4519   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
4520   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
4521
4522   if (Exchange)
4523     {
4524       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
4525       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
4526       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
4527       mdbUseDefaults_v[0] = "TRUE";
4528       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
4529       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
4530       
4531       argv[0] = user_name;
4532     
4533       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4534         {
4535           if(!strcmp(save_argv[1], "EXCHANGE") || 
4536              (strstr(save_argv[3], search_string) != NULL))
4537             {
4538               argv[0] = exchange_acl;
4539               argv[1] = "USER";
4540               argv[2] = user_name;
4541               
4542               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4543               
4544               if ((rc) && (rc != MR_EXISTS))
4545                 {
4546                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4547                           user_name, exchange_acl, error_message(rc));
4548                 }
4549             } 
4550           else 
4551             {
4552               alt_recipient_v[0] = alt_recipient;
4553               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
4554             }
4555         }
4556       else
4557         {
4558           alt_recipient_v[0] = alt_recipient;
4559           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
4560           
4561           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
4562         }
4563     }
4564   else
4565     {
4566       mail_v[0] = contact_mail;
4567       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
4568     }
4569
4570   if(strlen(av[U_FIRST])) {
4571     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
4572   }
4573
4574   if(strlen(av[U_LAST])) {
4575     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
4576   }
4577
4578   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
4579     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
4580   } else {
4581     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
4582   }
4583
4584   if (strlen(av[U_MIDDLE]) == 1) {
4585     initials_v[0] = av[U_MIDDLE];
4586     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
4587   }
4588
4589   if (strlen(call_args[2]) != 0)    
4590     {
4591       mitMoiraId_v[0] = call_args[2];
4592       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
4593     }
4594   
4595   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD); 
4596
4597   if (strlen(av[U_UID]) != 0)
4598     {
4599       uid_v[0] = av[U_UID];
4600       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
4601
4602       if (!UseSFU30)
4603         {
4604           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
4605         }
4606       else
4607         {
4608           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
4609         }
4610     }
4611
4612   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
4613       mitid_v[0] = av[U_MITID];
4614   else
4615       mitid_v[0] = "none";
4616
4617   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
4618
4619   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, WinHomeDir, 
4620                        WinProfileDir, homedir_v, winProfile_v,
4621                        drives_v, mods, LDAP_MOD_ADD, n);
4622
4623   sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4624   sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
4625   attr_array[0] = "sAMAccountName";
4626   attr_array[1] = NULL;
4627   group_count = 0;
4628   group_base = NULL;
4629
4630   if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
4631                            attr_array, &group_base, &group_count, 
4632                            LDAP_SCOPE_SUBTREE) != 0))
4633     return(1);
4634
4635   if (group_count != 1)
4636     {
4637       com_err(whoami, 0, "Unable to process user security template: %s - "
4638               "security not set", "UserTemplate.u");
4639       return(1);
4640     }
4641
4642   strcpy(TemplateDn, group_base->dn);
4643   strcpy(TemplateSamName, group_base->value);
4644   linklist_free(group_base);
4645   group_base = NULL;
4646   group_count = 0;
4647
4648   rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, LDAP_SCOPE_SUBTREE,
4649                          filter_exp, NULL, 0, apsServerControls, NULL,
4650                          NULL, 0, &psMsg);
4651
4652   if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
4653     {
4654       com_err(whoami, 0, "Unable to find user security template: %s - "
4655               "security not set", "UserTemplate.u");
4656       return(1);
4657     }
4658
4659   ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
4660                                   "ntSecurityDescriptor");
4661   if (ppsValues == NULL)
4662     {
4663       com_err(whoami, 0, "Unable to find user security template: %s - "
4664               "security not set", "UserTemplate.u");
4665       return(1);
4666     }
4667   
4668   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4669      LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
4670
4671   mods[n] = NULL;
4672
4673   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
4674
4675   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4676     {
4677       OldUseSFU30 = UseSFU30;
4678       SwitchSFU(mods, &UseSFU30, n);
4679       if (OldUseSFU30 != UseSFU30)
4680         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
4681     }
4682
4683   for (i = 0; i < n; i++)
4684     free(mods[i]);
4685
4686   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4687     {
4688       com_err(whoami, 0, "Unable to create user %s : %s",
4689               user_name, ldap_err2string(rc));
4690       callback_rc = rc;
4691       return(rc);
4692     }
4693
4694   if ((rc == LDAP_SUCCESS) && (SetPassword))
4695     {
4696       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
4697         {
4698           ad_kdc_disconnect();
4699           if (!ad_server_connect(default_server, ldap_domain))
4700             {
4701               com_err(whoami, 0, "Unable to set password for user %s : %s",
4702                       user_name, 
4703                       "cannot get changepw ticket from windows domain");
4704             }
4705           else
4706             {
4707               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
4708                 {
4709                   com_err(whoami, 0, "Unable to set password for user %s "
4710                           ": %ld", user_name, rc);
4711                 }
4712             }
4713         }
4714     }
4715
4716   return(0);
4717 }
4718
4719 int user_change_status(LDAP *ldap_handle, char *dn_path, 
4720                        char *user_name, char *MoiraId,
4721                        int operation)
4722 {
4723   char      filter[128];
4724   char      *attr_array[3];
4725   char      temp[256];
4726   char      distinguished_name[1024];
4727   char      **modvalues;
4728   char      *mitMoiraId_v[] = {NULL, NULL};
4729   LDAPMod   *mods[20];
4730   LK_ENTRY  *group_base;
4731   int       group_count;
4732   int       rc;
4733   int       i;
4734   int       n;
4735   ULONG     ulongValue;
4736
4737   if (!check_string(user_name))
4738     {
4739       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4740               user_name);
4741       return(AD_INVALID_NAME);
4742     }
4743
4744   group_count = 0;
4745   group_base = NULL;
4746
4747   if (strlen(MoiraId) != 0)
4748     {
4749       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4750       attr_array[0] = "UserAccountControl";
4751       attr_array[1] = NULL;
4752       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4753                                &group_base, &group_count, 
4754                                LDAP_SCOPE_SUBTREE)) != 0)
4755         {
4756           com_err(whoami, 0, "Unable to process user %s : %s",
4757                   user_name, ldap_err2string(rc));
4758           return(rc);
4759         }
4760     }
4761
4762   if (group_count != 1)
4763     {
4764       linklist_free(group_base);
4765       group_count = 0;
4766       group_base = NULL;
4767       sprintf(filter, "(sAMAccountName=%s)", user_name);
4768       attr_array[0] = "UserAccountControl";
4769       attr_array[1] = NULL;
4770       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4771                                &group_base, &group_count, 
4772                                LDAP_SCOPE_SUBTREE)) != 0)
4773         {
4774           com_err(whoami, 0, "Unable to process user %s : %s",
4775                   user_name, ldap_err2string(rc));
4776           return(rc);
4777         }
4778     }
4779   
4780   if (group_count != 1)
4781     {
4782       linklist_free(group_base);
4783       com_err(whoami, 0, "Unable to find user %s in AD",
4784               user_name);
4785       return(LDAP_NO_SUCH_OBJECT);
4786     }
4787
4788   strcpy(distinguished_name, group_base->dn);
4789   ulongValue = atoi((*group_base).value);
4790
4791   if (operation == MEMBER_DEACTIVATE)
4792     ulongValue |= UF_ACCOUNTDISABLE;
4793   else    
4794     ulongValue &= ~UF_ACCOUNTDISABLE;
4795
4796   sprintf(temp, "%ld", ulongValue);
4797
4798   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
4799                                 temp, &modvalues, REPLACE)) == 1)
4800     goto cleanup;
4801
4802   linklist_free(group_base);
4803   group_base = NULL;
4804   group_count = 0;
4805   n = 0;
4806   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
4807
4808   if (strlen(MoiraId) != 0)
4809     {
4810     mitMoiraId_v[0] = MoiraId;
4811     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
4812     }
4813
4814   mods[n] = NULL;
4815   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4816
4817   for (i = 0; i < n; i++)
4818     free(mods[i]);
4819
4820   free_values(modvalues);
4821
4822   if (rc != LDAP_SUCCESS)
4823     {
4824       com_err(whoami, 0, "Unable to change status of user %s : %s",
4825               user_name, ldap_err2string(rc));
4826     }
4827   
4828  cleanup:
4829   return(rc);
4830 }
4831
4832 int user_delete(LDAP *ldap_handle, char *dn_path, 
4833                 char *u_name, char *MoiraId)
4834 {
4835   char      filter[128];
4836   char      *attr_array[3];
4837   char      distinguished_name[1024];
4838   char      user_name[512];
4839   LK_ENTRY  *group_base;
4840   int       group_count;
4841   int       rc;
4842   char      temp[256];
4843
4844   if (!check_string(u_name))
4845     return(AD_INVALID_NAME);
4846
4847   strcpy(user_name, u_name);
4848   group_count = 0;
4849   group_base = NULL;
4850
4851   if (strlen(MoiraId) != 0)
4852     {
4853       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4854       attr_array[0] = "name";
4855       attr_array[1] = NULL;
4856       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4857                                &group_base, &group_count, 
4858                                LDAP_SCOPE_SUBTREE)) != 0)
4859         {
4860           com_err(whoami, 0, "Unable to process user %s : %s",
4861                   user_name, ldap_err2string(rc));
4862           goto cleanup;
4863         }
4864     }
4865   
4866   if (group_count != 1)
4867     {
4868       linklist_free(group_base);
4869       group_count = 0;
4870       group_base = NULL;
4871       sprintf(filter, "(sAMAccountName=%s)", user_name);
4872       attr_array[0] = "name";
4873       attr_array[1] = NULL;
4874       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4875                                &group_base, &group_count, 
4876                                LDAP_SCOPE_SUBTREE)) != 0)
4877         {
4878           com_err(whoami, 0, "Unable to process user %s : %s",
4879                   user_name, ldap_err2string(rc));
4880           goto cleanup;
4881         }
4882     }
4883
4884   if (group_count != 1)
4885     {
4886       com_err(whoami, 0, "Unable to find user %s in AD",
4887               user_name);
4888       goto cleanup;
4889     }
4890   
4891   strcpy(distinguished_name, group_base->dn);
4892
4893   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
4894     {
4895       com_err(whoami, 0, "Unable to process user %s : %s",
4896               user_name, ldap_err2string(rc));
4897     }
4898
4899   /* Need to add code to delete mit.edu contact */
4900   
4901   if (Exchange)
4902     {
4903       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
4904
4905       if(rc = ldap_delete_s(ldap_handle, temp))
4906         {
4907           com_err(whoami, 0, "Unable to delete user contact for %s",
4908                   user_name);
4909         }
4910     }
4911
4912  cleanup:
4913   linklist_free(group_base);
4914
4915   return(0);
4916 }
4917
4918 void linklist_free(LK_ENTRY *linklist_base)
4919 {
4920   LK_ENTRY *linklist_previous;
4921
4922   while (linklist_base != NULL)
4923     {
4924       if (linklist_base->dn != NULL)
4925         free(linklist_base->dn);
4926
4927       if (linklist_base->attribute != NULL)
4928         free(linklist_base->attribute);
4929
4930       if (linklist_base->value != NULL)
4931         free(linklist_base->value);
4932
4933       if (linklist_base->member != NULL)
4934         free(linklist_base->member);
4935
4936       if (linklist_base->type != NULL)
4937         free(linklist_base->type);
4938
4939       if (linklist_base->list != NULL)
4940         free(linklist_base->list);
4941
4942       linklist_previous = linklist_base;
4943       linklist_base = linklist_previous->next;
4944       free(linklist_previous);
4945     }
4946 }
4947
4948 void free_values(char **modvalues)
4949 {
4950   int i;
4951
4952   i = 0;
4953
4954   if (modvalues != NULL)
4955     {
4956     while (modvalues[i] != NULL)
4957       {
4958         free(modvalues[i]);
4959         modvalues[i] = NULL;
4960         ++i;
4961       }
4962     free(modvalues);
4963   }
4964 }
4965
4966 static int illegalchars[] = {
4967   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
4968   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
4969   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
4970   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
4971   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
4972   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
4973   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
4974   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4982   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4983 };
4984
4985 int check_string(char *s)
4986 {
4987   char  character;
4988
4989   for (; *s; s++)
4990     {
4991       character = *s;
4992
4993       if (isupper(character))
4994         character = tolower(character);
4995
4996       if (illegalchars[(unsigned) character])
4997         return 0;
4998     }
4999
5000   return(1);
5001 }
5002
5003 int check_container_name(char *s)
5004 {
5005   char  character;
5006
5007   for (; *s; s++)
5008     {
5009       character = *s;
5010
5011       if (isupper(character))
5012         character = tolower(character);
5013
5014       if (character == ' ')
5015         continue;
5016
5017       if (illegalchars[(unsigned) character])
5018         return 0;
5019     }
5020
5021   return(1);
5022 }
5023
5024 int mr_connect_cl(char *server, char *client, int version, int auth)
5025 {
5026   int   status;
5027   char  *motd;
5028   char  temp[128];
5029
5030   status = mr_connect(server);
5031
5032   if (status)
5033     {
5034       com_err(whoami, status, "while connecting to Moira");
5035       return status;
5036     }
5037
5038   status = mr_motd(&motd);
5039
5040   if (status)
5041     {
5042       mr_disconnect();
5043       com_err(whoami, status, "while checking server status");
5044       return status;
5045     }
5046
5047   if (motd)
5048     {
5049       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5050       com_err(whoami, status, temp);
5051       mr_disconnect();
5052       return status;
5053     }
5054
5055   status = mr_version(version);
5056
5057   if (status)
5058     {
5059       if (status == MR_UNKNOWN_PROC)
5060         {
5061           if (version > 2)
5062             status = MR_VERSION_HIGH;
5063           else
5064             status = MR_SUCCESS;
5065         }
5066
5067       if (status == MR_VERSION_HIGH)
5068         {
5069           com_err(whoami, 0, "Warning: This client is running newer code "
5070                   "than the server.");
5071                   com_err(whoami, 0, "Some operations may not work.");
5072         }
5073       else if (status && status != MR_VERSION_LOW)
5074         {
5075           com_err(whoami, status, "while setting query version number.");
5076           mr_disconnect();
5077           return status;
5078         }
5079     }
5080
5081   if (auth)
5082     {
5083       status = mr_krb5_auth(client);
5084       if (status)
5085         {
5086           com_err(whoami, status, "while authenticating to Moira.");
5087           mr_disconnect();
5088           return status;
5089         }
5090     }
5091   
5092   return MR_SUCCESS;
5093 }
5094
5095 void AfsToWinAfs(char* path, char* winPath)
5096 {
5097   char* pathPtr;
5098   char* winPathPtr;
5099   strcpy(winPath, WINAFS);
5100   pathPtr = path + strlen(AFS);
5101   winPathPtr = winPath + strlen(WINAFS);
5102   
5103   while (*pathPtr)
5104     {
5105       if (*pathPtr == '/')
5106         *winPathPtr = '\\';
5107       else
5108         *winPathPtr = *pathPtr;
5109       
5110       pathPtr++;
5111       winPathPtr++;
5112     }
5113 }
5114
5115 int GetAceInfo(int ac, char **av, void *ptr)
5116 {
5117   char **call_args;
5118   int   security_flag;
5119
5120   call_args = ptr;
5121   
5122   strcpy(call_args[0], av[L_ACE_TYPE]);
5123   strcpy(call_args[1], av[L_ACE_NAME]);
5124   security_flag = 0;
5125   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5126   return(LDAP_SUCCESS);  
5127 }
5128
5129 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5130 {
5131   char filter[128];
5132   char *attr_array[3];
5133   int  group_count;
5134   int  rc;
5135   LK_ENTRY  *group_base;
5136   
5137   group_count = 0;
5138   group_base = NULL;
5139   
5140   sprintf(filter, "(sAMAccountName=%s)", Name);
5141   attr_array[0] = "sAMAccountName";
5142   attr_array[1] = NULL;
5143
5144   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5145                            &group_base, &group_count, 
5146                            LDAP_SCOPE_SUBTREE)) != 0)
5147     {
5148       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5149               Name, ldap_err2string(rc));
5150       return(1);
5151     }
5152
5153   linklist_free(group_base);
5154   group_base = NULL;
5155
5156   if (group_count == 0)
5157     return(0);
5158   
5159   return(1);
5160 }
5161
5162 #define MAX_ACE 7
5163
5164 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5165                int UpdateGroup, int *ProcessGroup, char *maillist)
5166 {
5167   char  *av[2];
5168   char  GroupName[256];
5169   char  *call_args[7];
5170   int   rc;
5171   char  *AceInfo[4];
5172   char  AceType[32];
5173   char  AceName[128];
5174   char  AceMembership[2];
5175   char  AceOu[256];
5176   char  temp[128];
5177   char  *save_argv[U_END];
5178
5179   if (!SetGroupAce)
5180     {
5181       com_err(whoami, 0, "ProcessAce disabled, skipping");
5182       return(0);
5183     }
5184
5185   strcpy(GroupName, Name);
5186   
5187   if (strcasecmp(Type, "LIST"))
5188     return(1);
5189
5190   while (1)
5191     {
5192       av[0] = GroupName;
5193       AceInfo[0] = AceType;
5194       AceInfo[1] = AceName;
5195       AceInfo[2] = AceMembership;
5196       AceInfo[3] = AceOu;
5197       memset(AceType, '\0', sizeof(AceType));
5198       memset(AceName, '\0', sizeof(AceName));
5199       memset(AceMembership, '\0', sizeof(AceMembership));
5200       memset(AceOu, '\0', sizeof(AceOu));
5201       callback_rc = 0;
5202     
5203       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5204         { 
5205           com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5206                   GroupName, error_message(rc));
5207           return(1);
5208         }
5209
5210       if (callback_rc)
5211         {
5212           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5213           return(1);
5214         }
5215
5216       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5217         return(0);
5218
5219       strcpy(temp, AceName);
5220
5221       if (!strcasecmp(AceType, "LIST"))
5222         sprintf(temp, "%s%s", AceName, group_suffix);
5223
5224       if (!UpdateGroup)
5225         {
5226           if (checkADname(ldap_handle, dn_path, temp))
5227             return(0);
5228           (*ProcessGroup) = 1;
5229         }
5230
5231       if (!strcasecmp(AceInfo[0], "LIST"))
5232         {
5233           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5234                              AceMembership, 0, UpdateGroup, maillist))
5235             return(1);
5236         }
5237       else if (!strcasecmp(AceInfo[0], "USER"))
5238         {
5239           av[0] = AceName;
5240           call_args[0] = (char *)ldap_handle;
5241           call_args[1] = dn_path;
5242           call_args[2] = "";
5243           call_args[3] = NULL;
5244           callback_rc = 0;
5245
5246           if (rc = mr_query("get_user_account_by_login", 1, av, 
5247                             save_query_info, save_argv))
5248             {
5249               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5250                       AceName, Name);
5251               return(1);
5252             }
5253
5254           if (rc = user_create(U_END, save_argv, call_args)) 
5255             {
5256               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5257                       AceName, Name);
5258               return(1);
5259             }
5260           
5261           if (callback_rc)
5262             {
5263               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5264                       AceName, Name);
5265               return(1);
5266             }
5267
5268           return(0);
5269         }
5270       else
5271         return(1);
5272
5273       if (!strcasecmp(AceType, "LIST"))
5274         {
5275           if (!strcasecmp(GroupName, AceName))
5276             return(0);
5277         }
5278
5279       strcpy(GroupName, AceName);
5280     }
5281   
5282   return(1);
5283 }
5284
5285 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
5286                    char *group_name, char *group_ou, char *group_membership, 
5287                    int group_security_flag, int updateGroup, char *maillist)
5288 {
5289   char  *av[3];
5290   char  *call_args[8];
5291   int   rc;
5292   LK_ENTRY  *group_base;
5293   int  group_count;
5294   char filter[128];
5295   char *attr_array[3];
5296
5297   av[0] = group_name;
5298   call_args[0] = (char *)ldap_handle;
5299   call_args[1] = dn_path;
5300   call_args[2] = group_name;
5301   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
5302   call_args[4] = (char *)updateGroup;
5303   call_args[5] = MoiraId;
5304   call_args[6] = "0";
5305   call_args[7] = NULL;
5306   callback_rc = 0;
5307
5308   group_count = 0;
5309   group_base = NULL;
5310
5311   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
5312     {
5313       moira_disconnect();
5314       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
5315               error_message(rc));
5316       return(rc);
5317     }
5318
5319   if (callback_rc)
5320     {
5321       moira_disconnect();
5322       com_err(whoami, 0, "Unable to create list %s", group_name);
5323       return(callback_rc);
5324     }
5325
5326   return(0);
5327 }
5328
5329 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
5330                    char *group_ou, char *group_membership, 
5331                    int group_security_flag, char *MoiraId)
5332 {
5333   char      *av[3];
5334   char      *call_args[7];
5335   char      *pUserOu;
5336   LK_ENTRY  *ptr;
5337   int       rc;
5338   char      member[256];
5339   char      *s;
5340
5341   com_err(whoami, 0, "Populating group %s", group_name);
5342   av[0] = group_name;
5343   call_args[0] = (char *)ldap_handle;
5344   call_args[1] = dn_path;
5345   call_args[2] = group_name;
5346   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
5347   call_args[4] = NULL;
5348   member_base = NULL;
5349
5350   if (rc = mr_query("get_end_members_of_list", 1, av,
5351                     member_list_build, call_args))
5352     {
5353       com_err(whoami, 0, "Unable to populate list %s : %s", 
5354               group_name, error_message(rc));
5355       return(3);
5356     }
5357
5358   if (member_base != NULL)
5359     {
5360       ptr = member_base;
5361
5362       while (ptr != NULL)
5363         {
5364           if (!strcasecmp(ptr->type, "LIST"))
5365             {
5366               ptr = ptr->next;
5367               continue;
5368             }
5369
5370           pUserOu = user_ou;
5371
5372           if (!strcasecmp(ptr->type, "STRING"))
5373             {
5374               if (contact_create(ldap_handle, dn_path, ptr->member, 
5375                                  contact_ou))
5376                 return(3);
5377
5378               pUserOu = contact_ou;
5379             }
5380           else if (!strcasecmp(ptr->type, "KERBEROS"))
5381             {
5382               if (contact_create(ldap_handle, dn_path, ptr->member, 
5383                                  kerberos_ou))
5384                 return(3);
5385
5386               pUserOu = kerberos_ou;
5387             }
5388
5389           rc = member_add(ldap_handle, dn_path, group_name,
5390                           group_ou, group_membership, ptr->member, 
5391                           pUserOu, MoiraId);
5392           ptr = ptr->next;
5393         }
5394
5395       linklist_free(member_base);
5396       member_base = NULL;
5397     }
5398
5399   return(0);
5400 }
5401
5402 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
5403                   char *group_name, char *group_ou, char *group_membership, 
5404                   int group_security_flag, int type, char *maillist)
5405 {
5406   char      before_desc[512];
5407   char      before_name[256];
5408   char      before_group_ou[256];
5409   char      before_group_membership[2];
5410   char      distinguishedName[256];
5411   char      ad_distinguishedName[256];
5412   char      filter[128];
5413   char      *attr_array[3];
5414   int       before_security_flag;
5415   int       group_count;
5416   int       rc;
5417   LK_ENTRY  *group_base;
5418   LK_ENTRY  *ptr;
5419   char      ou_both[512];
5420   char      ou_security[512];
5421   char      ou_distribution[512];
5422   char      ou_neither[512];
5423
5424   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
5425   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
5426
5427   memset(filter, '\0', sizeof(filter));
5428   group_base = NULL;
5429   group_count = 0;
5430
5431   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
5432                         "*", MoiraId, 
5433                         "distinguishedName", &group_base, 
5434                         &group_count, filter))
5435     return(rc);
5436
5437   if (type == CHECK_GROUPS)
5438     {
5439       if (group_count == 1)
5440         {
5441           if (!strcasecmp(group_base->value, distinguishedName))
5442             {
5443               linklist_free(group_base);
5444               return(0);
5445             }
5446         }
5447
5448       linklist_free(group_base);
5449
5450       if (group_count == 0)
5451         return(AD_NO_GROUPS_FOUND);
5452
5453       if (group_count == 1)
5454         return(AD_WRONG_GROUP_DN_FOUND);
5455
5456       return(AD_MULTIPLE_GROUPS_FOUND);
5457     }
5458
5459   if (group_count == 0)
5460     {
5461       return(AD_NO_GROUPS_FOUND);
5462     }
5463
5464   if (group_count > 1)
5465     {
5466       ptr = group_base;
5467
5468       while (ptr != NULL)
5469         {
5470           if (!strcasecmp(distinguishedName, ptr->value))
5471             break;
5472
5473           ptr = ptr->next;
5474         }
5475
5476       if (ptr == NULL)
5477         {
5478           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
5479                   MoiraId);
5480           ptr = group_base;
5481
5482           while (ptr != NULL)
5483             {
5484               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
5485               ptr = ptr->next;
5486             }
5487
5488           linklist_free(group_base);
5489           return(AD_MULTIPLE_GROUPS_FOUND);
5490         }
5491
5492       ptr = group_base;
5493
5494       while (ptr != NULL)
5495         {
5496           if (strcasecmp(distinguishedName, ptr->value))
5497             rc = ldap_delete_s(ldap_handle, ptr->value);
5498
5499           ptr = ptr->next;
5500         }
5501
5502       linklist_free(group_base);
5503       memset(filter, '\0', sizeof(filter));
5504       group_base = NULL;
5505       group_count = 0;
5506
5507       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
5508                             "*", MoiraId, 
5509                             "distinguishedName", &group_base, 
5510                             &group_count, filter))
5511         return(rc);
5512
5513       if (group_count == 0)
5514         return(AD_NO_GROUPS_FOUND);
5515
5516       if (group_count > 1)
5517         return(AD_MULTIPLE_GROUPS_FOUND);
5518     }
5519   
5520   strcpy(ad_distinguishedName, group_base->value);
5521   linklist_free(group_base);
5522   group_base = NULL;
5523   group_count = 0;
5524
5525   attr_array[0] = "sAMAccountName";
5526   attr_array[1] = NULL;
5527
5528   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5529                            &group_base, &group_count, 
5530                            LDAP_SCOPE_SUBTREE)) != 0)
5531     {
5532       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
5533                MoiraId, ldap_err2string(rc));
5534       return(rc);
5535     }
5536
5537   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
5538   
5539   if (!strcasecmp(ad_distinguishedName, distinguishedName))
5540     {
5541       linklist_free(group_base);
5542       group_base = NULL;
5543       group_count = 0;
5544       return(0);
5545     }
5546
5547   linklist_free(group_base);
5548   group_base = NULL;
5549   group_count = 0;
5550   memset(ou_both, '\0', sizeof(ou_both));
5551   memset(ou_security, '\0', sizeof(ou_security));
5552   memset(ou_distribution, '\0', sizeof(ou_distribution));
5553   memset(ou_neither, '\0', sizeof(ou_neither));
5554   memset(before_name, '\0', sizeof(before_name));
5555   memset(before_desc, '\0', sizeof(before_desc));
5556   memset(before_group_membership, '\0', sizeof(before_group_membership));
5557   attr_array[0] = "name";
5558   attr_array[1] = NULL;
5559
5560   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5561                            &group_base, &group_count, 
5562                            LDAP_SCOPE_SUBTREE)) != 0)
5563     {
5564       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
5565               MoiraId, ldap_err2string(rc));
5566       return(rc);
5567     }
5568
5569   strcpy(before_name, group_base->value);
5570   linklist_free(group_base);
5571   group_base = NULL;
5572   group_count = 0;
5573   attr_array[0] = "description";
5574   attr_array[1] = NULL;
5575
5576   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5577                            &group_base, &group_count, 
5578                            LDAP_SCOPE_SUBTREE)) != 0)
5579     {
5580       com_err(whoami, 0, 
5581               "Unable to get list description with MoiraId = %s: %s",
5582               MoiraId, ldap_err2string(rc));
5583       return(rc);
5584     }
5585
5586   if (group_count != 0)
5587     {
5588       strcpy(before_desc, group_base->value);
5589       linklist_free(group_base);
5590       group_base = NULL;
5591       group_count = 0;
5592     }
5593
5594   change_to_lower_case(ad_distinguishedName);  
5595   strcpy(ou_both, group_ou_both);
5596   change_to_lower_case(ou_both);
5597   strcpy(ou_security, group_ou_security);
5598   change_to_lower_case(ou_security);
5599   strcpy(ou_distribution, group_ou_distribution);
5600   change_to_lower_case(ou_distribution);
5601   strcpy(ou_neither, group_ou_neither);
5602   change_to_lower_case(ou_neither);
5603
5604   if (strstr(ad_distinguishedName, ou_both))
5605     {
5606       strcpy(before_group_ou, group_ou_both);
5607       before_group_membership[0] = 'B';
5608       before_security_flag = 1;
5609     }
5610   else if (strstr(ad_distinguishedName, ou_security))
5611     {
5612       strcpy(before_group_ou, group_ou_security);
5613       before_group_membership[0] = 'S';
5614       before_security_flag = 1;
5615     }
5616   else if (strstr(ad_distinguishedName, ou_distribution))
5617     {
5618       strcpy(before_group_ou, group_ou_distribution);
5619       before_group_membership[0] = 'D';
5620       before_security_flag = 0;
5621     }
5622   else if (strstr(ad_distinguishedName, ou_neither))
5623     {
5624       strcpy(before_group_ou, group_ou_neither);
5625       before_group_membership[0] = 'N';
5626       before_security_flag = 0;
5627     }
5628   else
5629     return(AD_NO_OU_FOUND);
5630
5631   rc = group_rename(ldap_handle, dn_path, before_name, 
5632                     before_group_membership, 
5633                     before_group_ou, before_security_flag, before_desc,
5634                     group_name, group_membership, group_ou, 
5635                     group_security_flag,
5636                     before_desc, MoiraId, filter, maillist);
5637
5638   return(rc);
5639 }
5640
5641 void change_to_lower_case(char *ptr)
5642 {
5643   int i;
5644
5645   for (i = 0; i < (int)strlen(ptr); i++)
5646     {
5647       ptr[i] = tolower(ptr[i]);
5648     }
5649 }
5650
5651 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
5652                  char *group_name, char *group_membership, 
5653                  char *MoiraId, char *attribute,
5654                  LK_ENTRY **linklist_base, int *linklist_count,
5655                  char *rFilter)
5656 {
5657   LK_ENTRY  *pPtr;
5658   char  filter[128];
5659   char  *attr_array[3];
5660   int   rc;
5661
5662   (*linklist_base) = NULL;
5663   (*linklist_count) = 0;
5664
5665   if (strlen(rFilter) != 0)
5666     {
5667       strcpy(filter, rFilter);
5668       attr_array[0] = attribute;
5669       attr_array[1] = NULL;
5670       
5671       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5672                                linklist_base, linklist_count, 
5673                                LDAP_SCOPE_SUBTREE)) != 0)
5674         {
5675           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
5676                   MoiraId, ldap_err2string(rc));
5677          return(rc);
5678        }
5679
5680     if ((*linklist_count) == 1)
5681       {
5682         strcpy(rFilter, filter);
5683         return(0);
5684       }
5685     }
5686
5687   linklist_free((*linklist_base));
5688   (*linklist_base) = NULL;
5689   (*linklist_count) = 0;
5690
5691   if (strlen(MoiraId) != 0)
5692     {
5693       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
5694       attr_array[0] = attribute;
5695       attr_array[1] = NULL;
5696
5697       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5698                                linklist_base, linklist_count, 
5699                                LDAP_SCOPE_SUBTREE)) != 0)
5700         {
5701           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
5702                   MoiraId, ldap_err2string(rc));
5703          return(rc);
5704        }
5705     }
5706
5707   if ((*linklist_count) > 1)
5708     {
5709       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
5710       pPtr = (*linklist_base);
5711
5712       while (pPtr)
5713         {
5714           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
5715                   MoiraId);
5716           pPtr = pPtr->next;
5717         }
5718
5719       linklist_free((*linklist_base));
5720       (*linklist_base) = NULL;
5721       (*linklist_count) = 0;
5722     }
5723
5724   if ((*linklist_count) == 1)
5725     {
5726       if (!memcmp(&(*linklist_base)->value[3], group_name, strlen(group_name)))
5727         {
5728           strcpy(rFilter, filter);
5729           return(0);
5730         }
5731     }
5732
5733   linklist_free((*linklist_base));
5734   (*linklist_base) = NULL;
5735   (*linklist_count) = 0;
5736   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
5737   attr_array[0] = attribute;
5738   attr_array[1] = NULL;
5739
5740   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5741                            linklist_base, linklist_count, 
5742                            LDAP_SCOPE_SUBTREE)) != 0)
5743     {
5744       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
5745               MoiraId, ldap_err2string(rc));
5746       return(rc);
5747     }
5748
5749   if ((*linklist_count) == 1)
5750     {
5751       strcpy(rFilter, filter);
5752       return(0);
5753     }
5754
5755   return(0);
5756 }
5757
5758 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
5759 {
5760   char filter[128];
5761   char *attr_array[3];
5762   char SamAccountName[64];
5763   int  group_count;
5764   int  rc;
5765   LK_ENTRY  *group_base;
5766   LK_ENTRY  *gPtr;
5767
5768   group_count = 0;
5769   group_base = NULL;
5770
5771   if (strlen(MoiraId) != 0)
5772     {
5773       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5774       attr_array[0] = "sAMAccountName";
5775       attr_array[1] = NULL;
5776       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5777                                &group_base, &group_count, 
5778                                LDAP_SCOPE_SUBTREE)) != 0)
5779         {
5780           com_err(whoami, 0, "Unable to process user %s : %s",
5781                   UserName, ldap_err2string(rc));
5782           return(rc);
5783         }
5784
5785       if (group_count > 1)
5786         {
5787           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
5788                   MoiraId);
5789           gPtr = group_base;
5790
5791           while (gPtr)
5792             {
5793               com_err(whoami, 0, "user %s exist with MoiraId = %s",
5794                       gPtr->value, MoiraId);
5795               gPtr = gPtr->next;
5796             }
5797         }
5798     }
5799
5800   if (group_count != 1)
5801     {
5802       linklist_free(group_base);
5803       group_count = 0;
5804       group_base = NULL;
5805       sprintf(filter, "(sAMAccountName=%s)", UserName);
5806       attr_array[0] = "sAMAccountName";
5807       attr_array[1] = NULL;
5808
5809       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5810                                &group_base, &group_count, 
5811                                LDAP_SCOPE_SUBTREE)) != 0)
5812         {
5813           com_err(whoami, 0, "Unable to process user %s : %s",
5814                   UserName, ldap_err2string(rc));
5815           return(rc);
5816         }
5817     }
5818
5819   if (group_count != 1)
5820     {
5821       linklist_free(group_base);
5822       return(AD_NO_USER_FOUND);
5823     }
5824
5825   strcpy(SamAccountName, group_base->value);
5826   linklist_free(group_base);
5827   group_count = 0;
5828   rc = 0;
5829
5830   if (strcmp(SamAccountName, UserName))
5831     {
5832       rc = user_rename(ldap_handle, dn_path, SamAccountName, 
5833                        UserName);
5834     }
5835
5836   return(0);
5837 }
5838
5839 void container_get_dn(char *src, char *dest)
5840 {
5841   char *sPtr;
5842   char *array[20];
5843   char name[256];
5844   int  n;
5845
5846   memset(array, '\0', 20 * sizeof(array[0]));
5847
5848   if (strlen(src) == 0)
5849     return;
5850
5851   strcpy(name, src);
5852   sPtr = name;
5853   n = 0;
5854   array[n] = name;
5855   ++n;
5856
5857   while (*sPtr)
5858     {
5859       if ((*sPtr) == '/')
5860         {
5861           (*sPtr) = '\0';
5862           ++sPtr;
5863           array[n] = sPtr;
5864           ++n;
5865         }
5866       else
5867         ++sPtr;
5868     }
5869
5870   strcpy(dest, "OU=");
5871
5872   while (n != 0)
5873     {
5874       strcat(dest, array[n-1]);
5875       --n;
5876       if (n > 0)
5877         {
5878           strcat(dest, ",OU=");
5879         }
5880     }
5881
5882   return;
5883 }
5884
5885 void container_get_name(char *src, char *dest)
5886 {
5887   char *sPtr;
5888   char *dPtr;
5889
5890   if (strlen(src) == 0)
5891     return;
5892
5893   sPtr = src;
5894   dPtr = src;
5895
5896   while (*sPtr)
5897     {
5898       if ((*sPtr) == '/')
5899         {
5900           dPtr = sPtr;
5901           ++dPtr;
5902         }
5903       ++sPtr;
5904     }
5905
5906   strcpy(dest, dPtr);
5907   return;
5908 }
5909
5910 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
5911 {
5912   char cName[256];
5913   char *av[7];
5914   int  i;
5915   int  rc;
5916
5917   strcpy(cName, name);
5918
5919   for (i = 0; i < (int)strlen(cName); i++)
5920     {
5921       if (cName[i] == '/')
5922         {
5923           cName[i] = '\0';
5924           av[CONTAINER_NAME] = cName;
5925           av[CONTAINER_DESC] = "";
5926           av[CONTAINER_LOCATION] = "";
5927           av[CONTAINER_CONTACT] = "";
5928           av[CONTAINER_TYPE] = "";
5929           av[CONTAINER_ID] = "";
5930           av[CONTAINER_ROWID] = "";
5931           rc = container_create(ldap_handle, dn_path, 7, av);
5932
5933           if (rc == LDAP_SUCCESS)
5934             {
5935               com_err(whoami, 0, "container %s created without a mitMoiraId", 
5936                       cName);
5937             }
5938
5939           cName[i] = '/';
5940         }
5941     }
5942 }
5943
5944 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
5945                      char **before, int afterc, char **after)
5946 {
5947   char      dName[256];
5948   char      cName[256];
5949   char      new_cn[128];
5950   char      new_dn_path[256];
5951   char      temp[256];
5952   char      distinguishedName[256];
5953   char      *pPtr;
5954   int       rc;
5955   int       i;
5956
5957   memset(cName, '\0', sizeof(cName));
5958   container_get_name(after[CONTAINER_NAME], cName);
5959
5960   if (!check_container_name(cName))
5961     {
5962       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
5963               cName);
5964       return(AD_INVALID_NAME);
5965     }
5966
5967   memset(distinguishedName, '\0', sizeof(distinguishedName));
5968
5969   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
5970                                            distinguishedName, beforec, before))
5971     return(rc);
5972
5973   if (strlen(distinguishedName) == 0)
5974     {
5975       rc = container_create(ldap_handle, dn_path, afterc, after);
5976       return(rc);
5977     }
5978
5979   strcpy(temp, after[CONTAINER_NAME]);
5980   pPtr = temp;
5981
5982   for (i = 0; i < (int)strlen(temp); i++)
5983     {
5984       if (temp[i] == '/')
5985         {
5986           pPtr = &temp[i];
5987         }
5988     }
5989
5990   (*pPtr) = '\0';
5991
5992   container_get_dn(temp, dName);
5993
5994   if (strlen(temp) != 0)
5995     sprintf(new_dn_path, "%s,%s", dName, dn_path);
5996   else
5997     sprintf(new_dn_path, "%s", dn_path);
5998
5999   sprintf(new_cn, "OU=%s", cName);
6000
6001   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6002
6003   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6004                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6005     {
6006       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6007               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6008               ldap_err2string(rc));
6009       return(rc);
6010     }
6011
6012   memset(dName, '\0', sizeof(dName));
6013   container_get_dn(after[CONTAINER_NAME], dName);
6014   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6015
6016   return(rc);
6017 }
6018
6019 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6020 {
6021   char      distinguishedName[256];
6022   int       rc;
6023
6024   memset(distinguishedName, '\0', sizeof(distinguishedName));
6025
6026   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6027                                            distinguishedName, count, av))
6028     return(rc);
6029
6030   if (strlen(distinguishedName) == 0)
6031     return(0);
6032
6033   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6034     {
6035       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6036         container_move_objects(ldap_handle, dn_path, distinguishedName);
6037       else
6038         com_err(whoami, 0, "Unable to delete container %s from AD : %s",
6039                 av[CONTAINER_NAME], ldap_err2string(rc));
6040     }
6041
6042   return(rc);
6043 }
6044
6045 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6046 {
6047   char      *attr_array[3];
6048   LK_ENTRY  *group_base;
6049   int       group_count;
6050   LDAPMod   *mods[20];
6051   char      *objectClass_v[] = {"top", 
6052                            "organizationalUnit", 
6053                            NULL};
6054
6055   char *ou_v[] = {NULL, NULL};
6056   char *name_v[] = {NULL, NULL};
6057   char *moiraId_v[] = {NULL, NULL};
6058   char *desc_v[] = {NULL, NULL};
6059   char *managedBy_v[] = {NULL, NULL};
6060   char dName[256];
6061   char cName[256];
6062   char managedByDN[256];
6063   char filter[256];
6064   char temp[256];
6065   int  n;
6066   int  i;
6067   int  rc;
6068
6069   memset(filter, '\0', sizeof(filter));
6070   memset(dName, '\0', sizeof(dName));
6071   memset(cName, '\0', sizeof(cName));
6072   memset(managedByDN, '\0', sizeof(managedByDN));
6073   container_get_dn(av[CONTAINER_NAME], dName);
6074   container_get_name(av[CONTAINER_NAME], cName);
6075
6076   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6077     {
6078       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6079               cName);
6080       return(AD_INVALID_NAME);
6081     }
6082
6083   if (!check_container_name(cName))
6084     {
6085       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6086               cName);
6087       return(AD_INVALID_NAME);
6088     }
6089
6090   n = 0;
6091   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6092   name_v[0] = cName;
6093   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6094   ou_v[0] = cName;
6095   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6096
6097   if (strlen(av[CONTAINER_ROWID]) != 0)
6098     {
6099       moiraId_v[0] = av[CONTAINER_ROWID];
6100       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6101     }
6102
6103   if (strlen(av[CONTAINER_DESC]) != 0)
6104     {
6105       desc_v[0] = av[CONTAINER_DESC];
6106       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6107     }
6108
6109   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6110     {
6111       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6112         {
6113           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6114                               kerberos_ou))
6115             {
6116               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6117                       kerberos_ou, dn_path);
6118               managedBy_v[0] = managedByDN;
6119               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6120             }
6121         }
6122       else
6123         {
6124           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6125             {
6126               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6127                       "(objectClass=user)))", av[CONTAINER_ID]);
6128             }
6129
6130           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6131             {
6132               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6133                       av[CONTAINER_ID]);
6134             }
6135
6136           if (strlen(filter) != 0)
6137             {
6138               attr_array[0] = "distinguishedName";
6139               attr_array[1] = NULL;
6140               group_count = 0;
6141               group_base = NULL;
6142               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6143                                        attr_array, 
6144                                        &group_base, &group_count, 
6145                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6146                 {
6147                   if (group_count == 1)
6148                     {
6149                       strcpy(managedByDN, group_base->value);
6150                       managedBy_v[0] = managedByDN;
6151                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6152                     }
6153                   linklist_free(group_base);
6154                   group_base = NULL;
6155                   group_count = 0;
6156                 }
6157             }
6158         }
6159     }
6160   
6161   mods[n] = NULL;
6162
6163   sprintf(temp, "%s,%s", dName, dn_path);
6164   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
6165   
6166   for (i = 0; i < n; i++)
6167     free(mods[i]);
6168   
6169   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
6170     {
6171       com_err(whoami, 0, "Unable to create container %s : %s",
6172               cName, ldap_err2string(rc));
6173       return(rc);
6174     }
6175
6176   if (rc == LDAP_ALREADY_EXISTS)
6177     {
6178       if (strlen(av[CONTAINER_ROWID]) != 0)
6179         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
6180     }
6181
6182   return(rc);
6183 }
6184
6185 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
6186                      char **before, int afterc, char **after)
6187 {
6188   char distinguishedName[256];
6189   int  rc;
6190
6191   memset(distinguishedName, '\0', sizeof(distinguishedName));
6192
6193   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6194                                            distinguishedName, afterc, after))
6195     return(rc);
6196
6197   if (strlen(distinguishedName) == 0)
6198     {
6199       rc = container_create(ldap_handle, dn_path, afterc, after);
6200       return(rc);
6201     }
6202   
6203   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6204   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
6205                           after);
6206
6207   return(rc);
6208 }
6209
6210 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
6211                                     char *distinguishedName, int count, 
6212                                     char **av)
6213 {
6214   char      *attr_array[3];
6215   LK_ENTRY  *group_base;
6216   int       group_count;
6217   char      dName[256];
6218   char      cName[256];
6219   char      filter[512];
6220   int       rc;
6221
6222   memset(filter, '\0', sizeof(filter));
6223   memset(dName, '\0', sizeof(dName));
6224   memset(cName, '\0', sizeof(cName));
6225   container_get_dn(av[CONTAINER_NAME], dName);
6226   container_get_name(av[CONTAINER_NAME], cName);
6227
6228   if (strlen(dName) == 0)
6229     {
6230       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6231               av[CONTAINER_NAME]);
6232       return(AD_INVALID_NAME);
6233     }
6234
6235   if (!check_container_name(cName))
6236     {
6237       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6238               cName);
6239       return(AD_INVALID_NAME);
6240     }
6241   
6242   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
6243           av[CONTAINER_ROWID]);
6244   attr_array[0] = "distinguishedName";
6245   attr_array[1] = NULL;
6246   group_count = 0;
6247   group_base = NULL;
6248
6249   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6250                            &group_base, &group_count, 
6251                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6252     {
6253       if (group_count == 1)
6254         {
6255           strcpy(distinguishedName, group_base->value);
6256         }
6257
6258       linklist_free(group_base);
6259       group_base = NULL;
6260       group_count = 0;
6261     }
6262
6263   if (strlen(distinguishedName) == 0)
6264     {
6265       sprintf(filter, "(&(objectClass=organizationalUnit)"
6266               "(distinguishedName=%s,%s))", dName, dn_path);
6267       attr_array[0] = "distinguishedName";
6268       attr_array[1] = NULL;
6269       group_count = 0;
6270       group_base = NULL;
6271
6272       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6273                                &group_base, &group_count, 
6274                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6275         {
6276           if (group_count == 1)
6277             {
6278               strcpy(distinguishedName, group_base->value);
6279             }
6280
6281           linklist_free(group_base);
6282           group_base = NULL;
6283           group_count = 0;
6284         }
6285     }
6286
6287   return(0);
6288 }
6289
6290 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
6291                        char *distinguishedName, int count, char **av)
6292 {
6293   char      *attr_array[5];
6294   LK_ENTRY  *group_base;
6295   LK_ENTRY  *pPtr;
6296   LDAPMod   *mods[20];
6297   int       group_count;
6298   char      filter[512];
6299   char      *moiraId_v[] = {NULL, NULL};
6300   char      *desc_v[] = {NULL, NULL};
6301   char      *managedBy_v[] = {NULL, NULL};
6302   char      managedByDN[256];
6303   char      moiraId[64];
6304   char      desc[256];
6305   char      ad_path[512];
6306   int       rc;
6307   int       i;
6308   int       n;
6309
6310
6311   strcpy(ad_path, distinguishedName);
6312
6313   if (strlen(dName) != 0)
6314     sprintf(ad_path, "%s,%s", dName, dn_path);
6315
6316   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
6317           ad_path);
6318
6319   if (strlen(av[CONTAINER_ID]) != 0)
6320     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
6321             av[CONTAINER_ROWID]);
6322
6323   attr_array[0] = "mitMoiraId";
6324   attr_array[1] = "description";
6325   attr_array[2] = "managedBy";
6326   attr_array[3] = NULL;
6327   group_count = 0;
6328   group_base = NULL;
6329
6330   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6331                            &group_base, &group_count, 
6332                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
6333     {
6334       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
6335               av[CONTAINER_NAME], ldap_err2string(rc));
6336       return(rc);
6337     }
6338
6339   memset(managedByDN, '\0', sizeof(managedByDN));
6340   memset(moiraId, '\0', sizeof(moiraId));
6341   memset(desc, '\0', sizeof(desc));
6342   pPtr = group_base;
6343
6344   while (pPtr)
6345     {
6346       if (!strcasecmp(pPtr->attribute, "description"))
6347         strcpy(desc, pPtr->value);
6348       else if (!strcasecmp(pPtr->attribute, "managedBy"))
6349         strcpy(managedByDN, pPtr->value);
6350       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
6351         strcpy(moiraId, pPtr->value);
6352       pPtr = pPtr->next;
6353     }
6354
6355   linklist_free(group_base);
6356   group_base = NULL;
6357   group_count = 0;
6358
6359   n = 0;
6360   if (strlen(av[CONTAINER_ROWID]) != 0)
6361     {
6362       moiraId_v[0] = av[CONTAINER_ROWID];
6363       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
6364     }
6365
6366   if (strlen(av[CONTAINER_DESC]) != 0)
6367     {
6368       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
6369                        dName);
6370     }
6371   else
6372     {
6373       if (strlen(desc) != 0)
6374         {
6375           attribute_update(ldap_handle, ad_path, "", "description", dName);
6376         }
6377     }
6378
6379   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6380     {
6381       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6382         {
6383           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6384                               kerberos_ou))
6385             {
6386               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6387                       kerberos_ou, dn_path);
6388               managedBy_v[0] = managedByDN;
6389               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
6390             }
6391           else
6392             {
6393               if (strlen(managedByDN) != 0)
6394                 {
6395                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
6396                                    dName);
6397                 }
6398             }
6399         }
6400       else
6401         {
6402           memset(filter, '\0', sizeof(filter));
6403
6404           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6405             {
6406               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6407                       "(objectClass=user)))", av[CONTAINER_ID]);
6408             }
6409
6410           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6411             {
6412               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6413                       av[CONTAINER_ID]);
6414             }
6415
6416           if (strlen(filter) != 0)
6417             {
6418               attr_array[0] = "distinguishedName";
6419               attr_array[1] = NULL;
6420               group_count = 0;
6421               group_base = NULL;
6422               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6423                                        attr_array, &group_base, &group_count, 
6424                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6425                 {
6426                   if (group_count == 1)
6427                     {
6428                       strcpy(managedByDN, group_base->value);
6429                       managedBy_v[0] = managedByDN;
6430                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
6431                     }
6432                   else
6433                     {
6434                       if (strlen(managedByDN) != 0)
6435                         {
6436                           attribute_update(ldap_handle, ad_path, "", 
6437                                            "managedBy", dName);
6438                         }
6439                     }
6440
6441                   linklist_free(group_base);
6442                   group_base = NULL;
6443                   group_count = 0;
6444                 }
6445             }
6446           else
6447             {
6448               if (strlen(managedByDN) != 0)
6449                 {
6450                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
6451                                    dName);
6452                 }
6453             }
6454         }
6455     }
6456
6457   mods[n] = NULL;
6458
6459   if (n == 0)
6460     return(LDAP_SUCCESS);
6461
6462   rc = ldap_modify_s(ldap_handle, ad_path, mods);
6463
6464   for (i = 0; i < n; i++)
6465     free(mods[i]);
6466
6467   if (rc != LDAP_SUCCESS)
6468     {
6469       com_err(whoami, 0, "Unable to modify container info for %s : %s",
6470               av[CONTAINER_NAME], ldap_err2string(rc));
6471       return(rc);
6472     }
6473   
6474   return(rc);
6475 }
6476
6477 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
6478 {
6479   char      *attr_array[3];
6480   LK_ENTRY  *group_base;
6481   LK_ENTRY  *pPtr;
6482   int       group_count;
6483   char      filter[512];
6484   char      new_cn[128];
6485   char      temp[256];
6486   int       rc;
6487   int       NumberOfEntries = 10;
6488   int       i;
6489   int       count;
6490
6491   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
6492
6493   for (i = 0; i < 3; i++)
6494     {
6495       memset(filter, '\0', sizeof(filter));
6496
6497       if (i == 0)
6498         {
6499           strcpy(filter, "(!(|(objectClass=computer)"
6500                  "(objectClass=organizationalUnit)))");
6501           attr_array[0] = "cn";
6502           attr_array[1] = NULL;
6503         }
6504       else if (i == 1)
6505         {
6506           strcpy(filter, "(objectClass=computer)");
6507           attr_array[0] = "cn";
6508           attr_array[1] = NULL;
6509         }
6510       else
6511         {
6512           strcpy(filter, "(objectClass=organizationalUnit)");
6513           attr_array[0] = "ou";
6514           attr_array[1] = NULL;
6515         }
6516
6517       while (1)
6518         {
6519           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
6520                                    &group_base, &group_count, 
6521                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
6522             {
6523               break;
6524             }
6525
6526           if (group_count == 0)
6527             break;
6528
6529           pPtr = group_base;
6530
6531           while(pPtr)
6532             {
6533               if (!strcasecmp(pPtr->attribute, "cn"))
6534                 {
6535                   sprintf(new_cn, "cn=%s", pPtr->value);
6536                   if (i == 0)
6537                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
6538                   if (i == 1)
6539                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
6540                   count = 1;
6541
6542                   while (1)
6543                     {
6544                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
6545                                          TRUE, NULL, NULL);
6546                       if (rc == LDAP_ALREADY_EXISTS)
6547                         {
6548                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
6549                           ++count;
6550                         }
6551                       else
6552                         break;
6553                     }
6554                 }
6555               else if (!strcasecmp(pPtr->attribute, "ou"))
6556                 {
6557                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
6558                 }
6559
6560               pPtr = pPtr->next;
6561             }
6562
6563           linklist_free(group_base);
6564           group_base = NULL;
6565           group_count = 0;
6566         }
6567     }
6568
6569   return(0);
6570 }
6571
6572 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
6573                    char *machine_ou, char *NewMachineName)
6574 {
6575   LK_ENTRY  *group_base;
6576   int  group_count;
6577   int  i;
6578   char filter[128];
6579   char *attr_array[3];
6580   char cn[256];
6581   char dn[256];
6582   char temp[256];
6583   char *pPtr;
6584   int   rc;
6585
6586   strcpy(NewMachineName, member);
6587   rc = moira_connect();
6588   rc = GetMachineName(NewMachineName);
6589   moira_disconnect();
6590
6591   if (strlen(NewMachineName) == 0)
6592     {
6593       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
6594               member);
6595       return(1);
6596     }
6597
6598   pPtr = NULL;
6599   pPtr = strchr(NewMachineName, '.');
6600
6601   if (pPtr != NULL)
6602     (*pPtr) = '\0';
6603
6604   group_base = NULL;
6605   group_count = 0;
6606   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
6607   attr_array[0] = "cn";
6608   attr_array[1] = NULL;
6609   sprintf(temp, "%s", dn_path);
6610
6611   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
6612                            &group_base, &group_count, 
6613                            LDAP_SCOPE_SUBTREE)) != 0)
6614     {
6615       com_err(whoami, 0, "Unable to process machine %s : %s",
6616               member, ldap_err2string(rc));
6617       return(1);
6618     }
6619
6620   if (group_count != 1)
6621     {
6622       com_err(whoami, 0, 
6623               "Unable to process machine %s : machine not found in AD",
6624               NewMachineName);
6625       return(1);
6626     }
6627
6628   strcpy(dn, group_base->dn);
6629   strcpy(cn, group_base->value);
6630
6631   for (i = 0; i < (int)strlen(dn); i++)
6632     dn[i] = tolower(dn[i]);
6633
6634   for (i = 0; i < (int)strlen(cn); i++)
6635     cn[i] = tolower(cn[i]);
6636
6637   linklist_free(group_base);
6638   pPtr = NULL;
6639   pPtr = strstr(dn, cn);
6640
6641   if (pPtr == NULL)
6642     {
6643       com_err(whoami, 0, "Unable to process machine %s",
6644               member);
6645       return(1);
6646     }
6647
6648   pPtr += strlen(cn) + 1;
6649   strcpy(machine_ou, pPtr);
6650   pPtr = NULL;
6651   pPtr = strstr(machine_ou, "dc=");
6652
6653   if (pPtr == NULL)
6654     {
6655       com_err(whoami, 0, "Unable to process machine %s",
6656               member);
6657       return(1);
6658     }
6659
6660   --pPtr;
6661   (*pPtr) = '\0';
6662
6663   return(0);
6664 }
6665
6666 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
6667                        char *MoiraMachineName, char *DestinationOu)
6668 {
6669   char        NewCn[128];
6670   char        OldDn[512];
6671   char        MachineName[128];
6672   char        filter[128];
6673   char        *attr_array[3];
6674   char        NewOu[256];
6675   char        *cPtr = NULL;
6676   int         group_count;
6677   long        rc;
6678   LK_ENTRY    *group_base;
6679
6680   group_count = 0;
6681   group_base = NULL;
6682   
6683   strcpy(MachineName, MoiraMachineName);
6684   rc = GetMachineName(MachineName);
6685
6686   if (strlen(MachineName) == 0)
6687     {
6688       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
6689               MoiraMachineName);
6690       return(1);
6691     }
6692   
6693   cPtr = strchr(MachineName, '.');
6694
6695   if (cPtr != NULL)
6696     (*cPtr) = '\0';
6697
6698   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
6699   attr_array[0] = "sAMAccountName";
6700   attr_array[1] = NULL;
6701
6702   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6703                            &group_base, 
6704                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
6705     {
6706       com_err(whoami, 0, "Unable to process machine %s : %s",
6707               MoiraMachineName, ldap_err2string(rc));
6708       return(1);
6709     }
6710   
6711   if (group_count == 1)
6712     strcpy(OldDn, group_base->dn);
6713
6714   linklist_free(group_base);
6715   group_base = NULL;
6716
6717   if (group_count != 1)
6718     {
6719       com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
6720               MoiraMachineName);
6721       return(1);
6722     }
6723
6724   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
6725   cPtr = strchr(OldDn, ',');
6726
6727   if (cPtr != NULL)
6728     {
6729       ++cPtr;
6730       if (!strcasecmp(cPtr, NewOu))
6731         return(0);
6732     }
6733
6734   sprintf(NewCn, "CN=%s", MachineName);
6735   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
6736
6737   return(rc);
6738 }
6739
6740 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
6741 {
6742   char    Name[128];
6743   char    *pPtr;
6744   int     rc;
6745   
6746   memset(Name, '\0', sizeof(Name));
6747   strcpy(Name, machine_name);
6748   pPtr = NULL;
6749   pPtr = strchr(Name, '.');
6750
6751   if (pPtr != NULL)
6752     (*pPtr) = '\0';
6753
6754   strcat(Name, "$");
6755   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
6756 }
6757
6758 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
6759                                 char *machine_name, char *container_name)
6760 {
6761   int     rc;
6762   char    *av[2];
6763   char    *call_args[2];
6764   
6765   av[0] = machine_name;
6766   call_args[0] = (char *)container_name;
6767   rc = mr_query("get_machine_to_container_map", 1, av, 
6768                 machine_GetMoiraContainer, call_args);
6769   return(rc);
6770 }
6771
6772 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
6773 {
6774   char **call_args;
6775   
6776   call_args = ptr;
6777   strcpy(call_args[0], av[1]);
6778   return(0);
6779 }
6780
6781 int Moira_container_group_create(char **after)
6782 {
6783   long rc;
6784   char GroupName[64];
6785   char *argv[20];
6786   
6787   memset(GroupName, '\0', sizeof(GroupName));
6788   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
6789                               after[CONTAINER_ROWID]);
6790   if (rc)
6791     return rc;
6792   
6793   argv[L_NAME] = GroupName;
6794   argv[L_ACTIVE] = "1";
6795   argv[L_PUBLIC] = "0";
6796   argv[L_HIDDEN] = "0";
6797   argv[L_MAILLIST] = "0";
6798   argv[L_GROUP] = "1";
6799   argv[L_GID] = UNIQUE_GID;
6800   argv[L_NFSGROUP] = "0";
6801   argv[L_MAILMAN] = "0";
6802   argv[L_MAILMAN_SERVER] = "[NONE]";
6803   argv[L_DESC] = "auto created container group";
6804   argv[L_ACE_TYPE] = "USER";
6805   argv[L_MEMACE_TYPE] = "USER";
6806   argv[L_ACE_NAME] = "sms";
6807   argv[L_MEMACE_NAME] = "sms";
6808
6809   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
6810     {
6811       com_err(whoami, 0, 
6812               "Unable to create container group %s for container %s: %s",
6813               GroupName, after[CONTAINER_NAME], error_message(rc));
6814     }
6815
6816   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
6817   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
6818   
6819   return(rc);
6820 }
6821
6822 int Moira_container_group_update(char **before, char **after)
6823 {
6824   long rc;
6825   char BeforeGroupName[64];
6826   char AfterGroupName[64];
6827   char *argv[20];
6828   
6829   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
6830     return(0);
6831
6832   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
6833   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
6834   if (strlen(BeforeGroupName) == 0)
6835     return(0);
6836
6837   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
6838   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
6839                               after[CONTAINER_ROWID]);
6840   if (rc)
6841     return rc;
6842
6843   if (strcasecmp(BeforeGroupName, AfterGroupName))
6844     {
6845       argv[L_NAME] = BeforeGroupName;
6846       argv[L_NAME + 1] = AfterGroupName;
6847       argv[L_ACTIVE + 1] = "1";
6848       argv[L_PUBLIC + 1] = "0";
6849       argv[L_HIDDEN + 1] = "0";
6850       argv[L_MAILLIST + 1] = "0";
6851       argv[L_GROUP + 1] = "1";
6852       argv[L_GID + 1] = UNIQUE_GID;
6853       argv[L_NFSGROUP + 1] = "0";
6854       argv[L_MAILMAN + 1] = "0";
6855       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
6856       argv[L_DESC + 1] = "auto created container group";
6857       argv[L_ACE_TYPE + 1] = "USER";
6858       argv[L_MEMACE_TYPE + 1] = "USER";
6859       argv[L_ACE_NAME + 1] = "sms";
6860       argv[L_MEMACE_NAME + 1] = "sms";
6861       
6862       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
6863         {
6864           com_err(whoami, 0, 
6865                   "Unable to rename container group from %s to %s: %s",
6866                   BeforeGroupName, AfterGroupName, error_message(rc));
6867         }
6868     }
6869   
6870   return(rc);
6871 }
6872
6873 int Moira_container_group_delete(char **before)
6874 {
6875   long rc = 0;
6876   char *argv[13];
6877   char GroupName[64];
6878   char ParentGroupName[64];
6879   
6880   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
6881   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
6882
6883   memset(GroupName, '\0', sizeof(GroupName));
6884
6885   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
6886     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
6887   
6888   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
6889     {
6890       argv[0] = ParentGroupName;
6891       argv[1] = "LIST";
6892       argv[2] = GroupName;
6893
6894       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
6895         {
6896           com_err(whoami, 0, 
6897                   "Unable to delete container group %s from list: %s",
6898                   GroupName, ParentGroupName, error_message(rc));
6899         }
6900     }
6901   
6902   if (strlen(GroupName) != 0)
6903     {
6904       argv[0] = GroupName;
6905
6906       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
6907         {
6908           com_err(whoami, 0, "Unable to delete container group %s : %s",
6909                   GroupName, error_message(rc));
6910         }
6911     }
6912   
6913   return(rc);
6914 }
6915
6916 int Moira_groupname_create(char *GroupName, char *ContainerName,
6917                            char *ContainerRowID)
6918 {
6919   char *ptr;
6920   char *ptr1;
6921   char temp[64];
6922   char newGroupName[64];
6923   char tempGroupName[64];
6924   char tempgname[64];
6925   char *argv[1];
6926   int  i;
6927   long rc;
6928
6929   strcpy(temp, ContainerName);
6930   
6931   ptr1 = strrchr(temp, '/');
6932
6933   if (ptr1 != NULL)
6934   {
6935     *ptr1 = '\0';
6936     ptr = ++ptr1;
6937     ptr1 = strrchr(temp, '/');
6938
6939     if (ptr1 != NULL)
6940     {
6941         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
6942     }
6943     else
6944         strcpy(tempgname, ptr);
6945   }
6946   else
6947     strcpy(tempgname, temp);
6948
6949   if (strlen(tempgname) > 25)
6950     tempgname[25] ='\0';
6951
6952   sprintf(newGroupName, "cnt-%s", tempgname);
6953
6954   /* change everything to lower case */
6955   ptr = newGroupName;
6956
6957   while (*ptr)
6958     {
6959       if (isupper(*ptr))
6960         *ptr = tolower(*ptr);
6961
6962       if (*ptr == ' ')
6963         *ptr = '-';
6964
6965       ptr++;
6966     }
6967
6968   strcpy(tempGroupName, newGroupName);
6969   i = (int)'0';
6970
6971   /* append 0-9 then a-z if a duplicate is found */
6972   while(1)
6973     {
6974       argv[0] = newGroupName;
6975
6976       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
6977         {
6978           if (rc == MR_NO_MATCH)
6979             break;
6980           com_err(whoami, 0, "Moira error while creating group name for "
6981                   "container %s : %s", ContainerName, error_message(rc));
6982           return rc;
6983         }
6984
6985       sprintf(newGroupName, "%s-%c", tempGroupName, i);
6986
6987       if (i == (int)'z')
6988         {
6989           com_err(whoami, 0, "Unable to find a unique group name for "
6990                   "container %s: too many duplicate container names",
6991                   ContainerName);
6992           return 1;
6993         }
6994
6995       if (i == '9')
6996         i = 'a';
6997       else
6998         i++;
6999     }
7000
7001   strcpy(GroupName, newGroupName);
7002   return(0);
7003 }
7004
7005 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7006 {
7007   long rc;
7008   char *argv[3];
7009   
7010   argv[0] = origContainerName;
7011   argv[1] = GroupName;
7012   
7013   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7014     {
7015       com_err(whoami, 0, 
7016               "Unable to set container group %s in container %s: %s",
7017               GroupName, origContainerName, error_message(rc));
7018     }
7019   
7020   return(0);
7021 }
7022
7023 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7024  {
7025    char ContainerName[64];
7026    char ParentGroupName[64];
7027    char *argv[3];
7028    long rc;
7029
7030    strcpy(ContainerName, origContainerName);
7031    
7032    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7033
7034    /* top-level container */
7035    if (strlen(ParentGroupName) == 0)
7036      return(0);
7037    
7038    argv[0] = ParentGroupName;
7039    argv[1] = "LIST";
7040    argv[2] = GroupName;
7041
7042    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7043      {
7044        com_err(whoami, 0, 
7045                "Unable to add container group %s to parent group %s: %s",
7046                GroupName, ParentGroupName, error_message(rc));
7047      }
7048    
7049    return(0);
7050  }
7051
7052 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7053 {
7054   char **call_args;
7055   
7056   call_args = ptr;
7057   strcpy(call_args[0], av[1]);
7058
7059   return(0);
7060 }
7061
7062 int Moira_getGroupName(char *origContainerName, char *GroupName,
7063                        int ParentFlag)
7064 {
7065   char ContainerName[64];
7066   char *argv[3];
7067   char *call_args[3];
7068   char *ptr;
7069   long rc;
7070
7071   strcpy(ContainerName, origContainerName);
7072
7073   if (ParentFlag)
7074     {
7075       ptr = strrchr(ContainerName, '/');
7076
7077       if (ptr != NULL)
7078         (*ptr) = '\0';
7079       else
7080         return(0);
7081     }
7082
7083   argv[0] = ContainerName;
7084   argv[1] = NULL;
7085   call_args[0] = GroupName;
7086   call_args[1] = NULL;
7087
7088   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7089                       call_args)))
7090     {
7091       if (strlen(GroupName) != 0)
7092         return(0);
7093     }
7094
7095   if (rc)
7096     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7097             ContainerName, error_message(rc));
7098   else
7099     com_err(whoami, 0, "Unable to get container group from container %s",
7100             ContainerName);
7101   
7102   return(0);
7103 }
7104
7105 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7106                                           int DeleteMachine)
7107 {
7108   char *argv[3];
7109   long rc;
7110   
7111   if (strcmp(GroupName, "[none]") == 0)
7112     return 0;
7113
7114   argv[0] = GroupName;
7115   argv[1] = "MACHINE";
7116   argv[2] = MachineName;
7117
7118   if (!DeleteMachine)
7119     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7120   else
7121     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7122
7123   if (rc)
7124     {
7125       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7126               MachineName, GroupName, error_message(rc));
7127     }
7128
7129   return(0);
7130 }
7131
7132 int GetMachineName(char *MachineName)
7133 {
7134   char    *args[2];
7135   char    NewMachineName[1024];
7136   char    *szDot;
7137   int     rc = 0;
7138   int     i;
7139   DWORD   dwLen = 0;
7140   char    *call_args[2];
7141   
7142   // If the address happens to be in the top-level MIT domain, great!
7143   strcpy(NewMachineName, MachineName);
7144
7145   for (i = 0; i < (int)strlen(NewMachineName); i++)
7146     NewMachineName[i] = toupper(NewMachineName[i]);
7147
7148   szDot = strchr(NewMachineName,'.');
7149
7150   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7151     {
7152       return(0);
7153     }
7154   
7155   // If not, see if it has a Moira alias in the top-level MIT domain.
7156   memset(NewMachineName, '\0', sizeof(NewMachineName));
7157   args[0] = "*";
7158   args[1] = MachineName;
7159   call_args[0] = NewMachineName;
7160   call_args[1] = NULL;
7161
7162   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7163     {
7164       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7165               MachineName, error_message(rc));
7166       strcpy(MachineName, "");
7167       return(0);
7168     }
7169   
7170   if (strlen(NewMachineName) != 0)
7171     strcpy(MachineName, NewMachineName);
7172   else
7173     strcpy(MachineName, "");
7174
7175   return(0);
7176 }
7177
7178 int ProcessMachineName(int ac, char **av, void *ptr)
7179 {
7180   char    **call_args;
7181   char    MachineName[1024];
7182   char    *szDot;
7183   int     i;
7184   
7185   call_args = ptr;
7186
7187   if (strlen(call_args[0]) == 0)
7188     {
7189       strcpy(MachineName, av[0]);
7190
7191       for (i = 0; i < (int)strlen(MachineName); i++)
7192         MachineName[i] = toupper(MachineName[i]);
7193
7194       szDot = strchr(MachineName,'.');
7195
7196         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
7197           {
7198             strcpy(call_args[0], MachineName);
7199           }
7200     }
7201
7202   return(0);
7203 }
7204
7205 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
7206 {
7207   int i;
7208   
7209   if (*UseSFU30)
7210     {
7211       for (i = 0; i < n; i++)
7212         {
7213           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
7214             mods[i]->mod_type = "uidNumber";
7215         }
7216
7217       (*UseSFU30) = 0;
7218     }
7219   else
7220     {
7221       for (i = 0; i < n; i++)
7222         {
7223           if (!strcmp(mods[i]->mod_type, "uidNumber"))
7224             mods[i]->mod_type = "msSFU30UidNumber";
7225         }
7226
7227       (*UseSFU30) = 1;
7228     }
7229 }
7230
7231 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
7232                      char *DistinguishedName,
7233                      char *WinHomeDir, char *WinProfileDir,
7234                      char **homedir_v, char **winProfile_v,
7235                      char **drives_v, LDAPMod **mods, 
7236                      int OpType, int n)
7237 {
7238   char **hp;
7239   char cWeight[3];
7240   char cPath[1024];
7241   char path[1024];
7242   char winPath[1024];
7243   char winProfile[1024];
7244   char homeDrive[8];
7245   int  last_weight;
7246   int  i;
7247   int  rc;
7248   LDAPMod *DelMods[20];
7249   
7250   memset(homeDrive, '\0', sizeof(homeDrive));
7251   memset(path, '\0', sizeof(path));
7252   memset(winPath, '\0', sizeof(winPath));
7253   memset(winProfile, '\0', sizeof(winProfile));
7254   hp = NULL;
7255
7256   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
7257       (!strcasecmp(WinProfileDir, "[afs]")))
7258     {
7259       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
7260         {
7261           memset(cWeight, 0, sizeof(cWeight));
7262           memset(cPath, 0, sizeof(cPath));
7263           last_weight = 1000;
7264           i = 0;
7265
7266           while (hp[i] != NULL)
7267             {
7268               if (sscanf(hp[i], "%*s %s", cPath))
7269                 {
7270                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
7271                     {
7272                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
7273                         {
7274                           if (atoi(cWeight) < last_weight)
7275                             {
7276                               strcpy(path, cPath);
7277                               last_weight = (int)atoi(cWeight);
7278                             }
7279                         }
7280                       else 
7281                         strcpy(path, cPath);
7282                     }
7283                 }
7284               ++i;
7285             }
7286
7287           if (strlen(path))
7288             {
7289               if (!strnicmp(path, AFS, strlen(AFS)))
7290                 {
7291                   AfsToWinAfs(path, winPath);
7292                   strcpy(winProfile, winPath);
7293                   strcat(winProfile, "\\.winprofile");
7294                 }
7295             }
7296         }
7297       else
7298         return(n);
7299     }
7300
7301     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
7302         (!strcasecmp(WinProfileDir, "[dfs]")))
7303     {
7304       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
7305               user_name[0], user_name);
7306
7307       if (!strcasecmp(WinProfileDir, "[dfs]"))
7308         {
7309           strcpy(winProfile, path);
7310           strcat(winProfile, "\\.winprofile");
7311         }
7312
7313       if (!strcasecmp(WinHomeDir, "[dfs]"))
7314         strcpy(winPath, path);
7315     }
7316     
7317     if (hp != NULL)
7318       {
7319         i = 0;
7320         while (hp[i])
7321           {
7322             free(hp[i]);
7323             i++;
7324           }
7325       }
7326     
7327     if (!strcasecmp(WinHomeDir, "[local]"))
7328       memset(winPath, '\0', sizeof(winPath));
7329     else if (!strcasecmp(WinHomeDir, "[afs]") || 
7330              !strcasecmp(WinHomeDir, "[dfs]"))
7331       {
7332         strcpy(homeDrive, "H:");
7333       }
7334     else
7335       {
7336         strcpy(winPath, WinHomeDir);
7337         if (!strncmp(WinHomeDir, "\\\\", 2))
7338           {
7339             strcpy(homeDrive, "H:");
7340           }        
7341       }
7342     
7343     // nothing needs to be done if WinProfileDir is [afs].
7344     if (!strcasecmp(WinProfileDir, "[local]"))
7345       memset(winProfile, '\0', sizeof(winProfile));
7346     else if (strcasecmp(WinProfileDir, "[afs]") && 
7347              strcasecmp(WinProfileDir, "[dfs]"))
7348       {
7349         strcpy(winProfile, WinProfileDir);
7350       }
7351     
7352     if (strlen(winProfile) != 0)
7353       {
7354         if (winProfile[strlen(winProfile) - 1] == '\\')
7355           winProfile[strlen(winProfile) - 1] = '\0';
7356       }
7357
7358     if (strlen(winPath) != 0)
7359       {
7360         if (winPath[strlen(winPath) - 1] == '\\')
7361           winPath[strlen(winPath) - 1] = '\0';
7362       }
7363     
7364     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
7365       strcat(winProfile, "\\");
7366
7367     if ((winPath[1] == ':') && (strlen(winPath) == 2))
7368       strcat(winPath, "\\");
7369     
7370     if (strlen(winPath) == 0)
7371       {
7372         if (OpType == LDAP_MOD_REPLACE)
7373           {
7374             i = 0;
7375             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
7376             DelMods[i] = NULL;
7377             //unset homeDirectory attribute for user.
7378             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7379             free(DelMods[0]);
7380           }
7381       }
7382     else
7383       {
7384         homedir_v[0] = strdup(winPath);
7385         ADD_ATTR("homeDirectory", homedir_v, OpType);
7386       }
7387     
7388     if (strlen(winProfile) == 0)
7389       {
7390         if (OpType == LDAP_MOD_REPLACE)
7391           {
7392             i = 0;
7393             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
7394             DelMods[i] = NULL;
7395             //unset profilePate attribute for user.
7396             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7397             free(DelMods[0]);
7398           }
7399       }
7400     else
7401       {
7402         winProfile_v[0] = strdup(winProfile);
7403         ADD_ATTR("profilePath", winProfile_v, OpType);
7404       }
7405     
7406     if (strlen(homeDrive) == 0)
7407       {
7408         if (OpType == LDAP_MOD_REPLACE)
7409           {
7410             i = 0;
7411             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
7412             DelMods[i] = NULL;
7413             //unset homeDrive attribute for user
7414             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
7415             free(DelMods[0]);
7416           }
7417       }
7418     else
7419       {
7420         drives_v[0] = strdup(homeDrive);
7421         ADD_ATTR("homeDrive", drives_v, OpType);
7422       }
7423
7424     return(n);
7425 }
7426
7427 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
7428                      char *attribute_value, char *attribute, char *user_name)
7429 {
7430   char      *mod_v[] = {NULL, NULL};
7431   LDAPMod   *DelMods[20];
7432   LDAPMod   *mods[20];
7433   int       n;
7434   int       i;
7435   int       rc;
7436   
7437   if (strlen(attribute_value) == 0)
7438     {
7439       i = 0;
7440       DEL_ATTR(attribute, LDAP_MOD_DELETE);
7441       DelMods[i] = NULL;
7442       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
7443       free(DelMods[0]);
7444     }
7445   else
7446     {
7447       n = 0;
7448       mod_v[0] = attribute_value;
7449       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
7450       mods[n] = NULL;
7451
7452       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
7453                               mods)) != LDAP_SUCCESS)
7454         {
7455           free(mods[0]);
7456           n = 0;
7457           mod_v[0] = attribute_value;
7458           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
7459           mods[n] = NULL;
7460
7461           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
7462                                   mods)) != LDAP_SUCCESS)
7463             {
7464               com_err(whoami, 0, "Unable to change the %s attribute for %s "
7465                       "in the AD : %s",
7466                       attribute, user_name, ldap_err2string(rc));
7467             }
7468         }
7469
7470       free(mods[0]);
7471     }
7472   
7473   return(rc);
7474 }
7475
7476 void StringTrim(char *StringToTrim)
7477 {
7478   char *t, *s;
7479   char *save;
7480
7481   save = strdup(StringToTrim);
7482
7483   s = save;
7484
7485   while (isspace(*s))
7486     s++;
7487
7488   /* skip to end of string */
7489   if (*s == '\0')
7490     {
7491       if (*save)
7492         *save = '\0';
7493       strcpy(StringToTrim, save);
7494       return;
7495     }
7496   
7497   for (t = s; *t; t++)
7498     continue;
7499
7500   while (t > s)
7501     {
7502       --t;
7503       if (!isspace(*t))
7504         {
7505           t++;
7506           break;
7507         }
7508     }
7509
7510   if (*t)
7511     *t = '\0';
7512   
7513   strcpy(StringToTrim, s);
7514   return;
7515 }
7516
7517 int ReadConfigFile(char *DomainName)
7518 {
7519     int     Count;
7520     int     i;
7521     int     k;
7522     char    temp[256];
7523     char    temp1[256];
7524     FILE    *fptr;
7525
7526     Count = 0;
7527
7528     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
7529
7530     if ((fptr = fopen(temp, "r")) != NULL)
7531       {
7532         while (fgets(temp, sizeof(temp), fptr) != 0)
7533           {
7534             for (i = 0; i < (int)strlen(temp); i++)
7535               temp[i] = toupper(temp[i]);
7536
7537             if (temp[strlen(temp) - 1] == '\n')
7538               temp[strlen(temp) - 1] = '\0';
7539
7540             StringTrim(temp);
7541
7542             if (strlen(temp) == 0)
7543               continue;
7544
7545             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
7546               {
7547                 if (strlen(temp) > (strlen(DOMAIN)))
7548                   {
7549                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
7550                     StringTrim(ldap_domain);
7551                   }
7552               }
7553             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
7554               {
7555                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
7556                   {
7557                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
7558                     StringTrim(PrincipalName);
7559                   }
7560               }
7561             else if (!strncmp(temp, SERVER, strlen(SERVER)))
7562               {
7563                 if (strlen(temp) > (strlen(SERVER)))
7564                   {
7565                     ServerList[Count] = calloc(1, 256);
7566                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
7567                     StringTrim(ServerList[Count]);
7568                     ++Count;
7569                   }
7570               }
7571             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
7572               {
7573                 if (strlen(temp) > (strlen(MSSFU)))
7574                   {
7575                     strcpy(temp1, &temp[strlen(MSSFU)]);
7576                     StringTrim(temp1);
7577                     if (!strcmp(temp1, SFUTYPE))
7578                       UseSFU30 = 1;
7579                   }
7580               }
7581             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
7582               {
7583                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
7584                   {
7585                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
7586                     StringTrim(temp1);
7587                     if (!strcasecmp(temp1, "NO")) 
7588                       {
7589                         UseGroupSuffix = 0;
7590                         memset(group_suffix, '\0', sizeof(group_suffix));
7591                       }
7592                   }
7593               }
7594             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
7595               {
7596                 if (strlen(temp) > (strlen(GROUP_TYPE)))
7597                   {
7598                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
7599                     StringTrim(temp1);
7600                     if (!strcasecmp(temp1, "UNIVERSAL")) 
7601                       UseGroupUniversal = 1;
7602                   }
7603               }
7604             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
7605               {
7606                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
7607                   {
7608                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
7609                     StringTrim(temp1);
7610                     if (!strcasecmp(temp1, "NO"))
7611                       SetGroupAce = 0;
7612                   }
7613               }
7614             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
7615               {
7616                 if (strlen(temp) > (strlen(SET_PASSWORD)))
7617                   {
7618                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
7619                     StringTrim(temp1);
7620                     if (!strcasecmp(temp1, "NO"))
7621                       SetPassword = 0;
7622                   }
7623               }
7624             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
7625               {
7626                 if (strlen(temp) > (strlen(EXCHANGE)))
7627                   {
7628                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
7629                     StringTrim(temp1);
7630                     if (!strcasecmp(temp1, "YES"))
7631                       Exchange = 1;
7632                   }
7633               }
7634             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
7635                               strlen(PROCESS_MACHINE_CONTAINER)))
7636               {
7637                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
7638                   {
7639                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
7640                     StringTrim(temp1);
7641                     if (!strcasecmp(temp1, "NO"))
7642                       ProcessMachineContainer = 0;
7643                   }
7644               }
7645             else
7646               {
7647                 if (strlen(ldap_domain) != 0)
7648                   {
7649                     memset(ldap_domain, '\0', sizeof(ldap_domain));
7650                     break;
7651                   }
7652
7653                 if (strlen(temp) != 0)
7654                   strcpy(ldap_domain, temp);
7655               }
7656           }
7657         fclose(fptr);
7658       }
7659     
7660     if (strlen(ldap_domain) == 0)
7661       {
7662       strcpy(ldap_domain, DomainName);
7663       }
7664
7665     if (Count == 0)
7666         return(0);
7667
7668     for (i = 0; i < Count; i++)
7669       {
7670         if (ServerList[i] != 0)
7671           {
7672             strcat(ServerList[i], ".");
7673             strcat(ServerList[i], ldap_domain);
7674             for (k = 0; k < (int)strlen(ServerList[i]); k++)
7675               ServerList[i][k] = toupper(ServerList[i][k]);
7676           }
7677       }
7678     
7679     return(0);
7680 }
7681
7682 int ReadDomainList()
7683 {
7684   int     Count;
7685   int     i;
7686   char    temp[128];
7687   char    temp1[128];
7688   FILE    *fptr;
7689   unsigned char c[11];
7690   unsigned char stuff[256];
7691   int     rc;
7692   int     ok;
7693
7694   Count = 0;
7695   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
7696
7697   if ((fptr = fopen(temp, "r")) != NULL)
7698     {
7699       while (fgets(temp, sizeof(temp), fptr) != 0)
7700         {
7701           for (i = 0; i < (int)strlen(temp); i++)
7702             temp[i] = toupper(temp[i]);
7703
7704           if (temp[strlen(temp) - 1] == '\n')
7705             temp[strlen(temp) - 1] = '\0';
7706
7707           StringTrim(temp);
7708
7709           if (strlen(temp) == 0)
7710             continue;
7711
7712           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
7713             {
7714               if (strlen(temp) > (strlen(DOMAIN)))
7715                 {
7716                   strcpy(temp1, &temp[strlen(DOMAIN)]);
7717                   StringTrim(temp1);
7718                   strcpy(temp, temp1);
7719                 }
7720             }
7721           
7722           strcpy(DomainNames[Count], temp);
7723           StringTrim(DomainNames[Count]);
7724           ++Count;
7725         }
7726
7727       fclose(fptr);
7728     }
7729
7730   if (Count == 0)
7731     {
7732       critical_alert("incremental", "%s", "winad.incr cannot run due to a "
7733                      "configuration error in winad.cfg");
7734       return(1);
7735     }
7736   
7737   return(0);
7738 }
7739
7740 int email_isvalid(const char *address) {
7741   int        count = 0;
7742   const char *c, *domain;
7743   static char *rfc822_specials = "()<>@,;:\\\"[]";
7744
7745   if(address[strlen(address) - 1] == '.') 
7746     return 0;
7747     
7748   /* first we validate the name portion (name@domain) */
7749   for (c = address;  *c;  c++) {
7750     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
7751                        '\"')) {
7752       while (*++c) {
7753         if (*c == '\"') 
7754           break;
7755         if (*c == '\\' && (*++c == ' ')) 
7756           continue;
7757         if (*c <= ' ' || *c >= 127) 
7758           return 0;
7759       }
7760
7761       if (!*c++) 
7762         return 0;
7763       if (*c == '@') 
7764         break;
7765       if (*c != '.') 
7766         return 0;
7767       continue;
7768     }
7769
7770     if (*c == '@') 
7771       break;
7772     if (*c <= ' ' || *c >= 127) 
7773       return 0;
7774     if (strchr(rfc822_specials, *c)) 
7775       return 0;
7776   }
7777
7778   if (c == address || *(c - 1) == '.') 
7779     return 0;
7780
7781   /* next we validate the domain portion (name@domain) */
7782   if (!*(domain = ++c)) return 0;
7783   do {
7784     if (*c == '.') {
7785       if (c == domain || *(c - 1) == '.') 
7786         return 0;
7787       count++;
7788     }
7789     if (*c <= ' ' || *c >= 127) 
7790       return 0;
7791     if (strchr(rfc822_specials, *c)) 
7792       return 0;
7793   } while (*++c);
7794
7795   return (count >= 1);
7796 }
7797
7798 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
7799              char **homeServerName) 
7800 {
7801   LK_ENTRY *group_base;
7802   LK_ENTRY *sub_group_base;
7803   LK_ENTRY *gPtr;
7804   LK_ENTRY *sub_gPtr;
7805   int      group_count;
7806   int      sub_group_count;
7807   char     filter[1024];
7808   char     sub_filter[1024];
7809   char     search_path[1024];
7810   char     range[1024];
7811   char     *attr_array[3];
7812   char     *s;
7813   int      homeMDB_count = -1;
7814   int      rc;
7815   int      i;
7816   int      mdbbl_count;
7817   int      rangeStep = 1500;
7818   int      rangeLow = 0;
7819   int      rangeHigh = rangeLow + (rangeStep - 1);
7820   int      isLast = 0;
7821
7822   /* Grumble..... microsoft not making it searchable from the root *grr* */
7823
7824   memset(filter, '\0', sizeof(filter));
7825   memset(search_path, '\0', sizeof(search_path));
7826   
7827   sprintf(filter, "(objectClass=msExchMDB)");
7828   sprintf(search_path, "CN=Configuration,%s", dn_path);
7829   attr_array[0] = "distinguishedName";
7830   attr_array[1] = NULL;
7831   
7832   group_base = NULL;
7833   group_count = 0;
7834   
7835   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
7836                            &group_base, &group_count, 
7837                            LDAP_SCOPE_SUBTREE)) != 0) 
7838     {
7839       com_err(whoami, 0, "Unable to find msExchMDB %s",
7840               ldap_err2string(rc));
7841       return(rc);
7842     }
7843   
7844   if (group_count) 
7845     {
7846       gPtr = group_base;
7847       
7848       while(gPtr) {
7849         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
7850             ((s = strstr(gPtr->dn, "Recovery")) != (char *) NULL))
7851           {
7852             gPtr = gPtr->next;
7853             continue;
7854           }
7855
7856         /* 
7857          * Due to limits in active directory we need to use the LDAP
7858          * range semantics to query and return all the values in 
7859          * large lists, we will stop increasing the range when
7860          * the result count is 0.
7861          */
7862
7863         i = 0;  
7864         mdbbl_count = 0;
7865
7866         for(;;) 
7867           {
7868             memset(sub_filter, '\0', sizeof(sub_filter));
7869             memset(range, '\0', sizeof(range));
7870             sprintf(sub_filter, "(objectClass=msExchMDB)");
7871
7872             if(isLast)
7873               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
7874             else 
7875               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
7876
7877             attr_array[0] = range;
7878             attr_array[1] = NULL;
7879             
7880             sub_group_base = NULL;
7881             sub_group_count = 0;
7882             
7883             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
7884                                      attr_array, &sub_group_base, 
7885                                      &sub_group_count, 
7886                                      LDAP_SCOPE_SUBTREE)) != 0) 
7887               {
7888                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
7889                         ldap_err2string(rc));
7890                 return(rc);
7891               }
7892
7893             if(!sub_group_count)
7894               {
7895                 if(isLast) 
7896                   {
7897                     isLast = 0;
7898                     rangeLow = 0;
7899                     rangeHigh = rangeLow + (rangeStep - 1);
7900                     break;
7901                   }
7902                 else
7903                   isLast++;
7904               }
7905
7906             mdbbl_count += sub_group_count;
7907             rangeLow = rangeHigh + 1;
7908             rangeHigh = rangeLow + (rangeStep - 1);
7909           }
7910
7911         /* First time through, need to initialize or update the least used */
7912         
7913         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
7914                 mdbbl_count);
7915
7916         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
7917           {
7918             homeMDB_count = mdbbl_count; 
7919             *homeMDB = strdup(gPtr->dn);
7920           }
7921
7922         gPtr = gPtr->next;
7923         linklist_free(sub_group_base);
7924       }
7925     }
7926
7927   linklist_free(group_base);
7928   
7929   /* 
7930    * Ok found the server least allocated need to now query to get its
7931    * msExchHomeServerName so we can set it as a user attribute
7932    */
7933   
7934   attr_array[0] = "legacyExchangeDN";
7935   attr_array[1] = NULL; 
7936   
7937   group_count = 0;
7938   group_base = NULL;
7939   
7940   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
7941                            attr_array, &group_base, 
7942                            &group_count, 
7943                            LDAP_SCOPE_SUBTREE)) != 0) 
7944     {
7945       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
7946               ldap_err2string(rc));
7947       return(rc);
7948     }  
7949   
7950   if(group_count) 
7951     {
7952       *homeServerName = strdup(group_base->value);
7953       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
7954         {
7955           *s = '\0';
7956         }
7957     } 
7958
7959   linklist_free(group_base);
7960   
7961   return(rc);
7962 }
7963       
7964 char *lowercase(char *s)
7965 {
7966   char *p;
7967
7968   for (p = s; *p; p++)
7969     {
7970       if (isupper(*p))
7971         *p = tolower(*p);
7972     }
7973   return s;
7974 }
7975
7976 char *uppercase(char *s)
7977 {
7978   char *p;
7979
7980   for (p = s; *p; p++)
7981     {
7982       if (islower(*p))
7983         *p = toupper(*p);
7984     }
7985   return s;
7986 }
7987
7988 int save_query_info(int argc, char **argv, void *hint)
7989 {
7990   int i;
7991   char **nargv = hint;
7992
7993   for(i = 0; i < argc; i++)
7994     nargv[i] = strdup(argv[i]);
7995
7996   return MR_CONT;
7997 }
This page took 0.680343 seconds and 3 git commands to generate.