]> andersk Git - moira.git/blob - incremental/ldap/winad.c
Complain on mismatched usernames.
[moira.git] / incremental / ldap / winad.c
1 /* $Header$
2 /* ldap.incr arguments example
3  *
4  * arguments when moira creates the account - ignored by ldap.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/ldap/"
204 #define WINADCFG "ldap.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 "ldap.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/ldap/noldap"
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 REALM "REALM:"
378 #define ACTIVE_DIRECTORY "ACTIVE_DIRECTORY:"
379 #define PORT "PORT:"
380 #define PROCESS_MACHINE_CONTAINER "PROCESS_MACHINE_CONTAINER:"
381 #define MAX_DOMAINS 10
382 char DomainNames[MAX_DOMAINS][128];
383
384 LK_ENTRY *member_base = NULL;
385
386 char   PrincipalName[128];
387 static char tbl_buf[1024];
388 char  kerberos_ou[] = "OU=kerberos,OU=moira";
389 char  contact_ou[] = "OU=strings,OU=moira";
390 char  user_ou[] = "OU=users,OU=moira";
391 char  group_ou_distribution[1024];
392 char  group_ou_root[1024];
393 char  group_ou_security[1024];
394 char  group_ou_neither[1024];
395 char  group_ou_both[1024]; 
396 char  orphans_machines_ou[] = "OU=Machines,OU=Orphans";
397 char  orphans_other_ou[] = "OU=Other,OU=Orphans";
398 char  security_template_ou[] = "OU=security_templates";
399 char *whoami;
400 char ldap_domain[256];
401 char ldap_realm[256];
402 char ldap_port[256];
403 char *ServerList[MAX_SERVER_NAMES];
404 char default_server[256];
405 static char tbl_buf[1024];
406 char group_suffix[256];
407 char exchange_acl[256];
408 int  mr_connections = 0;
409 int  callback_rc;
410 int  UseSFU30 = 0;
411 int  UseGroupSuffix = 1;
412 int  UseGroupUniversal = 0;
413 int  SetGroupAce = 1;
414 int  SetPassword = 1;
415 int  Exchange = 0;
416 int  ProcessMachineContainer = 1;
417 int  ActiveDirectory = 1;
418 int  UpdateDomainList;
419
420 extern int set_password(char *user, char *password, char *domain);
421
422 int ad_get_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
423                  char *group_membership, char *MoiraId, char *attribute,
424                  LK_ENTRY **linklist_base, int *linklist_count,
425                  char *rFilter);
426 void AfsToWinAfs(char* path, char* winPath);
427 int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path, 
428                char *Win2kPassword, char *Win2kUser, char *default_server,
429                int connect_to_kdc, char **ServerList, char *ldap_realm,
430                char *ldap_port);
431 void ad_kdc_disconnect();
432 int ad_server_connect(char *connectedServer, char *domain);
433 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
434                      char *attribute_value, char *attribute, char *user_name);
435 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer);
436 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name);
437 int check_winad(void);
438 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, 
439                char *MoiraId);
440 /* containers */
441 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
442                        char *distinguishedName, int count, char **av);
443 void container_check(LDAP *ldap_handle, char *dn_path, char *name);
444 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av);
445 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av);
446 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
447                                     char *distinguishedName, int count, 
448                                     char **av);
449 void container_get_dn(char *src, char *dest);
450 void container_get_name(char *src, char *dest);
451 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName);
452 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
453                      char **before, int afterc, char **after);
454 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
455                      char **before, int afterc, char **after);
456
457 int GetAceInfo(int ac, char **av, void *ptr);
458 int get_group_membership(char *group_membership, char *group_ou, 
459                          int *security_flag, char **av);
460 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
461                    char *machine_ou, char *pPtr);
462 int Moira_container_group_create(char **after);
463 int Moira_container_group_delete(char **before);
464 int Moira_groupname_create(char *GroupName, char *ContainerName,
465                            char *ContainerRowID);
466 int Moira_container_group_update(char **before, char **after);
467 int Moira_process_machine_container_group(char *MachineName, char* groupName,
468                                           int DeleteMachine);
469 int Moira_addGroupToParent(char *origContainerName, char *GroupName);
470 int Moira_getContainerGroup(int ac, char **av, void *ptr);
471 int Moira_getGroupName(char *origContainerName, char *GroupName,
472                        int ParentFlag);
473 int Moira_setContainerGroup(char *ContainerName, char *GroupName);
474 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *group_name, char *Type,
475                int UpdateGroup, int *ProcessGroup, char *maillist);
476 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
477                   char *group_name, char *group_ou, char *group_membership, 
478                   int group_security_flag, int type, char *maillist);
479 int process_lists(int ac, char **av, void *ptr);
480 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
481                          char *TargetGroupName, int HiddenGroup, 
482                          char *AceType, char *AceName);
483 int ProcessMachineName(int ac, char **av, void *ptr);
484 int ReadConfigFile(char *DomainName);
485 int ReadDomainList();
486 void StringTrim(char *StringToTrim);
487 char *escape_string(char *s);
488 int save_query_info(int argc, char **argv, void *hint);
489 int user_create(int ac, char **av, void *ptr);
490 int user_change_status(LDAP *ldap_handle, char *dn_path, 
491                        char *user_name, char *MoiraId, int operation);
492 int user_delete(LDAP *ldap_handle, char *dn_path, 
493                 char *u_name, char *MoiraId);
494 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
495                 char *user_name);
496 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
497                 char *uid, char *MitId, char *MoiraId, int State,
498                 char *WinHomeDir, char *WinProfileDir, char *first,
499                 char *middle, char *last, char *shell, char *class);
500 void change_to_lower_case(char *ptr);
501 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou);
502 int contact_remove_email(LDAP *ld, char *bind_path,
503                          LK_ENTRY **linklist_entry, int linklist_current);
504 int group_create(int ac, char **av, void *ptr);
505 int group_delete(LDAP *ldap_handle, char *dn_path, 
506                  char *group_name, char *group_membership, char *MoiraId);
507 int group_rename(LDAP *ldap_handle, char *dn_path, 
508                  char *before_group_name, char *before_group_membership, 
509                  char *before_group_ou, int before_security_flag, 
510                  char *before_desc, char *after_group_name, 
511                  char *after_group_membership, char *after_group_ou, 
512                  int after_security_flag, char *after_desc,
513                  char *MoiraId, char *filter, char *maillist);
514 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name);
515 int machine_GetMoiraContainer(int ac, char **av, void *ptr);
516 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
517                                 char *machine_name, char *container_name);
518 int machine_move_to_ou(LDAP *ldap_handle, char *dn_path, 
519                        char *MoiraMachineName, char *DestinationOu);
520 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
521                    char *group_name, char *group_ou, char *group_membership, 
522                    int group_security_flag, int updateGroup, char *maillist);
523 int member_list_build(int ac, char **av, void *ptr);
524 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
525                char *group_ou, char *group_membership, 
526                char *user_name, char *pUserOu, char *MoiraId);
527 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
528                   char *group_ou, char *group_membership, char *user_name,
529                   char *pUserOu, char *MoiraId);
530 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
531                    char *group_ou, char *group_membership, 
532                    int group_security_flag, char *MoiraId);
533 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
534                      char *DistinguishedName,
535                      char *WinHomeDir, char *WinProfileDir,
536                      char **homedir_v, char **winProfile_v,
537                      char **drives_v, LDAPMod **mods, 
538                      int OpType, int n);
539 int sid_update(LDAP *ldap_handle, char *dn_path);
540 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n);
541 int check_string(char *s);
542 int check_container_name(char* s);
543
544 int mr_connect_cl(char *server, char *client, int version, int auth);
545 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
546                   char **before, int beforec, char **after, int afterc);
547 void do_filesys(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
548                 char **before, int beforec, char **after, int afterc);
549 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
550              char **before, int beforec, char **after, int afterc);
551 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
552              char **before, int beforec, char **after, int afterc);
553 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
554                char **before, int beforec, char **after, int afterc);
555 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
556                 char **before, int beforec, char **after, int afterc);
557 int linklist_create_entry(char *attribute, char *value,
558                           LK_ENTRY **linklist_entry);
559 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
560                    char **attr_array, LK_ENTRY **linklist_base, 
561                    int *linklist_count, unsigned long ScopeType);
562 void linklist_free(LK_ENTRY *linklist_base);
563
564 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
565                         char *distinguished_name, LK_ENTRY **linklist_current);
566 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
567                      LK_ENTRY **linklist_base, int *linklist_count);
568 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
569                     char *Attribute, char *distinguished_name, 
570                     LK_ENTRY **linklist_current);
571
572 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
573                         char *oldValue, char *newValue,
574                         char ***modvalues, int type);
575 void free_values(char **modvalues);
576
577 int convert_domain_to_dn(char *domain, char **bind_path);
578 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
579                             char *distinguished_name);
580 int moira_disconnect(void);
581 int moira_connect(void);
582 void print_to_screen(const char *fmt, ...);
583 int GetMachineName(char *MachineName);
584 int tickets_get_k5();
585 int destroy_cache(void);
586 int dest_tkt(void);
587
588 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB,
589                  char **homeServerName);
590
591 int main(int argc, char **argv)
592 {
593   unsigned long   rc;
594   int             beforec;
595   int             afterc;
596   int             i;
597   int             j;
598   int             k;
599   int             OldUseSFU30;
600   char            *table;
601   char            **before;
602   char            **after;
603   LDAP            *ldap_handle;
604   char            dn_path[256];
605   char            *orig_argv[64];
606   
607   whoami = ((whoami = (char *)strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
608   
609   if (argc < 4)
610     {
611       com_err(whoami, 0, "Unable to process %s", "argc < 4");
612       exit(1);
613     }
614   
615   if (argc < (4 + atoi(argv[2]) + atoi(argv[3])))
616     {
617       com_err(whoami, 0, "Unable to process %s", 
618               "argc < (4 + beforec + afterc)");
619       exit(1);
620     }
621
622   if (!strcmp(argv[1], "filesys"))
623     exit(0);
624
625   for (i = 1; i < argc; i++)
626     {
627       strcat(tbl_buf, argv[i]);
628       strcat(tbl_buf, " ");
629     }
630
631   com_err(whoami, 0, "%s", tbl_buf);
632
633   if (check_winad())
634     {
635       com_err(whoami, 0, "%s failed", "check_winad()");
636       exit(1);
637     }
638
639   initialize_sms_error_table();
640   initialize_krb_error_table();
641
642   UpdateDomainList = 0;
643   memset(DomainNames, '\0', sizeof(DomainNames[0]) * MAX_DOMAINS);
644
645   if (ReadDomainList())
646     {
647       com_err(whoami, 0, "%s failed", "ReadDomainList()");
648       exit(1);
649     }
650
651   for (i = 0; i < argc; i++)
652      orig_argv[i] = NULL;
653
654   for (k = 0; k < MAX_DOMAINS; k++)
655     {
656       if (strlen(DomainNames[k]) == 0)
657         continue;
658       for (i = 0; i < argc; i++)
659         {
660           if (orig_argv[i] != NULL)
661             free(orig_argv[i]);
662           orig_argv[i] = strdup(argv[i]);
663         }
664
665       memset(PrincipalName, '\0', sizeof(PrincipalName));
666       memset(ldap_domain, '\0', sizeof(ldap_domain));
667       memset(ServerList, '\0', sizeof(ServerList[0]) * MAX_SERVER_NAMES);
668       memset(default_server, '\0', sizeof(default_server));
669       memset(dn_path, '\0', sizeof(dn_path));
670       memset(group_suffix, '\0', sizeof(group_suffix));
671       memset(exchange_acl, '\0', sizeof(exchange_acl));
672
673       UseSFU30 = 0;
674       UseGroupSuffix = 1;
675       UseGroupUniversal = 0;
676       SetGroupAce = 1;
677       SetPassword = 1;
678       Exchange = 0;
679       ProcessMachineContainer = 1;
680       ActiveDirectory = 1;
681
682       sprintf(group_suffix, "%s", "_group");
683       sprintf(exchange_acl, "%s", "exchange-acl");
684
685       beforec = atoi(orig_argv[2]);
686       afterc = atoi(orig_argv[3]);
687       table = orig_argv[1];
688       before = &orig_argv[4];
689       after = &orig_argv[4 + beforec];
690
691       if (afterc == 0)
692         after = NULL;
693
694       if (beforec == 0)
695         before = NULL;
696
697       if (ReadConfigFile(DomainNames[k]))
698         continue;
699
700       if(ActiveDirectory)
701         {
702           sprintf(group_ou_distribution, "OU=mail,OU=lists,OU=moira");
703           sprintf(group_ou_root, "OU=lists,OU=moira");
704           sprintf(group_ou_security, "OU=group,OU=lists,OU=moira");
705           sprintf(group_ou_neither, "OU=special,OU=lists,OU=moira");
706           sprintf(group_ou_both, "OU=mail,OU=group,OU=lists,OU=moira");
707         }
708       else
709         {
710           sprintf(group_ou_distribution, "OU=lists,OU=moira");
711           sprintf(group_ou_root, "OU=lists,OU=moira");
712           sprintf(group_ou_security, "OU=lists,OU=moira");
713           sprintf(group_ou_neither, "OU=lists,OU=moira");
714           sprintf(group_ou_both, "OU=lists,OU=moira");
715         }
716
717       OldUseSFU30 = UseSFU30;
718
719       for (i = 0; i < 5; i++)
720         {
721           ldap_handle = (LDAP *)NULL;
722           if (!(rc = ad_connect(&ldap_handle, ldap_domain, dn_path, "", "", 
723                                 default_server, SetPassword, ServerList, 
724                                 ldap_realm, ldap_port)))
725             {
726               com_err(whoami, 0, "connected to domain %s", DomainNames[k]);
727               break;
728             }
729         }
730
731       if ((rc) || (ldap_handle == NULL))
732         {
733           critical_alert("incremental",
734                          "ldap.incr cannot connect to any server in "
735                          "domain %s", DomainNames[k]);
736           continue;
737         }
738
739       for (i = 0; i < (int)strlen(table); i++)
740         table[i] = tolower(table[i]);
741
742       if (!strcmp(table, "users"))
743         do_user(ldap_handle, dn_path, ldap_domain, before, beforec, after,
744                 afterc);
745       else if (!strcmp(table, "list"))
746         do_list(ldap_handle, dn_path, ldap_domain, before, beforec, after,
747                 afterc);
748       else if (!strcmp(table, "imembers"))
749         do_member(ldap_handle, dn_path, ldap_domain, before, beforec, after,
750                   afterc);
751       else if (!strcmp(table, "containers"))
752         do_container(ldap_handle, dn_path, ldap_domain, before, beforec, after,
753                      afterc);
754       else if (!strcmp(table, "mcntmap"))
755         do_mcntmap(ldap_handle, dn_path, ldap_domain, before, beforec, after,
756                    afterc);
757
758       if(SetPassword) 
759         ad_kdc_disconnect();
760
761       for (i = 0; i < MAX_SERVER_NAMES; i++)
762         {
763           if (ServerList[i] != NULL)
764             {
765               free(ServerList[i]);
766               ServerList[i] = NULL;
767             }
768         }
769       
770       rc = ldap_unbind_s(ldap_handle);
771     }
772   
773   exit(0);
774 }
775
776 void do_mcntmap(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
777                 char **before, int beforec, char **after, int afterc)
778 {
779   char    MoiraContainerName[128];
780   char    ADContainerName[128];
781   char    MachineName[1024];
782   char    OriginalMachineName[1024];
783   long    rc;
784   int     DeleteMachine;
785   char    MoiraContainerGroup[64];
786
787   if (!ProcessMachineContainer)
788     {
789       com_err(whoami, 0, "Process machines and containers disabled, skipping");
790       return;
791     }
792   
793   DeleteMachine = 0;
794   memset(ADContainerName, '\0', sizeof(ADContainerName));
795   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
796   
797   if ((beforec == 0) && (afterc == 0))
798     return;
799   
800   if (rc = moira_connect())
801     {
802       critical_alert("AD incremental",
803                      "Error contacting Moira server : %s",
804                      error_message(rc));
805       return;
806     }
807   
808   if ((beforec != 0) && (afterc == 0)) /*remove a machine*/
809     {
810       strcpy(OriginalMachineName, before[OU_MACHINE_NAME]);
811       strcpy(MachineName, before[OU_MACHINE_NAME]);
812       strcpy(MoiraContainerGroup, before[OU_CONTAINER_GROUP]);
813       DeleteMachine = 1;
814       com_err(whoami, 0, "removing machine %s from %s", 
815               OriginalMachineName, before[OU_CONTAINER_NAME]);
816     }
817   else if ((beforec == 0) && (afterc != 0)) /*add a machine*/
818     {
819       strcpy(OriginalMachineName, after[OU_MACHINE_NAME]);
820       strcpy(MachineName, after[OU_MACHINE_NAME]);
821       strcpy(MoiraContainerGroup, after[OU_CONTAINER_GROUP]);
822       com_err(whoami, 0, "adding machine %s to container %s", 
823               OriginalMachineName, after[OU_CONTAINER_NAME]);
824     }
825   else
826     {
827       moira_disconnect();
828       return;
829     }
830   
831   rc = GetMachineName(MachineName);
832
833   if (strlen(MachineName) == 0)
834     {
835       moira_disconnect();
836       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
837               OriginalMachineName);
838       return;
839     }
840
841   Moira_process_machine_container_group(MachineName, MoiraContainerGroup,
842                                         DeleteMachine);
843
844   if (machine_check(ldap_handle, dn_path, MachineName))
845     {
846       com_err(whoami, 0, "Unable to find machine %s (alias %s) in AD.", 
847               OriginalMachineName, MachineName);
848       moira_disconnect();
849       return;
850     }
851
852   memset(MoiraContainerName, '\0', sizeof(MoiraContainerName));
853   machine_get_moira_container(ldap_handle, dn_path, MachineName, 
854                               MoiraContainerName);
855
856   if (strlen(MoiraContainerName) == 0)
857     {
858       com_err(whoami, 0, "Unable to fine machine %s (alias %s) container "
859               "in Moira - moving to orphans OU.",
860               OriginalMachineName, MachineName);
861       machine_move_to_ou(ldap_handle, dn_path, MachineName, 
862                          orphans_machines_ou);
863       moira_disconnect();
864       return;
865     }
866
867   container_get_dn(MoiraContainerName, ADContainerName);
868
869   if (MoiraContainerName[strlen(MoiraContainerName) - 1] != '/')
870     strcat(MoiraContainerName, "/");
871
872   container_check(ldap_handle, dn_path, MoiraContainerName);
873   machine_move_to_ou(ldap_handle, dn_path, MachineName, ADContainerName);
874   moira_disconnect();
875   return;
876 }
877
878 void do_container(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
879                   char **before, int beforec, char **after, int afterc)
880 {
881   long rc;
882
883   if (!ProcessMachineContainer)
884     {
885       com_err(whoami, 0, "Process machines and containers disabled, skipping");
886       return;
887     }
888
889   if ((beforec == 0) && (afterc == 0))
890     return;
891
892   if (rc = moira_connect())
893     {
894       critical_alert("AD incremental", "Error contacting Moira server : %s",
895                      error_message(rc));
896       return;
897     }
898
899   if ((beforec != 0) && (afterc == 0)) /*delete a new container*/
900     {
901       com_err(whoami, 0, "deleting container %s", before[CONTAINER_NAME]);
902       container_delete(ldap_handle, dn_path, beforec, before);
903       Moira_container_group_delete(before);
904       moira_disconnect();
905       return;
906     }
907
908   if ((beforec == 0) && (afterc != 0)) /*create a container*/
909     {
910       com_err(whoami, 0, "creating container %s", after[CONTAINER_NAME]);
911       container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
912       container_create(ldap_handle, dn_path, afterc, after);
913       Moira_container_group_create(after);
914       moira_disconnect();
915       return;
916     }
917
918   if (strcasecmp(before[CONTAINER_NAME], after[CONTAINER_NAME]))
919     {
920       com_err(whoami, 0, "renaming container %s to %s", 
921               before[CONTAINER_NAME], after[CONTAINER_NAME]);
922       container_rename(ldap_handle, dn_path, beforec, before, afterc, after);
923       Moira_container_group_update(before, after);
924       moira_disconnect();
925       return;
926     }
927
928   com_err(whoami, 0, "updating container %s information", 
929           after[CONTAINER_NAME]);
930   container_update(ldap_handle, dn_path, beforec, before, afterc, after);
931   Moira_container_group_update(before, after);
932   moira_disconnect();
933   return;
934 }
935
936 #define L_LIST_DESC 9
937 #define L_LIST_ID   10
938
939 void do_list(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
940              char **before, int beforec, char **after, int afterc)
941 {
942   int   updateGroup;
943   int   ProcessGroup;
944   long  rc;
945   char  group_membership[6];
946   char  list_id[32];
947   int   security_flag;
948   char  filter[128];
949   char  group_ou[256];
950   char  before_list_id[32];
951   char  before_group_membership[1];
952   int   before_security_flag;
953   char  before_group_ou[256];
954   LK_ENTRY *ptr = NULL;
955
956   if (beforec == 0 && afterc == 0)
957     return;
958
959   memset(list_id, '\0', sizeof(list_id));
960   memset(before_list_id, '\0', sizeof(before_list_id));
961   memset(before_group_ou, '\0', sizeof(before_group_ou));
962   memset(before_group_membership, '\0', sizeof(before_group_membership));
963   memset(group_ou, '\0', sizeof(group_ou));
964   memset(group_membership, '\0', sizeof(group_membership));
965   updateGroup = 0;
966
967   if (beforec > L_GID)
968     {
969       if (beforec < L_LIST_ID)
970         return;
971       if (beforec > L_LIST_DESC)
972         {
973           strcpy(before_list_id, before[L_LIST_ID]);
974         }
975       before_security_flag = 0;
976       get_group_membership(before_group_membership, before_group_ou, 
977                            &before_security_flag, before);
978     }
979
980   if (afterc > L_GID)
981     {
982       if (afterc < L_LIST_ID)
983         return;
984       if (afterc > L_LIST_DESC)
985         {
986           strcpy(list_id, after[L_LIST_ID]);
987         }
988       security_flag = 0;
989       get_group_membership(group_membership, group_ou, &security_flag, after);
990     }
991   
992   if ((beforec == 0) && (afterc == 0)) /*this case should never happen*/
993     return;
994
995   updateGroup = 0;
996   
997   if (beforec)
998     {
999       updateGroup = 1;
1000
1001       if ((rc = process_group(ldap_handle, dn_path, before_list_id, 
1002                               before[L_NAME], before_group_ou, 
1003                               before_group_membership, 
1004                               before_security_flag, CHECK_GROUPS,
1005                               before[L_MAILLIST])))
1006         {
1007           if (rc == AD_NO_GROUPS_FOUND)
1008             updateGroup = 0;
1009           else
1010             {
1011               if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
1012                   (rc == AD_MULTIPLE_GROUPS_FOUND))
1013                 {
1014                   rc = process_group(ldap_handle, dn_path, before_list_id, 
1015                                      before[L_NAME], before_group_ou, 
1016                                      before_group_membership, 
1017                                      before_security_flag, CLEANUP_GROUPS,
1018                                      before[L_MAILLIST]);
1019                 }
1020               if ((rc != AD_NO_GROUPS_FOUND) && (rc != 0))
1021                 {
1022                   com_err(whoami, 0, "Unable to process list %s",
1023                           before[L_NAME]);
1024                   return;
1025                 }
1026               if (rc == AD_NO_GROUPS_FOUND)
1027                 updateGroup = 0;
1028             }
1029         }
1030     }
1031
1032   if ((beforec != 0) && (afterc != 0))
1033     {
1034       if (((strcmp(after[L_NAME], before[L_NAME])) || 
1035            ((!strcmp(after[L_NAME], before[L_NAME])) && 
1036             (strcmp(before_group_ou, group_ou)))) &&
1037           (updateGroup == 1))
1038         {
1039           com_err(whoami, 0, "Changing list name from %s to %s",
1040                   before[L_NAME], after[L_NAME]);
1041
1042           if ((strlen(before_group_ou) == 0) || 
1043               (strlen(before_group_membership) == 0) ||
1044               (strlen(group_ou) == 0) || (strlen(group_membership) == 0))
1045             {
1046               com_err(whoami, 0, "%s", "Unable to find the group OU's");
1047               return;
1048             }
1049
1050           memset(filter, '\0', sizeof(filter));
1051
1052           if ((rc = group_rename(ldap_handle, dn_path, 
1053                                  before[L_NAME], before_group_membership, 
1054                                  before_group_ou, before_security_flag, 
1055                                  before[L_LIST_DESC], after[L_NAME], 
1056                                  group_membership, group_ou, security_flag, 
1057                                  after[L_LIST_DESC],
1058                                  list_id, filter, after[L_MAILLIST])))
1059             {
1060               if (rc != AD_NO_GROUPS_FOUND)
1061                 {
1062                   com_err(whoami, 0, 
1063                           "Unable to change list name from %s to %s",
1064                           before[L_NAME], after[L_NAME]);
1065                   return;
1066                 }
1067               updateGroup = 0;
1068             }
1069           beforec = 0;
1070         }
1071       else
1072         beforec = 0;
1073     }
1074   
1075   if (beforec)
1076     {
1077       if ((strlen(before_group_ou) == 0) || 
1078           (strlen(before_group_membership) == 0))
1079         {
1080           com_err(whoami, 0, 
1081                   "Unable to find the group OU for group %s", before[L_NAME]);
1082           return;
1083         }
1084
1085       com_err(whoami, 0, "Deleting group %s", before[L_NAME]);
1086       rc = group_delete(ldap_handle, dn_path, before[L_NAME], 
1087                         before_group_membership, before_list_id);
1088       return;
1089     }
1090
1091   if (afterc)
1092     {
1093       if (!updateGroup)
1094         {
1095           com_err(whoami, 0, "Creating group %s", after[L_NAME]);
1096
1097           if (rc = process_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1098                                   group_ou, group_membership, 
1099                                   security_flag, CHECK_GROUPS,
1100                                  after[L_MAILLIST]))
1101             {
1102               if (rc != AD_NO_GROUPS_FOUND)
1103                 {
1104                   if ((rc == AD_WRONG_GROUP_DN_FOUND) || 
1105                       (rc == AD_MULTIPLE_GROUPS_FOUND))
1106                     {
1107                       rc = process_group(ldap_handle, dn_path, list_id, 
1108                                          after[L_NAME], 
1109                                          group_ou, group_membership, 
1110                                          security_flag, CLEANUP_GROUPS,
1111                                          after[L_MAILLIST]);
1112                     }
1113
1114                   if (rc)
1115                     {
1116                       com_err(whoami, 0, 
1117                               "Unable to create list %s", after[L_NAME]);
1118                       return;
1119                     }
1120                 }
1121             }
1122         }
1123       else
1124         com_err(whoami, 0, "Updating group %s information", after[L_NAME]);
1125
1126       if (rc = moira_connect())
1127         {
1128           critical_alert("AD incremental",
1129                          "Error contacting Moira server : %s",
1130                          error_message(rc));
1131           return;
1132         }
1133
1134       ProcessGroup = 0;
1135
1136       if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 0, 
1137                      &ProcessGroup, after[L_MAILLIST]))
1138         return;
1139
1140       if (ProcessGroup)
1141         {
1142           if (ProcessAce(ldap_handle, dn_path, after[L_NAME], "LIST", 1, 
1143                          &ProcessGroup, after[L_MAILLIST]))
1144             return;
1145         }
1146
1147       if (make_new_group(ldap_handle, dn_path, list_id, after[L_NAME], 
1148                          group_ou, group_membership, security_flag, 
1149                          updateGroup, after[L_MAILLIST]))
1150         {
1151           moira_disconnect();
1152           return;
1153         }
1154     
1155       if (atoi(after[L_ACTIVE]))
1156         {
1157           populate_group(ldap_handle, dn_path, after[L_NAME], group_ou, 
1158                          group_membership, security_flag, list_id);
1159         }
1160
1161       moira_disconnect();
1162     }
1163   return;
1164 }
1165
1166 #define LM_EXTRA_ACTIVE   (LM_END)
1167 #define LM_EXTRA_PUBLIC   (LM_END+1)
1168 #define LM_EXTRA_HIDDEN   (LM_END+2)
1169 #define LM_EXTRA_MAILLIST (LM_END+3)
1170 #define LM_EXTRA_GROUP    (LM_END+4)
1171 #define LM_EXTRA_GID      (LM_END+5)
1172 #define LMN_LIST_ID       (LM_END+6)
1173 #define LM_LIST_ID        (LM_END+7)
1174 #define LM_USER_ID        (LM_END+8)
1175 #define LM_EXTRA_END      (LM_END+9)
1176
1177 void do_member(LDAP *ldap_handle, char *dn_path, char *ldap_hostname,
1178                char **before, int beforec, char **after, int afterc)
1179 {
1180   LK_ENTRY *group_base;
1181   int group_count;
1182   char  filter[128];
1183   char *attr_array[3];
1184   char  group_name[128];
1185   char  user_name[128];
1186   char  user_type[128];
1187   char  moira_list_id[32];
1188   char  moira_user_id[32];
1189   char  group_membership[1];
1190   char  group_ou[256];
1191   char  machine_ou[256];
1192   char  member[256];
1193   char  *args[16];
1194   char  **ptr;
1195   char  *av[7];
1196   char  *call_args[7];
1197   char  *pUserOu;
1198   char  *s;
1199   char  NewMachineName[1024];
1200   int   security_flag;
1201   int   rc;
1202   int   ProcessGroup;
1203   char  *save_argv[U_END];
1204
1205   pUserOu = NULL;
1206   ptr = NULL;
1207   memset(moira_list_id, '\0', sizeof(moira_list_id));
1208   memset(moira_user_id, '\0', sizeof(moira_user_id));
1209
1210   if (afterc)
1211     {
1212       if (afterc < LM_EXTRA_GID)
1213         return;
1214
1215       if (!atoi(after[LM_EXTRA_ACTIVE]))
1216         {
1217           com_err(whoami, 0, 
1218                   "Unable to add %s to group %s : group not active", 
1219                   after[2], after[0]);
1220           return;
1221         }
1222
1223       ptr = after;
1224
1225       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1226         return;
1227
1228       strcpy(user_name, after[LM_MEMBER]);
1229       strcpy(group_name, after[LM_LIST]);
1230       strcpy(user_type, after[LM_TYPE]);
1231
1232       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1233         {
1234           if (afterc > LM_EXTRA_GROUP)
1235             {
1236               strcpy(moira_list_id, after[LMN_LIST_ID]);
1237               strcpy(moira_user_id, after[LM_LIST_ID]);
1238             }
1239         }
1240       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1241         {
1242           if (afterc > LMN_LIST_ID)
1243             {
1244               strcpy(moira_list_id, after[LM_LIST_ID]);
1245               strcpy(moira_user_id, after[LM_USER_ID]);
1246             }
1247         }
1248       else
1249         {
1250           if (afterc > LM_EXTRA_GID)
1251             strcpy(moira_list_id, after[LMN_LIST_ID]);
1252         }
1253     }
1254   else if (beforec)
1255     {
1256       if (beforec < LM_EXTRA_GID)
1257         return;
1258       if (!atoi(before[LM_EXTRA_ACTIVE]))
1259         {
1260           com_err(whoami, 0, 
1261                   "Unable to add %s to group %s : group not active", 
1262                   before[2], before[0]);
1263           return;
1264         }
1265
1266       ptr = before;
1267
1268       if (!strcasecmp(ptr[LM_TYPE], "LIST"))
1269         return;
1270
1271       strcpy(user_name, before[LM_MEMBER]);
1272       strcpy(group_name, before[LM_LIST]);
1273       strcpy(user_type, before[LM_TYPE]);
1274
1275       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1276         {
1277           if (beforec > LM_EXTRA_GROUP)
1278             {
1279               strcpy(moira_list_id, before[LMN_LIST_ID]);
1280               strcpy(moira_user_id, before[LM_LIST_ID]);
1281             }
1282         }
1283       else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1284         {
1285           if (beforec > LMN_LIST_ID)
1286             {
1287               strcpy(moira_list_id, before[LM_LIST_ID]);
1288               strcpy(moira_user_id, before[LM_USER_ID]);
1289             }
1290         }
1291       else
1292         {
1293           if (beforec > LM_EXTRA_GID)
1294             strcpy(moira_list_id, before[LMN_LIST_ID]);
1295         }
1296     }
1297
1298   if (ptr == NULL)
1299     {
1300       com_err(whoami, 0, 
1301               "Unable to process group : beforec = %d, afterc = %d", 
1302               beforec, afterc);
1303       return;
1304     }
1305
1306   args[L_NAME] = ptr[LM_LIST];
1307   args[L_ACTIVE] = ptr[LM_EXTRA_ACTIVE];
1308   args[L_PUBLIC] = ptr[LM_EXTRA_PUBLIC];
1309   args[L_HIDDEN] = ptr[LM_EXTRA_HIDDEN];
1310   args[L_MAILLIST] = ptr[LM_EXTRA_MAILLIST];
1311   args[L_GROUP] = ptr[LM_EXTRA_GROUP];
1312   args[L_GID] = ptr[LM_EXTRA_GID];
1313
1314   security_flag = 0;
1315   memset(group_ou, '\0', sizeof(group_ou));
1316   get_group_membership(group_membership, group_ou, &security_flag, args);
1317
1318   if (strlen(group_ou) == 0)
1319     {
1320       com_err(whoami, 0, "Unable to find the group OU for group %s", 
1321               group_name);
1322       return;
1323     }
1324
1325   if (rc = process_group(ldap_handle, dn_path, moira_list_id, group_name, 
1326                          group_ou, group_membership, security_flag, 
1327                          CHECK_GROUPS, args[L_MAILLIST]))
1328     {
1329       if (rc != AD_NO_GROUPS_FOUND)
1330         {
1331           if (rc = process_group(ldap_handle, dn_path, moira_list_id, 
1332                                  group_name, group_ou, group_membership, 
1333                                  security_flag, CLEANUP_GROUPS,
1334                                  args[L_MAILLIST]))
1335             {
1336               if (rc != AD_NO_GROUPS_FOUND)
1337                 {
1338                   if (afterc)
1339                     com_err(whoami, 0, "Unable to add %s to group %s - " 
1340                             "unable to process group", user_name, group_name);
1341                   else
1342                     com_err(whoami, 0, "Unable to remove %s from group %s - "
1343                             "unable to process group", user_name, group_name);
1344                   return;
1345                 }
1346             }
1347         }
1348     }
1349
1350   if (rc == AD_NO_GROUPS_FOUND)
1351     {
1352       if (rc = moira_connect())
1353         {
1354           critical_alert("AD incremental",
1355                          "Error contacting Moira server : %s",
1356                          error_message(rc));
1357           return;
1358         }
1359       
1360       com_err(whoami, 0, "creating group %s", group_name);
1361       ProcessGroup = 0;
1362
1363       if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 0, 
1364                      &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1365         return;
1366
1367       if (ProcessGroup)
1368         {
1369           if (ProcessAce(ldap_handle, dn_path, ptr[LM_LIST], "LIST", 1, 
1370                          &ProcessGroup, ptr[LM_EXTRA_MAILLIST]))
1371             return;
1372         }
1373
1374       if (make_new_group(ldap_handle, dn_path, moira_list_id, ptr[LM_LIST], 
1375                          group_ou, group_membership, security_flag, 0,
1376                          ptr[LM_EXTRA_MAILLIST]))
1377         {
1378           moira_disconnect();
1379           return;
1380         }
1381     
1382       if (atoi(ptr[LM_EXTRA_ACTIVE]))
1383         {
1384           populate_group(ldap_handle, dn_path, ptr[LM_LIST], group_ou, 
1385                          group_membership, security_flag, moira_list_id);
1386         }
1387
1388       moira_disconnect();
1389     }
1390
1391   rc = 0;
1392
1393   if (beforec)
1394     {
1395       com_err(whoami, 0, "removing user %s from list %s", user_name, 
1396               group_name);
1397       pUserOu = user_ou;
1398
1399       if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1400         {
1401           memset(machine_ou, '\0', sizeof(machine_ou));
1402           memset(NewMachineName, '\0', sizeof(NewMachineName));
1403           if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], 
1404                              machine_ou, NewMachineName))
1405             return;
1406           if (ptr[LM_MEMBER] != NULL)     
1407             free(ptr[LM_MEMBER]);
1408           ptr[LM_MEMBER] = strdup(NewMachineName);
1409           pUserOu = machine_ou;
1410         }
1411
1412       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1413         {
1414           strcpy(member, ptr[LM_MEMBER]);
1415
1416           if (Exchange) 
1417             {
1418               if((s = strchr(member, '@')) == (char *) NULL)
1419                 { 
1420                   strcat(member, "@mit.edu");
1421                   
1422                   if (ptr[LM_MEMBER] != NULL)
1423                     free(ptr[LM_MEMBER]);
1424                   ptr[LM_MEMBER] = strdup(member);
1425                 }
1426           
1427               if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1428                 {
1429                   s = strrchr(member, '.');
1430                   *s = '\0';
1431                   strcat(s, ".mit.edu");
1432                   
1433                   if (ptr[LM_MEMBER] != NULL)
1434                     free(ptr[LM_MEMBER]);
1435                   ptr[LM_MEMBER] = strdup(member);
1436                 }
1437             }
1438
1439           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1440                              contact_ou))
1441                 return;
1442
1443           pUserOu = contact_ou;
1444         }
1445       else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1446         {
1447           if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1448                              kerberos_ou))
1449             return;
1450
1451           pUserOu = kerberos_ou;
1452         }
1453
1454       if (rc = moira_connect()) {
1455         critical_alert("AD incremental",
1456                        "Error contacting Moira server : %s",
1457                        error_message(rc));              
1458         return;
1459       }
1460       
1461       if (rc = populate_group(ldap_handle, dn_path, group_name,
1462                               group_ou, group_membership, 
1463                               security_flag, moira_list_id))
1464         com_err(whoami, 0, "Unable to remove %s from group %s", user_name, 
1465                 group_name);
1466       
1467       moira_disconnect();
1468       
1469       if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1470         {
1471           if (rc = moira_connect())
1472             {
1473               critical_alert("AD incremental",
1474                              "Error contacting Moira server : %s",
1475                              error_message(rc));
1476               return;
1477             }
1478           
1479           if (rc = populate_group(ldap_handle, dn_path, group_name,
1480                                   group_ou, group_membership, security_flag,
1481                                   moira_list_id))
1482             com_err(whoami, 0, "Unable to remove %s from group %s",
1483                     user_name, group_name);
1484
1485           moira_disconnect();
1486         }
1487       return;
1488     }
1489   
1490   com_err(whoami, 0, "Adding %s to list %s", user_name, group_name);
1491   pUserOu = user_ou;
1492   
1493   if (!strcasecmp(ptr[LM_TYPE], "MACHINE"))
1494     {
1495       memset(machine_ou, '\0', sizeof(machine_ou));
1496       memset(NewMachineName, '\0', sizeof(NewMachineName));
1497
1498       if (get_machine_ou(ldap_handle, dn_path, ptr[LM_MEMBER], machine_ou, 
1499                          NewMachineName))
1500         return;
1501
1502       if (ptr[LM_MEMBER] != NULL)
1503         free(ptr[LM_MEMBER]);
1504
1505       ptr[LM_MEMBER] = strdup(NewMachineName);
1506       pUserOu = machine_ou;
1507     }
1508   else if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1509     {
1510       strcpy(member, ptr[LM_MEMBER]);
1511
1512       if (Exchange) 
1513         {
1514           if((s = strchr(member, '@')) == (char *) NULL)
1515             { 
1516               strcat(member, "@mit.edu");
1517               
1518               if (ptr[LM_MEMBER] != NULL)
1519                 free(ptr[LM_MEMBER]);
1520               ptr[LM_MEMBER] = strdup(member);
1521             }
1522           
1523           if(!strncasecmp(&member[strlen(member) - 6], ".LOCAL", 6)) 
1524             {
1525               s = strrchr(member, '.');
1526               *s = '\0';
1527               strcat(s, ".mit.edu");
1528               
1529               if (ptr[LM_MEMBER] != NULL)
1530                 free(ptr[LM_MEMBER]);
1531               ptr[LM_MEMBER] = strdup(member);
1532             }
1533         }
1534       
1535       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1536                          contact_ou))
1537         return;
1538
1539       pUserOu = contact_ou;
1540     }
1541   else if (!strcasecmp(ptr[LM_TYPE], "KERBEROS"))
1542     {
1543       if (contact_create(ldap_handle, dn_path, ptr[LM_MEMBER], 
1544                          kerberos_ou))
1545         return;
1546
1547       pUserOu = kerberos_ou;
1548     }
1549   else if (!strcasecmp(ptr[LM_TYPE], "USER"))
1550     {
1551       if ((rc = check_user(ldap_handle, dn_path, ptr[LM_MEMBER], 
1552                            moira_user_id)) == AD_NO_USER_FOUND)
1553         {
1554           if (rc = moira_connect())
1555             {
1556               critical_alert("AD incremental", 
1557                              "Error connection to Moira : %s",
1558                              error_message(rc));
1559               return;
1560             }
1561
1562           com_err(whoami, 0, "creating user %s", ptr[LM_MEMBER]);
1563           av[0] = ptr[LM_MEMBER];
1564           call_args[0] = (char *)ldap_handle;
1565           call_args[1] = dn_path;
1566           call_args[2] = moira_user_id;
1567           call_args[3] = NULL;
1568           
1569           callback_rc = 0;
1570
1571           if (Exchange)
1572             {
1573               group_count = 0;
1574               group_base = NULL;
1575           
1576               sprintf(filter, "(&(objectClass=group)(cn=%s))", ptr[LM_MEMBER]);
1577               attr_array[0] = "cn";
1578               attr_array[1] = NULL;
1579               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
1580                                        attr_array, &group_base, &group_count,
1581                                        LDAP_SCOPE_SUBTREE)) != 0)
1582                 {
1583                   com_err(whoami, 0, "Unable to process user %s : %s",
1584                           ptr[LM_MEMBER], ldap_err2string(rc));
1585                   return;
1586                 }
1587               
1588               if (group_count)
1589                 {
1590                   com_err(whoami, 0, "Object already exists with name %s",
1591                           ptr[LM_MEMBER]);
1592                   return;
1593                 }
1594           
1595               linklist_free(group_base);
1596               group_count = 0;
1597               group_base = NULL;
1598             }
1599
1600           if (rc = mr_query("get_user_account_by_login", 1, av, 
1601                             save_query_info, save_argv))
1602             {
1603               moira_disconnect();
1604               com_err(whoami, 0, "Unable to create user %s : %s",
1605                       ptr[LM_MEMBER], error_message(rc));
1606               return;
1607             }
1608         
1609           if (rc = user_create(U_END, save_argv, call_args)) 
1610             {
1611               moira_disconnect();
1612               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1613               return;
1614             }
1615
1616           if (callback_rc)
1617             {
1618               moira_disconnect();
1619               com_err(whoami, 0, "Unable to create user %s", ptr[LM_MEMBER]);
1620               return;
1621             }
1622         }
1623       else
1624         {
1625           if (rc != 0)
1626             return;
1627         }
1628       pUserOu = user_ou;
1629     }
1630
1631   if (rc = moira_connect()) {
1632     critical_alert("AD incremental",
1633                    "Error contacting Moira server : %s",
1634                    error_message(rc));              
1635     return;
1636   }
1637
1638   if (rc = populate_group(ldap_handle, dn_path, group_name,
1639                           group_ou, group_membership, security_flag,
1640                           moira_list_id))
1641     com_err(whoami, 0, "Unable to add %s to group %s", user_name, 
1642             group_name);
1643   
1644   moira_disconnect();
1645
1646   if (!strcasecmp(ptr[LM_TYPE], "STRING"))
1647     {
1648       if (rc = moira_connect())
1649         {
1650           critical_alert("AD incremental",
1651                          "Error contacting Moira server : %s",
1652                          error_message(rc));
1653           return;
1654         }
1655       
1656       if (rc = populate_group(ldap_handle, dn_path, group_name,
1657                               group_ou, group_membership, security_flag,
1658                               moira_list_id))
1659         com_err(whoami, 0, "Unable to add %s to group %s",
1660                 user_name, group_name);
1661       
1662       moira_disconnect();
1663     }
1664
1665   return;
1666 }
1667
1668
1669 #define U_USER_ID    10
1670 #define U_HOMEDIR    11
1671 #define U_PROFILEDIR 12
1672
1673 void do_user(LDAP *ldap_handle, char *dn_path, char *ldap_hostname, 
1674              char **before, int beforec, char **after, 
1675              int afterc)
1676 {
1677   LK_ENTRY *group_base;
1678   int   group_count;
1679   char  filter[128];
1680   char  *attr_array[3];
1681   int   rc;
1682   char  *av[7];
1683   char  after_user_id[32];
1684   char  before_user_id[32];
1685   char  *call_args[7];
1686   char  *save_argv[U_END];
1687
1688   if ((beforec == 0) && (afterc == 0))
1689     return;
1690
1691   memset(after_user_id, '\0', sizeof(after_user_id));
1692   memset(before_user_id, '\0', sizeof(before_user_id));
1693
1694   if (beforec > U_USER_ID)
1695     strcpy(before_user_id, before[U_USER_ID]);
1696
1697   if (afterc > U_USER_ID)
1698     strcpy(after_user_id, after[U_USER_ID]);
1699
1700   if ((beforec == 0) && (afterc == 0)) /*this case should never happen */
1701     return;
1702
1703   if ((beforec == 0) && (afterc != 0)) 
1704     {
1705       /*this case only happens when the account*/
1706       /*account is first created but not usable*/
1707
1708       com_err(whoami, 0, "Unable to process user %s because the user account "
1709               "is not yet usable", after[U_NAME]);
1710       return;
1711     }
1712
1713   /*this case only happens when the account is expunged */
1714
1715   if ((beforec != 0) && (afterc == 0)) 
1716     {                                 
1717       if (atoi(before[U_STATE]) == 0)
1718         {
1719           com_err(whoami, 0, "expunging user %s from AD", before[U_NAME]);
1720           user_delete(ldap_handle, dn_path, before[U_NAME], before_user_id);
1721         }
1722       else
1723         {
1724           com_err(whoami, 0, "Unable to process because user %s has been "
1725                   "previously expungeded", before[U_NAME]);
1726         }
1727       return;
1728     }
1729
1730   /*process anything that gets here*/
1731
1732   if ((rc = check_user(ldap_handle, dn_path, before[U_NAME], 
1733                        before_user_id)) == AD_NO_USER_FOUND)
1734     {
1735       if (!check_string(after[U_NAME]))
1736         return;
1737
1738       if (rc = moira_connect())
1739         {
1740           critical_alert("AD incremental", 
1741                          "Error connection to Moira : %s",
1742                          error_message(rc));
1743           return;
1744         }
1745
1746       com_err(whoami, 0, "creating user %s", after[U_NAME]);
1747       
1748       av[0] = after[U_NAME];
1749       call_args[0] = (char *)ldap_handle;
1750       call_args[1] = dn_path;
1751       call_args[2] = after_user_id;
1752       call_args[3] = NULL;
1753       callback_rc = 0;
1754
1755       if (Exchange) 
1756         {
1757           group_count = 0;
1758           group_base = NULL;
1759           
1760           sprintf(filter, "(&(objectClass=group)(cn=%s))", after[U_NAME]);
1761           attr_array[0] = "cn";
1762           attr_array[1] = NULL;
1763           
1764           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
1765                                    &group_base, &group_count,
1766                                    LDAP_SCOPE_SUBTREE)) != 0)
1767             {
1768               com_err(whoami, 0, "Unable to process user %s : %s",
1769                       after[U_NAME], ldap_err2string(rc));
1770               return;
1771             }
1772           
1773           if (group_count >= 1)
1774             {
1775               com_err(whoami, 0, "Object already exists with name %s",
1776                       after[U_NAME]);
1777               return;
1778             }
1779       
1780           linklist_free(group_base);
1781           group_count = 0;
1782           group_base = NULL;
1783         }
1784
1785       if (rc = mr_query("get_user_account_by_login", 1, av,
1786                         save_query_info, save_argv))
1787         {
1788           moira_disconnect();
1789           com_err(whoami, 0, "Unable to create user %s : %s",
1790                   after[U_NAME], error_message(rc));
1791           return;
1792         }
1793
1794       if (rc = user_create(U_END, save_argv, call_args)) 
1795         {
1796           com_err(whoami, 0, "Unable to create user %s : %s",
1797                   after[U_NAME], error_message(rc));
1798           return;
1799         }
1800       
1801       if (callback_rc)
1802         {
1803           moira_disconnect();
1804           com_err(whoami, 0, "Unable to create user %s", after[U_NAME]);
1805           return;
1806         }
1807
1808       return;
1809     }
1810   else
1811     {
1812       if (rc != 0)
1813         return;
1814     }
1815
1816   if (strcmp(before[U_NAME], after[U_NAME]))
1817     {
1818       if ((check_string(before[U_NAME])) && (check_string(after[U_NAME])))
1819         {
1820           com_err(whoami, 0, "changing user %s to %s", 
1821                   before[U_NAME], after[U_NAME]);
1822
1823           if ((rc = user_rename(ldap_handle, dn_path, before[U_NAME], 
1824                                 after[U_NAME])) != LDAP_SUCCESS)
1825             {
1826               return;
1827             }
1828         }
1829     }
1830
1831   com_err(whoami, 0, "updating user %s information", after[U_NAME]);
1832   rc = user_update(ldap_handle, dn_path, after[U_NAME],
1833                    after[U_UID], after[U_MITID], 
1834                    after_user_id, atoi(after[U_STATE]),
1835                    after[U_HOMEDIR], after[U_PROFILEDIR],
1836                    after[U_FIRST], after[U_MIDDLE], after[U_LAST], 
1837                    after[U_SHELL], after[U_CLASS]);
1838
1839   return;
1840 }
1841
1842 int construct_newvalues(LK_ENTRY *linklist_base, int modvalue_count, 
1843                         char *oldValue, char *newValue,
1844                         char ***modvalues, int type)
1845 {
1846   LK_ENTRY    *linklist_ptr;
1847   int         i;
1848   char        *cPtr;
1849   
1850   if (((*modvalues) = calloc(1, 
1851                              (modvalue_count + 1) * sizeof(char *))) == NULL)
1852     {
1853       return(1);
1854     }
1855
1856   for (i = 0; i < (modvalue_count + 1); i++)
1857     (*modvalues)[i] = NULL;
1858
1859   if (modvalue_count != 0)
1860     {
1861       linklist_ptr = linklist_base;
1862       for (i = 0; i < modvalue_count; i++)
1863         {
1864           if ((oldValue != NULL) && (newValue != NULL))
1865             {
1866               if ((cPtr = (char *)strstr(linklist_ptr->value, oldValue))
1867                   != (char *)NULL)
1868                 {
1869                   if (type == REPLACE)
1870                     {
1871                       if (((*modvalues)[i] = calloc(1, strlen(newValue) + 1))
1872                           == NULL)
1873                         return(1);
1874                       memset((*modvalues)[i], '\0', strlen(newValue) + 1);
1875                       strcpy((*modvalues)[i], newValue);
1876                     }
1877                   else
1878                     {
1879                       if (((*modvalues)[i] = calloc(1, 
1880                                         (int)(cPtr - linklist_ptr->value) + 
1881                                                (linklist_ptr->length - 
1882                                                strlen(oldValue)) + 
1883                                                strlen(newValue) + 1)) == NULL)
1884                         return(1);
1885                       memset((*modvalues)[i], '\0', 
1886                              (int)(cPtr - linklist_ptr->value) + 
1887                              (linklist_ptr->length - strlen(oldValue)) + 
1888                              strlen(newValue) + 1);
1889                       memcpy((*modvalues)[i], linklist_ptr->value, 
1890                              (int)(cPtr - linklist_ptr->value));
1891                       strcat((*modvalues)[i], newValue);
1892                       strcat((*modvalues)[i], 
1893                              &linklist_ptr->value[(int)(cPtr - 
1894                                      linklist_ptr->value) + strlen(oldValue)]);
1895                     }
1896                 }
1897               else
1898                 {
1899                   (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1900                   memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1901                   memcpy((*modvalues)[i], linklist_ptr->value,
1902                          linklist_ptr->length);
1903                 }
1904             }
1905         else
1906             {
1907               (*modvalues)[i] = calloc(1, linklist_ptr->length + 1);
1908               memset((*modvalues)[i], '\0', linklist_ptr->length + 1);
1909               memcpy((*modvalues)[i], linklist_ptr->value,
1910                      linklist_ptr->length);
1911             }
1912           linklist_ptr = linklist_ptr->next;
1913         }
1914       (*modvalues)[i] = NULL;
1915     }
1916   return(0);
1917 }
1918
1919
1920 int linklist_build(LDAP *ldap_handle, char *dn_path, char *search_exp, 
1921                    char **attr_array, LK_ENTRY **linklist_base,
1922                    int *linklist_count, unsigned long ScopeType)
1923 {
1924   ULONG       rc;
1925   LDAPMessage *ldap_entry;
1926
1927   rc = 0;
1928   ldap_entry = NULL;
1929   (*linklist_base) = NULL;
1930   (*linklist_count) = 0;
1931
1932   if ((rc = ldap_search_s(ldap_handle, dn_path, ScopeType, 
1933                           search_exp, attr_array, 0, 
1934                           &ldap_entry)) != LDAP_SUCCESS)
1935       {
1936         if (rc != LDAP_SIZELIMIT_EXCEEDED)
1937           return(0);
1938       }
1939
1940   rc = retrieve_entries(ldap_handle, ldap_entry, linklist_base, 
1941                         linklist_count);
1942
1943   ldap_msgfree(ldap_entry);
1944   return(rc);
1945 }
1946
1947 int retrieve_entries(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
1948                      LK_ENTRY **linklist_base, int *linklist_count)
1949 {
1950   char        distinguished_name[1024];
1951   LK_ENTRY    *linklist_ptr;
1952   int         rc;
1953
1954   if ((ldap_entry = ldap_first_entry(ldap_handle, ldap_entry)) == NULL)
1955     return(0);
1956   
1957   memset(distinguished_name, '\0', sizeof(distinguished_name));
1958   get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1959
1960   if ((rc = retrieve_attributes(ldap_handle, ldap_entry, distinguished_name,
1961                                 linklist_base)) != 0)
1962     return(rc);
1963
1964   while ((ldap_entry = ldap_next_entry(ldap_handle, ldap_entry)) != NULL)
1965     {
1966       memset(distinguished_name, '\0', sizeof(distinguished_name));
1967       get_distinguished_name(ldap_handle, ldap_entry, distinguished_name);
1968       
1969       if ((rc = retrieve_attributes(ldap_handle, ldap_entry, 
1970                                     distinguished_name, linklist_base)) != 0)
1971         return(rc);
1972     }
1973
1974   linklist_ptr = (*linklist_base);
1975   (*linklist_count) = 0;
1976
1977   while (linklist_ptr != NULL)
1978     {
1979       ++(*linklist_count);
1980       linklist_ptr = linklist_ptr->next;
1981     }
1982
1983   return(0);
1984 }
1985
1986 int retrieve_attributes(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
1987                         char *distinguished_name, LK_ENTRY **linklist_current)
1988 {
1989   char        *Attribute;
1990   BerElement  *ptr;
1991
1992   ptr = NULL;
1993
1994   if ((Attribute = ldap_first_attribute(ldap_handle, ldap_entry, 
1995                                         &ptr)) != NULL)
1996     {
1997       retrieve_values(ldap_handle, ldap_entry, Attribute, distinguished_name,
1998                       linklist_current);
1999       ldap_memfree(Attribute);
2000       while ((Attribute = ldap_next_attribute(ldap_handle, ldap_entry, 
2001                                               ptr)) != NULL)
2002         {
2003           retrieve_values(ldap_handle, ldap_entry, Attribute,
2004                           distinguished_name, linklist_current);
2005           ldap_memfree(Attribute);
2006         }
2007     }
2008
2009   ldap_ber_free(ptr, 0);
2010
2011   return(0);
2012 }
2013
2014 int retrieve_values(LDAP *ldap_handle, LDAPMessage *ldap_entry,
2015                     char *Attribute, char *distinguished_name,
2016                     LK_ENTRY **linklist_current)
2017 {
2018   char        **str_value;
2019   char        temp[256];
2020   void        **Ptr;
2021   int         use_bervalue;
2022   LK_ENTRY    *linklist_previous;
2023   LDAP_BERVAL **ber_value;
2024   DWORD       ber_length;
2025
2026 #ifdef LDAP_DEBUG
2027   SID         *sid;
2028   GUID        *guid;
2029   int         i;
2030   int         intValue;
2031   DWORD       *subauth;
2032   SID_IDENTIFIER_AUTHORITY    *sid_auth;
2033   unsigned char   *subauth_count;
2034 #endif /*LDAP_BEGUG*/
2035
2036   use_bervalue = 0;
2037   memset(temp, '\0', sizeof(temp));
2038
2039   if ((!strcmp(Attribute, "objectSid")) ||
2040       (!strcmp(Attribute, "objectGUID")))
2041     use_bervalue = 1;
2042   
2043   if (use_bervalue)
2044     {
2045       ber_value = ldap_get_values_len(ldap_handle, ldap_entry, Attribute);
2046       Ptr = (void **)ber_value;
2047       str_value = NULL;
2048     }
2049   else
2050     {
2051       str_value = ldap_get_values(ldap_handle, ldap_entry, Attribute);
2052       Ptr = (void **)str_value;
2053       ber_value = NULL;
2054     }
2055
2056   if (Ptr != NULL)
2057     {
2058       for (; *Ptr; Ptr++) 
2059         {
2060           if ((linklist_previous = calloc(1, sizeof(LK_ENTRY))) == NULL)
2061             return(1);
2062
2063           memset(linklist_previous, '\0', sizeof(LK_ENTRY));
2064           linklist_previous->next = (*linklist_current);
2065           (*linklist_current) = linklist_previous;
2066           
2067           if (((*linklist_current)->attribute = calloc(1, 
2068                                               strlen(Attribute) + 1)) == NULL)
2069             return(1);
2070
2071           memset((*linklist_current)->attribute, '\0', strlen(Attribute) + 1);
2072           strcpy((*linklist_current)->attribute, Attribute);
2073
2074           if (use_bervalue)
2075             {
2076               ber_length = (*(LDAP_BERVAL **)Ptr)->bv_len;
2077
2078               if (((*linklist_current)->value = calloc(1, ber_length)) == NULL)
2079                 return(1);
2080
2081               memset((*linklist_current)->value, '\0', ber_length);
2082               memcpy((*linklist_current)->value, 
2083                      (*(LDAP_BERVAL **)Ptr)->bv_val, ber_length);
2084               (*linklist_current)->length = ber_length;
2085             }
2086           else
2087             {
2088               if (((*linklist_current)->value = calloc(1, 
2089                                                     strlen(*Ptr) + 1)) == NULL)
2090                 return(1);
2091
2092               memset((*linklist_current)->value, '\0', strlen(*Ptr) + 1);
2093               (*linklist_current)->length = strlen(*Ptr);
2094               strcpy((*linklist_current)->value, *Ptr);
2095             }
2096
2097           (*linklist_current)->ber_value = use_bervalue;
2098
2099           if (((*linklist_current)->dn = calloc(1, 
2100                                       strlen(distinguished_name) + 1)) == NULL)
2101             return(1);
2102
2103           memset((*linklist_current)->dn, '\0', 
2104                  strlen(distinguished_name) + 1);
2105           strcpy((*linklist_current)->dn, distinguished_name);
2106
2107 #ifdef LDAP_DEBUG
2108           if (!strcmp(Attribute, "objectGUID"))
2109             {
2110               guid = (GUID *)((*linklist_current)->value);
2111               sprintf(temp, 
2112                       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 
2113                       guid->Data1, guid->Data2, guid->Data3, 
2114                       guid->Data4[0], guid->Data4[1], guid->Data4[2], 
2115                       guid->Data4[3], guid->Data4[4], guid->Data4[5], 
2116                       guid->Data4[6], guid->Data4[7]);
2117               print_to_screen("     %20s : {%s}\n", Attribute, temp);
2118             }
2119           else if (!strcmp(Attribute, "objectSid"))
2120             {
2121               sid = (SID *)((*(LDAP_BERVAL **)Ptr)->bv_val);
2122
2123 #ifdef _WIN32
2124               print_to_screen("        Revision = %d\n", sid->Revision);
2125               print_to_screen("        SID Identifier Authority:\n");
2126               sid_auth = &sid->IdentifierAuthority;
2127               if (sid_auth->Value[0])
2128                 print_to_screen("            SECURITY_NULL_SID_AUTHORITY\n");
2129               else if (sid_auth->Value[1])
2130                 print_to_screen("            SECURITY_WORLD_SID_AUTHORITY\n");
2131               else if (sid_auth->Value[2])
2132                 print_to_screen("            SECURITY_LOCAL_SID_AUTHORITY\n");
2133               else if (sid_auth->Value[3])
2134                 print_to_screen("           SECURITY_CREATOR_SID_AUTHORITY\n");
2135               else if (sid_auth->Value[5])
2136                 print_to_screen("            SECURITY_NT_AUTHORITY\n");
2137               else
2138                 print_to_screen("            UNKNOWN SID AUTHORITY\n");
2139               subauth_count = GetSidSubAuthorityCount(sid);
2140               print_to_screen("        SidSubAuthorityCount = %d\n", 
2141                               *subauth_count);
2142               print_to_screen("        SidSubAuthority:\n");
2143               for (i = 0; i < *subauth_count; i++)
2144                 {
2145                   if ((subauth = GetSidSubAuthority(sid, i)) != NULL)
2146                     print_to_screen("            %u\n", *subauth);
2147                 }
2148 #endif
2149             }
2150           else if ((!memcmp(Attribute, "userAccountControl", 
2151                             strlen("userAccountControl"))) ||
2152                    (!memcmp(Attribute, "sAMAccountType", 
2153                             strlen("sAmAccountType"))))
2154             {
2155               intValue = atoi(*Ptr);
2156               print_to_screen("     %20s : %ld\n",Attribute, intValue);
2157
2158               if (!memcmp(Attribute, "userAccountControl", 
2159                           strlen("userAccountControl")))
2160                 {
2161                   if (intValue & UF_ACCOUNTDISABLE)
2162                     print_to_screen("     %20s :    %s\n", 
2163                                     "", "Account disabled");
2164                   else
2165                     print_to_screen("     %20s :    %s\n", 
2166                                     "", "Account active");
2167                   if (intValue & UF_HOMEDIR_REQUIRED)
2168                     print_to_screen("     %20s :    %s\n", 
2169                                     "", "Home directory required");
2170                   if (intValue & UF_LOCKOUT)
2171                     print_to_screen("     %20s :    %s\n", 
2172                                     "", "Account locked out");
2173                   if (intValue & UF_PASSWD_NOTREQD)
2174                     print_to_screen("     %20s :    %s\n", 
2175                                     "", "No password required");
2176                   if (intValue & UF_PASSWD_CANT_CHANGE)
2177                     print_to_screen("     %20s :    %s\n",
2178                                     "", "Cannot change password");
2179                   if (intValue & UF_TEMP_DUPLICATE_ACCOUNT)
2180                     print_to_screen("     %20s :    %s\n", 
2181                                     "", "Temp duplicate account");
2182                   if (intValue & UF_NORMAL_ACCOUNT)
2183                     print_to_screen("     %20s :    %s\n", 
2184                                     "", "Normal account");
2185                   if (intValue & UF_INTERDOMAIN_TRUST_ACCOUNT)
2186                     print_to_screen("     %20s :    %s\n", 
2187                                     "", "Interdomain trust account");
2188                   if (intValue & UF_WORKSTATION_TRUST_ACCOUNT)
2189                     print_to_screen("     %20s :    %s\n", 
2190                                     "", "Workstation trust account");
2191                   if (intValue & UF_SERVER_TRUST_ACCOUNT)
2192                     print_to_screen("     %20s :    %s\n", 
2193                                     "", "Server trust account");
2194                 }
2195             }
2196           else
2197             {
2198               print_to_screen("     %20s : %s\n",Attribute, *Ptr);
2199             }
2200 #endif /*LDAP_DEBUG*/
2201         }
2202
2203       if (str_value != NULL)
2204         ldap_value_free(str_value);
2205
2206       if (ber_value != NULL)
2207         ldap_value_free_len(ber_value);
2208     }
2209
2210   (*linklist_current) = linklist_previous;
2211
2212   return(0);
2213 }
2214
2215 int moira_connect(void)
2216 {
2217   long    rc;
2218   char    HostName[64];
2219
2220   if (!mr_connections++)
2221     {
2222
2223 #ifdef _WIN32
2224       memset(HostName, '\0', sizeof(HostName));
2225       strcpy(HostName, "ttsp");
2226       rc = mr_connect_cl(HostName, "ldap.incr", QUERY_VERSION, 1);
2227 #else
2228       struct utsname uts;
2229       uname(&uts);
2230       rc = mr_connect_cl(uts.nodename, "ldap.incr", QUERY_VERSION, 1);
2231 #endif /*WIN32*/
2232
2233       return rc;
2234     }
2235
2236   return 0;
2237 }
2238
2239 int check_winad(void)
2240 {
2241   int i;
2242   
2243   for (i = 0; file_exists(STOP_FILE); i++)
2244     {
2245       if (i > 30)
2246         {
2247           critical_alert("AD incremental",
2248                          "WINAD incremental failed (%s exists): %s",
2249                          STOP_FILE, tbl_buf);
2250           return(1);
2251         }
2252
2253       sleep(60);
2254     }
2255
2256   return(0);
2257 }
2258
2259 int moira_disconnect(void)
2260 {
2261
2262   if (!--mr_connections)
2263     {
2264       mr_disconnect();
2265     }
2266
2267   return 0;
2268 }
2269
2270 void get_distinguished_name(LDAP *ldap_handle, LDAPMessage *ldap_entry, 
2271                             char *distinguished_name)
2272 {
2273   char    *CName;
2274   
2275   CName = ldap_get_dn(ldap_handle, ldap_entry);
2276
2277   if (CName == NULL)
2278     return;
2279
2280   strcpy(distinguished_name, CName);
2281   ldap_memfree(CName);
2282 }
2283
2284 int linklist_create_entry(char *attribute, char *value, 
2285                           LK_ENTRY **linklist_entry)
2286 {
2287   (*linklist_entry) = calloc(1, sizeof(LK_ENTRY));
2288
2289   if (!(*linklist_entry))
2290     {
2291       return(1);
2292     }
2293
2294   memset((*linklist_entry), '\0', sizeof(LK_ENTRY));
2295   (*linklist_entry)->attribute = calloc(1, strlen(attribute) + 1);
2296   memset((*linklist_entry)->attribute, '\0', strlen(attribute) + 1);
2297   strcpy((*linklist_entry)->attribute, attribute);
2298   (*linklist_entry)->value = calloc(1, strlen(value) + 1);
2299   memset((*linklist_entry)->value, '\0', strlen(value) + 1);
2300   strcpy((*linklist_entry)->value, value);
2301   (*linklist_entry)->length = strlen(value);
2302   (*linklist_entry)->next = NULL;
2303
2304   return(0);
2305 }
2306
2307 void print_to_screen(const char *fmt, ...)
2308 {
2309   va_list pvar;
2310
2311   va_start(pvar, fmt);
2312   vfprintf(stderr, fmt, pvar);
2313   fflush(stderr);
2314   va_end(pvar);
2315 }
2316
2317 int get_group_membership(char *group_membership, char *group_ou, 
2318                          int *security_flag, char **av)
2319 {
2320   int  maillist_flag;
2321   int  group_flag;
2322   
2323   maillist_flag = atoi(av[L_MAILLIST]);
2324   group_flag = atoi(av[L_GROUP]);
2325
2326   if (security_flag != NULL)
2327     (*security_flag) = 0;
2328   
2329   if ((maillist_flag) && (group_flag))
2330     {
2331       if (group_membership != NULL)
2332         group_membership[0] = 'B';
2333
2334       if (security_flag != NULL)
2335         (*security_flag) = 1;
2336
2337       if (group_ou != NULL)
2338         strcpy(group_ou, group_ou_both);
2339     }
2340   else if ((!maillist_flag) && (group_flag))
2341     {
2342       if (group_membership != NULL)
2343         group_membership[0] = 'S';
2344
2345       if (security_flag != NULL)
2346         (*security_flag) = 1;
2347
2348       if (group_ou != NULL)
2349         strcpy(group_ou, group_ou_security);
2350     }
2351   else if ((maillist_flag) && (!group_flag))
2352     {
2353       if (group_membership != NULL)
2354         group_membership[0] = 'D';
2355
2356       if (group_ou != NULL)
2357         strcpy(group_ou, group_ou_distribution);
2358     }
2359   else
2360     {
2361       if (group_membership != NULL)
2362         group_membership[0] = 'N';
2363
2364       if (group_ou != NULL)
2365         strcpy(group_ou, group_ou_neither);
2366     }
2367
2368   return(0);
2369 }
2370
2371 int group_rename(LDAP *ldap_handle, char *dn_path, 
2372                  char *before_group_name, char *before_group_membership, 
2373                  char *before_group_ou, int before_security_flag, 
2374                  char *before_desc, char *after_group_name, 
2375                  char *after_group_membership, char *after_group_ou, 
2376                  int after_security_flag, char *after_desc,
2377                  char *MoiraId, char *filter, char *maillist)
2378 {
2379   LDAPMod   *mods[20];
2380   char      old_dn[512];
2381   char      new_dn[512];
2382   char      new_dn_path[512];
2383   char      sam_name[256];
2384   char      mail[256];
2385   char      mail_nickname[256];
2386   char      proxy_address[256];
2387   char      address_book[256];
2388   char      *attr_array[3];
2389   char      *mitMoiraId_v[] = {NULL, NULL};
2390   char      *name_v[] = {NULL, NULL};
2391   char      *samAccountName_v[] = {NULL, NULL};
2392   char      *groupTypeControl_v[] = {NULL, NULL};
2393   char      *mail_v[] = {NULL, NULL};
2394   char      *proxy_address_v[] = {NULL, NULL};
2395   char      *mail_nickname_v[] = {NULL, NULL};
2396   char      *report_to_originator_v[] = {NULL, NULL};
2397   char      *address_book_v[] = {NULL, NULL};
2398   char      *legacy_exchange_dn_v[] = {NULL, NULL};
2399   u_int     groupTypeControl;
2400   char      groupTypeControlStr[80];
2401   char      contact_mail[256];
2402   int       n;
2403   int       i;
2404   int       rc;
2405   LK_ENTRY  *group_base;
2406   int       group_count;
2407   int       MailDisabled = 0;
2408
2409   if(UseGroupUniversal)
2410     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2411   else
2412     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2413      
2414   if (!check_string(before_group_name))
2415     {
2416       com_err(whoami, 0, 
2417               "Unable to process invalid LDAP list name %s", 
2418               before_group_name);
2419       return(AD_INVALID_NAME);
2420     }
2421
2422   if (!check_string(after_group_name))
2423     {
2424       com_err(whoami, 0, 
2425               "Unable to process invalid LDAP list name %s", after_group_name);
2426       return(AD_INVALID_NAME);
2427     }
2428
2429   if (Exchange) 
2430     {
2431       if(atoi(maillist)) 
2432         {
2433           group_count = 0;
2434           group_base = NULL;
2435           
2436           sprintf(filter, "(&(objectClass=user)(cn=%s))", after_group_name);
2437           attr_array[0] = "cn";
2438           attr_array[1] = NULL;
2439
2440           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
2441                                    &group_base, &group_count,
2442                                    LDAP_SCOPE_SUBTREE)) != 0)
2443           {
2444             com_err(whoami, 0, "Unable to process group %s : %s",
2445                     after_group_name, ldap_err2string(rc));
2446             return(rc);
2447           }
2448           
2449           if (group_count)
2450             {
2451               com_err(whoami, 0, "Object already exists with name %s",
2452                       after_group_name);
2453               MailDisabled++;
2454             }
2455         
2456           linklist_free(group_base);
2457           group_base = NULL;
2458           group_count = 0;
2459         }
2460     }
2461
2462   group_count = 0;
2463   group_base = NULL;
2464
2465   if (rc = ad_get_group(ldap_handle, dn_path, before_group_name, 
2466                         before_group_membership, 
2467                         MoiraId, "samAccountName", &group_base, 
2468                         &group_count, filter))
2469     return(rc);
2470
2471   if (group_count == 0)
2472     {
2473       return(AD_NO_GROUPS_FOUND);
2474     }
2475
2476   if (group_count != 1)
2477     {
2478       com_err(whoami, 0, "Unable to process multiple groups with "
2479               "MoiraId = %s exist in the AD", MoiraId);
2480       return(AD_MULTIPLE_GROUPS_FOUND);
2481     }
2482
2483   strcpy(old_dn, group_base->dn);
2484
2485   linklist_free(group_base);
2486   group_base = NULL;
2487   group_count = 0;
2488   attr_array[0] = "sAMAccountName";
2489   attr_array[1] = NULL;
2490
2491   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
2492                            &group_base, &group_count, 
2493                            LDAP_SCOPE_SUBTREE)) != 0)
2494     {
2495       com_err(whoami, 0, "Unable to get list %s dn : %s",
2496               after_group_name, ldap_err2string(rc));
2497       return(rc);
2498     }
2499
2500   if (group_count != 1)
2501     {
2502       com_err(whoami, 0,
2503               "Unable to get sAMAccountName for group %s", 
2504               before_group_name);
2505       return(AD_LDAP_FAILURE);
2506     }
2507   
2508   strcpy(sam_name, group_base->value);
2509   linklist_free(group_base);
2510   group_base = NULL;
2511   group_count = 0;
2512   
2513   sprintf(new_dn_path, "%s,%s", after_group_ou, dn_path);
2514   sprintf(new_dn, "cn=%s", after_group_name);
2515   sprintf(mail, "%s@%s", after_group_name, lowercase(ldap_domain));
2516   sprintf(contact_mail, "%s@mit.edu", after_group_name); 
2517   sprintf(proxy_address, "SMTP:%s@%s", after_group_name, 
2518           lowercase(ldap_domain));
2519   sprintf(mail_nickname, "%s", after_group_name);
2520
2521   com_err(whoami, 0, "Old %s New %s,%s", old_dn, new_dn, new_dn_path);
2522
2523   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, new_dn_path,
2524                               TRUE, NULL, NULL)) != LDAP_SUCCESS)
2525     {
2526       com_err(whoami, 0, "Unable to rename list from %s to %s : %s",
2527               before_group_name, after_group_name, ldap_err2string(rc));
2528       return(rc);
2529     }
2530   
2531   name_v[0] = after_group_name;
2532
2533   if (!strncmp(&sam_name[strlen(sam_name) - strlen(group_suffix)], 
2534                group_suffix, strlen(group_suffix)))
2535     {
2536       sprintf(sam_name, "%s%s", after_group_name, group_suffix);
2537     }
2538   else
2539     {
2540       com_err(whoami, 0, 
2541               "Unable to rename list from %s to %s : sAMAccountName not found",
2542               before_group_name, after_group_name);
2543       return(rc);
2544     }
2545
2546   samAccountName_v[0] = sam_name;
2547
2548   if (after_security_flag)
2549     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2550
2551   sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2552   groupTypeControl_v[0] = groupTypeControlStr;
2553   mitMoiraId_v[0] = MoiraId;
2554
2555   sprintf(new_dn, "cn=%s,%s,%s", after_group_name, after_group_ou, dn_path);
2556   rc = attribute_update(ldap_handle, new_dn, after_desc, "description", 
2557                         after_group_name);
2558   n = 0;
2559   ADD_ATTR("samAccountName", samAccountName_v, LDAP_MOD_REPLACE);
2560   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
2561   ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2562   ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_REPLACE);
2563
2564   if (Exchange)
2565     {
2566       if(atoi(maillist) && !MailDisabled && email_isvalid(mail)) 
2567         {
2568           mail_nickname_v[0] = mail_nickname;
2569           proxy_address_v[0] = proxy_address;
2570           mail_v[0] = mail;
2571           report_to_originator_v[0] = "TRUE";
2572
2573           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2574           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2575           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2576           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2577                    LDAP_MOD_REPLACE);
2578         } 
2579       else 
2580         {
2581           mail_nickname_v[0] = NULL;
2582           proxy_address_v[0] = NULL;
2583           mail_v[0] = NULL;
2584           legacy_exchange_dn_v[0] = NULL;
2585           address_book_v[0] = NULL;
2586           report_to_originator_v[0] = NULL;
2587
2588           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2589           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2590           ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2591           ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, LDAP_MOD_REPLACE);
2592           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2593           ADD_ATTR("reportToOriginator", report_to_originator_v, 
2594                    LDAP_MOD_REPLACE);
2595         }
2596     }
2597   else
2598     {
2599       if(atoi(maillist) && email_isvalid(contact_mail)) 
2600         {
2601           mail_v[0] = contact_mail;
2602           ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2603         }
2604     }
2605
2606   mods[n] = NULL;
2607
2608   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
2609     {
2610       com_err(whoami, 0, 
2611               "Unable to modify list data for %s after renaming: %s",
2612               after_group_name, ldap_err2string(rc));
2613     }
2614
2615   for (i = 0; i < n; i++)
2616     free(mods[i]);
2617
2618   return(rc);
2619 }
2620
2621 int group_create(int ac, char **av, void *ptr)
2622 {
2623   LDAPMod *mods[20];
2624   char new_dn[256];
2625   char group_ou[256];
2626   char new_group_name[256];
2627   char sam_group_name[256];
2628   char cn_group_name[256];
2629   char mail[256];
2630   char contact_mail[256];
2631   char mail_nickname[256];
2632   char proxy_address[256];
2633   char address_book[256];
2634   char *cn_v[] = {NULL, NULL};
2635   char *objectClass_v[] = {"top", "group", NULL};
2636   char *objectClass_ldap_v[] = {"top", "microsoftComTop", "securityPrincipal",
2637                                 "group", "mailRecipient", NULL};
2638   char info[256];
2639   char *samAccountName_v[] = {NULL, NULL};
2640   char *altSecurityIdentities_v[] = {NULL, NULL};
2641   char *member_v[] = {NULL, NULL};
2642   char *name_v[] = {NULL, NULL};
2643   char *desc_v[] = {NULL, NULL};
2644   char *info_v[] = {NULL, NULL};
2645   char *mitMoiraId_v[] = {NULL, NULL};
2646   char *mitMoiraPublic_v[] = {NULL, NULL};
2647   char *mitMoiraHidden_v[] = {NULL, NULL};
2648   char *groupTypeControl_v[] = {NULL, NULL};
2649   char *mail_v[] = {NULL, NULL};
2650   char *proxy_address_v[] = {NULL, NULL};
2651   char *mail_nickname_v[] = {NULL, NULL};
2652   char *report_to_originator_v[] = {NULL, NULL};
2653   char *address_book_v[] = {NULL, NULL};
2654   char *legacy_exchange_dn_v[] = {NULL, NULL};
2655   char *gidNumber_v[] = {NULL, NULL};
2656   char groupTypeControlStr[80];
2657   char group_membership[1];
2658   int  i;
2659   int  security_flag;
2660   u_int groupTypeControl;
2661   int  n;
2662   int  rc;
2663   int  updateGroup;
2664   int  MailDisabled = 0;
2665   char **call_args;
2666   LK_ENTRY *group_base;
2667   int  group_count;
2668   char filter[1024];
2669   char *attr_array[3];
2670   
2671   call_args = ptr;
2672
2673   if(UseGroupUniversal)
2674     groupTypeControl = ADS_GROUP_TYPE_UNIVERSAL_GROUP;
2675   else 
2676     groupTypeControl = ADS_GROUP_TYPE_GLOBAL_GROUP;
2677
2678   if (!check_string(av[L_NAME]))
2679     {
2680       com_err(whoami, 0, "Unable to process invalid LDAP list name %s", 
2681               av[L_NAME]);
2682       return(AD_INVALID_NAME);
2683     }
2684
2685   updateGroup = (int)call_args[4];
2686   memset(group_ou, 0, sizeof(group_ou));
2687   memset(group_membership, 0, sizeof(group_membership));
2688   security_flag = 0;
2689
2690   get_group_membership(group_membership, group_ou, &security_flag, av);
2691
2692   strcpy(new_group_name, av[L_NAME]);
2693   sprintf(new_dn, "cn=%s,%s,%s", new_group_name, group_ou, call_args[1]);
2694   sprintf(contact_mail, "%s@mit.edu", av[L_NAME]);
2695   sprintf(mail, "%s@%s", av[L_NAME], lowercase(ldap_domain));
2696   sprintf(mail_nickname, "%s", av[L_NAME]);
2697
2698   if (security_flag)
2699     groupTypeControl |= ADS_GROUP_TYPE_SECURITY_ENABLED;
2700   
2701   sprintf(sam_group_name, "%s%s", av[L_NAME], group_suffix);
2702
2703   if (!updateGroup)
2704     {
2705       sprintf(groupTypeControlStr, "%ld", groupTypeControl);
2706       groupTypeControl_v[0] = groupTypeControlStr;
2707
2708       strcpy(cn_group_name, av[L_NAME]);
2709       
2710       samAccountName_v[0] = sam_group_name;
2711       name_v[0] = new_group_name;
2712       cn_v[0] = new_group_name;
2713
2714       n = 0;
2715       ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
2716
2717       if(ActiveDirectory)
2718         {
2719           ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
2720         } 
2721       else
2722         {
2723           mitMoiraPublic_v[0] = av[L_PUBLIC];
2724           mitMoiraHidden_v[0] = av[L_HIDDEN];
2725           ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
2726           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_ADD);
2727           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_ADD);
2728           
2729           if(atoi(av[L_GROUP])) 
2730             {
2731               gidNumber_v[0] = av[L_GID];
2732               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_ADD);
2733             }
2734         }
2735
2736       ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
2737       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
2738       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
2739
2740       if (Exchange)
2741         {
2742           if(atoi(av[L_MAILLIST])) 
2743             {
2744               group_count = 0;
2745               group_base = NULL;
2746               
2747               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2748               attr_array[0] = "cn";
2749               attr_array[1] = NULL;
2750               
2751               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2752                                        filter, attr_array, &group_base, 
2753                                        &group_count,
2754                                        LDAP_SCOPE_SUBTREE)) != 0)
2755                 {
2756                   com_err(whoami, 0, "Unable to process group %s : %s",
2757                           av[L_NAME], ldap_err2string(rc));
2758                   return(rc);
2759                 }
2760               
2761               if (group_count)
2762                 {
2763                   com_err(whoami, 0, "Object already exists with name %s",
2764                           av[L_NAME]);
2765                   MailDisabled++;
2766                 }
2767         
2768               linklist_free(group_base);
2769               group_base = NULL;
2770               group_count = 0;
2771             }
2772           
2773           if(atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2774             {
2775               mail_nickname_v[0] = mail_nickname;
2776               report_to_originator_v[0] = "TRUE";
2777
2778               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
2779               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2780                        LDAP_MOD_ADD);
2781             }
2782         }
2783       else
2784         {
2785           if(atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2786             {
2787               mail_v[0] = contact_mail;
2788               ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
2789             }
2790         }
2791       
2792       if (strlen(av[L_DESC]) != 0)
2793         {
2794           desc_v[0] = av[L_DESC];
2795           ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
2796         }
2797       
2798       ADD_ATTR("groupType", groupTypeControl_v, LDAP_MOD_ADD);
2799
2800       if (strlen(av[L_ACE_NAME]) != 0)
2801         {
2802           sprintf(info, "The Administrator of this list is: %s", 
2803                   av[L_ACE_NAME]);
2804           info_v[0] = info;
2805           ADD_ATTR("info", info_v, LDAP_MOD_ADD);
2806         }
2807
2808       if (strlen(call_args[5]) != 0)
2809         {
2810           mitMoiraId_v[0] = call_args[5];
2811           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD);
2812         }
2813           
2814       mods[n] = NULL;
2815       
2816       rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
2817       
2818       for (i = 0; i < n; i++)
2819         free(mods[i]);
2820
2821       if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
2822         {
2823           com_err(whoami, 0, "Unable to create list %s in AD : %s",
2824                   av[L_NAME], ldap_err2string(rc));
2825           callback_rc = rc;
2826           return(rc);
2827         }
2828     }
2829
2830   if ((rc == LDAP_ALREADY_EXISTS) || (updateGroup))
2831     {
2832       rc = attribute_update((LDAP *)call_args[0], new_dn, av[L_DESC], 
2833                             "description", av[L_NAME]);
2834       sprintf(info, "The Administrator of this list is: %s", av[L_ACE_NAME]);
2835
2836       rc = attribute_update((LDAP *)call_args[0], new_dn, info, "info", 
2837                                 av[L_NAME]);
2838
2839       n = 0;
2840
2841       if (strlen(call_args[5]) != 0)
2842         {
2843           mitMoiraId_v[0] = call_args[5];
2844           ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
2845         }
2846
2847       if (!(atoi(av[L_ACTIVE])))
2848         {
2849           member_v[0] = NULL;
2850           ADD_ATTR("member", member_v, LDAP_MOD_REPLACE);
2851         }
2852    
2853       if (!ActiveDirectory) 
2854         {
2855           mitMoiraPublic_v[0] = av[L_PUBLIC];
2856           mitMoiraHidden_v[0] = av[L_HIDDEN];
2857           ADD_ATTR("mitMoiraPublic", mitMoiraPublic_v, LDAP_MOD_REPLACE);
2858           ADD_ATTR("mitMoiraHidden", mitMoiraHidden_v, LDAP_MOD_REPLACE);
2859
2860           if(atoi(av[L_GROUP])) 
2861             {
2862               gidNumber_v[0] = av[L_GID];
2863               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2864             }
2865           else
2866             {
2867               ADD_ATTR("gidNumber", gidNumber_v, LDAP_MOD_REPLACE);
2868             }
2869         }
2870
2871       if (Exchange)
2872         {
2873           if(atoi(av[L_MAILLIST])) 
2874             {
2875               group_count = 0;
2876               group_base = NULL;
2877               
2878               sprintf(filter, "(&(objectClass=user)(cn=%s))", av[L_NAME]);
2879               attr_array[0] = "cn";
2880               attr_array[1] = NULL;
2881               
2882               if ((rc = linklist_build((LDAP *)call_args[0], call_args[1], 
2883                                        filter, attr_array, &group_base, 
2884                                        &group_count,
2885                                        LDAP_SCOPE_SUBTREE)) != 0)
2886                 {
2887                   com_err(whoami, 0, "Unable to process group %s : %s",
2888                           av[L_NAME], ldap_err2string(rc));
2889                   return(rc);
2890                 }
2891               
2892               if (group_count)
2893                 {
2894                   com_err(whoami, 0, "Object already exists with name %s",
2895                           av[L_NAME]);
2896                   MailDisabled++;
2897                 }
2898               
2899               linklist_free(group_base);
2900               group_base = NULL;
2901               group_count = 0;
2902             }
2903
2904           if (atoi(av[L_MAILLIST]) && !MailDisabled && email_isvalid(mail)) 
2905             {
2906               mail_nickname_v[0] = mail_nickname;
2907               report_to_originator_v[0] = "TRUE";
2908
2909               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2910               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2911                        LDAP_MOD_REPLACE);
2912             }
2913           else 
2914             {
2915               mail_v[0] = NULL;
2916               mail_nickname_v[0] = NULL;
2917               proxy_address_v[0] = NULL;
2918               legacy_exchange_dn_v[0] = NULL;
2919               address_book_v[0] = NULL;
2920               report_to_originator_v[0] = NULL;
2921
2922               ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
2923               ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
2924               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2925               ADD_ATTR("legacyExchangeDN", legacy_exchange_dn_v, 
2926                        LDAP_MOD_REPLACE);
2927               ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
2928               ADD_ATTR("reportToOriginator", report_to_originator_v, 
2929                        LDAP_MOD_REPLACE);
2930             }
2931         }
2932       else
2933         {
2934           if (atoi(av[L_MAILLIST]) && email_isvalid(contact_mail)) 
2935             {
2936               mail_v[0] = contact_mail;
2937               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2938             }
2939           else
2940             {
2941               mail_v[0] = NULL;
2942               ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
2943             }
2944         }
2945    
2946       mods[n] = NULL;
2947       rc = LDAP_SUCCESS;
2948
2949       if (n != 0)
2950         {
2951           rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
2952
2953           for (i = 0; i < n; i++)
2954               free(mods[i]);
2955
2956           if (rc != LDAP_SUCCESS)
2957             {
2958               com_err(whoami, 0, "Unable to update list %s in AD : %s",
2959                       av[L_NAME], ldap_err2string(rc));
2960               callback_rc = rc;
2961               return(rc);
2962             }
2963         }
2964     }
2965
2966   ProcessGroupSecurity((LDAP *)call_args[0], call_args[1], av[L_NAME], 
2967                        atoi(av[L_HIDDEN]),  av[L_ACE_TYPE], av[L_ACE_NAME]);
2968
2969   return(LDAP_SUCCESS);
2970 }
2971
2972 int ProcessGroupSecurity(LDAP *ldap_handle, char *dn_path, 
2973                          char *TargetGroupName, int HiddenGroup, 
2974                          char *AceType, char *AceName)
2975 {
2976   char          filter_exp[1024];
2977   char          *attr_array[5];
2978   char          search_path[512];
2979   char          root_ou[128];
2980   char          TemplateDn[512];
2981   char          TemplateSamName[128];
2982   char          TargetDn[512];
2983   char          TargetSamName[128];
2984   char          AceSamAccountName[128];
2985   char          AceDn[256];
2986   unsigned char AceSid[128];
2987   unsigned char UserTemplateSid[128];
2988   char          acBERBuf[N_SD_BER_BYTES];
2989   char          GroupSecurityTemplate[256];
2990   char          hide_addres_lists[256];
2991   char          address_book[256];
2992   char          *hide_address_lists_v[] = {NULL, NULL};
2993   char          *address_book_v[] = {NULL, NULL};
2994   char          *owner_v[] = {NULL, NULL};
2995   int           AceSidCount;
2996   int           UserTemplateSidCount;
2997   int           group_count;
2998   int           n;
2999   int           i;
3000   int           rc;
3001   int           nVal;
3002   ULONG         dwInfo;
3003   int           array_count = 0;
3004   LDAPMod       *mods[20];
3005   LK_ENTRY      *group_base;
3006   LDAP_BERVAL   **ppsValues;
3007   LDAPControl sControl = {"1.2.840.113556.1.4.801",
3008                           { N_SD_BER_BYTES, acBERBuf },
3009                           TRUE
3010                          };
3011   LDAPControl *apsServerControls[] = {&sControl, NULL};
3012   LDAPMessage *psMsg;
3013
3014   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | 
3015     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
3016   BEREncodeSecurityBits(dwInfo, acBERBuf);
3017
3018   sprintf(search_path, "%s,%s", group_ou_root, dn_path);
3019   sprintf(filter_exp, "(sAMAccountName=%s%s)", TargetGroupName, group_suffix);
3020   attr_array[0] = "sAMAccountName";
3021   attr_array[1] = NULL;
3022   group_count = 0;
3023   group_base = NULL;
3024
3025   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3026                            &group_base, &group_count, 
3027                            LDAP_SCOPE_SUBTREE) != 0))
3028     return(1);
3029
3030   if (group_count != 1)
3031     {
3032       linklist_free(group_base);
3033       return(1);
3034     }
3035
3036   strcpy(TargetDn, group_base->dn);
3037   strcpy(TargetSamName, group_base->value);
3038   linklist_free(group_base);
3039   group_base = NULL;
3040   group_count = 0;
3041
3042   UserTemplateSidCount = 0;
3043   memset(UserTemplateSid, '\0', sizeof(UserTemplateSid));
3044   memset(AceSamAccountName, '\0', sizeof(AceSamAccountName));
3045   memset(AceSid, '\0', sizeof(AceSid));
3046   AceSidCount = 0;
3047   group_base = NULL;
3048   group_count = 0;
3049
3050   if (strlen(AceName) != 0)
3051     {
3052       if (!strcmp(AceType, "LIST"))
3053         {
3054           sprintf(AceSamAccountName, "%s%s", AceName, group_suffix);
3055           strcpy(root_ou, group_ou_root);
3056         }
3057       else if (!strcmp(AceType, "USER"))
3058         {
3059           sprintf(AceSamAccountName, "%s", AceName);
3060           strcpy(root_ou, user_ou);
3061         }
3062
3063       if (ActiveDirectory)
3064         {
3065           if (strlen(AceSamAccountName) != 0)
3066             {
3067               sprintf(search_path, "%s", dn_path);
3068               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3069               attr_array[0] = "objectSid";
3070               attr_array[1] = NULL;
3071               group_count = 0;
3072               group_base = NULL;
3073               
3074               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3075                                        attr_array, &group_base, &group_count, 
3076                                        LDAP_SCOPE_SUBTREE) != 0))
3077                 return(1);
3078               if (group_count == 1)
3079                 {
3080                   strcpy(AceDn, group_base->dn);
3081                   AceSidCount = group_base->length;
3082                   memcpy(AceSid, group_base->value, AceSidCount);
3083                 }
3084               linklist_free(group_base);
3085               group_base = NULL;
3086               group_count = 0;
3087             }
3088         }
3089       else
3090         {
3091           if (strlen(AceSamAccountName) != 0)
3092             {
3093               sprintf(search_path, "%s", dn_path);
3094               sprintf(filter_exp, "(sAMAccountName=%s)", AceSamAccountName);
3095               attr_array[0] = "samAccountName";
3096               attr_array[1] = NULL;
3097               group_count = 0;
3098               group_base = NULL;
3099               
3100               if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3101                                        attr_array, &group_base, &group_count, 
3102                                        LDAP_SCOPE_SUBTREE) != 0))
3103                 return(1);
3104               if (group_count == 1)
3105                 {
3106                   strcpy(AceDn, group_base->dn);
3107                 }
3108               linklist_free(group_base);
3109               group_base = NULL;
3110               group_count = 0;
3111             }
3112         }
3113     }
3114
3115   if (!ActiveDirectory) 
3116     {
3117       if (strlen(AceDn) != 0) 
3118         {
3119           owner_v[0] = strdup(AceDn);
3120           n = 0;
3121           ADD_ATTR("owner", owner_v, LDAP_MOD_REPLACE);
3122
3123           mods[n] = NULL;
3124
3125           rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3126           
3127           for (i = 0; i < n; i++)
3128             free(mods[i]);
3129
3130           if (rc != LDAP_SUCCESS)
3131             com_err(whoami, 0, "Unable to set owner for group %s : %s",
3132               TargetGroupName, ldap_err2string(rc));
3133         }
3134
3135       return(rc);
3136     }
3137   
3138   if (AceSidCount == 0)
3139     {
3140       com_err(whoami, 0, "Group %s: Administrator: %s, Type: %s - does not "
3141               "have an AD SID.", TargetGroupName, AceName, AceType);
3142       com_err(whoami, 0, "   Non-admin security group template will be used.");
3143     }
3144   else
3145     {
3146       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3147       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
3148       attr_array[0] = "objectSid";
3149       attr_array[1] = NULL;
3150
3151       group_count = 0;
3152       group_base = NULL;
3153
3154       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
3155                                attr_array, &group_base, &group_count, 
3156                                LDAP_SCOPE_SUBTREE) != 0))
3157         return(1);
3158
3159       if ((rc != 0) || (group_count != 1))
3160         {
3161           com_err(whoami, 0, "Unable to process user security template: %s", 
3162                   "UserTemplate");
3163           AceSidCount = 0;
3164         }
3165       else
3166         {
3167           UserTemplateSidCount = group_base->length;
3168           memcpy(UserTemplateSid, group_base->value, UserTemplateSidCount);
3169         }
3170       linklist_free(group_base);
3171       group_base = NULL;
3172       group_count = 0;
3173     }
3174
3175   if (HiddenGroup)
3176     {
3177       if (AceSidCount == 0)
3178         {
3179           strcpy(GroupSecurityTemplate, HIDDEN_GROUP);
3180           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP);
3181         }
3182       else
3183         {
3184           strcpy(GroupSecurityTemplate, HIDDEN_GROUP_WITH_ADMIN);
3185           sprintf(filter_exp, "(sAMAccountName=%s)", HIDDEN_GROUP_WITH_ADMIN);
3186         }
3187     }
3188   else
3189     {
3190       if (AceSidCount == 0)
3191         {
3192           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP);
3193           sprintf(filter_exp, "(sAMAccountName=%s)", NOT_HIDDEN_GROUP);
3194         }
3195       else
3196         {
3197           strcpy(GroupSecurityTemplate, NOT_HIDDEN_GROUP_WITH_ADMIN);
3198           sprintf(filter_exp, "(sAMAccountName=%s)", 
3199                   NOT_HIDDEN_GROUP_WITH_ADMIN);
3200         }
3201     }
3202
3203   sprintf(search_path, "%s,%s", security_template_ou, dn_path);
3204   attr_array[0] = "sAMAccountName";
3205   attr_array[1] = NULL;
3206   group_count = 0;
3207   group_base = NULL;
3208
3209   if ((rc = linklist_build(ldap_handle, search_path, filter_exp, attr_array, 
3210                            &group_base, &group_count, 
3211                            LDAP_SCOPE_SUBTREE) != 0))
3212     return(1);
3213
3214   if (group_count != 1)
3215     {
3216       linklist_free(group_base);
3217       com_err(whoami, 0, "Unable to process group security template: %s - "
3218               "security not set", GroupSecurityTemplate);
3219       return(1);
3220     }
3221
3222   strcpy(TemplateDn, group_base->dn);
3223   strcpy(TemplateSamName, group_base->value);
3224   linklist_free(group_base);
3225   group_base = NULL;
3226   group_count = 0;
3227   
3228   sprintf(filter_exp, "(sAMAccountName=%s)", TemplateSamName);
3229   rc = ldap_search_ext_s(ldap_handle,
3230                          TemplateDn,
3231                          LDAP_SCOPE_SUBTREE,
3232                          filter_exp,
3233                          NULL,
3234                          0,
3235                          apsServerControls,
3236                          NULL,
3237                          NULL,
3238                          0,
3239                          &psMsg);
3240
3241   if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
3242     {
3243       com_err(whoami, 0, "Unable to find group security template: %s - "
3244               "security not set", GroupSecurityTemplate);
3245       return(1);
3246     }
3247
3248   ppsValues = ldap_get_values_len(ldap_handle, psMsg, "ntSecurityDescriptor");
3249
3250   if (ppsValues == NULL)
3251     {
3252       com_err(whoami, 0, "Unable to find group security descriptor for group "
3253               "%s - security not set", GroupSecurityTemplate);
3254       return(1);
3255     }
3256   
3257   if (AceSidCount != 0)
3258     {
3259       for (nVal = 0; ppsValues[nVal] != NULL; nVal++)
3260         {
3261           for (i = 0; 
3262                i < (int)(ppsValues[nVal]->bv_len - UserTemplateSidCount); i++)
3263             {
3264               if (!memcmp(&ppsValues[nVal]->bv_val[i], UserTemplateSid, 
3265                           UserTemplateSidCount))
3266                 {
3267                   memcpy(&ppsValues[nVal]->bv_val[i], AceSid, AceSidCount);
3268                   break;
3269                 }
3270             }
3271         }
3272     }
3273
3274   n = 0;
3275   ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues, 
3276            LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
3277
3278   if (Exchange)
3279     {
3280       if(HiddenGroup) 
3281         {
3282           hide_address_lists_v[0] = "TRUE";
3283           address_book_v[0] = NULL;
3284           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3285                    LDAP_MOD_REPLACE);
3286           ADD_ATTR("showInAddressBook", address_book_v, LDAP_MOD_REPLACE);
3287         } else {
3288           hide_address_lists_v[0] = NULL;
3289           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v, 
3290                    LDAP_MOD_REPLACE);
3291         }
3292     }
3293
3294   mods[n] = NULL;
3295
3296   rc = ldap_modify_s(ldap_handle, TargetDn, mods);
3297
3298   for (i = 0; i < n; i++)
3299     free(mods[i]);
3300
3301   ldap_value_free_len(ppsValues);
3302   ldap_msgfree(psMsg);
3303
3304   if (rc != LDAP_SUCCESS)
3305     {
3306       com_err(whoami, 0, "Unable to set security settings for group %s : %s",
3307               TargetGroupName, ldap_err2string(rc));
3308
3309       if (AceSidCount != 0)
3310         {
3311           com_err(whoami, 0, 
3312                   "Trying to set security for group %s without admin.",
3313                   TargetGroupName);
3314
3315           if (rc = ProcessGroupSecurity(ldap_handle, dn_path, TargetGroupName, 
3316                                         HiddenGroup, "", ""))
3317             {
3318               com_err(whoami, 0, "Unable to set security for group %s.",
3319                       TargetGroupName);
3320               return(rc);
3321             }
3322         }
3323       return(rc);
3324     }
3325
3326   return(rc);
3327 }
3328
3329 int group_delete(LDAP *ldap_handle, char *dn_path, char *group_name, 
3330                  char *group_membership, char *MoiraId)
3331 {
3332   LK_ENTRY  *group_base;
3333   char      temp[512];
3334   char      filter[128];
3335   int       group_count;
3336   int       rc;
3337
3338   if (!check_string(group_name))
3339     {
3340       com_err(whoami, 0, 
3341               "Unable to process invalid LDAP list name %s", group_name);
3342       return(AD_INVALID_NAME);
3343     }
3344
3345   memset(filter, '\0', sizeof(filter));
3346   group_count = 0;
3347   group_base = NULL;
3348   sprintf(temp, "%s,%s", group_ou_root, dn_path);
3349
3350   if (rc = ad_get_group(ldap_handle, temp, group_name, 
3351                         group_membership, MoiraId, 
3352                         "samAccountName", &group_base, 
3353                         &group_count, filter))
3354     return(rc);
3355
3356   if (group_count == 1)
3357     {
3358       if ((rc = ldap_delete_s(ldap_handle, group_base->dn)) != LDAP_SUCCESS)
3359         {
3360           linklist_free(group_base);
3361           com_err(whoami, 0, "Unable to delete list %s from AD : %s",
3362                   group_name, ldap_err2string(rc));
3363           return(rc);
3364         }
3365       linklist_free(group_base);
3366     }
3367   else
3368     {
3369       linklist_free(group_base);
3370       com_err(whoami, 0, "Unable to find list %s in AD.", group_name);
3371       return(AD_NO_GROUPS_FOUND);
3372     }
3373   
3374   return(0);
3375 }
3376
3377 int BEREncodeSecurityBits(ULONG uBits, char *pBuffer)
3378 {
3379     *pBuffer++ = 0x30;
3380     *pBuffer++ = 0x03;
3381     *pBuffer++ = 0x02;
3382     *pBuffer++ = 0x00;
3383     return(N_SD_BER_BYTES);
3384 }
3385
3386 int process_lists(int ac, char **av, void *ptr)
3387 {
3388   int   rc;
3389   int   security_flag;
3390   char  group_ou[256];
3391   char  group_membership[2];
3392   char  **call_args;
3393
3394   call_args = ptr;
3395
3396   security_flag = 0;
3397   memset(group_ou, '\0', sizeof(group_ou));
3398   memset(group_membership, '\0', sizeof(group_membership));
3399   get_group_membership(group_membership, group_ou, &security_flag, av);
3400   rc = populate_group((LDAP *)call_args[0], (char *)call_args[1], 
3401                       av[L_NAME], group_ou, group_membership, 
3402                       security_flag, "");
3403
3404   return(0);
3405 }
3406
3407 int member_list_build(int ac, char **av, void *ptr)
3408 {
3409   LK_ENTRY  *linklist;
3410   char      temp[1024];
3411   char      **call_args;
3412   char      *s;
3413   call_args = ptr;
3414   
3415   strcpy(temp, av[ACE_NAME]);
3416
3417   if (!check_string(temp))
3418     return(0);
3419
3420   if (!strcmp(av[ACE_TYPE], "USER"))
3421     {
3422       if (!((int)call_args[3] & MOIRA_USERS))
3423         return(0);
3424     }
3425   else if (!strcmp(av[ACE_TYPE], "STRING"))
3426     {
3427       if (Exchange)
3428         {
3429           if((s = strchr(temp, '@')) == (char *) NULL) 
3430             {
3431               strcat(temp, "@mit.edu");
3432             }
3433           
3434           if(!strncasecmp(&temp[strlen(temp) - 6], ".LOCAL", 6))
3435             {
3436               s = strrchr(temp, '.');
3437               *s = '\0';
3438               strcat(s, ".mit.edu");
3439             }
3440         }
3441       
3442       if (!((int)call_args[3] & MOIRA_STRINGS))
3443         return(0);
3444
3445       if (contact_create((LDAP *)call_args[0], call_args[1], temp, contact_ou))
3446         return(0);
3447
3448     }
3449   else if (!strcmp(av[ACE_TYPE], "LIST"))
3450     {
3451       if (!((int)call_args[3] & MOIRA_LISTS))
3452         return(0);
3453     }
3454   else if (!strcmp(av[ACE_TYPE], "KERBEROS"))
3455     {
3456       if (!((int)call_args[3] & MOIRA_KERBEROS))
3457         return(0);
3458
3459       if (contact_create((LDAP *)call_args[0], call_args[1], temp, 
3460                          kerberos_ou))
3461         return(0);
3462
3463     }
3464   else
3465     return(0);
3466
3467   linklist = member_base;
3468
3469   while (linklist)
3470     {
3471     if (!strcasecmp(temp, linklist->member))
3472       return(0);
3473
3474     linklist = linklist->next;
3475     }
3476
3477   linklist = calloc(1, sizeof(LK_ENTRY));
3478   linklist->op = 1;
3479   linklist->dn = NULL;
3480   linklist->list = calloc(1, strlen(call_args[2]) + 1);
3481   strcpy(linklist->list, call_args[2]);
3482   linklist->type = calloc(1, strlen(av[ACE_TYPE]) + 1);
3483   strcpy(linklist->type, av[ACE_TYPE]);
3484   linklist->member = calloc(1, strlen(temp) + 1);
3485   strcpy(linklist->member, temp);
3486   linklist->next = member_base;
3487   member_base = linklist;
3488
3489   return(0);
3490 }
3491
3492 int member_remove(LDAP *ldap_handle, char *dn_path, char *group_name, 
3493                   char *group_ou, char *group_membership, char *user_name,
3494                   char *UserOu, char *MoiraId)
3495 {
3496   char        distinguished_name[1024];
3497   char        *modvalues[2];
3498   char        temp[256];
3499   char        filter[128];
3500   char        *attr_array[3];
3501   int         group_count;
3502   int         i;
3503   int         n;
3504   LDAPMod     *mods[20];
3505   LK_ENTRY    *group_base;
3506   ULONG       rc;
3507   char        *s;
3508
3509   if (!check_string(group_name))
3510     return(AD_INVALID_NAME);
3511
3512   memset(filter, '\0', sizeof(filter));
3513   group_base = NULL;
3514   group_count = 0;
3515
3516   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3517                         group_membership, MoiraId, 
3518                         "samAccountName", &group_base, 
3519                         &group_count, filter))
3520     return(rc);
3521
3522   if (group_count != 1)
3523     {
3524       com_err(whoami, 0, "Unable to find list %s in AD",
3525               group_name);
3526       linklist_free(group_base);
3527       group_base = NULL;
3528       group_count = 0;
3529       goto cleanup;
3530     }
3531
3532   strcpy(distinguished_name, group_base->dn);
3533   linklist_free(group_base);
3534   group_base = NULL;
3535   group_count = 0;
3536
3537   if(ActiveDirectory)
3538     {
3539       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3540     }
3541   else
3542     {
3543       if(!strcmp(UserOu, user_ou))
3544         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3545       else
3546         sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3547     }
3548
3549   modvalues[0] = temp;
3550   modvalues[1] = NULL;
3551
3552   n = 0;
3553   ADD_ATTR("member", modvalues, LDAP_MOD_DELETE);
3554   mods[n] = NULL;
3555   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3556
3557   for (i = 0; i < n; i++)
3558     free(mods[i]);
3559
3560   if (rc == LDAP_UNWILLING_TO_PERFORM)
3561     rc = LDAP_SUCCESS;
3562
3563   if (rc != LDAP_SUCCESS)
3564     {
3565       com_err(whoami, 0, "Unable to modify list %s members : %s",
3566               group_name, ldap_err2string(rc));
3567       goto cleanup;
3568     }
3569
3570   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou))) 
3571     {
3572       if (Exchange)
3573         {
3574           if(!strcmp(UserOu, contact_ou) && 
3575              ((s = strstr(user_name, "@mit.edu")) != (char *) NULL))
3576             {
3577               memset(temp, '\0', sizeof(temp));
3578               strcpy(temp, user_name);
3579               s = strchr(temp, '@');
3580               *s = '\0';
3581               
3582               sprintf(filter, "(&(objectClass=user)(mailNickName=%s))", temp);
3583           
3584               if ((rc = linklist_build(ldap_handle, dn_path, filter, NULL,
3585                                        &group_base, &group_count, 
3586                                        LDAP_SCOPE_SUBTREE) != 0))
3587                 return(rc);       
3588               
3589               if(group_count)
3590                 goto cleanup;
3591               
3592               linklist_free(group_base);
3593               group_base = NULL;
3594               group_count = 0;
3595             }
3596           
3597           sprintf(filter, "(distinguishedName=%s)", temp);
3598           attr_array[0] = "memberOf";
3599           attr_array[1] = NULL;
3600           
3601           if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array,
3602                                    &group_base, &group_count, 
3603                                    LDAP_SCOPE_SUBTREE) != 0))
3604             return(rc);
3605           
3606
3607           if(!group_count) 
3608             {
3609               com_err(whoami, 0, "Removing unreferenced object %s", temp);
3610           
3611               if ((rc = ldap_delete_s(ldap_handle, temp)) != 0) 
3612                 return(rc);
3613             }
3614         }
3615     }
3616
3617  cleanup:
3618   return(rc);
3619 }
3620
3621 int member_add(LDAP *ldap_handle, char *dn_path, char *group_name, 
3622                char *group_ou, char *group_membership, char *user_name, 
3623                char *UserOu, char *MoiraId)
3624 {
3625   char        distinguished_name[1024];
3626   char        *modvalues[2];
3627   char        temp[256];
3628   char        filter[128];
3629   int         group_count;
3630   int         n;
3631   int         i;
3632   LDAPMod     *mods[20];
3633   LK_ENTRY    *group_base;
3634   ULONG       rc;
3635
3636   if (!check_string(group_name))
3637     return(AD_INVALID_NAME);
3638
3639   rc = 0;
3640   memset(filter, '\0', sizeof(filter));
3641   group_base = NULL;
3642   group_count = 0;
3643
3644   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
3645                         group_membership, MoiraId, 
3646                         "samAccountName", &group_base, 
3647                         &group_count, filter))
3648     return(rc);
3649
3650   if (group_count != 1)
3651     {
3652       linklist_free(group_base);
3653       group_base = NULL;
3654       group_count = 0;
3655       com_err(whoami, 0, "Unable to find list %s %d in AD",
3656               group_name, group_count);
3657       return(AD_MULTIPLE_GROUPS_FOUND);
3658     }
3659
3660   strcpy(distinguished_name, group_base->dn);
3661   linklist_free(group_base);
3662   group_base = NULL;
3663   group_count = 0;
3664
3665   if(ActiveDirectory)
3666     {
3667       sprintf(temp, "CN=%s,%s,%s", user_name, UserOu, dn_path);
3668     }
3669   else 
3670     {
3671       if(!strcmp(UserOu, user_ou))
3672         sprintf(temp, "uid=%s,%s,%s", user_name, UserOu, dn_path);
3673       else
3674         sprintf(temp, "cn=%s,%s,%s", user_name, UserOu, dn_path);
3675     }
3676
3677   modvalues[0] = temp;
3678   modvalues[1] = NULL;
3679
3680   n = 0;
3681   ADD_ATTR("member", modvalues, LDAP_MOD_ADD);
3682   mods[n] = NULL;
3683   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
3684
3685   if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
3686     rc = LDAP_SUCCESS;
3687
3688   if ((!strcmp(UserOu, contact_ou)) || (!strcmp(UserOu, kerberos_ou)))
3689     {
3690       if (rc == LDAP_UNWILLING_TO_PERFORM)
3691         rc = LDAP_SUCCESS;
3692     }
3693
3694   for (i = 0; i < n; i++)
3695     free(mods[i]);
3696
3697   if (rc != LDAP_SUCCESS)
3698     {
3699       com_err(whoami, 0, "Unable to add %s to list %s as a member : %s",
3700               user_name, group_name, ldap_err2string(rc));
3701     }
3702
3703   return(rc);
3704 }
3705
3706 int contact_remove_email(LDAP *ld, char *bind_path,
3707                          LK_ENTRY **linklist_base, int linklist_current)
3708 {
3709   LK_ENTRY  *gPtr;
3710   int       rc;
3711   char      *mail_v[] = {NULL, NULL};
3712   LDAPMod   *mods[20];
3713   int n;
3714   int i;
3715
3716   mail_v[0] = NULL;
3717
3718   n = 0;
3719   ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
3720   ADD_ATTR("mailNickName", mail_v, LDAP_MOD_REPLACE);
3721   ADD_ATTR("proxyAddresses", mail_v, LDAP_MOD_REPLACE);
3722   ADD_ATTR("targetAddress", mail_v, LDAP_MOD_REPLACE);
3723   mods[n] = NULL;
3724
3725   gPtr = (*linklist_base);
3726   
3727   while(gPtr) {
3728     rc = ldap_modify_s(ld, gPtr->dn, mods);
3729     
3730     if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
3731       {
3732         com_err(whoami, 0, "Unable to modify contact %s in AD : %s",
3733                 gPtr->dn, ldap_err2string(rc));
3734         return(rc);
3735       }
3736
3737     gPtr = gPtr->next;
3738   }
3739
3740   for (i = 0; i < n; i++)
3741     free(mods[i]);
3742   
3743     return(rc);
3744 }
3745
3746 int contact_create(LDAP *ld, char *bind_path, char *user, char *group_ou)
3747 {
3748   LDAPMod *mods[20];
3749   LK_ENTRY  *group_base;
3750   int  group_count;
3751   char new_dn[256];
3752   char cn_user_name[256];
3753   char contact_name[256];
3754   char mail_nickname[256];
3755   char proxy_address_internal[256];
3756   char proxy_address_external[256];
3757   char target_address[256];
3758   char internal_contact_name[256];
3759   char filter[128];
3760   char mail[256];
3761   char principal[256];
3762   char mit_address_book[256];
3763   char default_address_book[256];
3764   char contact_address_book[256];
3765   char uid[256];
3766   char *email_v[] = {NULL, NULL};
3767   char *cn_v[] = {NULL, NULL};
3768   char *contact_v[] = {NULL, NULL};
3769   char *uid_v[] = {NULL, NULL};
3770   char *mail_nickname_v[] = {NULL, NULL};
3771   char *proxy_address_internal_v[] = {NULL, NULL};
3772   char *proxy_address_external_v[] = {NULL, NULL};
3773   char *target_address_v[] = {NULL, NULL};
3774   char *mit_address_book_v[] = {NULL, NULL};
3775   char *default_address_book_v[] = {NULL, NULL};
3776   char *contact_address_book_v[] = {NULL, NULL};
3777   char *hide_address_lists_v[] = {NULL, NULL};
3778   char *attr_array[3];
3779   char *objectClass_v[] = {"top", "person", 
3780                            "organizationalPerson", 
3781                            "contact", NULL};
3782   char *objectClass_ldap_v[] = {"top", "person", "microsoftComTop", 
3783                                 "inetOrgPerson", "organizationalPerson",
3784                                 "contact", "mailRecipient", "eduPerson",
3785                                 NULL};
3786   char *name_v[] = {NULL, NULL};
3787   char *desc_v[] = {NULL, NULL};
3788   char *s;
3789   int  n;
3790   int  rc;
3791   int  i;
3792   char temp[256];
3793   char *c;
3794   char *mail_routing_v[] = {NULL, NULL};
3795   char *principal_v[] = {NULL, NULL};
3796
3797   if (!check_string(user))
3798     {
3799       com_err(whoami, 0, "Unable to process invalid LDAP name %s", user);
3800       return(AD_INVALID_NAME);
3801     }
3802
3803   strcpy(mail, user);
3804   strcpy(contact_name, mail);
3805   strcpy(internal_contact_name, mail);
3806   
3807   if((s = strchr(internal_contact_name, '@')) != NULL) {
3808     *s = '?';
3809   }
3810
3811   sprintf(cn_user_name,"CN=%s,%s,%s", escape_string(contact_name), group_ou, 
3812           bind_path);
3813
3814   sprintf(target_address, "SMTP:%s", contact_name);
3815   sprintf(proxy_address_external, "SMTP:%s", contact_name);
3816   sprintf(mail_nickname, "%s", internal_contact_name);
3817  
3818   cn_v[0] = cn_user_name;
3819   contact_v[0] = contact_name;
3820   uid_v[0] = uid;
3821   name_v[0] = user;
3822   desc_v[0] = "Auto account created by Moira";
3823   email_v[0] = mail;
3824   proxy_address_internal_v[0] = proxy_address_internal;
3825   proxy_address_external_v[0] = proxy_address_external;
3826   mail_nickname_v[0] = mail_nickname;
3827   target_address_v[0] = target_address;
3828   mit_address_book_v[0] = mit_address_book;
3829   default_address_book_v[0] = default_address_book;
3830   contact_address_book_v[0] = contact_address_book;
3831   strcpy(new_dn, cn_user_name);
3832   n = 0;
3833
3834   ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
3835
3836   if(!ActiveDirectory)
3837     {
3838       if(!strcmp(group_ou, contact_ou))
3839         sprintf(uid, "%s%s", contact_name, "_strings");
3840       
3841       if(!strcmp(group_ou, kerberos_ou))
3842         sprintf(uid, "%s%s", contact_name, "_kerberos");
3843
3844       uid_v[0] = uid;
3845
3846       ADD_ATTR("sn", contact_v, LDAP_MOD_ADD);
3847       ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
3848     }
3849
3850   if(ActiveDirectory)
3851     {
3852       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
3853     }
3854   else
3855     {
3856       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
3857     }
3858
3859   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
3860   ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
3861   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
3862
3863   if (Exchange)
3864     {
3865       if (!strcmp(group_ou, contact_ou) && email_isvalid(mail))
3866         {
3867           group_count = 0;
3868           group_base = NULL;
3869           
3870           sprintf(filter, "(&(objectClass=user)(cn=%s))", mail);
3871           attr_array[0] = "cn";
3872           attr_array[1] = NULL;
3873
3874           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3875                                    &group_base, &group_count, 
3876                                    LDAP_SCOPE_SUBTREE)) != 0) 
3877             {
3878               com_err(whoami, 0, "Unable to process contact %s : %s", 
3879                       user, ldap_err2string(rc));
3880               return(rc);
3881             }
3882       
3883           if (group_count) 
3884             {
3885               com_err(whoami, 0, "Object already exists with name %s",
3886                       user);
3887               return(1);
3888             }
3889
3890           linklist_free(group_base);
3891           group_base = NULL;
3892           group_count = 0;
3893       
3894           sprintf(filter, "(&(objectClass=group)(cn=%s))", mail);
3895           attr_array[0] = "cn";
3896           attr_array[1] = NULL;
3897
3898           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3899                                    &group_base, &group_count, 
3900                                    LDAP_SCOPE_SUBTREE)) != 0) 
3901             {
3902               com_err(whoami, 0, "Unable to process contact %s : %s", 
3903                       user, ldap_err2string(rc));
3904               return(rc);
3905             }
3906           
3907           if (group_count) 
3908             {
3909               com_err(whoami, 0, "Object already exists with name %s",
3910                       user);
3911               return(1);
3912             }
3913   
3914           linklist_free(group_base);
3915           group_count = 0;
3916           group_base = NULL;
3917           
3918           sprintf(filter, "(&(objectClass=user)(mail=%s))", mail);
3919           attr_array[0] = "cn";
3920           attr_array[1] = NULL;
3921
3922           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3923                                    &group_base, &group_count, 
3924                                    LDAP_SCOPE_SUBTREE)) != 0) 
3925             {
3926               com_err(whoami, 0, "Unable to process contact %s : %s", 
3927                       user, ldap_err2string(rc));
3928               return(rc);
3929             }
3930           
3931           if (group_count) 
3932             {
3933               com_err(whoami, 0, "Object already exists with name %s",
3934                       user);
3935               return(1);
3936             }
3937
3938           linklist_free(group_base);
3939           group_base = NULL;
3940           group_count = 0;
3941
3942           sprintf(filter, "(&(objectClass=group)(mail=%s))", mail);
3943           attr_array[0] = "cn";
3944           attr_array[1] = NULL;
3945
3946           if ((rc = linklist_build(ld, bind_path, filter, attr_array,
3947                                    &group_base, &group_count, 
3948                                    LDAP_SCOPE_SUBTREE)) != 0) 
3949             {
3950               com_err(whoami, 0, "Unable to process contact %s : %s", 
3951                       user, ldap_err2string(rc));
3952               return(rc);
3953             }
3954       
3955           if (group_count) 
3956             {
3957               com_err(whoami, 0, "Object already exists with name %s",
3958                       user);
3959               return(1);
3960             }
3961           
3962           linklist_free(group_base);
3963           group_base = NULL;
3964           group_count = 0;
3965           
3966           ADD_ATTR("mail", email_v, LDAP_MOD_ADD);
3967           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
3968           ADD_ATTR("proxyAddresses", proxy_address_external_v, LDAP_MOD_ADD);
3969           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_ADD);
3970           
3971           hide_address_lists_v[0] = "TRUE";
3972           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
3973                    LDAP_MOD_ADD);
3974         }
3975     }
3976
3977   if(!ActiveDirectory) 
3978     {
3979       if((c = strchr(mail, '@')) == NULL)
3980           sprintf(temp, "%s@mit.edu", mail);
3981       else
3982           sprintf(temp, "%s", mail);
3983
3984       mail_routing_v[0] = temp;
3985       email_v[0] = temp;
3986       principal_v[0] = principal;
3987
3988       if(!strcmp(group_ou, contact_ou))
3989         {
3990           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
3991         }
3992
3993       if(!strcmp(group_ou, contact_ou))
3994         {
3995           ADD_ATTR("eduPersonPrincipalName", mail_routing_v, LDAP_MOD_ADD);
3996         }
3997     }
3998
3999   mods[n] = NULL;
4000
4001   rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4002
4003   for (i = 0; i < n; i++)
4004     free(mods[i]);
4005   
4006   if (Exchange)
4007     {
4008       if ((rc != LDAP_SUCCESS) && (rc == LDAP_ALREADY_EXISTS) &&
4009           !strcmp(group_ou, contact_ou) && email_isvalid(mail))
4010         {
4011           n = 0;
4012           
4013           ADD_ATTR("mail", email_v, LDAP_MOD_REPLACE);
4014           ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE);
4015           ADD_ATTR("proxyAddresses", proxy_address_external_v, 
4016                    LDAP_MOD_REPLACE);
4017           ADD_ATTR("targetAddress", target_address_v, LDAP_MOD_REPLACE);
4018
4019           hide_address_lists_v[0] = "TRUE";
4020           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4021                    LDAP_MOD_REPLACE);
4022     
4023           mods[n] = NULL;
4024           rc = ldap_modify_s(ld, new_dn, mods);
4025       
4026           if (rc) 
4027             {
4028               com_err(whoami, 0, "Unable to update contact %s", mail);
4029             }
4030       
4031           for (i = 0; i < n; i++)
4032             free(mods[i]);
4033         }
4034     }
4035
4036   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4037     {
4038       n = 0;
4039       ADD_ATTR("cn", contact_v, LDAP_MOD_ADD);
4040       
4041       if(ActiveDirectory)
4042         {
4043           ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
4044         }
4045       else
4046         {
4047           ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
4048         }
4049
4050       ADD_ATTR("name", name_v, LDAP_MOD_ADD);
4051       ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
4052       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
4053       mods[n] = NULL;
4054       rc = ldap_add_ext_s(ld, new_dn, mods, NULL, NULL);
4055
4056       for (i = 0; i < n; i++)
4057         free(mods[i]);
4058     }
4059
4060   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
4061     {
4062       com_err(whoami, 0, "Unable to create contact %s : %s",
4063               user, ldap_err2string(rc));
4064       return(rc);
4065     }
4066
4067   return(0);
4068 }
4069
4070 int user_update(LDAP *ldap_handle, char *dn_path, char *user_name,
4071                 char *Uid, char *MitId, char *MoiraId, int State,
4072                 char *WinHomeDir, char *WinProfileDir, char *first,
4073                 char *middle, char *last, char *shell, char *class)
4074 {
4075   LDAPMod   *mods[20];
4076   LK_ENTRY  *group_base;
4077   int  group_count;
4078   char distinguished_name[512];
4079   char displayName[256];
4080   char *mitMoiraId_v[] = {NULL, NULL};
4081   char *mitMoiraClass_v[] = {NULL, NULL};
4082   char *mitMoiraStatus_v[] = {NULL, NULL};
4083   char *uid_v[] = {NULL, NULL};
4084   char *mitid_v[] = {NULL, NULL};
4085   char *homedir_v[] = {NULL, NULL};
4086   char *winProfile_v[] = {NULL, NULL};
4087   char *drives_v[] = {NULL, NULL};
4088   char *userAccountControl_v[] = {NULL, NULL};
4089   char *alt_recipient_v[] = {NULL, NULL};
4090   char *hide_address_lists_v[] = {NULL, NULL};
4091   char *mail_v[] = {NULL, NULL};
4092   char *gid_v[] = {NULL, NULL};
4093   char *loginshell_v[] = {NULL, NULL};
4094   char *principal_v[] = {NULL, NULL};
4095   char userAccountControlStr[80];
4096   int  n;
4097   int  rc;
4098   int  i;
4099   int  OldUseSFU30;
4100   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4101     UF_PASSWD_CANT_CHANGE;
4102   char filter[128];
4103   char *attr_array[3];
4104   char temp[1024];
4105   char mail[256];
4106   char contact_mail[256];
4107   char filter_exp[1024];
4108   char search_path[512];
4109   char TemplateDn[512];
4110   char TemplateSamName[128];
4111   char alt_recipient[256];
4112   char principal[256];
4113   char status[256];
4114   char acBERBuf[N_SD_BER_BYTES];
4115   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4116                           { N_SD_BER_BYTES, acBERBuf },
4117                           TRUE};
4118   LDAPControl *apsServerControls[] = {&sControl, NULL};
4119   LDAPMessage *psMsg;
4120   LDAP_BERVAL   **ppsValues;
4121   ULONG dwInfo;
4122   char *argv[3];
4123   char *homeMDB;
4124   char *homeServerName;
4125   char *save_argv[7];
4126   char search_string[256];
4127   char *p, *q;
4128   char *mail_routing_v[] = {NULL, NULL};
4129   char *c;
4130
4131   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4132     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4133   BEREncodeSecurityBits(dwInfo, acBERBuf);
4134
4135   if (!check_string(user_name))
4136     {
4137       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4138               user_name);
4139       return(AD_INVALID_NAME);
4140     }
4141   
4142   memset(contact_mail, '\0', sizeof(contact_mail));
4143   sprintf(contact_mail, "%s@mit.edu", user_name);
4144   memset(mail, '\0', sizeof(mail));
4145   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4146   memset(alt_recipient, '\0', sizeof(alt_recipient));
4147   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4148           dn_path);
4149   sprintf(search_string, "@%s", uppercase(ldap_domain));
4150
4151   if (Exchange)
4152     {
4153       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4154         {
4155           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4156         }
4157     }
4158
4159   group_count = 0;
4160   group_base = NULL;
4161
4162   memset(displayName, '\0', sizeof(displayName));
4163
4164   if (strlen(MoiraId) != 0)
4165     {
4166       if(ActiveDirectory)
4167         {
4168           sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
4169         }
4170       else
4171         {
4172           sprintf(filter, 
4173                   "(&(objectClass=mitPerson)(mitMoiraId=%s))", MoiraId);
4174         }
4175
4176       attr_array[0] = "cn";
4177       attr_array[1] = NULL;
4178       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
4179                                &group_base, &group_count, 
4180                                LDAP_SCOPE_SUBTREE)) != 0)
4181         {
4182           com_err(whoami, 0, "Unable to process user %s : %s",
4183                   user_name, ldap_err2string(rc));
4184           return(rc);
4185         }
4186     }
4187
4188   if (group_count != 1)
4189     {
4190       linklist_free(group_base);
4191       group_base = NULL;
4192       group_count = 0;
4193       sprintf(filter, "(sAMAccountName=%s)", user_name);
4194       attr_array[0] = "cn";
4195       attr_array[1] = NULL;
4196       sprintf(temp, "%s,%s", user_ou, dn_path);
4197       if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
4198                                &group_base, &group_count, 
4199                                LDAP_SCOPE_SUBTREE)) != 0)
4200         {
4201           com_err(whoami, 0, "Unable to process user %s : %s",
4202                   user_name, ldap_err2string(rc));
4203           return(rc);
4204         }
4205     }
4206
4207   if (group_count != 1)
4208     {
4209       com_err(whoami, 0, "Unable to find user %s in AD",
4210               user_name);
4211       linklist_free(group_base);
4212       return(AD_NO_USER_FOUND);
4213     }
4214
4215   strcpy(distinguished_name, group_base->dn);
4216
4217   linklist_free(group_base);
4218   group_count = 0;
4219
4220   if(!ActiveDirectory) 
4221     {
4222       if (rc = moira_connect())
4223         {
4224           critical_alert("AD incremental", 
4225                          "Error contacting Moira server : %s",
4226                          error_message(rc));
4227           return;
4228         }
4229   
4230       argv[0] = user_name;
4231       
4232       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4233         {
4234           n = 0;
4235           ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_REPLACE);
4236           mods[n] = NULL;
4237           rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4238           
4239           if (rc == LDAP_ALREADY_EXISTS || rc == LDAP_TYPE_OR_VALUE_EXISTS)
4240             rc = LDAP_SUCCESS;
4241
4242           if(rc)
4243             com_err(whoami, 0, 
4244                     "Unable to set the mailRoutingAddress for %s : %s",
4245                     user_name, ldap_err2string(rc));
4246           
4247           p = strdup(save_argv[3]);
4248           
4249           if((c = strchr(p, ',')) != NULL) 
4250             {
4251               q = strtok(p, ",");
4252               StringTrim(q);
4253
4254               if ((c = strchr(q, '@')) == NULL)
4255                 sprintf(temp, "%s@mit.edu", q);
4256               else
4257                 sprintf(temp, "%s", q);
4258               
4259               if(email_isvalid(temp) && State != US_DELETED) 
4260                 {
4261                   mail_routing_v[0]  = temp;
4262                   
4263                   n = 0;
4264                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4265                   mods[n] = NULL;
4266                   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4267
4268                   if (rc == LDAP_ALREADY_EXISTS || 
4269                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
4270                     rc = LDAP_SUCCESS;
4271     
4272                   if(rc)
4273                     com_err(whoami, 0, 
4274                             "Unable to set the mailRoutingAddress for %s : %s",
4275                             user_name, ldap_err2string(rc));
4276                 }
4277
4278               while((q = strtok(NULL, ",")) != NULL) {
4279                 StringTrim(q);
4280                 
4281                 if((c = strchr(q, '@')) == NULL) 
4282                   sprintf(temp, "%s@mit.edu", q);
4283                 else
4284                   sprintf(temp, "%s", q);
4285
4286                 if(email_isvalid(temp) && State != US_DELETED) 
4287                   {
4288                     mail_routing_v[0]  = temp;
4289                 
4290                     n = 0;
4291                     ADD_ATTR("mailRoutingAddress", mail_routing_v, 
4292                              LDAP_MOD_ADD);
4293                     mods[n] = NULL;
4294                     rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4295                     
4296                     if (rc == LDAP_ALREADY_EXISTS || 
4297                         rc == LDAP_TYPE_OR_VALUE_EXISTS)
4298                       rc = LDAP_SUCCESS;
4299                     
4300                     if(rc)
4301                       com_err(whoami, 0, 
4302                               "Unable to set the mailRoutingAddress for " 
4303                               "%s : %s",
4304                               user_name, ldap_err2string(rc));
4305                   }
4306               }
4307             } else {
4308               StringTrim(p);
4309
4310             if((c = strchr(p, '@')) == NULL)
4311               sprintf(temp, "%s@mit.edu", p);
4312             else
4313               sprintf(temp, "%s", p);
4314             
4315             if(email_isvalid(temp) && State != US_DELETED) 
4316               {
4317                 mail_routing_v[0]  = temp;
4318                 
4319                 n = 0;
4320                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
4321                 mods[n] = NULL;
4322                 rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4323                 
4324                 if (rc == LDAP_ALREADY_EXISTS || 
4325                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
4326                   rc = LDAP_SUCCESS;
4327                 
4328                 if(rc)
4329                   com_err(whoami, 0, 
4330                           "Unable to set the mailRoutingAddress for %s : %s",
4331                           user_name, ldap_err2string(rc));
4332               }
4333             }
4334         }
4335       moira_disconnect();
4336     }
4337
4338   if ((strlen(MitId) != 0) && (MitId[0] == '9'))
4339     rc = attribute_update(ldap_handle, distinguished_name, MitId, 
4340                           "employeeID", user_name);
4341   else
4342     rc = attribute_update(ldap_handle, distinguished_name, "none", 
4343                           "employeeID", user_name);
4344
4345   if(strlen(first)) {
4346     strcat(displayName, first);
4347   }
4348
4349   if(strlen(middle)) {
4350     if(strlen(first)) 
4351       strcat(displayName, " ");
4352
4353     strcat(displayName, middle);
4354   }
4355
4356   if(strlen(last)) {
4357     if(strlen(middle) || strlen(first))
4358       strcat(displayName, " ");
4359
4360     strcat(displayName, last);
4361   }
4362
4363   if(strlen(displayName))
4364     rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4365                           "displayName", user_name);
4366   else
4367     rc = attribute_update(ldap_handle, distinguished_name, user_name,
4368                           "displayName", user_name);
4369
4370   if(!ActiveDirectory)
4371     {
4372       if(strlen(displayName))
4373         rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4374                               "cn", user_name);
4375       else
4376         rc = attribute_update(ldap_handle, distinguished_name, user_name,
4377                               "cn", user_name);
4378     }
4379
4380   if(!ActiveDirectory)
4381     {
4382       rc = attribute_update(ldap_handle, distinguished_name, displayName, 
4383                             "eduPersonNickname", user_name);
4384     }
4385
4386   if(strlen(first))
4387     rc = attribute_update(ldap_handle, distinguished_name, first, 
4388                           "givenName", user_name);
4389   else
4390     rc = attribute_update(ldap_handle, distinguished_name, "",
4391                           "givenName", user_name);
4392
4393   if(strlen(middle) == 1) 
4394     rc = attribute_update(ldap_handle, distinguished_name, middle,
4395                           "initials", user_name);
4396   else 
4397     rc = attribute_update(ldap_handle, distinguished_name, "",
4398                           "initials", user_name);
4399   
4400   if(strlen(last))
4401     rc = attribute_update(ldap_handle, distinguished_name, last,
4402                           "sn", user_name);
4403   else 
4404     rc = attribute_update(ldap_handle, distinguished_name, "",
4405                           "sn", user_name);
4406
4407   if(ActiveDirectory)
4408     {
4409       rc = attribute_update(ldap_handle, distinguished_name, Uid, "uid", 
4410                             user_name);
4411     }
4412   else
4413     {
4414       rc = attribute_update(ldap_handle, distinguished_name, user_name, "uid", 
4415                             user_name);
4416     }
4417     
4418   rc = attribute_update(ldap_handle, distinguished_name, MoiraId, 
4419                         "mitMoiraId", user_name);
4420
4421   n = 0;
4422   uid_v[0] = Uid;
4423
4424   if(ActiveDirectory)
4425     {
4426       if (!UseSFU30)
4427         {
4428           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4429         }
4430       else
4431         {
4432           ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_REPLACE);
4433         }
4434     }
4435   else
4436     {
4437       sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4438       sprintf(status, "%d", State);
4439       principal_v[0] = principal;
4440       loginshell_v[0] = shell;
4441       mitMoiraClass_v[0] = class;
4442       mitMoiraStatus_v[0] = status;
4443       gid_v[0] = "101";
4444       ADD_ATTR("uidNumber", uid_v, LDAP_MOD_REPLACE);
4445       ADD_ATTR("gidNumber", gid_v, LDAP_MOD_REPLACE);
4446       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_REPLACE);
4447       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4448       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_REPLACE);
4449       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_REPLACE);
4450     }
4451
4452   if ((State != US_NO_PASSWD) && (State != US_REGISTERED))
4453     {
4454       userAccountControl |= UF_ACCOUNTDISABLE;
4455
4456       if (Exchange)
4457         {
4458           hide_address_lists_v[0] = "TRUE";
4459           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4460                    LDAP_MOD_REPLACE);
4461         }
4462     }
4463   else
4464     {
4465       if (Exchange)
4466         {
4467           hide_address_lists_v[0] = NULL;
4468           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4469                    LDAP_MOD_REPLACE);
4470         }
4471     }
4472
4473   sprintf(userAccountControlStr, "%ld", userAccountControl);
4474   userAccountControl_v[0] = userAccountControlStr;
4475   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_REPLACE);
4476
4477   if (Exchange)
4478     {
4479       if (rc = moira_connect())
4480         {
4481           critical_alert("AD incremental", 
4482                          "Error contacting Moira server : %s",
4483                          error_message(rc));
4484           return;
4485         }
4486  
4487       argv[0] = user_name;
4488
4489       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
4490         {
4491           if(!strcmp(save_argv[1], "EXCHANGE") || 
4492              (strstr(save_argv[3], search_string) != NULL))
4493             {
4494               alt_recipient_v[0] = NULL;
4495               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4496
4497               argv[0] = exchange_acl;
4498               argv[1] = "USER";
4499               argv[2] = user_name;
4500               
4501               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
4502               
4503               if ((rc) && (rc != MR_EXISTS))
4504                 {
4505                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
4506                           user_name, exchange_acl, error_message(rc));
4507                 }
4508             }
4509           else 
4510             {
4511               alt_recipient_v[0] = alt_recipient;
4512               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4513               
4514               argv[0] = exchange_acl;
4515               argv[1] = "USER";
4516               argv[2] = user_name;
4517               
4518               rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4519               
4520               if ((rc) && (rc != MR_NO_MATCH))
4521                 {  
4522                   com_err(whoami, 0,
4523                           "Unable to remove user %s from %s: %s, %d",
4524                           user_name, exchange_acl, error_message(rc), rc);
4525                 }  
4526             }
4527         }
4528       else
4529         {
4530           alt_recipient_v[0] = alt_recipient;
4531           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_REPLACE);
4532           
4533           argv[0] = exchange_acl;
4534           argv[1] = "USER";
4535           argv[2] = user_name;
4536           
4537           rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
4538           
4539           if ((rc) && (rc != MR_NO_MATCH))
4540             {  
4541               com_err(whoami, 0,
4542                       "Unable to remove user %s from %s: %s, %d",
4543                       user_name, exchange_acl, error_message(rc), rc);
4544             }  
4545         }
4546       
4547       moira_disconnect();
4548     }
4549   else
4550     {
4551       mail_v[0] = contact_mail;
4552       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE);
4553     }
4554
4555   n = SetHomeDirectory(ldap_handle, user_name, distinguished_name, WinHomeDir, 
4556                        WinProfileDir, homedir_v, winProfile_v,
4557                        drives_v, mods, LDAP_MOD_REPLACE, n);
4558
4559   if(ActiveDirectory)
4560     {
4561       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
4562       sprintf(search_path, "%s,%s", security_template_ou, dn_path);
4563       attr_array[0] = "sAMAccountName";
4564       attr_array[1] = NULL;
4565       group_count = 0;
4566       group_base = NULL;
4567     
4568       if ((rc = linklist_build(ldap_handle, search_path, filter_exp, 
4569                                attr_array,
4570                                &group_base, &group_count, 
4571                                LDAP_SCOPE_SUBTREE) != 0))
4572         return(1);
4573       
4574       if (group_count != 1)
4575         {
4576           com_err(whoami, 0, "Unable to process user security template: %s - "
4577                   "security not set", "UserTemplate.u");
4578           return(1);
4579         }
4580
4581       strcpy(TemplateDn, group_base->dn);
4582       strcpy(TemplateSamName, group_base->value);
4583       linklist_free(group_base);
4584       group_base = NULL;
4585       group_count = 0;
4586       
4587       rc = ldap_search_ext_s(ldap_handle, search_path, LDAP_SCOPE_SUBTREE,
4588                              filter_exp, NULL, 0, apsServerControls, NULL,
4589                              NULL, 0, &psMsg);
4590
4591       if ((psMsg = ldap_first_entry(ldap_handle, psMsg)) == NULL)
4592         {
4593           com_err(whoami, 0, "Unable to find user security template: %s - "
4594                   "security not set", "UserTemplate.u");
4595           return(1);
4596         }
4597       
4598       ppsValues = ldap_get_values_len(ldap_handle, psMsg, 
4599                                       "ntSecurityDescriptor");
4600
4601       if (ppsValues == NULL)
4602         {
4603           com_err(whoami, 0, "Unable to find user security template: %s - "
4604                   "security not set", "UserTemplate.u");
4605           return(1);
4606         }
4607       
4608       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
4609                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
4610     }
4611
4612   mods[n] = NULL;
4613
4614   if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
4615                           mods)) != LDAP_SUCCESS)
4616     {
4617       OldUseSFU30 = UseSFU30;
4618       SwitchSFU(mods, &UseSFU30, n);
4619       if (OldUseSFU30 != UseSFU30)
4620         rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
4621       if (rc)
4622         {
4623           com_err(whoami, 0, "Unable to modify user data for %s : %s",
4624                   user_name, ldap_err2string(rc));
4625         }
4626     }
4627   
4628   for (i = 0; i < n; i++)
4629     free(mods[i]);
4630
4631   return(rc);
4632 }
4633
4634 int user_rename(LDAP *ldap_handle, char *dn_path, char *before_user_name, 
4635                 char *user_name)
4636 {
4637   LDAPMod *mods[20];
4638   char new_dn[256];
4639   char old_dn[256];
4640   char upn[256];
4641   char mail[256];
4642   char contact_mail[256];
4643   char proxy_address[256];
4644   char query_base_dn[256];
4645   char temp[256];
4646   char *userPrincipalName_v[] = {NULL, NULL};
4647   char *altSecurityIdentities_v[] = {NULL, NULL};
4648   char *name_v[] = {NULL, NULL};
4649   char *samAccountName_v[] = {NULL, NULL};
4650   char *mail_v[] = {NULL, NULL};
4651   char *mail_nickname_v[] = {NULL, NULL};
4652   char *proxy_address_v[] = {NULL, NULL};
4653   char *query_base_dn_v[] = {NULL, NULL};
4654   char *principal_v[] = {NULL, NULL};
4655   char principal[256];
4656   int  n;
4657   int  rc;
4658   int  i;
4659
4660   if (!check_string(before_user_name))
4661     {
4662       com_err(whoami, 0, 
4663               "Unable to process invalid LDAP user name %s", before_user_name);
4664       return(AD_INVALID_NAME);
4665     }
4666
4667   if (!check_string(user_name))
4668     {
4669       com_err(whoami, 0, 
4670               "Unable to process invalid LDAP user name %s", user_name);
4671       return(AD_INVALID_NAME);
4672     }
4673
4674   strcpy(user_name, user_name);
4675  
4676   if(ActiveDirectory)
4677     sprintf(old_dn, "cn=%s,%s,%s", before_user_name, user_ou, dn_path);
4678   else
4679     sprintf(old_dn, "uid=%s,%s,%s", before_user_name, user_ou, dn_path);
4680
4681   if(ActiveDirectory)
4682     sprintf(new_dn, "cn=%s", user_name);
4683   else
4684     sprintf(new_dn, "uid=%s", user_name);
4685
4686   sprintf(mail, "%s@%s", user_name, lowercase(ldap_domain));
4687   sprintf(contact_mail, "%s@mit.edu", user_name);
4688   sprintf(proxy_address, "SMTP:%s@%s", user_name, lowercase(ldap_domain)); 
4689   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4690
4691   if ((rc = ldap_rename_s(ldap_handle, old_dn, new_dn, NULL, TRUE, 
4692                            NULL, NULL)) != LDAP_SUCCESS)
4693     {
4694       com_err(whoami, 0, "Unable to rename user from %s to %s : %s",
4695               before_user_name, user_name, ldap_err2string(rc));
4696       return(rc);
4697     }
4698
4699   if (Exchange)
4700     {
4701       sprintf(temp, "cn=%s@mit.edu,%s,%s", before_user_name, contact_ou, 
4702               dn_path);
4703
4704       if(rc = ldap_delete_s(ldap_handle, temp))
4705         {
4706           com_err(whoami, 0, "Unable to delete user contact for %s",
4707                   user_name);
4708         }
4709       
4710       if(contact_create(ldap_handle, dn_path, contact_mail, contact_ou))
4711         {
4712           com_err(whoami, 0, "Unable to create user contact %s", contact_mail);
4713         }
4714     }
4715
4716   name_v[0] = user_name;
4717   sprintf(upn, "%s@%s", user_name, ldap_domain);
4718   userPrincipalName_v[0] = upn;
4719   principal_v[0] = principal;
4720   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4721   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, dn_path);
4722   altSecurityIdentities_v[0] = temp;
4723   samAccountName_v[0] = user_name;
4724   mail_v[0] = mail;
4725   mail_nickname_v[0] = user_name;
4726   proxy_address_v[0] = proxy_address; 
4727   query_base_dn_v[0] = query_base_dn;
4728
4729   n = 0;
4730   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_REPLACE);
4731   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_REPLACE);
4732   ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4733   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_REPLACE);
4734
4735   if(!ActiveDirectory)
4736     {
4737       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_REPLACE);
4738       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_REPLACE);
4739       ADD_ATTR("displayName", name_v, LDAP_MOD_REPLACE);
4740       ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_REPLACE);
4741     }
4742
4743   if (Exchange)
4744     {
4745       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_REPLACE);
4746       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_REPLACE); 
4747       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4748       ADD_ATTR("proxyAddresses", proxy_address_v, LDAP_MOD_REPLACE);
4749     }
4750   else
4751     {
4752       mail_v[0] = contact_mail;
4753       ADD_ATTR("mail", mail_v, LDAP_MOD_REPLACE); 
4754     }
4755
4756   mods[n] = NULL;
4757   
4758   if(ActiveDirectory)
4759     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, dn_path);
4760   else
4761     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, dn_path);
4762
4763   if ((rc = ldap_modify_s(ldap_handle, new_dn, mods)) != LDAP_SUCCESS)
4764     {
4765       com_err(whoami, 0, 
4766               "Unable to modify user data for %s after renaming : %s",
4767               user_name, ldap_err2string(rc));
4768     }
4769   
4770   for (i = 0; i < n; i++)
4771     free(mods[i]);
4772
4773   return(rc);
4774 }
4775
4776 int user_create(int ac, char **av, void *ptr)
4777 {
4778   LDAPMod *mods[20];
4779   char new_dn[256];
4780   char user_name[256];
4781   char sam_name[256];
4782   char upn[256];
4783   char mail[256];
4784   char contact_mail[256];
4785   char proxy_address[256];
4786   char mail_nickname[256];
4787   char query_base_dn[256];
4788   char displayName[256];
4789   char address_book[256];
4790   char alt_recipient[256];
4791   char *cn_v[] = {NULL, NULL};
4792   char *objectClass_v[] = {"top", "person", "organizationalPerson",
4793                            "user", NULL};
4794   char *objectClass_ldap_v[] = {"top", 
4795                                 "eduPerson", "posixAccount", 
4796                                 "apple-user", "shadowAccount",
4797                                 "microsoftComTop", "securityPrincipal",
4798                                 "inetOrgPerson", "user", 
4799                                 "organizationalPerson", "person",
4800                                 "mailRecipient", NULL};
4801
4802   char *samAccountName_v[] = {NULL, NULL};
4803   char *altSecurityIdentities_v[] = {NULL, NULL};
4804   char *mitMoiraId_v[] = {NULL, NULL};
4805   char *mitMoiraClass_v[] = {NULL, NULL};
4806   char *mitMoiraStatus_v[] = {NULL, NULL};
4807   char *name_v[] = {NULL, NULL};
4808   char *desc_v[] = {NULL, NULL};
4809   char *userPrincipalName_v[] = {NULL, NULL};
4810   char *userAccountControl_v[] = {NULL, NULL};
4811   char *uid_v[] = {NULL, NULL};
4812   char *gid_v[] = {NULL, NULL};
4813   char *mitid_v[] = {NULL, NULL};
4814   char *homedir_v[] = {NULL, NULL};
4815   char *winProfile_v[] = {NULL, NULL};
4816   char *drives_v[] = {NULL, NULL};
4817   char *mail_v[] = {NULL, NULL};
4818   char *givenName_v[] = {NULL, NULL};
4819   char *sn_v[] = {NULL, NULL};
4820   char *initials_v[] = {NULL, NULL};
4821   char *displayName_v[] = {NULL, NULL};
4822   char *proxy_address_v[] = {NULL, NULL};
4823   char *mail_nickname_v[] = {NULL, NULL};
4824   char *query_base_dn_v[] = {NULL, NULL};
4825   char *address_book_v[] = {NULL, NULL};
4826   char *homeMDB_v[] = {NULL, NULL};
4827   char *homeServerName_v[] = {NULL, NULL};
4828   char *mdbUseDefaults_v[] = {NULL, NULL};
4829   char *mailbox_guid_v[] = {NULL, NULL};
4830   char *user_culture_v[] = {NULL, NULL};
4831   char *user_account_control_v[] = {NULL, NULL};
4832   char *msexch_version_v[] = {NULL, NULL};
4833   char *alt_recipient_v[] = {NULL, NULL};
4834   char *hide_address_lists_v[] = {NULL, NULL};
4835   char *principal_v[] = {NULL, NULL};
4836   char *loginshell_v[] = {NULL, NULL};
4837   char userAccountControlStr[80];
4838   char temp[1024];
4839   char principal[256];
4840   char filter_exp[1024];
4841   char search_path[512];
4842   char *attr_array[3];
4843   u_int userAccountControl = UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD | 
4844     UF_PASSWD_CANT_CHANGE; 
4845   int  n;
4846   int  rc;
4847   int  i;
4848   int  OldUseSFU30;
4849   char **call_args;
4850   char WinHomeDir[1024];
4851   char WinProfileDir[1024];
4852   char *homeMDB;
4853   char *homeServerName;
4854   ULONG dwInfo;
4855   char acBERBuf[N_SD_BER_BYTES];
4856   LK_ENTRY  *group_base;
4857   int    group_count;
4858   char TemplateDn[512];
4859   char TemplateSamName[128];
4860   LDAP_BERVAL **ppsValues;
4861   LDAPControl sControl = {"1.2.840.113556.1.4.801",
4862                           { N_SD_BER_BYTES, acBERBuf },
4863                           TRUE};
4864   LDAPControl *apsServerControls[] = {&sControl, NULL};
4865   LDAPMessage *psMsg;
4866   char *argv[3];
4867   char *save_argv[7];
4868   char search_string[256];
4869   char *o_v[] = {NULL, NULL};
4870   char *p, *q;
4871   char *mail_routing_v[] = {NULL, NULL};
4872   char *c;
4873
4874   call_args = ptr;
4875
4876   dwInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
4877     DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
4878   BEREncodeSecurityBits(dwInfo, acBERBuf);
4879
4880   if (!check_string(av[U_NAME]))
4881     {
4882       callback_rc = AD_INVALID_NAME;
4883       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
4884               av[U_NAME]);
4885       return(AD_INVALID_NAME);
4886     }
4887
4888   memset(WinHomeDir, '\0', sizeof(WinHomeDir));
4889   memset(WinProfileDir, '\0', sizeof(WinProfileDir));
4890   memset(displayName, '\0', sizeof(displayName));
4891   memset(query_base_dn, '\0', sizeof(query_base_dn));
4892   strcpy(WinHomeDir, av[U_WINHOMEDIR]);
4893   strcpy(WinProfileDir, av[U_WINPROFILEDIR]);
4894   strcpy(user_name, av[U_NAME]);
4895   sprintf(upn, "%s@%s", user_name, ldap_domain);
4896   sprintf(sam_name, "%s", av[U_NAME]);
4897
4898   if(strlen(av[U_FIRST])) {
4899     strcat(displayName, av[U_FIRST]);
4900   }
4901
4902   if(strlen(av[U_MIDDLE])) {
4903     if(strlen(av[U_FIRST]))
4904        strcat(displayName, " "); 
4905   
4906     strcat(displayName, av[U_MIDDLE]);
4907   }
4908
4909   if(strlen(av[U_LAST])) {
4910     if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]))
4911       strcat(displayName, " ");
4912
4913     strcat(displayName, av[U_LAST]);
4914   }
4915
4916   samAccountName_v[0] = sam_name;
4917   if ((atoi(av[U_STATE]) != US_NO_PASSWD) && 
4918       (atoi(av[U_STATE]) != US_REGISTERED))
4919     {
4920       userAccountControl |= UF_ACCOUNTDISABLE;
4921
4922       if (Exchange)
4923         {
4924           hide_address_lists_v[0] = "TRUE";
4925           ADD_ATTR("msExchHideFromAddressLists", hide_address_lists_v,
4926                    LDAP_MOD_ADD);
4927         }
4928     }
4929
4930   sprintf(userAccountControlStr, "%ld", userAccountControl);
4931   userAccountControl_v[0] = userAccountControlStr;
4932   userPrincipalName_v[0] = upn;
4933   
4934   if(ActiveDirectory)
4935     cn_v[0] = user_name;
4936   else
4937     cn_v[0] = displayName;
4938     
4939   name_v[0] = user_name;
4940   desc_v[0] = "Auto account created by Moira";
4941   mail_v[0] = mail;
4942   givenName_v[0] = av[U_FIRST];
4943
4944   if(ActiveDirectory)
4945     sn_v[0] = av[U_LAST];
4946   else
4947     if(strlen(av[U_LAST]))
4948       sn_v[0] = av[U_LAST];
4949     else
4950       sn_v[0] = av[U_NAME];
4951
4952   displayName_v[0] = displayName;
4953   mail_nickname_v[0] = user_name;
4954   o_v[0] = "Massachusetts Institute of Technology";
4955
4956   sprintf(temp, "Kerberos:%s@%s", user_name, PRIMARY_REALM);
4957   sprintf(principal, "%s@%s", user_name, PRIMARY_REALM);
4958   altSecurityIdentities_v[0] = temp;    
4959   principal_v[0] = principal;
4960
4961   if(ActiveDirectory)
4962     sprintf(new_dn, "cn=%s,%s,%s", user_name, user_ou, call_args[1]);
4963   else
4964     sprintf(new_dn, "uid=%s,%s,%s", user_name, user_ou, call_args[1]);
4965
4966   sprintf(mail,"%s@%s", user_name, lowercase(ldap_domain));
4967   sprintf(contact_mail, "%s@mit.edu", user_name);
4968   sprintf(query_base_dn, "%s%s", ADDRESS_LIST_PREFIX, call_args[1]);
4969   query_base_dn_v[0] = query_base_dn;
4970   sprintf(alt_recipient, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, 
4971           call_args[1]);
4972   sprintf(search_string, "@%s", uppercase(ldap_domain));
4973
4974   if (Exchange)
4975     {
4976       if(contact_create((LDAP *)call_args[0], call_args[1], contact_mail, 
4977                         contact_ou))
4978         {
4979           com_err(whoami, 0, "Unable to create user contact %s", 
4980                   contact_mail);
4981         }
4982       
4983       if(find_homeMDB((LDAP *)call_args[0], call_args[1], &homeMDB, 
4984                       &homeServerName)) 
4985         {
4986           com_err(whoami, 0, "Unable to locate homeMB and homeServerName");
4987           return(1);
4988         }
4989       
4990       com_err(whoami, 0, "homeMDB:%s", homeMDB);
4991       com_err(whoami, 0, "homeServerName:%s", homeServerName);
4992   
4993       homeMDB_v[0] = homeMDB;
4994       homeServerName_v[0] = homeServerName; 
4995     }
4996
4997   n = 0;
4998
4999   ADD_ATTR("cn", cn_v, LDAP_MOD_ADD);
5000   
5001   if(ActiveDirectory) 
5002     {
5003       ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
5004     }
5005   else
5006     {
5007       ADD_ATTR("objectClass", objectClass_ldap_v, LDAP_MOD_ADD);
5008     }
5009
5010   ADD_ATTR("sAMAccountName", samAccountName_v, LDAP_MOD_ADD);
5011   ADD_ATTR("userPrincipalName", userPrincipalName_v, LDAP_MOD_ADD);
5012   ADD_ATTR("userAccountControl", userAccountControl_v, LDAP_MOD_ADD);
5013   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
5014   ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
5015
5016   if (Exchange)
5017     {
5018       ADD_ATTR("msExchQueryBaseDN", query_base_dn_v, LDAP_MOD_ADD);
5019       ADD_ATTR("mailNickName", mail_nickname_v, LDAP_MOD_ADD);
5020       ADD_ATTR("homeMDB", homeMDB_v, LDAP_MOD_ADD);
5021       mdbUseDefaults_v[0] = "TRUE";
5022       ADD_ATTR("mdbUseDefaults", mdbUseDefaults_v, LDAP_MOD_ADD);
5023       ADD_ATTR("msExchHomeServerName", homeServerName_v, LDAP_MOD_ADD); 
5024       
5025       argv[0] = user_name;
5026     
5027       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5028         {
5029           if(!strcmp(save_argv[1], "EXCHANGE") || 
5030              (strstr(save_argv[3], search_string) != NULL))
5031             {
5032               argv[0] = exchange_acl;
5033               argv[1] = "USER";
5034               argv[2] = user_name;
5035               
5036               rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
5037               
5038               if ((rc) && (rc != MR_EXISTS))
5039                 {
5040                   com_err(whoami, 0, "Unable to add user %s to %s: %s",
5041                           user_name, exchange_acl, error_message(rc));
5042                 }
5043             } 
5044           else 
5045             {
5046               alt_recipient_v[0] = alt_recipient;
5047               ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5048             }
5049         }
5050       else
5051         {
5052           alt_recipient_v[0] = alt_recipient;
5053           ADD_ATTR("altRecipient", alt_recipient_v, LDAP_MOD_ADD);
5054           
5055           com_err(whoami, 0, "Unable to fetch pobox for %s", user_name);
5056         }
5057     }
5058   else
5059     {
5060       mail_v[0] = contact_mail;
5061       ADD_ATTR("mail", mail_v, LDAP_MOD_ADD);
5062     }
5063
5064   if(strlen(av[U_FIRST])) {
5065     ADD_ATTR("givenName", givenName_v, LDAP_MOD_ADD);
5066   }
5067
5068   if(strlen(av[U_LAST]) || strlen(av[U_NAME])) {
5069     ADD_ATTR("sn", sn_v, LDAP_MOD_ADD);
5070   }
5071
5072   if(strlen(av[U_FIRST]) || strlen(av[U_MIDDLE]) || strlen(av[U_LAST])) {
5073     ADD_ATTR("displayName", displayName_v, LDAP_MOD_ADD);
5074
5075     if(!ActiveDirectory)
5076       {
5077         ADD_ATTR("eduPersonNickname", displayName_v, LDAP_MOD_ADD);      
5078       }
5079   } else {
5080     ADD_ATTR("displayName", name_v, LDAP_MOD_ADD);
5081
5082     if(!ActiveDirectory)
5083       {
5084         ADD_ATTR("eduPersonNickname", name_v, LDAP_MOD_ADD);            
5085       }
5086   }
5087
5088   if (strlen(av[U_MIDDLE]) == 1) {
5089     initials_v[0] = av[U_MIDDLE];
5090     ADD_ATTR("initials", initials_v, LDAP_MOD_ADD);
5091   }
5092
5093   if (strlen(call_args[2]) != 0)    
5094     {
5095       mitMoiraId_v[0] = call_args[2];
5096       ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_ADD); 
5097     }
5098
5099   ADD_ATTR("altSecurityIdentities", altSecurityIdentities_v, LDAP_MOD_ADD);
5100
5101   if(!ActiveDirectory)
5102     {
5103       loginshell_v[0] = av[U_SHELL];
5104       mitMoiraClass_v[0] = av[U_CLASS];
5105       mitMoiraStatus_v[0] = av[U_STATE];
5106       ADD_ATTR("loginShell", loginshell_v, LDAP_MOD_ADD);
5107       ADD_ATTR("uid", samAccountName_v, LDAP_MOD_ADD);
5108       ADD_ATTR("eduPersonPrincipalName", mail_v, LDAP_MOD_ADD);
5109       ADD_ATTR("o", o_v, LDAP_MOD_ADD);
5110       ADD_ATTR("mitMoiraClass", mitMoiraClass_v, LDAP_MOD_ADD);
5111       ADD_ATTR("mitMoiraStatus", mitMoiraStatus_v, LDAP_MOD_ADD);
5112     }
5113
5114   if (strlen(av[U_UID]) != 0)
5115     {
5116       uid_v[0] = av[U_UID];
5117
5118       if(ActiveDirectory) 
5119         {
5120           ADD_ATTR("uid", uid_v, LDAP_MOD_ADD);
5121         }
5122       else
5123         {
5124           gid_v[0] = "101";
5125           ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5126           ADD_ATTR("gidNumber", gid_v, LDAP_MOD_ADD);
5127         }
5128
5129       if(ActiveDirectory)
5130         {
5131           if (!UseSFU30)
5132             {
5133               ADD_ATTR("uidNumber", uid_v, LDAP_MOD_ADD);
5134             }
5135           else
5136             {
5137               ADD_ATTR("msSFU30UidNumber", uid_v, LDAP_MOD_ADD);
5138             }
5139         }
5140     }
5141
5142   if ((strlen(av[U_MITID]) != 0) && (av[U_MITID][0] == '9'))
5143       mitid_v[0] = av[U_MITID];
5144   else
5145       mitid_v[0] = "none";
5146
5147   ADD_ATTR("employeeID", mitid_v, LDAP_MOD_ADD);
5148
5149   n = SetHomeDirectory((LDAP *)call_args[0], user_name, new_dn, 
5150                        WinHomeDir, WinProfileDir, homedir_v, winProfile_v,
5151                        drives_v, mods, LDAP_MOD_ADD, n);
5152   
5153   if(ActiveDirectory) 
5154     {
5155       sprintf(filter_exp, "(sAMAccountName=%s)", "UserTemplate.u");
5156       sprintf(search_path, "%s,%s", security_template_ou, call_args[1]);
5157       attr_array[0] = "sAMAccountName";
5158       attr_array[1] = NULL;
5159       group_count = 0;
5160       group_base = NULL;
5161       
5162       if ((rc = linklist_build((LDAP *)call_args[0], search_path, filter_exp, 
5163                                attr_array, &group_base, &group_count, 
5164                                LDAP_SCOPE_SUBTREE) != 0))
5165         return(1);
5166       
5167       if (group_count != 1)
5168         {
5169           com_err(whoami, 0, "Unable to process user security template: %s - "
5170                   "security not set", "UserTemplate.u");
5171           return(1);
5172         }
5173       
5174       strcpy(TemplateDn, group_base->dn);
5175       strcpy(TemplateSamName, group_base->value);
5176       linklist_free(group_base);
5177       group_base = NULL;
5178       group_count = 0;
5179       
5180       rc = ldap_search_ext_s((LDAP *)call_args[0], search_path, 
5181                              LDAP_SCOPE_SUBTREE, filter_exp, NULL, 0, 
5182                              apsServerControls, NULL,
5183                              NULL, 0, &psMsg);
5184       
5185       if ((psMsg = ldap_first_entry((LDAP *)call_args[0], psMsg)) == NULL)
5186         {
5187           com_err(whoami, 0, "Unable to find user security template: %s - "
5188                   "security not set", "UserTemplate.u");
5189           return(1);
5190         }
5191       
5192       ppsValues = ldap_get_values_len((LDAP *)call_args[0], psMsg, 
5193                                       "ntSecurityDescriptor");
5194       if (ppsValues == NULL)
5195         {
5196           com_err(whoami, 0, "Unable to find user security template: %s - "
5197                   "security not set", "UserTemplate.u");
5198           return(1);
5199         }
5200       
5201       ADD_ATTR("ntSecurityDescriptor", (char **)ppsValues,
5202                LDAP_MOD_REPLACE | LDAP_MOD_BVALUES); 
5203     }
5204
5205   mods[n] = NULL;
5206
5207   rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5208
5209   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5210     {
5211       OldUseSFU30 = UseSFU30;
5212       SwitchSFU(mods, &UseSFU30, n);
5213       if (OldUseSFU30 != UseSFU30)
5214         rc = ldap_add_ext_s((LDAP *)call_args[0], new_dn, mods, NULL, NULL);
5215     }
5216
5217   for (i = 0; i < n; i++)
5218     free(mods[i]);
5219
5220   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
5221     {
5222       com_err(whoami, 0, "Unable to create user %s : %s",
5223               user_name, ldap_err2string(rc));
5224       callback_rc = rc;
5225       return(rc);
5226     }
5227
5228   if ((rc == LDAP_SUCCESS) && (SetPassword))
5229     {
5230       if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5231         {
5232           ad_kdc_disconnect();
5233           if (!ad_server_connect(default_server, ldap_domain))
5234             {
5235               com_err(whoami, 0, "Unable to set password for user %s : %s",
5236                       user_name, 
5237                       "cannot get changepw ticket from windows domain");
5238             }
5239           else
5240             {
5241               if ((rc = set_password(sam_name, "", ldap_domain)) != 0)
5242                 {
5243                   com_err(whoami, 0, "Unable to set password for user %s "
5244                           ": %ld", user_name, rc);
5245                 }
5246             }
5247         }
5248     }
5249
5250   if(!ActiveDirectory) 
5251     {
5252       if (rc = moira_connect())
5253         {
5254           critical_alert("AD incremental", 
5255                          "Error contacting Moira server : %s",
5256                          error_message(rc));
5257           return;
5258         }
5259   
5260       argv[0] = user_name;
5261       
5262       if (!(rc = mr_query("get_pobox", 1, argv, save_query_info, save_argv)))
5263         {
5264           p = strdup(save_argv[3]);
5265           
5266           if((c = strchr(p, ',')) != NULL) {
5267             q = strtok(p, ",");
5268             StringTrim(q);
5269
5270             if ((c = strchr(q, '@')) == NULL)
5271               sprintf(temp, "%s@mit.edu", q);
5272             else
5273               sprintf(temp, "%s", q);
5274
5275             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5276               {
5277                 mail_routing_v[0]  = temp;
5278
5279                 n = 0;
5280                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5281                 mods[n] = NULL;
5282                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5283                 
5284                 if (rc == LDAP_ALREADY_EXISTS || 
5285                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5286                   rc = LDAP_SUCCESS;
5287                 
5288                 if(rc)
5289                   com_err(whoami, 0, 
5290                           "Unable to set the mailRoutingAddress for %s : %s",
5291                           user_name, ldap_err2string(rc));
5292               }
5293
5294             while((q = strtok(NULL, ",")) != NULL) {
5295               StringTrim(q);
5296
5297               if((c = strchr(q, '@')) == NULL)
5298                 sprintf(temp, "%s@mit.edu", q);
5299               else
5300                 sprintf(temp, "%s", q);
5301
5302               if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED)
5303                 {
5304                   mail_routing_v[0]  = temp;
5305                   
5306                   n = 0;
5307                   ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5308                   mods[n] = NULL;
5309                   rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5310                   
5311                   if (rc == LDAP_ALREADY_EXISTS || 
5312                       rc == LDAP_TYPE_OR_VALUE_EXISTS)
5313                     rc = LDAP_SUCCESS;
5314                   
5315                   if(rc)
5316                     com_err(whoami, 0, 
5317                             "Unable to set the mailRoutingAddress for %s : %s",
5318                             user_name, ldap_err2string(rc));
5319                 }
5320             }
5321           } else {
5322             StringTrim(p);
5323
5324             if((c = strchr(p, '@')) == NULL)
5325               sprintf(temp, "%s@mit.edu", p);
5326             else
5327               sprintf(temp, "%s", p);
5328
5329             if(email_isvalid(temp) && atoi(av[U_STATE]) != US_DELETED) 
5330               {
5331                 mail_routing_v[0]  = temp;
5332                 
5333                 n = 0;
5334                 ADD_ATTR("mailRoutingAddress", mail_routing_v, LDAP_MOD_ADD);
5335                 mods[n] = NULL;
5336                 rc = ldap_modify_s((LDAP *)call_args[0], new_dn, mods);
5337                 
5338                 if (rc == LDAP_ALREADY_EXISTS || 
5339                     rc == LDAP_TYPE_OR_VALUE_EXISTS)
5340                   rc = LDAP_SUCCESS;
5341                 
5342                 if(rc)
5343                   com_err(whoami, 0, 
5344                           "Unable to set the mailRoutingAddress for %s : %s",
5345                           user_name, ldap_err2string(rc));
5346               }
5347           }
5348         }
5349       moira_disconnect();
5350     }
5351
5352   return(0);
5353 }
5354
5355 int user_change_status(LDAP *ldap_handle, char *dn_path, 
5356                        char *user_name, char *MoiraId,
5357                        int operation)
5358 {
5359   char      filter[128];
5360   char      *attr_array[3];
5361   char      temp[256];
5362   char      distinguished_name[1024];
5363   char      **modvalues;
5364   char      *mitMoiraId_v[] = {NULL, NULL};
5365   LDAPMod   *mods[20];
5366   LK_ENTRY  *group_base;
5367   int       group_count;
5368   int       rc;
5369   int       i;
5370   int       n;
5371   ULONG     ulongValue;
5372
5373   if (!check_string(user_name))
5374     {
5375       com_err(whoami, 0, "Unable to process invalid LDAP user name %s", 
5376               user_name);
5377       return(AD_INVALID_NAME);
5378     }
5379
5380   group_count = 0;
5381   group_base = NULL;
5382
5383   if (strlen(MoiraId) != 0)
5384     {
5385       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5386       attr_array[0] = "UserAccountControl";
5387       attr_array[1] = NULL;
5388       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5389                                &group_base, &group_count, 
5390                                LDAP_SCOPE_SUBTREE)) != 0)
5391         {
5392           com_err(whoami, 0, "Unable to process user %s : %s",
5393                   user_name, ldap_err2string(rc));
5394           return(rc);
5395         }
5396     }
5397
5398   if (group_count != 1)
5399     {
5400       linklist_free(group_base);
5401       group_count = 0;
5402       group_base = NULL;
5403       sprintf(filter, "(sAMAccountName=%s)", user_name);
5404       attr_array[0] = "UserAccountControl";
5405       attr_array[1] = NULL;
5406       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5407                                &group_base, &group_count, 
5408                                LDAP_SCOPE_SUBTREE)) != 0)
5409         {
5410           com_err(whoami, 0, "Unable to process user %s : %s",
5411                   user_name, ldap_err2string(rc));
5412           return(rc);
5413         }
5414     }
5415   
5416   if (group_count != 1)
5417     {
5418       linklist_free(group_base);
5419       com_err(whoami, 0, "Unable to find user %s in AD",
5420               user_name);
5421       return(LDAP_NO_SUCH_OBJECT);
5422     }
5423
5424   strcpy(distinguished_name, group_base->dn);
5425   ulongValue = atoi((*group_base).value);
5426
5427   if (operation == MEMBER_DEACTIVATE)
5428     ulongValue |= UF_ACCOUNTDISABLE;
5429   else    
5430     ulongValue &= ~UF_ACCOUNTDISABLE;
5431
5432   sprintf(temp, "%ld", ulongValue);
5433
5434   if ((rc = construct_newvalues(group_base, group_count, (*group_base).value, 
5435                                 temp, &modvalues, REPLACE)) == 1)
5436     goto cleanup;
5437
5438   linklist_free(group_base);
5439   group_base = NULL;
5440   group_count = 0;
5441   n = 0;
5442   ADD_ATTR("UserAccountControl", modvalues, LDAP_MOD_REPLACE);
5443
5444   if (strlen(MoiraId) != 0)
5445     {
5446     mitMoiraId_v[0] = MoiraId;
5447     ADD_ATTR("mitMoiraId", mitMoiraId_v, LDAP_MOD_REPLACE);
5448     }
5449
5450   mods[n] = NULL;
5451   rc = ldap_modify_s(ldap_handle, distinguished_name, mods);
5452
5453   for (i = 0; i < n; i++)
5454     free(mods[i]);
5455
5456   free_values(modvalues);
5457
5458   if (rc != LDAP_SUCCESS)
5459     {
5460       com_err(whoami, 0, "Unable to change status of user %s : %s",
5461               user_name, ldap_err2string(rc));
5462     }
5463   
5464  cleanup:
5465   return(rc);
5466 }
5467
5468 int user_delete(LDAP *ldap_handle, char *dn_path, 
5469                 char *u_name, char *MoiraId)
5470 {
5471   char      filter[128];
5472   char      *attr_array[3];
5473   char      distinguished_name[1024];
5474   char      user_name[512];
5475   LK_ENTRY  *group_base;
5476   int       group_count;
5477   int       rc;
5478   char      temp[256];
5479
5480   if (!check_string(u_name))
5481     return(AD_INVALID_NAME);
5482
5483   strcpy(user_name, u_name);
5484   group_count = 0;
5485   group_base = NULL;
5486
5487   if (strlen(MoiraId) != 0)
5488     {
5489       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
5490       attr_array[0] = "name";
5491       attr_array[1] = NULL;
5492       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5493                                &group_base, &group_count, 
5494                                LDAP_SCOPE_SUBTREE)) != 0)
5495         {
5496           com_err(whoami, 0, "Unable to process user %s : %s",
5497                   user_name, ldap_err2string(rc));
5498           goto cleanup;
5499         }
5500     }
5501   
5502   if (group_count != 1)
5503     {
5504       linklist_free(group_base);
5505       group_count = 0;
5506       group_base = NULL;
5507       sprintf(filter, "(sAMAccountName=%s)", user_name);
5508       attr_array[0] = "name";
5509       attr_array[1] = NULL;
5510       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5511                                &group_base, &group_count, 
5512                                LDAP_SCOPE_SUBTREE)) != 0)
5513         {
5514           com_err(whoami, 0, "Unable to process user %s : %s",
5515                   user_name, ldap_err2string(rc));
5516           goto cleanup;
5517         }
5518     }
5519
5520   if (group_count != 1)
5521     {
5522       com_err(whoami, 0, "Unable to find user %s in AD",
5523               user_name);
5524       goto cleanup;
5525     }
5526   
5527   strcpy(distinguished_name, group_base->dn);
5528
5529   if (rc = ldap_delete_s(ldap_handle, distinguished_name))
5530     {
5531       com_err(whoami, 0, "Unable to process user %s : %s",
5532               user_name, ldap_err2string(rc));
5533     }
5534
5535   /* Need to add code to delete mit.edu contact */
5536   
5537   if (Exchange)
5538     {
5539       sprintf(temp, "cn=%s@mit.edu,%s,%s", user_name, contact_ou, dn_path);
5540
5541       if(rc = ldap_delete_s(ldap_handle, temp))
5542         {
5543           com_err(whoami, 0, "Unable to delete user contact for %s",
5544                   user_name);
5545         }
5546     }
5547
5548  cleanup:
5549   linklist_free(group_base);
5550
5551   return(0);
5552 }
5553
5554 void linklist_free(LK_ENTRY *linklist_base)
5555 {
5556   LK_ENTRY *linklist_previous;
5557
5558   while (linklist_base != NULL)
5559     {
5560       if (linklist_base->dn != NULL)
5561         free(linklist_base->dn);
5562
5563       if (linklist_base->attribute != NULL)
5564         free(linklist_base->attribute);
5565
5566       if (linklist_base->value != NULL)
5567         free(linklist_base->value);
5568
5569       if (linklist_base->member != NULL)
5570         free(linklist_base->member);
5571
5572       if (linklist_base->type != NULL)
5573         free(linklist_base->type);
5574
5575       if (linklist_base->list != NULL)
5576         free(linklist_base->list);
5577
5578       linklist_previous = linklist_base;
5579       linklist_base = linklist_previous->next;
5580       free(linklist_previous);
5581     }
5582 }
5583
5584 void free_values(char **modvalues)
5585 {
5586   int i;
5587
5588   i = 0;
5589
5590   if (modvalues != NULL)
5591     {
5592     while (modvalues[i] != NULL)
5593       {
5594         free(modvalues[i]);
5595         modvalues[i] = NULL;
5596         ++i;
5597       }
5598     free(modvalues);
5599   }
5600 }
5601
5602 static int illegalchars[] = {
5603   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5604   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5605   1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
5606   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5607   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5608   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5609   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5610   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5611   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5612   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5613   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5614   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5615   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5616   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5617   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5618   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5619 };
5620
5621 static int illegalchars_ldap[] = {
5622   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
5623   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
5624   0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, /* SPACE - / */
5625   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
5626   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
5627   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, /* P - _ */
5628   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
5629   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5630   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5631   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5632   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5633   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5634   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5635   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5636   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5637   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5638 };
5639
5640 int check_string(char *s)
5641 {
5642   char  character;
5643
5644   for (; *s; s++)
5645     {
5646       character = *s;
5647
5648       if (isupper(character))
5649         character = tolower(character);
5650
5651       if(ActiveDirectory)
5652         {
5653           if (illegalchars[(unsigned) character])
5654             return 0;
5655         }
5656       else
5657         {
5658           if (illegalchars_ldap[(unsigned) character])
5659             return 0;
5660         }
5661     }
5662
5663   return(1);
5664 }
5665
5666 int check_container_name(char *s)
5667 {
5668   char  character;
5669
5670   for (; *s; s++)
5671     {
5672       character = *s;
5673
5674       if (isupper(character))
5675         character = tolower(character);
5676
5677       if (character == ' ')
5678         continue;
5679
5680       if (illegalchars[(unsigned) character])
5681         return 0;
5682     }
5683
5684   return(1);
5685 }
5686
5687 int mr_connect_cl(char *server, char *client, int version, int auth)
5688 {
5689   int   status;
5690   char  *motd;
5691   char  temp[128];
5692
5693   status = mr_connect(server);
5694
5695   if (status)
5696     {
5697       com_err(whoami, status, "while connecting to Moira");
5698       return status;
5699     }
5700
5701   status = mr_motd(&motd);
5702
5703   if (status)
5704     {
5705       mr_disconnect();
5706       com_err(whoami, status, "while checking server status");
5707       return status;
5708     }
5709
5710   if (motd)
5711     {
5712       sprintf(temp, "The Moira server is currently unavailable: %s", motd);
5713       com_err(whoami, status, temp);
5714       mr_disconnect();
5715       return status;
5716     }
5717
5718   status = mr_version(version);
5719
5720   if (status)
5721     {
5722       if (status == MR_UNKNOWN_PROC)
5723         {
5724           if (version > 2)
5725             status = MR_VERSION_HIGH;
5726           else
5727             status = MR_SUCCESS;
5728         }
5729
5730       if (status == MR_VERSION_HIGH)
5731         {
5732           com_err(whoami, 0, "Warning: This client is running newer code "
5733                   "than the server.");
5734                   com_err(whoami, 0, "Some operations may not work.");
5735         }
5736       else if (status && status != MR_VERSION_LOW)
5737         {
5738           com_err(whoami, status, "while setting query version number.");
5739           mr_disconnect();
5740           return status;
5741         }
5742     }
5743
5744   if (auth)
5745     {
5746       status = mr_krb5_auth(client);
5747       if (status)
5748         {
5749           com_err(whoami, status, "while authenticating to Moira.");
5750           mr_disconnect();
5751           return status;
5752         }
5753     }
5754   
5755   return MR_SUCCESS;
5756 }
5757
5758 void AfsToWinAfs(char* path, char* winPath)
5759 {
5760   char* pathPtr;
5761   char* winPathPtr;
5762   strcpy(winPath, WINAFS);
5763   pathPtr = path + strlen(AFS);
5764   winPathPtr = winPath + strlen(WINAFS);
5765   
5766   while (*pathPtr)
5767     {
5768       if (*pathPtr == '/')
5769         *winPathPtr = '\\';
5770       else
5771         *winPathPtr = *pathPtr;
5772       
5773       pathPtr++;
5774       winPathPtr++;
5775     }
5776 }
5777
5778 int GetAceInfo(int ac, char **av, void *ptr)
5779 {
5780   char **call_args;
5781   int   security_flag;
5782
5783   call_args = ptr;
5784   
5785   strcpy(call_args[0], av[L_ACE_TYPE]);
5786   strcpy(call_args[1], av[L_ACE_NAME]);
5787   security_flag = 0;
5788   get_group_membership(call_args[2], call_args[3], &security_flag, av);
5789   return(LDAP_SUCCESS);  
5790 }
5791
5792 int checkADname(LDAP *ldap_handle, char *dn_path, char *Name)
5793 {
5794   char filter[128];
5795   char *attr_array[3];
5796   int  group_count;
5797   int  rc;
5798   LK_ENTRY  *group_base;
5799   
5800   group_count = 0;
5801   group_base = NULL;
5802   
5803   sprintf(filter, "(sAMAccountName=%s)", Name);
5804   attr_array[0] = "sAMAccountName";
5805   attr_array[1] = NULL;
5806
5807   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
5808                            &group_base, &group_count, 
5809                            LDAP_SCOPE_SUBTREE)) != 0)
5810     {
5811       com_err(whoami, 0, "Unable to process ACE name %s : %s",
5812               Name, ldap_err2string(rc));
5813       return(1);
5814     }
5815
5816   linklist_free(group_base);
5817   group_base = NULL;
5818
5819   if (group_count == 0)
5820     return(0);
5821   
5822   return(1);
5823 }
5824
5825 #define MAX_ACE 7
5826
5827 int ProcessAce(LDAP *ldap_handle, char *dn_path, char *Name, char *Type, 
5828                int UpdateGroup, int *ProcessGroup, char *maillist)
5829 {
5830   char  *av[2];
5831   char  GroupName[256];
5832   char  *call_args[7];
5833   int   rc;
5834   char  *AceInfo[4];
5835   char  AceType[32];
5836   char  AceName[128];
5837   char  AceMembership[2];
5838   char  AceOu[256];
5839   char  temp[128];
5840   char  *save_argv[U_END];
5841
5842   if (!SetGroupAce)
5843     {
5844       com_err(whoami, 0, "ProcessAce disabled, skipping");
5845       return(0);
5846     }
5847
5848   strcpy(GroupName, Name);
5849   
5850   if (strcasecmp(Type, "LIST"))
5851     return(1);
5852
5853   while (1)
5854     {
5855       av[0] = GroupName;
5856       AceInfo[0] = AceType;
5857       AceInfo[1] = AceName;
5858       AceInfo[2] = AceMembership;
5859       AceInfo[3] = AceOu;
5860       memset(AceType, '\0', sizeof(AceType));
5861       memset(AceName, '\0', sizeof(AceName));
5862       memset(AceMembership, '\0', sizeof(AceMembership));
5863       memset(AceOu, '\0', sizeof(AceOu));
5864       callback_rc = 0;
5865     
5866       if (rc = mr_query("get_list_info", 1, av, GetAceInfo, AceInfo))
5867         { 
5868           com_err(whoami, 0, "Unable to get ACE info for list %s : %s", 
5869                   GroupName, error_message(rc));
5870           return(1);
5871         }
5872
5873       if (callback_rc)
5874         {
5875           com_err(whoami, 0, "Unable to get ACE info for list %s", GroupName);
5876           return(1);
5877         }
5878
5879       if ((strcasecmp(AceType, "USER")) && (strcasecmp(AceType, "LIST")))
5880         return(0);
5881
5882       strcpy(temp, AceName);
5883
5884       if (!strcasecmp(AceType, "LIST"))
5885         sprintf(temp, "%s%s", AceName, group_suffix);
5886
5887       if (!UpdateGroup)
5888         {
5889           if (checkADname(ldap_handle, dn_path, temp))
5890               return(0);
5891
5892           (*ProcessGroup) = 1;
5893         }
5894
5895       if (!strcasecmp(AceInfo[0], "LIST"))
5896         {
5897           if (make_new_group(ldap_handle, dn_path, "", AceName, AceOu, 
5898                              AceMembership, 0, UpdateGroup, maillist))
5899             return(1);
5900         }
5901       else if (!strcasecmp(AceInfo[0], "USER"))
5902         {
5903           av[0] = AceName;
5904           call_args[0] = (char *)ldap_handle;
5905           call_args[1] = dn_path;
5906           call_args[2] = "";
5907           call_args[3] = NULL;
5908           callback_rc = 0;
5909
5910           if (rc = mr_query("get_user_account_by_login", 1, av, 
5911                             save_query_info, save_argv))
5912             {
5913               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5914                       AceName, Name);
5915               return(1);
5916             }
5917
5918           if (rc = user_create(U_END, save_argv, call_args)) 
5919             {
5920               com_err(whoami, 0, "Unable to process user ACE %s for group %s.",
5921                       AceName, Name);
5922               return(1);
5923             }
5924           
5925           if (callback_rc)
5926             {
5927               com_err(whoami, 0, "Unable to process user Ace %s for group %s",
5928                       AceName, Name);
5929               return(1);
5930             }
5931
5932           return(0);
5933         }
5934       else
5935         return(1);
5936
5937       if (!strcasecmp(AceType, "LIST"))
5938         {
5939           if (!strcasecmp(GroupName, AceName))
5940             return(0);
5941         }
5942
5943       strcpy(GroupName, AceName);
5944     }
5945   
5946   return(1);
5947 }
5948
5949 int make_new_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
5950                    char *group_name, char *group_ou, char *group_membership, 
5951                    int group_security_flag, int updateGroup, char *maillist)
5952 {
5953   char  *av[3];
5954   char  *call_args[8];
5955   int   rc;
5956   LK_ENTRY  *group_base;
5957   int  group_count;
5958   char filter[128];
5959   char *attr_array[3];
5960
5961   av[0] = group_name;
5962   call_args[0] = (char *)ldap_handle;
5963   call_args[1] = dn_path;
5964   call_args[2] = group_name;
5965   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
5966   call_args[4] = (char *)updateGroup;
5967   call_args[5] = MoiraId;
5968   call_args[6] = "0";
5969   call_args[7] = NULL;
5970   callback_rc = 0;
5971
5972   group_count = 0;
5973   group_base = NULL;
5974
5975   if (rc = mr_query("get_list_info", 1, av, group_create, call_args))
5976     {
5977       moira_disconnect();
5978       com_err(whoami, 0, "Unable to create list %s : %s", group_name, 
5979               error_message(rc));
5980       return(rc);
5981     }
5982
5983   if (callback_rc)
5984     {
5985       moira_disconnect();
5986       com_err(whoami, 0, "Unable to create list %s", group_name);
5987       return(callback_rc);
5988     }
5989
5990   return(0);
5991 }
5992
5993 int populate_group(LDAP *ldap_handle, char *dn_path, char *group_name, 
5994                    char *group_ou, char *group_membership, 
5995                    int group_security_flag, char *MoiraId)
5996 {
5997   char      *av[3];
5998   char      *call_args[7];
5999   char      *pUserOu;
6000   LK_ENTRY  *ptr;
6001   int       rc;
6002   char      member[512];
6003   char      *s;
6004   char      **members;
6005   int       i = 0;
6006   int       j = 0;
6007   int       n = 0;
6008   char      group_dn[512];
6009   LDAPMod   *mods[20];
6010   char      *save_argv[U_END];
6011
6012   com_err(whoami, 0, "Populating group %s", group_name);
6013   av[0] = group_name;
6014   call_args[0] = (char *)ldap_handle;
6015   call_args[1] = dn_path;
6016   call_args[2] = group_name;
6017   call_args[3] = (char *)(MOIRA_USERS | MOIRA_KERBEROS | MOIRA_STRINGS);
6018   call_args[4] = NULL;
6019   member_base = NULL;
6020
6021   if (rc = mr_query("get_end_members_of_list", 1, av,
6022                     member_list_build, call_args))
6023     {
6024       com_err(whoami, 0, "Unable to populate list %s : %s", 
6025               group_name, error_message(rc));
6026       return(3);
6027     }
6028
6029   members = (char **)malloc(sizeof(char *) * 2);
6030   
6031   if (member_base != NULL)
6032     {
6033       ptr = member_base;
6034
6035       while (ptr != NULL)
6036         {
6037           if (!strcasecmp(ptr->type, "LIST"))
6038             {
6039               ptr = ptr->next;
6040               continue;
6041             }
6042           
6043           if(!strcasecmp(ptr->type, "USER")) 
6044             {
6045               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6046                                    "")) == AD_NO_USER_FOUND)
6047                 {
6048                   com_err(whoami, 0, "creating user %s", ptr->member);
6049
6050                   av[0] = ptr->member;
6051                   call_args[0] = (char *)ldap_handle;
6052                   call_args[1] = dn_path;
6053                   call_args[2] = "";
6054                   call_args[3] = NULL;
6055                   callback_rc = 0;
6056                   
6057                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6058                                     save_query_info, save_argv))
6059                     {
6060                       com_err(whoami, 0, "Unable to create user %s " 
6061                               "while populating group %s.", ptr->member,
6062                               group_name);
6063
6064                       return(3);
6065                     }
6066
6067                   if (rc = user_create(U_END, save_argv, call_args)) 
6068                     {
6069                       com_err(whoami, 0, "Unable to create user %s "
6070                               "while populating group %s.", ptr->member,
6071                               group_name);
6072                       
6073                       return(3);
6074                     }
6075           
6076                   if (callback_rc)
6077                     {
6078                       com_err(whoami, 0, "Unable to create user %s "
6079                               "while populating group %s", ptr->member, 
6080                               group_name);
6081
6082                       return(3);
6083                     }
6084                 }
6085
6086               pUserOu = user_ou;
6087                   
6088               if(ActiveDirectory) 
6089                 {
6090                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6091                           dn_path);
6092                 }
6093               else 
6094                 {
6095                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6096                           dn_path);
6097                 }
6098
6099             }
6100           else if (!strcasecmp(ptr->type, "STRING"))
6101             {
6102               if (contact_create(ldap_handle, dn_path, ptr->member,
6103                                  contact_ou))
6104                 return(3);
6105
6106               pUserOu = contact_ou;
6107               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6108                       pUserOu, dn_path);
6109             }
6110           else if (!strcasecmp(ptr->type, "KERBEROS"))
6111             {
6112               if (contact_create(ldap_handle, dn_path, ptr->member, 
6113                                  kerberos_ou))
6114                 return(3);
6115
6116               pUserOu = kerberos_ou;
6117               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6118                       pUserOu, dn_path);
6119             }
6120
6121           if(i > 1) 
6122             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6123           members[i++] = strdup(member);
6124
6125           ptr = ptr->next;
6126         }
6127     
6128       linklist_free(member_base);
6129       member_base = NULL;
6130     }
6131
6132   members[i] = NULL;
6133   
6134   n = 0;
6135   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6136   mods[n] = NULL;
6137   
6138   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6139   
6140   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6141                           mods)) != LDAP_SUCCESS)
6142     {
6143       com_err(whoami, 0,
6144               "Unable to populate group membership for %s: %s",
6145               group_dn, ldap_err2string(rc));
6146     }
6147   
6148   for (i = 0; i < n; i++)
6149     free(mods[i]);
6150   
6151   free(members);
6152
6153   return(0);
6154 }
6155
6156 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6157                   char *group_name, char *group_ou, char *group_membership, 
6158                   int group_security_flag, int type, char *maillist)
6159 {
6160   char      before_desc[512];
6161   char      before_name[256];
6162   char      before_group_ou[256];
6163   char      before_group_membership[2];
6164   char      distinguishedName[256];
6165   char      ad_distinguishedName[256];
6166   char      filter[128];
6167   char      *attr_array[3];
6168   int       before_security_flag;
6169   int       group_count;
6170   int       rc;
6171   LK_ENTRY  *group_base;
6172   LK_ENTRY  *ptr;
6173   char      ou_both[512];
6174   char      ou_security[512];
6175   char      ou_distribution[512];
6176   char      ou_neither[512];
6177   char      group_dn[512];
6178
6179   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6180   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6181
6182   memset(filter, '\0', sizeof(filter));
6183   group_base = NULL;
6184   group_count = 0;
6185
6186   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6187                         "*", MoiraId, 
6188                         "samAccountName", &group_base, 
6189                         &group_count, filter))
6190     return(rc);
6191
6192   if (type == CHECK_GROUPS)
6193     {
6194       if (group_count == 1)
6195         {
6196           strcpy(group_dn, group_base->dn);
6197
6198           if (!strcasecmp(group_dn, distinguishedName))
6199             {
6200               linklist_free(group_base);
6201               return(0);
6202             }
6203         }
6204
6205       linklist_free(group_base);
6206
6207       if (group_count == 0)
6208         return(AD_NO_GROUPS_FOUND);
6209
6210       if (group_count == 1)
6211         return(AD_WRONG_GROUP_DN_FOUND);
6212
6213       return(AD_MULTIPLE_GROUPS_FOUND);
6214     }
6215
6216   if (group_count == 0)
6217     {
6218       return(AD_NO_GROUPS_FOUND);
6219     }
6220
6221   if (group_count > 1)
6222     {
6223       ptr = group_base;
6224
6225       strcpy(group_dn, ptr->dn);
6226
6227       while (ptr != NULL)
6228         {
6229           if (!strcasecmp(group_dn, ptr->value))
6230             break;
6231
6232           ptr = ptr->next;
6233         }
6234
6235       if (ptr == NULL)
6236         {
6237           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6238                   MoiraId);
6239           ptr = group_base;
6240
6241           while (ptr != NULL)
6242             {
6243               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6244               ptr = ptr->next;
6245             }
6246
6247           linklist_free(group_base);
6248           return(AD_MULTIPLE_GROUPS_FOUND);
6249         }
6250
6251       ptr = group_base;
6252
6253       while (ptr != NULL)
6254         {
6255           strcpy(group_dn, ptr->dn);
6256
6257           if (strcasecmp(group_dn, ptr->value))
6258             rc = ldap_delete_s(ldap_handle, ptr->value);
6259
6260           ptr = ptr->next;
6261         }
6262
6263       linklist_free(group_base);
6264       memset(filter, '\0', sizeof(filter));
6265       group_base = NULL;
6266       group_count = 0;
6267
6268       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6269                             "*", MoiraId, 
6270                             "samAccountName", &group_base, 
6271                             &group_count, filter))
6272         return(rc);
6273
6274       if (group_count == 0)
6275         return(AD_NO_GROUPS_FOUND);
6276
6277       if (group_count > 1)
6278         return(AD_MULTIPLE_GROUPS_FOUND);
6279     }
6280
6281   strcpy(ad_distinguishedName, group_base->dn);
6282   linklist_free(group_base);
6283   group_base = NULL;
6284   group_count = 0;
6285
6286   attr_array[0] = "sAMAccountName";
6287   attr_array[1] = NULL;
6288   
6289   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6290                            &group_base, &group_count, 
6291                            LDAP_SCOPE_SUBTREE)) != 0)
6292     {
6293       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6294               MoiraId, ldap_err2string(rc));
6295       return(rc);
6296     }
6297   
6298   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6299
6300   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6301     {
6302       linklist_free(group_base);
6303       group_base = NULL;
6304       group_count = 0;
6305       return(0);
6306     }
6307
6308   linklist_free(group_base);
6309   group_base = NULL;
6310   group_count = 0;
6311   memset(ou_both, '\0', sizeof(ou_both));
6312   memset(ou_security, '\0', sizeof(ou_security));
6313   memset(ou_distribution, '\0', sizeof(ou_distribution));
6314   memset(ou_neither, '\0', sizeof(ou_neither));
6315   memset(before_name, '\0', sizeof(before_name));
6316   memset(before_desc, '\0', sizeof(before_desc));
6317   memset(before_group_membership, '\0', sizeof(before_group_membership));
6318   
6319   attr_array[0] = "name";
6320   attr_array[1] = NULL;
6321
6322   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6323                            &group_base, &group_count, 
6324                            LDAP_SCOPE_SUBTREE)) != 0)
6325     {
6326       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6327               MoiraId, ldap_err2string(rc));
6328       return(rc);
6329     }
6330
6331   strcpy(before_name, group_base->value);
6332   linklist_free(group_base);
6333   group_base = NULL;
6334   group_count = 0;
6335
6336   attr_array[0] = "description";
6337   attr_array[1] = NULL;
6338   
6339   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6340                            &group_base, &group_count, 
6341                            LDAP_SCOPE_SUBTREE)) != 0)
6342     {
6343       com_err(whoami, 0, 
6344               "Unable to get list description with MoiraId = %s: %s",
6345               MoiraId, ldap_err2string(rc));
6346       return(rc);
6347     }
6348
6349   if (group_count != 0)
6350     {
6351       strcpy(before_desc, group_base->value);
6352       linklist_free(group_base);
6353       group_base = NULL;
6354       group_count = 0;
6355     }
6356  
6357   change_to_lower_case(ad_distinguishedName);  
6358   strcpy(ou_both, group_ou_both);
6359   change_to_lower_case(ou_both);
6360   strcpy(ou_security, group_ou_security);
6361   change_to_lower_case(ou_security);
6362   strcpy(ou_distribution, group_ou_distribution);
6363   change_to_lower_case(ou_distribution);
6364   strcpy(ou_neither, group_ou_neither);
6365   change_to_lower_case(ou_neither);
6366
6367   if (strstr(ad_distinguishedName, ou_both))
6368     {
6369       strcpy(before_group_ou, group_ou_both);
6370       before_group_membership[0] = 'B';
6371       before_security_flag = 1;
6372     }
6373   else if (strstr(ad_distinguishedName, ou_security))
6374     {
6375       strcpy(before_group_ou, group_ou_security);
6376       before_group_membership[0] = 'S';
6377       before_security_flag = 1;
6378     }
6379   else if (strstr(ad_distinguishedName, ou_distribution))
6380     {
6381       strcpy(before_group_ou, group_ou_distribution);
6382       before_group_membership[0] = 'D';
6383       before_security_flag = 0;
6384     }
6385   else if (strstr(ad_distinguishedName, ou_neither))
6386     {
6387       strcpy(before_group_ou, group_ou_neither);
6388       before_group_membership[0] = 'N';
6389       before_security_flag = 0;
6390     }
6391   else
6392     return(AD_NO_OU_FOUND);
6393
6394   rc = group_rename(ldap_handle, dn_path, before_name, 
6395                     before_group_membership, 
6396                     before_group_ou, before_security_flag, before_desc,
6397                     group_name, group_membership, group_ou, 
6398                     group_security_flag,
6399                     before_desc, MoiraId, filter, maillist);
6400
6401   return(rc);
6402 }
6403
6404 void change_to_lower_case(char *ptr)
6405 {
6406   int i;
6407
6408   for (i = 0; i < (int)strlen(ptr); i++)
6409     {
6410       ptr[i] = tolower(ptr[i]);
6411     }
6412 }
6413
6414 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6415                  char *group_name, char *group_membership, 
6416                  char *MoiraId, char *attribute,
6417                  LK_ENTRY **linklist_base, int *linklist_count,
6418                  char *rFilter)
6419 {
6420   LK_ENTRY  *pPtr;
6421   char  filter[128];
6422   char  *attr_array[3];
6423   char  *dn;
6424   int   rc;
6425
6426   (*linklist_base) = NULL;
6427   (*linklist_count) = 0;
6428
6429   if (strlen(rFilter) != 0)
6430     {
6431       strcpy(filter, rFilter);
6432       attr_array[0] = attribute;
6433       attr_array[1] = NULL;
6434       
6435       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6436                                linklist_base, linklist_count, 
6437                                LDAP_SCOPE_SUBTREE)) != 0)
6438         {
6439           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6440                   MoiraId, ldap_err2string(rc));
6441          return(rc);
6442        }
6443
6444     if ((*linklist_count) == 1)
6445       {
6446         strcpy(rFilter, filter);
6447         return(0);
6448       }
6449     }
6450
6451   linklist_free((*linklist_base));
6452   (*linklist_base) = NULL;
6453   (*linklist_count) = 0;
6454
6455   if (strlen(MoiraId) != 0)
6456     {
6457       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6458
6459       attr_array[0] = attribute;
6460       attr_array[1] = NULL;
6461
6462       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6463                                linklist_base, linklist_count, 
6464                                LDAP_SCOPE_SUBTREE)) != 0)
6465         {
6466           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6467                   MoiraId, ldap_err2string(rc));
6468          return(rc);
6469        }
6470     }
6471
6472   if ((*linklist_count) > 1)
6473     {
6474       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6475       pPtr = (*linklist_base);
6476
6477       while (pPtr)
6478         {
6479           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6480                   MoiraId);
6481           pPtr = pPtr->next;
6482         }
6483
6484       linklist_free((*linklist_base));
6485       (*linklist_base) = NULL;
6486       (*linklist_count) = 0;
6487     }
6488
6489   if ((*linklist_count) == 1)
6490     {
6491
6492       pPtr = (*linklist_base);
6493       dn = strdup(pPtr->dn);
6494       dn += 3;
6495
6496       if (!memcmp(dn, group_name, strlen(group_name)))
6497         {
6498           strcpy(rFilter, filter);
6499           return(0);
6500         }
6501     }
6502
6503   linklist_free((*linklist_base));
6504   (*linklist_base) = NULL;
6505   (*linklist_count) = 0;
6506   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6507
6508   attr_array[0] = attribute;
6509   attr_array[1] = NULL;
6510
6511   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6512                            linklist_base, linklist_count, 
6513                            LDAP_SCOPE_SUBTREE)) != 0)
6514     {
6515       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6516               MoiraId, ldap_err2string(rc));
6517       return(rc);
6518     }
6519
6520   if ((*linklist_count) == 1)
6521     {
6522       strcpy(rFilter, filter);
6523       return(0);
6524     }
6525
6526   return(0);
6527 }
6528
6529 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6530 {
6531   char filter[128];
6532   char *attr_array[3];
6533   char SamAccountName[64];
6534   int  group_count;
6535   int  rc;
6536   LK_ENTRY  *group_base;
6537   LK_ENTRY  *gPtr;
6538
6539   group_count = 0;
6540   group_base = NULL;
6541
6542   if (strlen(MoiraId) != 0)
6543     {
6544       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6545
6546       attr_array[0] = "sAMAccountName";
6547       attr_array[1] = NULL;
6548       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6549                                &group_base, &group_count, 
6550                                LDAP_SCOPE_SUBTREE)) != 0)
6551         {
6552           com_err(whoami, 0, "Unable to process user %s : %s",
6553                   UserName, ldap_err2string(rc));
6554           return(rc);
6555         }
6556
6557       if (group_count > 1)
6558         {
6559           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6560                   MoiraId);
6561           gPtr = group_base;
6562
6563           while (gPtr)
6564             {
6565               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6566                       gPtr->value, MoiraId);
6567               gPtr = gPtr->next;
6568             }
6569         }
6570     }
6571
6572   if (group_count != 1)
6573     {
6574       linklist_free(group_base);
6575       group_count = 0;
6576       group_base = NULL;
6577       sprintf(filter, "(sAMAccountName=%s)", UserName);
6578       attr_array[0] = "sAMAccountName";
6579       attr_array[1] = NULL;
6580
6581       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6582                                &group_base, &group_count, 
6583                                LDAP_SCOPE_SUBTREE)) != 0)
6584         {
6585           com_err(whoami, 0, "Unable to process user %s : %s",
6586                   UserName, ldap_err2string(rc));
6587           return(rc);
6588         }
6589     }
6590
6591   if (group_count != 1)
6592     {
6593       linklist_free(group_base);
6594       return(AD_NO_USER_FOUND);
6595     }
6596
6597   strcpy(SamAccountName, group_base->value);
6598   linklist_free(group_base);
6599   group_count = 0;
6600   rc = 0;
6601
6602   if (strcmp(SamAccountName, UserName))
6603     {
6604       com_err(whoami, 0, 
6605               "User object %s with MoiraId %s has mismatched usernames " 
6606               "(LDAP username %s, Moira username %s)", SamAccountName,
6607               MoiraId, SamAccountName, UserName);
6608     }
6609
6610   return(0);
6611 }
6612
6613 void container_get_dn(char *src, char *dest)
6614 {
6615   char *sPtr;
6616   char *array[20];
6617   char name[256];
6618   int  n;
6619
6620   memset(array, '\0', 20 * sizeof(array[0]));
6621
6622   if (strlen(src) == 0)
6623     return;
6624
6625   strcpy(name, src);
6626   sPtr = name;
6627   n = 0;
6628   array[n] = name;
6629   ++n;
6630
6631   while (*sPtr)
6632     {
6633       if ((*sPtr) == '/')
6634         {
6635           (*sPtr) = '\0';
6636           ++sPtr;
6637           array[n] = sPtr;
6638           ++n;
6639         }
6640       else
6641         ++sPtr;
6642     }
6643
6644   strcpy(dest, "OU=");
6645
6646   while (n != 0)
6647     {
6648       strcat(dest, array[n-1]);
6649       --n;
6650       if (n > 0)
6651         {
6652           strcat(dest, ",OU=");
6653         }
6654     }
6655
6656   return;
6657 }
6658
6659 void container_get_name(char *src, char *dest)
6660 {
6661   char *sPtr;
6662   char *dPtr;
6663
6664   if (strlen(src) == 0)
6665     return;
6666
6667   sPtr = src;
6668   dPtr = src;
6669
6670   while (*sPtr)
6671     {
6672       if ((*sPtr) == '/')
6673         {
6674           dPtr = sPtr;
6675           ++dPtr;
6676         }
6677       ++sPtr;
6678     }
6679
6680   strcpy(dest, dPtr);
6681   return;
6682 }
6683
6684 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6685 {
6686   char cName[256];
6687   char *av[7];
6688   int  i;
6689   int  rc;
6690
6691   strcpy(cName, name);
6692
6693   for (i = 0; i < (int)strlen(cName); i++)
6694     {
6695       if (cName[i] == '/')
6696         {
6697           cName[i] = '\0';
6698           av[CONTAINER_NAME] = cName;
6699           av[CONTAINER_DESC] = "";
6700           av[CONTAINER_LOCATION] = "";
6701           av[CONTAINER_CONTACT] = "";
6702           av[CONTAINER_TYPE] = "";
6703           av[CONTAINER_ID] = "";
6704           av[CONTAINER_ROWID] = "";
6705           rc = container_create(ldap_handle, dn_path, 7, av);
6706
6707           if (rc == LDAP_SUCCESS)
6708             {
6709               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6710                       cName);
6711             }
6712
6713           cName[i] = '/';
6714         }
6715     }
6716 }
6717
6718 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6719                      char **before, int afterc, char **after)
6720 {
6721   char      dName[256];
6722   char      cName[256];
6723   char      new_cn[128];
6724   char      new_dn_path[256];
6725   char      temp[256];
6726   char      distinguishedName[256];
6727   char      *pPtr;
6728   int       rc;
6729   int       i;
6730
6731   memset(cName, '\0', sizeof(cName));
6732   container_get_name(after[CONTAINER_NAME], cName);
6733
6734   if (!check_container_name(cName))
6735     {
6736       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6737               cName);
6738       return(AD_INVALID_NAME);
6739     }
6740
6741   memset(distinguishedName, '\0', sizeof(distinguishedName));
6742
6743   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6744                                            distinguishedName, beforec, before))
6745     return(rc);
6746
6747   if (strlen(distinguishedName) == 0)
6748     {
6749       rc = container_create(ldap_handle, dn_path, afterc, after);
6750       return(rc);
6751     }
6752
6753   strcpy(temp, after[CONTAINER_NAME]);
6754   pPtr = temp;
6755
6756   for (i = 0; i < (int)strlen(temp); i++)
6757     {
6758       if (temp[i] == '/')
6759         {
6760           pPtr = &temp[i];
6761         }
6762     }
6763
6764   (*pPtr) = '\0';
6765
6766   container_get_dn(temp, dName);
6767
6768   if (strlen(temp) != 0)
6769     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6770   else
6771     sprintf(new_dn_path, "%s", dn_path);
6772
6773   sprintf(new_cn, "OU=%s", cName);
6774
6775   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6776
6777   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6778                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6779     {
6780       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6781               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6782               ldap_err2string(rc));
6783       return(rc);
6784     }
6785
6786   memset(dName, '\0', sizeof(dName));
6787   container_get_dn(after[CONTAINER_NAME], dName);
6788   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6789
6790   return(rc);
6791 }
6792
6793 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6794 {
6795   char      distinguishedName[256];
6796   int       rc;
6797
6798   memset(distinguishedName, '\0', sizeof(distinguishedName));
6799
6800   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6801                                            distinguishedName, count, av))
6802     return(rc);
6803
6804   if (strlen(distinguishedName) == 0)
6805     return(0);
6806
6807   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6808     {
6809       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6810         container_move_objects(ldap_handle, dn_path, distinguishedName);
6811       else
6812         com_err(whoami, 0, "Unable to delete container %s from AD : %s",
6813                 av[CONTAINER_NAME], ldap_err2string(rc));
6814     }
6815
6816   return(rc);
6817 }
6818
6819 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6820 {
6821   char      *attr_array[3];
6822   LK_ENTRY  *group_base;
6823   int       group_count;
6824   LDAPMod   *mods[20];
6825   char      *objectClass_v[] = {"top", 
6826                            "organizationalUnit", 
6827                            NULL};
6828
6829   char *ou_v[] = {NULL, NULL};
6830   char *name_v[] = {NULL, NULL};
6831   char *moiraId_v[] = {NULL, NULL};
6832   char *desc_v[] = {NULL, NULL};
6833   char *managedBy_v[] = {NULL, NULL};
6834   char dName[256];
6835   char cName[256];
6836   char managedByDN[256];
6837   char filter[256];
6838   char temp[256];
6839   int  n;
6840   int  i;
6841   int  rc;
6842     
6843   memset(filter, '\0', sizeof(filter));
6844   memset(dName, '\0', sizeof(dName));
6845   memset(cName, '\0', sizeof(cName));
6846   memset(managedByDN, '\0', sizeof(managedByDN));
6847   container_get_dn(av[CONTAINER_NAME], dName);
6848   container_get_name(av[CONTAINER_NAME], cName);
6849
6850   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6851     {
6852       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6853               cName);
6854       return(AD_INVALID_NAME);
6855     }
6856
6857   if (!check_container_name(cName))
6858     {
6859       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6860               cName);
6861       return(AD_INVALID_NAME);
6862     }
6863
6864   n = 0;
6865   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6866   name_v[0] = cName;
6867   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6868   ou_v[0] = cName;
6869   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6870
6871   if (strlen(av[CONTAINER_ROWID]) != 0)
6872     {
6873       moiraId_v[0] = av[CONTAINER_ROWID];
6874       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6875     }
6876
6877   if (strlen(av[CONTAINER_DESC]) != 0)
6878     {
6879       desc_v[0] = av[CONTAINER_DESC];
6880       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6881     }
6882
6883   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6884     {
6885       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6886         {
6887           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6888                               kerberos_ou))
6889             {
6890               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6891                       kerberos_ou, dn_path);
6892               managedBy_v[0] = managedByDN;
6893               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6894             }
6895         }
6896       else
6897         {
6898           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6899             {
6900               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6901                       "(objectClass=user)))", av[CONTAINER_ID]);
6902             }
6903
6904           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6905             {
6906               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6907                       av[CONTAINER_ID]);
6908             }
6909
6910           if (strlen(filter) != 0)
6911             {
6912               attr_array[0] = "distinguishedName";
6913               attr_array[1] = NULL;
6914               group_count = 0;
6915               group_base = NULL;
6916               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6917                                        attr_array, 
6918                                        &group_base, &group_count, 
6919                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6920                 {
6921                   if (group_count == 1)
6922                     {
6923                       strcpy(managedByDN, group_base->value);
6924                       managedBy_v[0] = managedByDN;
6925                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6926                     }
6927                   linklist_free(group_base);
6928                   group_base = NULL;
6929                   group_count = 0;
6930                 }
6931             }
6932         }
6933     }
6934   
6935   mods[n] = NULL;
6936
6937   sprintf(temp, "%s,%s", dName, dn_path);
6938   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
6939   
6940   for (i = 0; i < n; i++)
6941     free(mods[i]);
6942   
6943   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
6944     {
6945       com_err(whoami, 0, "Unable to create container %s : %s",
6946               cName, ldap_err2string(rc));
6947       return(rc);
6948     }
6949
6950   if (rc == LDAP_ALREADY_EXISTS)
6951     {
6952       if (strlen(av[CONTAINER_ROWID]) != 0)
6953         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
6954     }
6955
6956   return(rc);
6957 }
6958
6959 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
6960                      char **before, int afterc, char **after)
6961 {
6962   char distinguishedName[256];
6963   int  rc;
6964
6965   memset(distinguishedName, '\0', sizeof(distinguishedName));
6966
6967   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6968                                            distinguishedName, afterc, after))
6969     return(rc);
6970
6971   if (strlen(distinguishedName) == 0)
6972     {
6973       rc = container_create(ldap_handle, dn_path, afterc, after);
6974       return(rc);
6975     }
6976   
6977   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6978   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
6979                           after);
6980
6981   return(rc);
6982 }
6983
6984 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
6985                                     char *distinguishedName, int count, 
6986                                     char **av)
6987 {
6988   char      *attr_array[3];
6989   LK_ENTRY  *group_base;
6990   int       group_count;
6991   char      dName[256];
6992   char      cName[256];
6993   char      filter[512];
6994   int       rc;
6995
6996   memset(filter, '\0', sizeof(filter));
6997   memset(dName, '\0', sizeof(dName));
6998   memset(cName, '\0', sizeof(cName));
6999   container_get_dn(av[CONTAINER_NAME], dName);
7000   container_get_name(av[CONTAINER_NAME], cName);
7001
7002   if (strlen(dName) == 0)
7003     {
7004       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7005               av[CONTAINER_NAME]);
7006       return(AD_INVALID_NAME);
7007     }
7008
7009   if (!check_container_name(cName))
7010     {
7011       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7012               cName);
7013       return(AD_INVALID_NAME);
7014     }
7015   
7016   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7017           av[CONTAINER_ROWID]);
7018   attr_array[0] = "distinguishedName";
7019   attr_array[1] = NULL;
7020   group_count = 0;
7021   group_base = NULL;
7022
7023   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7024                            &group_base, &group_count, 
7025                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7026     {
7027       if (group_count == 1)
7028         {
7029           strcpy(distinguishedName, group_base->value);
7030         }
7031
7032       linklist_free(group_base);
7033       group_base = NULL;
7034       group_count = 0;
7035     }
7036
7037   if (strlen(distinguishedName) == 0)
7038     {
7039       sprintf(filter, "(&(objectClass=organizationalUnit)"
7040               "(distinguishedName=%s,%s))", dName, dn_path);
7041       attr_array[0] = "distinguishedName";
7042       attr_array[1] = NULL;
7043       group_count = 0;
7044       group_base = NULL;
7045
7046       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7047                                &group_base, &group_count, 
7048                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7049         {
7050           if (group_count == 1)
7051             {
7052               strcpy(distinguishedName, group_base->value);
7053             }
7054
7055           linklist_free(group_base);
7056           group_base = NULL;
7057           group_count = 0;
7058         }
7059     }
7060
7061   return(0);
7062 }
7063
7064 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7065                        char *distinguishedName, int count, char **av)
7066 {
7067   char      *attr_array[5];
7068   LK_ENTRY  *group_base;
7069   LK_ENTRY  *pPtr;
7070   LDAPMod   *mods[20];
7071   int       group_count;
7072   char      filter[512];
7073   char      *moiraId_v[] = {NULL, NULL};
7074   char      *desc_v[] = {NULL, NULL};
7075   char      *managedBy_v[] = {NULL, NULL};
7076   char      managedByDN[256];
7077   char      moiraId[64];
7078   char      desc[256];
7079   char      ad_path[512];
7080   int       rc;
7081   int       i;
7082   int       n;
7083
7084
7085   strcpy(ad_path, distinguishedName);
7086
7087   if (strlen(dName) != 0)
7088     sprintf(ad_path, "%s,%s", dName, dn_path);
7089
7090   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7091           ad_path);
7092
7093   if (strlen(av[CONTAINER_ID]) != 0)
7094     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7095             av[CONTAINER_ROWID]);
7096
7097   attr_array[0] = "mitMoiraId";
7098   attr_array[1] = "description";
7099   attr_array[2] = "managedBy";
7100   attr_array[3] = NULL;
7101   group_count = 0;
7102   group_base = NULL;
7103
7104   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7105                            &group_base, &group_count, 
7106                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7107     {
7108       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7109               av[CONTAINER_NAME], ldap_err2string(rc));
7110       return(rc);
7111     }
7112
7113   memset(managedByDN, '\0', sizeof(managedByDN));
7114   memset(moiraId, '\0', sizeof(moiraId));
7115   memset(desc, '\0', sizeof(desc));
7116   pPtr = group_base;
7117
7118   while (pPtr)
7119     {
7120       if (!strcasecmp(pPtr->attribute, "description"))
7121         strcpy(desc, pPtr->value);
7122       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7123         strcpy(managedByDN, pPtr->value);
7124       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7125         strcpy(moiraId, pPtr->value);
7126       pPtr = pPtr->next;
7127     }
7128
7129   linklist_free(group_base);
7130   group_base = NULL;
7131   group_count = 0;
7132
7133   n = 0;
7134   if (strlen(av[CONTAINER_ROWID]) != 0)
7135     {
7136       moiraId_v[0] = av[CONTAINER_ROWID];
7137       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7138     }
7139
7140   if (strlen(av[CONTAINER_DESC]) != 0)
7141     {
7142       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7143                        dName);
7144     }
7145   else
7146     {
7147       if (strlen(desc) != 0)
7148         {
7149           attribute_update(ldap_handle, ad_path, "", "description", dName);
7150         }
7151     }
7152
7153   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7154     {
7155       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7156         {
7157           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7158                               kerberos_ou))
7159             {
7160               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7161                       kerberos_ou, dn_path);
7162               managedBy_v[0] = managedByDN;
7163               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7164             }
7165           else
7166             {
7167               if (strlen(managedByDN) != 0)
7168                 {
7169                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7170                                    dName);
7171                 }
7172             }
7173         }
7174       else
7175         {
7176           memset(filter, '\0', sizeof(filter));
7177
7178           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7179             {
7180               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7181                       "(objectClass=user)))", av[CONTAINER_ID]);
7182             }
7183
7184           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7185             {
7186               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7187                       av[CONTAINER_ID]);
7188             }
7189
7190           if (strlen(filter) != 0)
7191             {
7192               attr_array[0] = "distinguishedName";
7193               attr_array[1] = NULL;
7194               group_count = 0;
7195               group_base = NULL;
7196               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7197                                        attr_array, &group_base, &group_count, 
7198                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7199                 {
7200                   if (group_count == 1)
7201                     {
7202                       strcpy(managedByDN, group_base->value);
7203                       managedBy_v[0] = managedByDN;
7204                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7205                     }
7206                   else
7207                     {
7208                       if (strlen(managedByDN) != 0)
7209                         {
7210                           attribute_update(ldap_handle, ad_path, "", 
7211                                            "managedBy", dName);
7212                         }
7213                     }
7214
7215                   linklist_free(group_base);
7216                   group_base = NULL;
7217                   group_count = 0;
7218                 }
7219             }
7220           else
7221             {
7222               if (strlen(managedByDN) != 0)
7223                 {
7224                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7225                                    dName);
7226                 }
7227             }
7228         }
7229     }
7230
7231   mods[n] = NULL;
7232
7233   if (n == 0)
7234     return(LDAP_SUCCESS);
7235
7236   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7237
7238   for (i = 0; i < n; i++)
7239     free(mods[i]);
7240
7241   if (rc != LDAP_SUCCESS)
7242     {
7243       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7244               av[CONTAINER_NAME], ldap_err2string(rc));
7245       return(rc);
7246     }
7247   
7248   return(rc);
7249 }
7250
7251 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7252 {
7253   char      *attr_array[3];
7254   LK_ENTRY  *group_base;
7255   LK_ENTRY  *pPtr;
7256   int       group_count;
7257   char      filter[512];
7258   char      new_cn[128];
7259   char      temp[256];
7260   int       rc;
7261   int       NumberOfEntries = 10;
7262   int       i;
7263   int       count;
7264
7265   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7266
7267   for (i = 0; i < 3; i++)
7268     {
7269       memset(filter, '\0', sizeof(filter));
7270
7271       if (i == 0)
7272         {
7273           strcpy(filter, "(!(|(objectClass=computer)"
7274                  "(objectClass=organizationalUnit)))");
7275           attr_array[0] = "cn";
7276           attr_array[1] = NULL;
7277         }
7278       else if (i == 1)
7279         {
7280           strcpy(filter, "(objectClass=computer)");
7281           attr_array[0] = "cn";
7282           attr_array[1] = NULL;
7283         }
7284       else
7285         {
7286           strcpy(filter, "(objectClass=organizationalUnit)");
7287           attr_array[0] = "ou";
7288           attr_array[1] = NULL;
7289         }
7290
7291       while (1)
7292         {
7293           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7294                                    &group_base, &group_count, 
7295                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7296             {
7297               break;
7298             }
7299
7300           if (group_count == 0)
7301             break;
7302
7303           pPtr = group_base;
7304
7305           while(pPtr)
7306             {
7307               if (!strcasecmp(pPtr->attribute, "cn"))
7308                 {
7309                   sprintf(new_cn, "cn=%s", pPtr->value);
7310                   if (i == 0)
7311                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7312                   if (i == 1)
7313                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7314                   count = 1;
7315
7316                   while (1)
7317                     {
7318                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7319                                          TRUE, NULL, NULL);
7320                       if (rc == LDAP_ALREADY_EXISTS)
7321                         {
7322                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7323                           ++count;
7324                         }
7325                       else
7326                         break;
7327                     }
7328                 }
7329               else if (!strcasecmp(pPtr->attribute, "ou"))
7330                 {
7331                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7332                 }
7333
7334               pPtr = pPtr->next;
7335             }
7336
7337           linklist_free(group_base);
7338           group_base = NULL;
7339           group_count = 0;
7340         }
7341     }
7342
7343   return(0);
7344 }
7345
7346 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7347                    char *machine_ou, char *NewMachineName)
7348 {
7349   LK_ENTRY  *group_base;
7350   int  group_count;
7351   int  i;
7352   char filter[128];
7353   char *attr_array[3];
7354   char cn[256];
7355   char dn[256];
7356   char temp[256];
7357   char *pPtr;
7358   int   rc;
7359
7360   strcpy(NewMachineName, member);
7361   rc = moira_connect();
7362   rc = GetMachineName(NewMachineName);
7363   moira_disconnect();
7364
7365   if (strlen(NewMachineName) == 0)
7366     {
7367       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7368               member);
7369       return(1);
7370     }
7371
7372   pPtr = NULL;
7373   pPtr = strchr(NewMachineName, '.');
7374
7375   if (pPtr != NULL)
7376     (*pPtr) = '\0';
7377
7378   group_base = NULL;
7379   group_count = 0;
7380   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7381   attr_array[0] = "cn";
7382   attr_array[1] = NULL;
7383   sprintf(temp, "%s", dn_path);
7384
7385   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7386                            &group_base, &group_count, 
7387                            LDAP_SCOPE_SUBTREE)) != 0)
7388     {
7389       com_err(whoami, 0, "Unable to process machine %s : %s",
7390               member, ldap_err2string(rc));
7391       return(1);
7392     }
7393
7394   if (group_count != 1)
7395     {
7396       com_err(whoami, 0, 
7397               "Unable to process machine %s : machine not found in AD",
7398               NewMachineName);
7399       return(1);
7400     }
7401
7402   strcpy(dn, group_base->dn);
7403   strcpy(cn, group_base->value);
7404
7405   for (i = 0; i < (int)strlen(dn); i++)
7406     dn[i] = tolower(dn[i]);
7407
7408   for (i = 0; i < (int)strlen(cn); i++)
7409     cn[i] = tolower(cn[i]);
7410
7411   linklist_free(group_base);
7412   pPtr = NULL;
7413   pPtr = strstr(dn, cn);
7414
7415   if (pPtr == NULL)
7416     {
7417       com_err(whoami, 0, "Unable to process machine %s",
7418               member);
7419       return(1);
7420     }
7421
7422   pPtr += strlen(cn) + 1;
7423   strcpy(machine_ou, pPtr);
7424   pPtr = NULL;
7425   pPtr = strstr(machine_ou, "dc=");
7426
7427   if (pPtr == NULL)
7428     {
7429       com_err(whoami, 0, "Unable to process machine %s",
7430               member);
7431       return(1);
7432     }
7433
7434   --pPtr;
7435   (*pPtr) = '\0';
7436
7437   return(0);
7438 }
7439
7440 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7441                        char *MoiraMachineName, char *DestinationOu)
7442 {
7443   char        NewCn[128];
7444   char        OldDn[512];
7445   char        MachineName[128];
7446   char        filter[128];
7447   char        *attr_array[3];
7448   char        NewOu[256];
7449   char        *cPtr = NULL;
7450   int         group_count;
7451   long        rc;
7452   LK_ENTRY    *group_base;
7453
7454   group_count = 0;
7455   group_base = NULL;
7456   
7457   strcpy(MachineName, MoiraMachineName);
7458   rc = GetMachineName(MachineName);
7459
7460   if (strlen(MachineName) == 0)
7461     {
7462       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7463               MoiraMachineName);
7464       return(1);
7465     }
7466   
7467   cPtr = strchr(MachineName, '.');
7468
7469   if (cPtr != NULL)
7470     (*cPtr) = '\0';
7471
7472   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7473   attr_array[0] = "sAMAccountName";
7474   attr_array[1] = NULL;
7475
7476   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7477                            &group_base, 
7478                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7479     {
7480       com_err(whoami, 0, "Unable to process machine %s : %s",
7481               MoiraMachineName, ldap_err2string(rc));
7482       return(1);
7483     }
7484   
7485   if (group_count == 1)
7486     strcpy(OldDn, group_base->dn);
7487
7488   linklist_free(group_base);
7489   group_base = NULL;
7490
7491   if (group_count != 1)
7492     {
7493       com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
7494               MoiraMachineName);
7495       return(1);
7496     }
7497
7498   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7499   cPtr = strchr(OldDn, ',');
7500
7501   if (cPtr != NULL)
7502     {
7503       ++cPtr;
7504       if (!strcasecmp(cPtr, NewOu))
7505         return(0);
7506     }
7507
7508   sprintf(NewCn, "CN=%s", MachineName);
7509   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7510
7511   return(rc);
7512 }
7513
7514 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7515 {
7516   char    Name[128];
7517   char    *pPtr;
7518   int     rc;
7519   
7520   memset(Name, '\0', sizeof(Name));
7521   strcpy(Name, machine_name);
7522   pPtr = NULL;
7523   pPtr = strchr(Name, '.');
7524
7525   if (pPtr != NULL)
7526     (*pPtr) = '\0';
7527
7528   strcat(Name, "$");
7529   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7530 }
7531
7532 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7533                                 char *machine_name, char *container_name)
7534 {
7535   int     rc;
7536   char    *av[2];
7537   char    *call_args[2];
7538   
7539   av[0] = machine_name;
7540   call_args[0] = (char *)container_name;
7541   rc = mr_query("get_machine_to_container_map", 1, av, 
7542                 machine_GetMoiraContainer, call_args);
7543   return(rc);
7544 }
7545
7546 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7547 {
7548   char **call_args;
7549   
7550   call_args = ptr;
7551   strcpy(call_args[0], av[1]);
7552   return(0);
7553 }
7554
7555 int Moira_container_group_create(char **after)
7556 {
7557   long rc;
7558   char GroupName[64];
7559   char *argv[20];
7560   
7561   memset(GroupName, '\0', sizeof(GroupName));
7562   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7563                               after[CONTAINER_ROWID]);
7564   if (rc)
7565     return rc;
7566   
7567   argv[L_NAME] = GroupName;
7568   argv[L_ACTIVE] = "1";
7569   argv[L_PUBLIC] = "0";
7570   argv[L_HIDDEN] = "0";
7571   argv[L_MAILLIST] = "0";
7572   argv[L_GROUP] = "1";
7573   argv[L_GID] = UNIQUE_GID;
7574   argv[L_NFSGROUP] = "0";
7575   argv[L_MAILMAN] = "0";
7576   argv[L_MAILMAN_SERVER] = "[NONE]";
7577   argv[L_DESC] = "auto created container group";
7578   argv[L_ACE_TYPE] = "USER";
7579   argv[L_MEMACE_TYPE] = "USER";
7580   argv[L_ACE_NAME] = "sms";
7581   argv[L_MEMACE_NAME] = "sms";
7582
7583   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7584     {
7585       com_err(whoami, 0, 
7586               "Unable to create container group %s for container %s: %s",
7587               GroupName, after[CONTAINER_NAME], error_message(rc));
7588     }
7589
7590   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7591   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7592   
7593   return(rc);
7594 }
7595
7596 int Moira_container_group_update(char **before, char **after)
7597 {
7598   long rc;
7599   char BeforeGroupName[64];
7600   char AfterGroupName[64];
7601   char *argv[20];
7602   
7603   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7604     return(0);
7605
7606   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7607   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7608   if (strlen(BeforeGroupName) == 0)
7609     return(0);
7610
7611   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7612   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7613                               after[CONTAINER_ROWID]);
7614   if (rc)
7615     return rc;
7616
7617   if (strcasecmp(BeforeGroupName, AfterGroupName))
7618     {
7619       argv[L_NAME] = BeforeGroupName;
7620       argv[L_NAME + 1] = AfterGroupName;
7621       argv[L_ACTIVE + 1] = "1";
7622       argv[L_PUBLIC + 1] = "0";
7623       argv[L_HIDDEN + 1] = "0";
7624       argv[L_MAILLIST + 1] = "0";
7625       argv[L_GROUP + 1] = "1";
7626       argv[L_GID + 1] = UNIQUE_GID;
7627       argv[L_NFSGROUP + 1] = "0";
7628       argv[L_MAILMAN + 1] = "0";
7629       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7630       argv[L_DESC + 1] = "auto created container group";
7631       argv[L_ACE_TYPE + 1] = "USER";
7632       argv[L_MEMACE_TYPE + 1] = "USER";
7633       argv[L_ACE_NAME + 1] = "sms";
7634       argv[L_MEMACE_NAME + 1] = "sms";
7635       
7636       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7637         {
7638           com_err(whoami, 0, 
7639                   "Unable to rename container group from %s to %s: %s",
7640                   BeforeGroupName, AfterGroupName, error_message(rc));
7641         }
7642     }
7643   
7644   return(rc);
7645 }
7646
7647 int Moira_container_group_delete(char **before)
7648 {
7649   long rc = 0;
7650   char *argv[13];
7651   char GroupName[64];
7652   char ParentGroupName[64];
7653   
7654   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7655   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7656
7657   memset(GroupName, '\0', sizeof(GroupName));
7658
7659   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7660     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7661   
7662   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7663     {
7664       argv[0] = ParentGroupName;
7665       argv[1] = "LIST";
7666       argv[2] = GroupName;
7667
7668       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7669         {
7670           com_err(whoami, 0, 
7671                   "Unable to delete container group %s from list: %s",
7672                   GroupName, ParentGroupName, error_message(rc));
7673         }
7674     }
7675   
7676   if (strlen(GroupName) != 0)
7677     {
7678       argv[0] = GroupName;
7679
7680       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7681         {
7682           com_err(whoami, 0, "Unable to delete container group %s : %s",
7683                   GroupName, error_message(rc));
7684         }
7685     }
7686   
7687   return(rc);
7688 }
7689
7690 int Moira_groupname_create(char *GroupName, char *ContainerName,
7691                            char *ContainerRowID)
7692 {
7693   char *ptr;
7694   char *ptr1;
7695   char temp[64];
7696   char newGroupName[64];
7697   char tempGroupName[64];
7698   char tempgname[64];
7699   char *argv[1];
7700   int  i;
7701   long rc;
7702
7703   strcpy(temp, ContainerName);
7704   
7705   ptr1 = strrchr(temp, '/');
7706
7707   if (ptr1 != NULL)
7708   {
7709     *ptr1 = '\0';
7710     ptr = ++ptr1;
7711     ptr1 = strrchr(temp, '/');
7712
7713     if (ptr1 != NULL)
7714     {
7715         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7716     }
7717     else
7718         strcpy(tempgname, ptr);
7719   }
7720   else
7721     strcpy(tempgname, temp);
7722
7723   if (strlen(tempgname) > 25)
7724     tempgname[25] ='\0';
7725
7726   sprintf(newGroupName, "cnt-%s", tempgname);
7727
7728   /* change everything to lower case */
7729   ptr = newGroupName;
7730
7731   while (*ptr)
7732     {
7733       if (isupper(*ptr))
7734         *ptr = tolower(*ptr);
7735
7736       if (*ptr == ' ')
7737         *ptr = '-';
7738
7739       ptr++;
7740     }
7741
7742   strcpy(tempGroupName, newGroupName);
7743   i = (int)'0';
7744
7745   /* append 0-9 then a-z if a duplicate is found */
7746   while(1)
7747     {
7748       argv[0] = newGroupName;
7749
7750       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7751         {
7752           if (rc == MR_NO_MATCH)
7753             break;
7754           com_err(whoami, 0, "Moira error while creating group name for "
7755                   "container %s : %s", ContainerName, error_message(rc));
7756           return rc;
7757         }
7758
7759       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7760
7761       if (i == (int)'z')
7762         {
7763           com_err(whoami, 0, "Unable to find a unique group name for "
7764                   "container %s: too many duplicate container names",
7765                   ContainerName);
7766           return 1;
7767         }
7768
7769       if (i == '9')
7770         i = 'a';
7771       else
7772         i++;
7773     }
7774
7775   strcpy(GroupName, newGroupName);
7776   return(0);
7777 }
7778
7779 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7780 {
7781   long rc;
7782   char *argv[3];
7783   
7784   argv[0] = origContainerName;
7785   argv[1] = GroupName;
7786   
7787   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7788     {
7789       com_err(whoami, 0, 
7790               "Unable to set container group %s in container %s: %s",
7791               GroupName, origContainerName, error_message(rc));
7792     }
7793   
7794   return(0);
7795 }
7796
7797 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7798  {
7799    char ContainerName[64];
7800    char ParentGroupName[64];
7801    char *argv[3];
7802    long rc;
7803
7804    strcpy(ContainerName, origContainerName);
7805    
7806    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7807
7808    /* top-level container */
7809    if (strlen(ParentGroupName) == 0)
7810      return(0);
7811    
7812    argv[0] = ParentGroupName;
7813    argv[1] = "LIST";
7814    argv[2] = GroupName;
7815
7816    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7817      {
7818        com_err(whoami, 0, 
7819                "Unable to add container group %s to parent group %s: %s",
7820                GroupName, ParentGroupName, error_message(rc));
7821      }
7822    
7823    return(0);
7824  }
7825
7826 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7827 {
7828   char **call_args;
7829   
7830   call_args = ptr;
7831   strcpy(call_args[0], av[1]);
7832
7833   return(0);
7834 }
7835
7836 int Moira_getGroupName(char *origContainerName, char *GroupName,
7837                        int ParentFlag)
7838 {
7839   char ContainerName[64];
7840   char *argv[3];
7841   char *call_args[3];
7842   char *ptr;
7843   long rc;
7844
7845   strcpy(ContainerName, origContainerName);
7846
7847   if (ParentFlag)
7848     {
7849       ptr = strrchr(ContainerName, '/');
7850
7851       if (ptr != NULL)
7852         (*ptr) = '\0';
7853       else
7854         return(0);
7855     }
7856
7857   argv[0] = ContainerName;
7858   argv[1] = NULL;
7859   call_args[0] = GroupName;
7860   call_args[1] = NULL;
7861
7862   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7863                       call_args)))
7864     {
7865       if (strlen(GroupName) != 0)
7866         return(0);
7867     }
7868
7869   if (rc)
7870     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7871             ContainerName, error_message(rc));
7872   else
7873     com_err(whoami, 0, "Unable to get container group from container %s",
7874             ContainerName);
7875   
7876   return(0);
7877 }
7878
7879 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7880                                           int DeleteMachine)
7881 {
7882   char *argv[3];
7883   long rc;
7884   
7885   if (strcmp(GroupName, "[none]") == 0)
7886     return 0;
7887
7888   argv[0] = GroupName;
7889   argv[1] = "MACHINE";
7890   argv[2] = MachineName;
7891
7892   if (!DeleteMachine)
7893     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7894   else
7895     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7896
7897   if (rc)
7898     {
7899       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7900               MachineName, GroupName, error_message(rc));
7901     }
7902
7903   return(0);
7904 }
7905
7906 int GetMachineName(char *MachineName)
7907 {
7908   char    *args[2];
7909   char    NewMachineName[1024];
7910   char    *szDot;
7911   int     rc = 0;
7912   int     i;
7913   DWORD   dwLen = 0;
7914   char    *call_args[2];
7915   
7916   // If the address happens to be in the top-level MIT domain, great!
7917   strcpy(NewMachineName, MachineName);
7918
7919   for (i = 0; i < (int)strlen(NewMachineName); i++)
7920     NewMachineName[i] = toupper(NewMachineName[i]);
7921
7922   szDot = strchr(NewMachineName,'.');
7923
7924   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7925     {
7926       return(0);
7927     }
7928   
7929   // If not, see if it has a Moira alias in the top-level MIT domain.
7930   memset(NewMachineName, '\0', sizeof(NewMachineName));
7931   args[0] = "*";
7932   args[1] = MachineName;
7933   call_args[0] = NewMachineName;
7934   call_args[1] = NULL;
7935
7936   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7937     {
7938       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7939               MachineName, error_message(rc));
7940       strcpy(MachineName, "");
7941       return(0);
7942     }
7943   
7944   if (strlen(NewMachineName) != 0)
7945     strcpy(MachineName, NewMachineName);
7946   else
7947     strcpy(MachineName, "");
7948
7949   return(0);
7950 }
7951
7952 int ProcessMachineName(int ac, char **av, void *ptr)
7953 {
7954   char    **call_args;
7955   char    MachineName[1024];
7956   char    *szDot;
7957   int     i;
7958   
7959   call_args = ptr;
7960
7961   if (strlen(call_args[0]) == 0)
7962     {
7963       strcpy(MachineName, av[0]);
7964
7965       for (i = 0; i < (int)strlen(MachineName); i++)
7966         MachineName[i] = toupper(MachineName[i]);
7967
7968       szDot = strchr(MachineName,'.');
7969
7970         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
7971           {
7972             strcpy(call_args[0], MachineName);
7973           }
7974     }
7975
7976   return(0);
7977 }
7978
7979 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
7980 {
7981   int i;
7982   
7983   if (*UseSFU30)
7984     {
7985       for (i = 0; i < n; i++)
7986         {
7987           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
7988             mods[i]->mod_type = "uidNumber";
7989         }
7990
7991       (*UseSFU30) = 0;
7992     }
7993   else
7994     {
7995       for (i = 0; i < n; i++)
7996         {
7997           if (!strcmp(mods[i]->mod_type, "uidNumber"))
7998             mods[i]->mod_type = "msSFU30UidNumber";
7999         }
8000
8001       (*UseSFU30) = 1;
8002     }
8003 }
8004
8005 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8006                      char *DistinguishedName,
8007                      char *WinHomeDir, char *WinProfileDir,
8008                      char **homedir_v, char **winProfile_v,
8009                      char **drives_v, LDAPMod **mods, 
8010                      int OpType, int n)
8011 {
8012   char **hp;
8013   char cWeight[3];
8014   char cPath[1024];
8015   char path[1024];
8016   char winPath[1024];
8017   char winProfile[1024];
8018   char homeDrive[8];
8019   char homedir[1024];
8020   char apple_homedir[1024];
8021   char *apple_homedir_v[] = {NULL, NULL};
8022   int  last_weight;
8023   int  i;
8024   int  rc;
8025   LDAPMod *DelMods[20];
8026   
8027   memset(homeDrive, '\0', sizeof(homeDrive));
8028   memset(path, '\0', sizeof(path));
8029   memset(winPath, '\0', sizeof(winPath));
8030   memset(winProfile, '\0', sizeof(winProfile));
8031   hp = NULL;
8032
8033   if(!ActiveDirectory) 
8034     {
8035       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
8036         {
8037           memset(cWeight, 0, sizeof(cWeight));
8038           memset(cPath, 0, sizeof(cPath));
8039           last_weight = 1000;
8040           i = 0;
8041           
8042           while (hp[i] != NULL)
8043             {
8044               if (sscanf(hp[i], "%*s %s", cPath))
8045                 {
8046                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
8047                     {
8048                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
8049                         {
8050                           if (atoi(cWeight) < last_weight)
8051                             {
8052                               strcpy(path, cPath);
8053                               last_weight = (int)atoi(cWeight);
8054                             }
8055                         }
8056                       else 
8057                         strcpy(path, cPath);
8058                     }
8059                 }
8060               ++i;
8061             }
8062           
8063           if (strlen(path))
8064             {
8065               if (!strnicmp(path, AFS, strlen(AFS)))
8066                 {
8067                   sprintf(homedir, "%s", path);
8068                   sprintf(apple_homedir, "%s/MacData", path);
8069                   homedir_v[0] = homedir;
8070                   apple_homedir_v[0] = apple_homedir;
8071                   ADD_ATTR("homeDirectory", homedir_v, OpType);
8072                   ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8073                            OpType);
8074                 }
8075             }
8076           else
8077             {
8078               if(user_name[0] && user_name[1]) 
8079                 {
8080                   sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", 
8081                           user_name[0], user_name[1], user_name);
8082                   sprintf(apple_homedir, "%s/MacData", homedir);
8083                   homedir_v[0] = "NONE";
8084                   apple_homedir_v[0] = "NONE";
8085                   ADD_ATTR("homeDirectory", homedir_v, OpType);
8086                   ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8087                            OpType);
8088                 }
8089             }
8090         }
8091       else
8092         {
8093           if(user_name[0] && user_name[1]) 
8094             {
8095               sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", 
8096                       user_name[0], user_name[1], user_name);
8097               sprintf(apple_homedir, "%s/MacData", homedir);
8098               homedir_v[0] = "NONE";
8099               apple_homedir_v[0] = "NONE";
8100               ADD_ATTR("homeDirectory", homedir_v, OpType);
8101               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8102                        OpType);
8103             }
8104         }
8105       return(n);
8106     }
8107       
8108   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8109       (!strcasecmp(WinProfileDir, "[afs]")))
8110     {
8111       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
8112         {
8113           memset(cWeight, 0, sizeof(cWeight));
8114           memset(cPath, 0, sizeof(cPath));
8115           last_weight = 1000;
8116           i = 0;
8117
8118           while (hp[i] != NULL)
8119             {
8120               if (sscanf(hp[i], "%*s %s", cPath))
8121                 {
8122                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
8123                     {
8124                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
8125                         {
8126                           if (atoi(cWeight) < last_weight)
8127                             {
8128                               strcpy(path, cPath);
8129                               last_weight = (int)atoi(cWeight);
8130                             }
8131                         }
8132                       else 
8133                         strcpy(path, cPath);
8134                     }
8135                 }
8136               ++i;
8137             }
8138
8139           if (strlen(path))
8140             {
8141               if (!strnicmp(path, AFS, strlen(AFS)))
8142                 {
8143                   AfsToWinAfs(path, winPath);
8144                   strcpy(winProfile, winPath);
8145                   strcat(winProfile, "\\.winprofile");
8146                 }
8147             }
8148         }
8149       else
8150         return(n);
8151     }
8152
8153     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8154         (!strcasecmp(WinProfileDir, "[dfs]")))
8155     {
8156       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8157               user_name[0], user_name);
8158
8159       if (!strcasecmp(WinProfileDir, "[dfs]"))
8160         {
8161           strcpy(winProfile, path);
8162           strcat(winProfile, "\\.winprofile");
8163         }
8164
8165       if (!strcasecmp(WinHomeDir, "[dfs]"))
8166         strcpy(winPath, path);
8167     }
8168     
8169     if (hp != NULL)
8170       {
8171         i = 0;
8172         while (hp[i])
8173           {
8174             free(hp[i]);
8175             i++;
8176           }
8177       }
8178     
8179     if (!strcasecmp(WinHomeDir, "[local]"))
8180       memset(winPath, '\0', sizeof(winPath));
8181     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8182              !strcasecmp(WinHomeDir, "[dfs]"))
8183       {
8184         strcpy(homeDrive, "H:");
8185       }
8186     else
8187       {
8188         strcpy(winPath, WinHomeDir);
8189         if (!strncmp(WinHomeDir, "\\\\", 2))
8190           {
8191             strcpy(homeDrive, "H:");
8192           }        
8193       }
8194     
8195     // nothing needs to be done if WinProfileDir is [afs].
8196     if (!strcasecmp(WinProfileDir, "[local]"))
8197       memset(winProfile, '\0', sizeof(winProfile));
8198     else if (strcasecmp(WinProfileDir, "[afs]") && 
8199              strcasecmp(WinProfileDir, "[dfs]"))
8200       {
8201         strcpy(winProfile, WinProfileDir);
8202       }
8203     
8204     if (strlen(winProfile) != 0)
8205       {
8206         if (winProfile[strlen(winProfile) - 1] == '\\')
8207           winProfile[strlen(winProfile) - 1] = '\0';
8208       }
8209
8210     if (strlen(winPath) != 0)
8211       {
8212         if (winPath[strlen(winPath) - 1] == '\\')
8213           winPath[strlen(winPath) - 1] = '\0';
8214       }
8215     
8216     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8217       strcat(winProfile, "\\");
8218
8219     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8220       strcat(winPath, "\\");
8221     
8222     if (strlen(winPath) == 0)
8223       {
8224         if (OpType == LDAP_MOD_REPLACE)
8225           {
8226             i = 0;
8227             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8228             DelMods[i] = NULL;
8229             //unset homeDirectory attribute for user.
8230             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8231             free(DelMods[0]);
8232           }
8233       }
8234     else
8235       {
8236         homedir_v[0] = strdup(winPath);
8237         ADD_ATTR("homeDirectory", homedir_v, OpType);
8238       }
8239     
8240     if (strlen(winProfile) == 0)
8241       {
8242         if (OpType == LDAP_MOD_REPLACE)
8243           {
8244             i = 0;
8245             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8246             DelMods[i] = NULL;
8247             //unset profilePate attribute for user.
8248             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8249             free(DelMods[0]);
8250           }
8251       }
8252     else
8253       {
8254         winProfile_v[0] = strdup(winProfile);
8255         ADD_ATTR("profilePath", winProfile_v, OpType);
8256       }
8257     
8258     if (strlen(homeDrive) == 0)
8259       {
8260         if (OpType == LDAP_MOD_REPLACE)
8261           {
8262             i = 0;
8263             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8264             DelMods[i] = NULL;
8265             //unset homeDrive attribute for user
8266             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8267             free(DelMods[0]);
8268           }
8269       }
8270     else
8271       {
8272         drives_v[0] = strdup(homeDrive);
8273         ADD_ATTR("homeDrive", drives_v, OpType);
8274       }
8275
8276     return(n);
8277 }
8278
8279 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8280                      char *attribute_value, char *attribute, char *user_name)
8281 {
8282   char      *mod_v[] = {NULL, NULL};
8283   LDAPMod   *DelMods[20];
8284   LDAPMod   *mods[20];
8285   int       n;
8286   int       i;
8287   int       rc;
8288   
8289   if (strlen(attribute_value) == 0)
8290     {
8291       i = 0;
8292       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8293       DelMods[i] = NULL;
8294       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8295       free(DelMods[0]);
8296     }
8297   else
8298     {
8299       n = 0;
8300       mod_v[0] = attribute_value;
8301       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8302       mods[n] = NULL;
8303
8304       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8305                               mods)) != LDAP_SUCCESS)
8306         {
8307           free(mods[0]);
8308           n = 0;
8309           mod_v[0] = attribute_value;
8310           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8311           mods[n] = NULL;
8312
8313           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8314                                   mods)) != LDAP_SUCCESS)
8315             {
8316               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8317                       "in the AD : %s",
8318                       attribute, user_name, ldap_err2string(rc));
8319             }
8320         }
8321
8322       free(mods[0]);
8323     }
8324   
8325   return(rc);
8326 }
8327
8328 void StringTrim(char *StringToTrim)
8329 {
8330   char *t, *s;
8331   char *save;
8332
8333   save = strdup(StringToTrim);
8334
8335   s = save;
8336
8337   while (isspace(*s))
8338     s++;
8339
8340   /* skip to end of string */
8341   if (*s == '\0')
8342     {
8343       if (*save)
8344         *save = '\0';
8345       strcpy(StringToTrim, save);
8346       return;
8347     }
8348   
8349   for (t = s; *t; t++)
8350     continue;
8351
8352   while (t > s)
8353     {
8354       --t;
8355       if (!isspace(*t))
8356         {
8357           t++;
8358           break;
8359         }
8360     }
8361
8362   if (*t)
8363     *t = '\0';
8364   
8365   strcpy(StringToTrim, s);
8366   return;
8367 }
8368
8369 int ReadConfigFile(char *DomainName)
8370 {
8371     int     Count;
8372     int     i;
8373     int     k;
8374     char    temp[256];
8375     char    temp1[256];
8376     FILE    *fptr;
8377
8378     Count = 0;
8379
8380     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8381
8382     if ((fptr = fopen(temp, "r")) != NULL)
8383       {
8384         while (fgets(temp, sizeof(temp), fptr) != 0)
8385           {
8386             for (i = 0; i < (int)strlen(temp); i++)
8387               temp[i] = toupper(temp[i]);
8388
8389             if (temp[strlen(temp) - 1] == '\n')
8390               temp[strlen(temp) - 1] = '\0';
8391
8392             StringTrim(temp);
8393
8394             if (strlen(temp) == 0)
8395               continue;
8396
8397             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8398               {
8399                 if (strlen(temp) > (strlen(DOMAIN)))
8400                   {
8401                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8402                     StringTrim(ldap_domain);
8403                   }
8404               }
8405             else if (!strncmp(temp, REALM, strlen(REALM)))
8406               {
8407                 if (strlen(temp) > (strlen(REALM)))
8408                   {
8409                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8410                     StringTrim(ldap_realm);
8411                   }
8412               }
8413             else if (!strncmp(temp, PORT, strlen(PORT)))
8414               {
8415                 if (strlen(temp) > (strlen(PORT)))
8416                   {
8417                     strcpy(ldap_port, &temp[strlen(PORT)]);
8418                     StringTrim(ldap_port);
8419                   }
8420               }
8421             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8422               {
8423                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8424                   {
8425                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8426                     StringTrim(PrincipalName);
8427                   }
8428               }
8429             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8430               {
8431                 if (strlen(temp) > (strlen(SERVER)))
8432                   {
8433                     ServerList[Count] = calloc(1, 256);
8434                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8435                     StringTrim(ServerList[Count]);
8436                     ++Count;
8437                   }
8438               }
8439             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8440               {
8441                 if (strlen(temp) > (strlen(MSSFU)))
8442                   {
8443                     strcpy(temp1, &temp[strlen(MSSFU)]);
8444                     StringTrim(temp1);
8445                     if (!strcmp(temp1, SFUTYPE))
8446                       UseSFU30 = 1;
8447                   }
8448               }
8449             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8450               {
8451                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8452                   {
8453                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8454                     StringTrim(temp1);
8455                     if (!strcasecmp(temp1, "NO")) 
8456                       {
8457                         UseGroupSuffix = 0;
8458                         memset(group_suffix, '\0', sizeof(group_suffix));
8459                       }
8460                   }
8461               }
8462             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8463               {
8464                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8465                   {
8466                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8467                     StringTrim(temp1);
8468                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8469                       UseGroupUniversal = 1;
8470                   }
8471               }
8472             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8473               {
8474                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8475                   {
8476                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8477                     StringTrim(temp1);
8478                     if (!strcasecmp(temp1, "NO"))
8479                       SetGroupAce = 0;
8480                   }
8481               }
8482             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8483               {
8484                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8485                   {
8486                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8487                     StringTrim(temp1);
8488                     if (!strcasecmp(temp1, "NO"))
8489                       SetPassword = 0;
8490                   }
8491               }
8492             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8493               {
8494                 if (strlen(temp) > (strlen(EXCHANGE)))
8495                   {
8496                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8497                     StringTrim(temp1);
8498                     if (!strcasecmp(temp1, "YES"))
8499                       Exchange = 1;
8500                   }
8501               }
8502             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8503                               strlen(PROCESS_MACHINE_CONTAINER)))
8504               {
8505                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8506                   {
8507                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8508                     StringTrim(temp1);
8509                     if (!strcasecmp(temp1, "NO"))
8510                       ProcessMachineContainer = 0;
8511                   }
8512               }
8513             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8514                               strlen(ACTIVE_DIRECTORY)))
8515               {
8516                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8517                   {
8518                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8519                     StringTrim(temp1);
8520                     if (!strcasecmp(temp1, "NO"))
8521                       ActiveDirectory = 0;
8522                   }
8523               }
8524             else
8525               {
8526                 if (strlen(ldap_domain) != 0)
8527                   {
8528                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8529                     break;
8530                   }
8531
8532                 if (strlen(temp) != 0)
8533                   strcpy(ldap_domain, temp);
8534               }
8535           }
8536         fclose(fptr);
8537       }
8538     
8539     if (strlen(ldap_domain) == 0)
8540       {
8541       strcpy(ldap_domain, DomainName);
8542       }
8543
8544     if (Count == 0)
8545         return(0);
8546
8547     for (i = 0; i < Count; i++)
8548       {
8549         if (ServerList[i] != 0)
8550           {
8551             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8552               ServerList[i][k] = toupper(ServerList[i][k]);
8553           }
8554       }
8555     
8556     return(0);
8557 }
8558
8559 int ReadDomainList()
8560 {
8561   int     Count;
8562   int     i;
8563   char    temp[128];
8564   char    temp1[128];
8565   FILE    *fptr;
8566   unsigned char c[11];
8567   unsigned char stuff[256];
8568   int     rc;
8569   int     ok;
8570
8571   Count = 0;
8572   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8573
8574   if ((fptr = fopen(temp, "r")) != NULL)
8575     {
8576       while (fgets(temp, sizeof(temp), fptr) != 0)
8577         {
8578           for (i = 0; i < (int)strlen(temp); i++)
8579             temp[i] = toupper(temp[i]);
8580
8581           if (temp[strlen(temp) - 1] == '\n')
8582             temp[strlen(temp) - 1] = '\0';
8583
8584           StringTrim(temp);
8585
8586           if (strlen(temp) == 0)
8587             continue;
8588
8589           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8590             {
8591               if (strlen(temp) > (strlen(DOMAIN)))
8592                 {
8593                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8594                   StringTrim(temp1);
8595                   strcpy(temp, temp1);
8596                 }
8597             }
8598           
8599           strcpy(DomainNames[Count], temp);
8600           StringTrim(DomainNames[Count]);
8601           ++Count;
8602         }
8603
8604       fclose(fptr);
8605     }
8606
8607   if (Count == 0)
8608     {
8609       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8610                      "configuration error in ldap.cfg");
8611       return(1);
8612     }
8613   
8614   return(0);
8615 }
8616
8617 int email_isvalid(const char *address) {
8618   int        count = 0;
8619   const char *c, *domain;
8620   static char *rfc822_specials = "()<>@,;:\\\"[]";
8621
8622   if(address[strlen(address) - 1] == '.') 
8623     return 0;
8624     
8625   /* first we validate the name portion (name@domain) */
8626   for (c = address;  *c;  c++) {
8627     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8628                        '\"')) {
8629       while (*++c) {
8630         if (*c == '\"') 
8631           break;
8632         if (*c == '\\' && (*++c == ' ')) 
8633           continue;
8634         if (*c <= ' ' || *c >= 127) 
8635           return 0;
8636       }
8637
8638       if (!*c++) 
8639         return 0;
8640       if (*c == '@') 
8641         break;
8642       if (*c != '.') 
8643         return 0;
8644       continue;
8645     }
8646
8647     if (*c == '@') 
8648       break;
8649     if (*c <= ' ' || *c >= 127) 
8650       return 0;
8651     if (strchr(rfc822_specials, *c)) 
8652       return 0;
8653   }
8654
8655   if (c == address || *(c - 1) == '.') 
8656     return 0;
8657
8658   /* next we validate the domain portion (name@domain) */
8659   if (!*(domain = ++c)) return 0;
8660   do {
8661     if (*c == '.') {
8662       if (c == domain || *(c - 1) == '.') 
8663         return 0;
8664       count++;
8665     }
8666     if (*c <= ' ' || *c >= 127) 
8667       return 0;
8668     if (strchr(rfc822_specials, *c)) 
8669       return 0;
8670   } while (*++c);
8671
8672   return (count >= 1);
8673 }
8674
8675 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8676              char **homeServerName) 
8677 {
8678   LK_ENTRY *group_base;
8679   LK_ENTRY *sub_group_base;
8680   LK_ENTRY *gPtr;
8681   LK_ENTRY *sub_gPtr;
8682   int      group_count;
8683   int      sub_group_count;
8684   char     filter[1024];
8685   char     sub_filter[1024];
8686   char     search_path[1024];
8687   char     range[1024];
8688   char     *attr_array[3];
8689   char     *s;
8690   int      homeMDB_count = -1;
8691   int      rc;
8692   int      i;
8693   int      mdbbl_count;
8694   int      rangeStep = 1500;
8695   int      rangeLow = 0;
8696   int      rangeHigh = rangeLow + (rangeStep - 1);
8697   int      isLast = 0;
8698
8699   /* Grumble..... microsoft not making it searchable from the root *grr* */
8700
8701   memset(filter, '\0', sizeof(filter));
8702   memset(search_path, '\0', sizeof(search_path));
8703   
8704   sprintf(filter, "(objectClass=msExchMDB)");
8705   sprintf(search_path, "CN=Configuration,%s", dn_path);
8706   attr_array[0] = "distinguishedName";
8707   attr_array[1] = NULL;
8708   
8709   group_base = NULL;
8710   group_count = 0;
8711   
8712   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8713                            &group_base, &group_count, 
8714                            LDAP_SCOPE_SUBTREE)) != 0) 
8715     {
8716       com_err(whoami, 0, "Unable to find msExchMDB %s",
8717               ldap_err2string(rc));
8718       return(rc);
8719     }
8720   
8721   if (group_count) 
8722     {
8723       gPtr = group_base;
8724       
8725       while(gPtr) {
8726         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8727             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8728             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8729           {
8730             gPtr = gPtr->next;
8731             continue;
8732           }
8733
8734         /* 
8735          * Due to limits in active directory we need to use the LDAP
8736          * range semantics to query and return all the values in 
8737          * large lists, we will stop increasing the range when
8738          * the result count is 0.
8739          */
8740
8741         i = 0;  
8742         mdbbl_count = 0;
8743
8744         for(;;) 
8745           {
8746             memset(sub_filter, '\0', sizeof(sub_filter));
8747             memset(range, '\0', sizeof(range));
8748             sprintf(sub_filter, "(objectClass=msExchMDB)");
8749
8750             if(isLast)
8751               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8752             else 
8753               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8754
8755             attr_array[0] = range;
8756             attr_array[1] = NULL;
8757             
8758             sub_group_base = NULL;
8759             sub_group_count = 0;
8760             
8761             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8762                                      attr_array, &sub_group_base, 
8763                                      &sub_group_count, 
8764                                      LDAP_SCOPE_SUBTREE)) != 0) 
8765               {
8766                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8767                         ldap_err2string(rc));
8768                 return(rc);
8769               }
8770
8771             if(!sub_group_count)
8772               {
8773                 if(isLast) 
8774                   {
8775                     isLast = 0;
8776                     rangeLow = 0;
8777                     rangeHigh = rangeLow + (rangeStep - 1);
8778                     break;
8779                   }
8780                 else
8781                   isLast++;
8782               }
8783
8784             mdbbl_count += sub_group_count;
8785             rangeLow = rangeHigh + 1;
8786             rangeHigh = rangeLow + (rangeStep - 1);
8787           }
8788
8789         /* First time through, need to initialize or update the least used */
8790         
8791         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8792                 mdbbl_count);
8793
8794         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8795           {
8796             homeMDB_count = mdbbl_count; 
8797             *homeMDB = strdup(gPtr->dn);
8798           }
8799
8800         gPtr = gPtr->next;
8801         linklist_free(sub_group_base);
8802       }
8803     }
8804
8805   linklist_free(group_base);
8806   
8807   /* 
8808    * Ok found the server least allocated need to now query to get its
8809    * msExchHomeServerName so we can set it as a user attribute
8810    */
8811   
8812   attr_array[0] = "legacyExchangeDN";
8813   attr_array[1] = NULL; 
8814   
8815   group_count = 0;
8816   group_base = NULL;
8817   
8818   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8819                            attr_array, &group_base, 
8820                            &group_count, 
8821                            LDAP_SCOPE_SUBTREE)) != 0) 
8822     {
8823       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8824               ldap_err2string(rc));
8825       return(rc);
8826     }  
8827   
8828   if(group_count) 
8829     {
8830       *homeServerName = strdup(group_base->value);
8831       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8832         {
8833           *s = '\0';
8834         }
8835     } 
8836
8837   linklist_free(group_base);
8838   
8839   return(rc);
8840 }
8841       
8842 char *lowercase(char *s)
8843 {
8844   char *p;
8845
8846   for (p = s; *p; p++)
8847     {
8848       if (isupper(*p))
8849         *p = tolower(*p);
8850     }
8851   return s;
8852 }
8853
8854 char *uppercase(char *s)
8855 {
8856   char *p;
8857
8858   for (p = s; *p; p++)
8859     {
8860       if (islower(*p))
8861         *p = toupper(*p);
8862     }
8863   return s;
8864 }
8865
8866 char *escape_string(char *s)
8867 {
8868   char *p, *q;
8869   char string[1024];
8870   char temp[1024];
8871   int i = 0;
8872   int spaces = 0;
8873
8874   memset(string, '\0', sizeof(string));
8875
8876   q = s;
8877
8878   /* Replace leading spaces */
8879
8880   while(isspace(*q)) {
8881     string[i++] = '\\';
8882     string[i++] = '2';
8883     string[i++] = '0';
8884     q++;
8885   }
8886
8887   /* Escape any special characters */
8888
8889   for(; *q != '\0'; q++) {
8890     if(*q == ',')
8891       string[i++] = '\\';
8892     if(*q == '+') 
8893       string[i++] = '\\';
8894     if(*q == '"') 
8895       string[i++] = '\\';
8896     if(*q == '\\') 
8897       string[i++] = '\\';
8898     if(*q == '<') 
8899       string[i++] = '\\';
8900     if(*q == '>') 
8901       string[i++] = '\\';
8902     if(*q == ';')
8903       string[i++] = '\\';
8904     if(*q == '#')
8905       string[i++] = '\\';
8906     if(*q == '=')
8907       string[i++] = '\\';
8908
8909     string[i++] = *q;
8910   }
8911
8912   return strdup(string);
8913 }
8914
8915 int save_query_info(int argc, char **argv, void *hint)
8916 {
8917   int i;
8918   char **nargv = hint;
8919
8920   for(i = 0; i < argc; i++)
8921     nargv[i] = strdup(argv[i]);
8922
8923   return MR_CONT;
8924 }
This page took 0.758364 seconds and 5 git commands to generate.