]> andersk Git - moira.git/blob - incremental/ldap/winad.c
From mark: special handling for PRODUCTION_PRINCIPAL and TEST_PRINCIPAL.
[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(!strcasecmp(ptr->member, PRODUCTION_PRINCIPAL) ||
6046                  !strcasecmp(ptr->member, TEST_PRINCIPAL))
6047                 {
6048                   ptr = ptr->next;
6049                   continue;
6050                 }
6051
6052               if ((rc = check_user(ldap_handle, dn_path, ptr->member,
6053                                    "")) == AD_NO_USER_FOUND)
6054                 {
6055                   com_err(whoami, 0, "creating user %s", ptr->member);
6056
6057                   av[0] = ptr->member;
6058                   call_args[0] = (char *)ldap_handle;
6059                   call_args[1] = dn_path;
6060                   call_args[2] = "";
6061                   call_args[3] = NULL;
6062                   callback_rc = 0;
6063                   
6064                   if (rc = mr_query("get_user_account_by_login", 1, av, 
6065                                     save_query_info, save_argv))
6066                     {
6067                       com_err(whoami, 0, "Unable to create user %s " 
6068                               "while populating group %s.", ptr->member,
6069                               group_name);
6070
6071                       return(3);
6072                     }
6073
6074                   if (rc = user_create(U_END, save_argv, call_args)) 
6075                     {
6076                       com_err(whoami, 0, "Unable to create user %s "
6077                               "while populating group %s.", ptr->member,
6078                               group_name);
6079                       
6080                       return(3);
6081                     }
6082           
6083                   if (callback_rc)
6084                     {
6085                       com_err(whoami, 0, "Unable to create user %s "
6086                               "while populating group %s", ptr->member, 
6087                               group_name);
6088
6089                       return(3);
6090                     }
6091                 }
6092
6093               pUserOu = user_ou;
6094                   
6095               if(ActiveDirectory) 
6096                 {
6097                   sprintf(member, "cn=%s,%s,%s", ptr->member, pUserOu, 
6098                           dn_path);
6099                 }
6100               else 
6101                 {
6102                   sprintf(member, "uid=%s,%s,%s", ptr->member, pUserOu, 
6103                           dn_path);
6104                 }
6105
6106             }
6107           else if (!strcasecmp(ptr->type, "STRING"))
6108             {
6109               if (contact_create(ldap_handle, dn_path, ptr->member,
6110                                  contact_ou))
6111                 return(3);
6112
6113               pUserOu = contact_ou;
6114               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6115                       pUserOu, dn_path);
6116             }
6117           else if (!strcasecmp(ptr->type, "KERBEROS"))
6118             {
6119               if (contact_create(ldap_handle, dn_path, ptr->member, 
6120                                  kerberos_ou))
6121                 return(3);
6122
6123               pUserOu = kerberos_ou;
6124               sprintf(member, "cn=%s,%s,%s", escape_string(ptr->member), 
6125                       pUserOu, dn_path);
6126             }
6127
6128           if(i > 1) 
6129             members = (char **)realloc(members, ((i + 2) * sizeof(char *)));
6130           members[i++] = strdup(member);
6131
6132           ptr = ptr->next;
6133         }
6134     
6135       linklist_free(member_base);
6136       member_base = NULL;
6137     }
6138
6139   members[i] = NULL;
6140   
6141   n = 0;
6142   ADD_ATTR("member", members, LDAP_MOD_REPLACE);
6143   mods[n] = NULL;
6144   
6145   sprintf(group_dn, "cn=%s,%s,%s", group_name, group_ou, dn_path);
6146   
6147   if ((rc = ldap_modify_s(ldap_handle, group_dn, 
6148                           mods)) != LDAP_SUCCESS)
6149     {
6150       com_err(whoami, 0,
6151               "Unable to populate group membership for %s: %s",
6152               group_dn, ldap_err2string(rc));
6153     }
6154   
6155   for (i = 0; i < n; i++)
6156     free(mods[i]);
6157   
6158   free(members);
6159
6160   return(0);
6161 }
6162
6163 int process_group(LDAP *ldap_handle, char *dn_path, char *MoiraId, 
6164                   char *group_name, char *group_ou, char *group_membership, 
6165                   int group_security_flag, int type, char *maillist)
6166 {
6167   char      before_desc[512];
6168   char      before_name[256];
6169   char      before_group_ou[256];
6170   char      before_group_membership[2];
6171   char      distinguishedName[256];
6172   char      ad_distinguishedName[256];
6173   char      filter[128];
6174   char      *attr_array[3];
6175   int       before_security_flag;
6176   int       group_count;
6177   int       rc;
6178   LK_ENTRY  *group_base;
6179   LK_ENTRY  *ptr;
6180   char      ou_both[512];
6181   char      ou_security[512];
6182   char      ou_distribution[512];
6183   char      ou_neither[512];
6184   char      group_dn[512];
6185
6186   memset(ad_distinguishedName, '\0', sizeof(ad_distinguishedName));
6187   sprintf(distinguishedName, "CN=%s,%s,%s", group_name, group_ou, dn_path);
6188
6189   memset(filter, '\0', sizeof(filter));
6190   group_base = NULL;
6191   group_count = 0;
6192
6193   if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6194                         "*", MoiraId, 
6195                         "samAccountName", &group_base, 
6196                         &group_count, filter))
6197     return(rc);
6198
6199   if (type == CHECK_GROUPS)
6200     {
6201       if (group_count == 1)
6202         {
6203           strcpy(group_dn, group_base->dn);
6204
6205           if (!strcasecmp(group_dn, distinguishedName))
6206             {
6207               linklist_free(group_base);
6208               return(0);
6209             }
6210         }
6211
6212       linklist_free(group_base);
6213
6214       if (group_count == 0)
6215         return(AD_NO_GROUPS_FOUND);
6216
6217       if (group_count == 1)
6218         return(AD_WRONG_GROUP_DN_FOUND);
6219
6220       return(AD_MULTIPLE_GROUPS_FOUND);
6221     }
6222
6223   if (group_count == 0)
6224     {
6225       return(AD_NO_GROUPS_FOUND);
6226     }
6227
6228   if (group_count > 1)
6229     {
6230       ptr = group_base;
6231
6232       strcpy(group_dn, ptr->dn);
6233
6234       while (ptr != NULL)
6235         {
6236           if (!strcasecmp(group_dn, ptr->value))
6237             break;
6238
6239           ptr = ptr->next;
6240         }
6241
6242       if (ptr == NULL)
6243         {
6244           com_err(whoami, 0, "%d groups with moira id = %s", group_count, 
6245                   MoiraId);
6246           ptr = group_base;
6247
6248           while (ptr != NULL)
6249             {
6250               com_err(whoami, 0, "%s with moira id = %s", ptr->value, MoiraId);
6251               ptr = ptr->next;
6252             }
6253
6254           linklist_free(group_base);
6255           return(AD_MULTIPLE_GROUPS_FOUND);
6256         }
6257
6258       ptr = group_base;
6259
6260       while (ptr != NULL)
6261         {
6262           strcpy(group_dn, ptr->dn);
6263
6264           if (strcasecmp(group_dn, ptr->value))
6265             rc = ldap_delete_s(ldap_handle, ptr->value);
6266
6267           ptr = ptr->next;
6268         }
6269
6270       linklist_free(group_base);
6271       memset(filter, '\0', sizeof(filter));
6272       group_base = NULL;
6273       group_count = 0;
6274
6275       if (rc = ad_get_group(ldap_handle, dn_path, group_name, 
6276                             "*", MoiraId, 
6277                             "samAccountName", &group_base, 
6278                             &group_count, filter))
6279         return(rc);
6280
6281       if (group_count == 0)
6282         return(AD_NO_GROUPS_FOUND);
6283
6284       if (group_count > 1)
6285         return(AD_MULTIPLE_GROUPS_FOUND);
6286     }
6287
6288   strcpy(ad_distinguishedName, group_base->dn);
6289   linklist_free(group_base);
6290   group_base = NULL;
6291   group_count = 0;
6292
6293   attr_array[0] = "sAMAccountName";
6294   attr_array[1] = NULL;
6295   
6296   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6297                            &group_base, &group_count, 
6298                            LDAP_SCOPE_SUBTREE)) != 0)
6299     {
6300       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6301               MoiraId, ldap_err2string(rc));
6302       return(rc);
6303     }
6304   
6305   sprintf(filter, "(sAMAccountName=%s)", group_base->value);
6306
6307   if (!strcasecmp(ad_distinguishedName, distinguishedName))
6308     {
6309       linklist_free(group_base);
6310       group_base = NULL;
6311       group_count = 0;
6312       return(0);
6313     }
6314
6315   linklist_free(group_base);
6316   group_base = NULL;
6317   group_count = 0;
6318   memset(ou_both, '\0', sizeof(ou_both));
6319   memset(ou_security, '\0', sizeof(ou_security));
6320   memset(ou_distribution, '\0', sizeof(ou_distribution));
6321   memset(ou_neither, '\0', sizeof(ou_neither));
6322   memset(before_name, '\0', sizeof(before_name));
6323   memset(before_desc, '\0', sizeof(before_desc));
6324   memset(before_group_membership, '\0', sizeof(before_group_membership));
6325   
6326   attr_array[0] = "name";
6327   attr_array[1] = NULL;
6328
6329   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6330                            &group_base, &group_count, 
6331                            LDAP_SCOPE_SUBTREE)) != 0)
6332     {
6333       com_err(whoami, 0, "Unable to get list name with MoiraId = %s: %s",
6334               MoiraId, ldap_err2string(rc));
6335       return(rc);
6336     }
6337
6338   strcpy(before_name, group_base->value);
6339   linklist_free(group_base);
6340   group_base = NULL;
6341   group_count = 0;
6342
6343   attr_array[0] = "description";
6344   attr_array[1] = NULL;
6345   
6346   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6347                            &group_base, &group_count, 
6348                            LDAP_SCOPE_SUBTREE)) != 0)
6349     {
6350       com_err(whoami, 0, 
6351               "Unable to get list description with MoiraId = %s: %s",
6352               MoiraId, ldap_err2string(rc));
6353       return(rc);
6354     }
6355
6356   if (group_count != 0)
6357     {
6358       strcpy(before_desc, group_base->value);
6359       linklist_free(group_base);
6360       group_base = NULL;
6361       group_count = 0;
6362     }
6363  
6364   change_to_lower_case(ad_distinguishedName);  
6365   strcpy(ou_both, group_ou_both);
6366   change_to_lower_case(ou_both);
6367   strcpy(ou_security, group_ou_security);
6368   change_to_lower_case(ou_security);
6369   strcpy(ou_distribution, group_ou_distribution);
6370   change_to_lower_case(ou_distribution);
6371   strcpy(ou_neither, group_ou_neither);
6372   change_to_lower_case(ou_neither);
6373
6374   if (strstr(ad_distinguishedName, ou_both))
6375     {
6376       strcpy(before_group_ou, group_ou_both);
6377       before_group_membership[0] = 'B';
6378       before_security_flag = 1;
6379     }
6380   else if (strstr(ad_distinguishedName, ou_security))
6381     {
6382       strcpy(before_group_ou, group_ou_security);
6383       before_group_membership[0] = 'S';
6384       before_security_flag = 1;
6385     }
6386   else if (strstr(ad_distinguishedName, ou_distribution))
6387     {
6388       strcpy(before_group_ou, group_ou_distribution);
6389       before_group_membership[0] = 'D';
6390       before_security_flag = 0;
6391     }
6392   else if (strstr(ad_distinguishedName, ou_neither))
6393     {
6394       strcpy(before_group_ou, group_ou_neither);
6395       before_group_membership[0] = 'N';
6396       before_security_flag = 0;
6397     }
6398   else
6399     return(AD_NO_OU_FOUND);
6400
6401   rc = group_rename(ldap_handle, dn_path, before_name, 
6402                     before_group_membership, 
6403                     before_group_ou, before_security_flag, before_desc,
6404                     group_name, group_membership, group_ou, 
6405                     group_security_flag,
6406                     before_desc, MoiraId, filter, maillist);
6407
6408   return(rc);
6409 }
6410
6411 void change_to_lower_case(char *ptr)
6412 {
6413   int i;
6414
6415   for (i = 0; i < (int)strlen(ptr); i++)
6416     {
6417       ptr[i] = tolower(ptr[i]);
6418     }
6419 }
6420
6421 int ad_get_group(LDAP *ldap_handle, char *dn_path, 
6422                  char *group_name, char *group_membership, 
6423                  char *MoiraId, char *attribute,
6424                  LK_ENTRY **linklist_base, int *linklist_count,
6425                  char *rFilter)
6426 {
6427   LK_ENTRY  *pPtr;
6428   char  filter[128];
6429   char  *attr_array[3];
6430   char  *dn;
6431   int   rc;
6432
6433   (*linklist_base) = NULL;
6434   (*linklist_count) = 0;
6435
6436   if (strlen(rFilter) != 0)
6437     {
6438       strcpy(filter, rFilter);
6439       attr_array[0] = attribute;
6440       attr_array[1] = NULL;
6441       
6442       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6443                                linklist_base, linklist_count, 
6444                                LDAP_SCOPE_SUBTREE)) != 0)
6445         {
6446           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6447                   MoiraId, ldap_err2string(rc));
6448          return(rc);
6449        }
6450
6451     if ((*linklist_count) == 1)
6452       {
6453         strcpy(rFilter, filter);
6454         return(0);
6455       }
6456     }
6457
6458   linklist_free((*linklist_base));
6459   (*linklist_base) = NULL;
6460   (*linklist_count) = 0;
6461
6462   if (strlen(MoiraId) != 0)
6463     {
6464       sprintf(filter, "(&(objectClass=group)(mitMoiraId=%s))", MoiraId);
6465
6466       attr_array[0] = attribute;
6467       attr_array[1] = NULL;
6468
6469       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6470                                linklist_base, linklist_count, 
6471                                LDAP_SCOPE_SUBTREE)) != 0)
6472         {
6473           com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6474                   MoiraId, ldap_err2string(rc));
6475          return(rc);
6476        }
6477     }
6478
6479   if ((*linklist_count) > 1)
6480     {
6481       com_err(whoami, 0, "multiple groups with mitMoiraId = %s", MoiraId);
6482       pPtr = (*linklist_base);
6483
6484       while (pPtr)
6485         {
6486           com_err(whoami, 0, "groups %s has mitMoiraId = %s", pPtr->value, 
6487                   MoiraId);
6488           pPtr = pPtr->next;
6489         }
6490
6491       linklist_free((*linklist_base));
6492       (*linklist_base) = NULL;
6493       (*linklist_count) = 0;
6494     }
6495
6496   if ((*linklist_count) == 1)
6497     {
6498
6499       pPtr = (*linklist_base);
6500       dn = strdup(pPtr->dn);
6501       dn += 3;
6502
6503       if (!memcmp(dn, group_name, strlen(group_name)))
6504         {
6505           strcpy(rFilter, filter);
6506           return(0);
6507         }
6508     }
6509
6510   linklist_free((*linklist_base));
6511   (*linklist_base) = NULL;
6512   (*linklist_count) = 0;
6513   sprintf(filter, "(sAMAccountName=%s%s)", group_name, group_suffix);
6514
6515   attr_array[0] = attribute;
6516   attr_array[1] = NULL;
6517
6518   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6519                            linklist_base, linklist_count, 
6520                            LDAP_SCOPE_SUBTREE)) != 0)
6521     {
6522       com_err(whoami, 0, "Unable to get list info with MoiraId = %s: %s",
6523               MoiraId, ldap_err2string(rc));
6524       return(rc);
6525     }
6526
6527   if ((*linklist_count) == 1)
6528     {
6529       strcpy(rFilter, filter);
6530       return(0);
6531     }
6532
6533   return(0);
6534 }
6535
6536 int check_user(LDAP *ldap_handle, char *dn_path, char *UserName, char *MoiraId)
6537 {
6538   char filter[128];
6539   char *attr_array[3];
6540   char SamAccountName[64];
6541   int  group_count;
6542   int  rc;
6543   LK_ENTRY  *group_base;
6544   LK_ENTRY  *gPtr;
6545
6546   group_count = 0;
6547   group_base = NULL;
6548
6549   if (strlen(MoiraId) != 0)
6550     {
6551       sprintf(filter, "(&(objectClass=user)(mitMoiraId=%s))", MoiraId);
6552
6553       attr_array[0] = "sAMAccountName";
6554       attr_array[1] = NULL;
6555       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6556                                &group_base, &group_count, 
6557                                LDAP_SCOPE_SUBTREE)) != 0)
6558         {
6559           com_err(whoami, 0, "Unable to process user %s : %s",
6560                   UserName, ldap_err2string(rc));
6561           return(rc);
6562         }
6563
6564       if (group_count > 1)
6565         {
6566           com_err(whoami, 0, "multiple users exist with MoiraId = %s",
6567                   MoiraId);
6568           gPtr = group_base;
6569
6570           while (gPtr)
6571             {
6572               com_err(whoami, 0, "user %s exist with MoiraId = %s",
6573                       gPtr->value, MoiraId);
6574               gPtr = gPtr->next;
6575             }
6576         }
6577     }
6578
6579   if (group_count != 1)
6580     {
6581       linklist_free(group_base);
6582       group_count = 0;
6583       group_base = NULL;
6584       sprintf(filter, "(sAMAccountName=%s)", UserName);
6585       attr_array[0] = "sAMAccountName";
6586       attr_array[1] = NULL;
6587
6588       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
6589                                &group_base, &group_count, 
6590                                LDAP_SCOPE_SUBTREE)) != 0)
6591         {
6592           com_err(whoami, 0, "Unable to process user %s : %s",
6593                   UserName, ldap_err2string(rc));
6594           return(rc);
6595         }
6596     }
6597
6598   if (group_count != 1)
6599     {
6600       linklist_free(group_base);
6601       return(AD_NO_USER_FOUND);
6602     }
6603
6604   strcpy(SamAccountName, group_base->value);
6605   linklist_free(group_base);
6606   group_count = 0;
6607   rc = 0;
6608
6609   if (strcmp(SamAccountName, UserName))
6610     {
6611       com_err(whoami, 0, 
6612               "User object %s with MoiraId %s has mismatched usernames " 
6613               "(LDAP username %s, Moira username %s)", SamAccountName,
6614               MoiraId, SamAccountName, UserName);
6615     }
6616
6617   return(0);
6618 }
6619
6620 void container_get_dn(char *src, char *dest)
6621 {
6622   char *sPtr;
6623   char *array[20];
6624   char name[256];
6625   int  n;
6626
6627   memset(array, '\0', 20 * sizeof(array[0]));
6628
6629   if (strlen(src) == 0)
6630     return;
6631
6632   strcpy(name, src);
6633   sPtr = name;
6634   n = 0;
6635   array[n] = name;
6636   ++n;
6637
6638   while (*sPtr)
6639     {
6640       if ((*sPtr) == '/')
6641         {
6642           (*sPtr) = '\0';
6643           ++sPtr;
6644           array[n] = sPtr;
6645           ++n;
6646         }
6647       else
6648         ++sPtr;
6649     }
6650
6651   strcpy(dest, "OU=");
6652
6653   while (n != 0)
6654     {
6655       strcat(dest, array[n-1]);
6656       --n;
6657       if (n > 0)
6658         {
6659           strcat(dest, ",OU=");
6660         }
6661     }
6662
6663   return;
6664 }
6665
6666 void container_get_name(char *src, char *dest)
6667 {
6668   char *sPtr;
6669   char *dPtr;
6670
6671   if (strlen(src) == 0)
6672     return;
6673
6674   sPtr = src;
6675   dPtr = src;
6676
6677   while (*sPtr)
6678     {
6679       if ((*sPtr) == '/')
6680         {
6681           dPtr = sPtr;
6682           ++dPtr;
6683         }
6684       ++sPtr;
6685     }
6686
6687   strcpy(dest, dPtr);
6688   return;
6689 }
6690
6691 void container_check(LDAP *ldap_handle, char *dn_path, char *name)
6692 {
6693   char cName[256];
6694   char *av[7];
6695   int  i;
6696   int  rc;
6697
6698   strcpy(cName, name);
6699
6700   for (i = 0; i < (int)strlen(cName); i++)
6701     {
6702       if (cName[i] == '/')
6703         {
6704           cName[i] = '\0';
6705           av[CONTAINER_NAME] = cName;
6706           av[CONTAINER_DESC] = "";
6707           av[CONTAINER_LOCATION] = "";
6708           av[CONTAINER_CONTACT] = "";
6709           av[CONTAINER_TYPE] = "";
6710           av[CONTAINER_ID] = "";
6711           av[CONTAINER_ROWID] = "";
6712           rc = container_create(ldap_handle, dn_path, 7, av);
6713
6714           if (rc == LDAP_SUCCESS)
6715             {
6716               com_err(whoami, 0, "container %s created without a mitMoiraId", 
6717                       cName);
6718             }
6719
6720           cName[i] = '/';
6721         }
6722     }
6723 }
6724
6725 int container_rename(LDAP *ldap_handle, char *dn_path, int beforec, 
6726                      char **before, int afterc, char **after)
6727 {
6728   char      dName[256];
6729   char      cName[256];
6730   char      new_cn[128];
6731   char      new_dn_path[256];
6732   char      temp[256];
6733   char      distinguishedName[256];
6734   char      *pPtr;
6735   int       rc;
6736   int       i;
6737
6738   memset(cName, '\0', sizeof(cName));
6739   container_get_name(after[CONTAINER_NAME], cName);
6740
6741   if (!check_container_name(cName))
6742     {
6743       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6744               cName);
6745       return(AD_INVALID_NAME);
6746     }
6747
6748   memset(distinguishedName, '\0', sizeof(distinguishedName));
6749
6750   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6751                                            distinguishedName, beforec, before))
6752     return(rc);
6753
6754   if (strlen(distinguishedName) == 0)
6755     {
6756       rc = container_create(ldap_handle, dn_path, afterc, after);
6757       return(rc);
6758     }
6759
6760   strcpy(temp, after[CONTAINER_NAME]);
6761   pPtr = temp;
6762
6763   for (i = 0; i < (int)strlen(temp); i++)
6764     {
6765       if (temp[i] == '/')
6766         {
6767           pPtr = &temp[i];
6768         }
6769     }
6770
6771   (*pPtr) = '\0';
6772
6773   container_get_dn(temp, dName);
6774
6775   if (strlen(temp) != 0)
6776     sprintf(new_dn_path, "%s,%s", dName, dn_path);
6777   else
6778     sprintf(new_dn_path, "%s", dn_path);
6779
6780   sprintf(new_cn, "OU=%s", cName);
6781
6782   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6783
6784   if ((rc = ldap_rename_s(ldap_handle, distinguishedName, new_cn, new_dn_path,
6785                           TRUE, NULL, NULL)) != LDAP_SUCCESS)
6786     {
6787       com_err(whoami, 0, "Unable to rename container from %s to %s : %s",
6788               before[CONTAINER_NAME], after[CONTAINER_NAME], 
6789               ldap_err2string(rc));
6790       return(rc);
6791     }
6792
6793   memset(dName, '\0', sizeof(dName));
6794   container_get_dn(after[CONTAINER_NAME], dName);
6795   rc = container_adupdate(ldap_handle, dn_path, dName, "", afterc, after);
6796
6797   return(rc);
6798 }
6799
6800 int container_delete(LDAP *ldap_handle, char *dn_path, int count, char **av)
6801 {
6802   char      distinguishedName[256];
6803   int       rc;
6804
6805   memset(distinguishedName, '\0', sizeof(distinguishedName));
6806
6807   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6808                                            distinguishedName, count, av))
6809     return(rc);
6810
6811   if (strlen(distinguishedName) == 0)
6812     return(0);
6813
6814   if ((rc = ldap_delete_s(ldap_handle, distinguishedName)) != LDAP_SUCCESS)
6815     {
6816       if (rc == LDAP_NOT_ALLOWED_ON_NONLEAF)
6817         container_move_objects(ldap_handle, dn_path, distinguishedName);
6818       else
6819         com_err(whoami, 0, "Unable to delete container %s from AD : %s",
6820                 av[CONTAINER_NAME], ldap_err2string(rc));
6821     }
6822
6823   return(rc);
6824 }
6825
6826 int container_create(LDAP *ldap_handle, char *dn_path, int count, char **av)
6827 {
6828   char      *attr_array[3];
6829   LK_ENTRY  *group_base;
6830   int       group_count;
6831   LDAPMod   *mods[20];
6832   char      *objectClass_v[] = {"top", 
6833                            "organizationalUnit", 
6834                            NULL};
6835
6836   char *ou_v[] = {NULL, NULL};
6837   char *name_v[] = {NULL, NULL};
6838   char *moiraId_v[] = {NULL, NULL};
6839   char *desc_v[] = {NULL, NULL};
6840   char *managedBy_v[] = {NULL, NULL};
6841   char dName[256];
6842   char cName[256];
6843   char managedByDN[256];
6844   char filter[256];
6845   char temp[256];
6846   int  n;
6847   int  i;
6848   int  rc;
6849     
6850   memset(filter, '\0', sizeof(filter));
6851   memset(dName, '\0', sizeof(dName));
6852   memset(cName, '\0', sizeof(cName));
6853   memset(managedByDN, '\0', sizeof(managedByDN));
6854   container_get_dn(av[CONTAINER_NAME], dName);
6855   container_get_name(av[CONTAINER_NAME], cName);
6856
6857   if ((strlen(cName) == 0) || (strlen(dName) == 0))
6858     {
6859       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6860               cName);
6861       return(AD_INVALID_NAME);
6862     }
6863
6864   if (!check_container_name(cName))
6865     {
6866       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
6867               cName);
6868       return(AD_INVALID_NAME);
6869     }
6870
6871   n = 0;
6872   ADD_ATTR("objectClass", objectClass_v, LDAP_MOD_ADD);
6873   name_v[0] = cName;
6874   ADD_ATTR("name", name_v, LDAP_MOD_ADD);
6875   ou_v[0] = cName;
6876   ADD_ATTR("ou", ou_v, LDAP_MOD_ADD);
6877
6878   if (strlen(av[CONTAINER_ROWID]) != 0)
6879     {
6880       moiraId_v[0] = av[CONTAINER_ROWID];
6881       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_ADD);
6882     }
6883
6884   if (strlen(av[CONTAINER_DESC]) != 0)
6885     {
6886       desc_v[0] = av[CONTAINER_DESC];
6887       ADD_ATTR("description", desc_v, LDAP_MOD_ADD);
6888     }
6889
6890   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
6891     {
6892       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
6893         {
6894           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
6895                               kerberos_ou))
6896             {
6897               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
6898                       kerberos_ou, dn_path);
6899               managedBy_v[0] = managedByDN;
6900               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6901             }
6902         }
6903       else
6904         {
6905           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
6906             {
6907               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
6908                       "(objectClass=user)))", av[CONTAINER_ID]);
6909             }
6910
6911           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
6912             {
6913               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
6914                       av[CONTAINER_ID]);
6915             }
6916
6917           if (strlen(filter) != 0)
6918             {
6919               attr_array[0] = "distinguishedName";
6920               attr_array[1] = NULL;
6921               group_count = 0;
6922               group_base = NULL;
6923               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
6924                                        attr_array, 
6925                                        &group_base, &group_count, 
6926                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
6927                 {
6928                   if (group_count == 1)
6929                     {
6930                       strcpy(managedByDN, group_base->value);
6931                       managedBy_v[0] = managedByDN;
6932                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_ADD);
6933                     }
6934                   linklist_free(group_base);
6935                   group_base = NULL;
6936                   group_count = 0;
6937                 }
6938             }
6939         }
6940     }
6941   
6942   mods[n] = NULL;
6943
6944   sprintf(temp, "%s,%s", dName, dn_path);
6945   rc = ldap_add_ext_s(ldap_handle, temp, mods, NULL, NULL);
6946   
6947   for (i = 0; i < n; i++)
6948     free(mods[i]);
6949   
6950   if ((rc != LDAP_SUCCESS) && (rc != LDAP_ALREADY_EXISTS))
6951     {
6952       com_err(whoami, 0, "Unable to create container %s : %s",
6953               cName, ldap_err2string(rc));
6954       return(rc);
6955     }
6956
6957   if (rc == LDAP_ALREADY_EXISTS)
6958     {
6959       if (strlen(av[CONTAINER_ROWID]) != 0)
6960         rc = container_adupdate(ldap_handle, dn_path, dName, "", count, av);
6961     }
6962
6963   return(rc);
6964 }
6965
6966 int container_update(LDAP *ldap_handle, char *dn_path, int beforec, 
6967                      char **before, int afterc, char **after)
6968 {
6969   char distinguishedName[256];
6970   int  rc;
6971
6972   memset(distinguishedName, '\0', sizeof(distinguishedName));
6973
6974   if (rc = container_get_distinguishedName(ldap_handle, dn_path, 
6975                                            distinguishedName, afterc, after))
6976     return(rc);
6977
6978   if (strlen(distinguishedName) == 0)
6979     {
6980       rc = container_create(ldap_handle, dn_path, afterc, after);
6981       return(rc);
6982     }
6983   
6984   container_check(ldap_handle, dn_path, after[CONTAINER_NAME]);
6985   rc = container_adupdate(ldap_handle, dn_path, "", distinguishedName, afterc,
6986                           after);
6987
6988   return(rc);
6989 }
6990
6991 int container_get_distinguishedName(LDAP *ldap_handle, char *dn_path, 
6992                                     char *distinguishedName, int count, 
6993                                     char **av)
6994 {
6995   char      *attr_array[3];
6996   LK_ENTRY  *group_base;
6997   int       group_count;
6998   char      dName[256];
6999   char      cName[256];
7000   char      filter[512];
7001   int       rc;
7002
7003   memset(filter, '\0', sizeof(filter));
7004   memset(dName, '\0', sizeof(dName));
7005   memset(cName, '\0', sizeof(cName));
7006   container_get_dn(av[CONTAINER_NAME], dName);
7007   container_get_name(av[CONTAINER_NAME], cName);
7008
7009   if (strlen(dName) == 0)
7010     {
7011       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7012               av[CONTAINER_NAME]);
7013       return(AD_INVALID_NAME);
7014     }
7015
7016   if (!check_container_name(cName))
7017     {
7018       com_err(whoami, 0, "Unable to process invalid LDAP container name %s", 
7019               cName);
7020       return(AD_INVALID_NAME);
7021     }
7022   
7023   sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7024           av[CONTAINER_ROWID]);
7025   attr_array[0] = "distinguishedName";
7026   attr_array[1] = NULL;
7027   group_count = 0;
7028   group_base = NULL;
7029
7030   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7031                            &group_base, &group_count, 
7032                            LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7033     {
7034       if (group_count == 1)
7035         {
7036           strcpy(distinguishedName, group_base->value);
7037         }
7038
7039       linklist_free(group_base);
7040       group_base = NULL;
7041       group_count = 0;
7042     }
7043
7044   if (strlen(distinguishedName) == 0)
7045     {
7046       sprintf(filter, "(&(objectClass=organizationalUnit)"
7047               "(distinguishedName=%s,%s))", dName, dn_path);
7048       attr_array[0] = "distinguishedName";
7049       attr_array[1] = NULL;
7050       group_count = 0;
7051       group_base = NULL;
7052
7053       if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7054                                &group_base, &group_count, 
7055                                LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7056         {
7057           if (group_count == 1)
7058             {
7059               strcpy(distinguishedName, group_base->value);
7060             }
7061
7062           linklist_free(group_base);
7063           group_base = NULL;
7064           group_count = 0;
7065         }
7066     }
7067
7068   return(0);
7069 }
7070
7071 int container_adupdate(LDAP *ldap_handle, char *dn_path, char *dName, 
7072                        char *distinguishedName, int count, char **av)
7073 {
7074   char      *attr_array[5];
7075   LK_ENTRY  *group_base;
7076   LK_ENTRY  *pPtr;
7077   LDAPMod   *mods[20];
7078   int       group_count;
7079   char      filter[512];
7080   char      *moiraId_v[] = {NULL, NULL};
7081   char      *desc_v[] = {NULL, NULL};
7082   char      *managedBy_v[] = {NULL, NULL};
7083   char      managedByDN[256];
7084   char      moiraId[64];
7085   char      desc[256];
7086   char      ad_path[512];
7087   int       rc;
7088   int       i;
7089   int       n;
7090
7091
7092   strcpy(ad_path, distinguishedName);
7093
7094   if (strlen(dName) != 0)
7095     sprintf(ad_path, "%s,%s", dName, dn_path);
7096
7097   sprintf(filter, "(&(objectClass=organizationalUnit)(distinguishedName=%s))",
7098           ad_path);
7099
7100   if (strlen(av[CONTAINER_ID]) != 0)
7101     sprintf(filter, "(&(objectClass=organizationalUnit)(mitMoiraId=%s))", 
7102             av[CONTAINER_ROWID]);
7103
7104   attr_array[0] = "mitMoiraId";
7105   attr_array[1] = "description";
7106   attr_array[2] = "managedBy";
7107   attr_array[3] = NULL;
7108   group_count = 0;
7109   group_base = NULL;
7110
7111   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7112                            &group_base, &group_count, 
7113                            LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7114     {
7115       com_err(whoami, 0, "Unable to retreive container info for %s : %s",
7116               av[CONTAINER_NAME], ldap_err2string(rc));
7117       return(rc);
7118     }
7119
7120   memset(managedByDN, '\0', sizeof(managedByDN));
7121   memset(moiraId, '\0', sizeof(moiraId));
7122   memset(desc, '\0', sizeof(desc));
7123   pPtr = group_base;
7124
7125   while (pPtr)
7126     {
7127       if (!strcasecmp(pPtr->attribute, "description"))
7128         strcpy(desc, pPtr->value);
7129       else if (!strcasecmp(pPtr->attribute, "managedBy"))
7130         strcpy(managedByDN, pPtr->value);
7131       else if (!strcasecmp(pPtr->attribute, "mitMoiraId"))
7132         strcpy(moiraId, pPtr->value);
7133       pPtr = pPtr->next;
7134     }
7135
7136   linklist_free(group_base);
7137   group_base = NULL;
7138   group_count = 0;
7139
7140   n = 0;
7141   if (strlen(av[CONTAINER_ROWID]) != 0)
7142     {
7143       moiraId_v[0] = av[CONTAINER_ROWID];
7144       ADD_ATTR("mitMoiraId", moiraId_v, LDAP_MOD_REPLACE);
7145     }
7146
7147   if (strlen(av[CONTAINER_DESC]) != 0)
7148     {
7149       attribute_update(ldap_handle, ad_path, av[CONTAINER_DESC], "description",
7150                        dName);
7151     }
7152   else
7153     {
7154       if (strlen(desc) != 0)
7155         {
7156           attribute_update(ldap_handle, ad_path, "", "description", dName);
7157         }
7158     }
7159
7160   if ((strlen(av[CONTAINER_TYPE]) != 0) && (strlen(av[CONTAINER_ID]) != 0))
7161     {
7162       if (!strcasecmp(av[CONTAINER_TYPE], "KERBEROS"))
7163         {
7164           if (!contact_create(ldap_handle, dn_path, av[CONTAINER_ID], 
7165                               kerberos_ou))
7166             {
7167               sprintf(managedByDN, "CN=%s,%s,%s", av[CONTAINER_ID], 
7168                       kerberos_ou, dn_path);
7169               managedBy_v[0] = managedByDN;
7170               ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7171             }
7172           else
7173             {
7174               if (strlen(managedByDN) != 0)
7175                 {
7176                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7177                                    dName);
7178                 }
7179             }
7180         }
7181       else
7182         {
7183           memset(filter, '\0', sizeof(filter));
7184
7185           if (!strcasecmp(av[CONTAINER_TYPE], "USER"))
7186             {
7187               sprintf(filter, "(&(cn=%s)(&(objectCategory=person)"
7188                       "(objectClass=user)))", av[CONTAINER_ID]);
7189             }
7190
7191           if (!strcasecmp(av[CONTAINER_TYPE], "LIST"))
7192             {
7193               sprintf(filter, "(&(objectClass=group)(cn=%s))", 
7194                       av[CONTAINER_ID]);
7195             }
7196
7197           if (strlen(filter) != 0)
7198             {
7199               attr_array[0] = "distinguishedName";
7200               attr_array[1] = NULL;
7201               group_count = 0;
7202               group_base = NULL;
7203               if ((rc = linklist_build(ldap_handle, dn_path, filter, 
7204                                        attr_array, &group_base, &group_count, 
7205                                        LDAP_SCOPE_SUBTREE)) == LDAP_SUCCESS)
7206                 {
7207                   if (group_count == 1)
7208                     {
7209                       strcpy(managedByDN, group_base->value);
7210                       managedBy_v[0] = managedByDN;
7211                       ADD_ATTR("managedBy", managedBy_v, LDAP_MOD_REPLACE);
7212                     }
7213                   else
7214                     {
7215                       if (strlen(managedByDN) != 0)
7216                         {
7217                           attribute_update(ldap_handle, ad_path, "", 
7218                                            "managedBy", dName);
7219                         }
7220                     }
7221
7222                   linklist_free(group_base);
7223                   group_base = NULL;
7224                   group_count = 0;
7225                 }
7226             }
7227           else
7228             {
7229               if (strlen(managedByDN) != 0)
7230                 {
7231                   attribute_update(ldap_handle, ad_path, "", "managedBy", 
7232                                    dName);
7233                 }
7234             }
7235         }
7236     }
7237
7238   mods[n] = NULL;
7239
7240   if (n == 0)
7241     return(LDAP_SUCCESS);
7242
7243   rc = ldap_modify_s(ldap_handle, ad_path, mods);
7244
7245   for (i = 0; i < n; i++)
7246     free(mods[i]);
7247
7248   if (rc != LDAP_SUCCESS)
7249     {
7250       com_err(whoami, 0, "Unable to modify container info for %s : %s",
7251               av[CONTAINER_NAME], ldap_err2string(rc));
7252       return(rc);
7253     }
7254   
7255   return(rc);
7256 }
7257
7258 int container_move_objects(LDAP *ldap_handle, char *dn_path, char *dName)
7259 {
7260   char      *attr_array[3];
7261   LK_ENTRY  *group_base;
7262   LK_ENTRY  *pPtr;
7263   int       group_count;
7264   char      filter[512];
7265   char      new_cn[128];
7266   char      temp[256];
7267   int       rc;
7268   int       NumberOfEntries = 10;
7269   int       i;
7270   int       count;
7271
7272   rc = ldap_set_option(ldap_handle, LDAP_OPT_SIZELIMIT, &NumberOfEntries);
7273
7274   for (i = 0; i < 3; i++)
7275     {
7276       memset(filter, '\0', sizeof(filter));
7277
7278       if (i == 0)
7279         {
7280           strcpy(filter, "(!(|(objectClass=computer)"
7281                  "(objectClass=organizationalUnit)))");
7282           attr_array[0] = "cn";
7283           attr_array[1] = NULL;
7284         }
7285       else if (i == 1)
7286         {
7287           strcpy(filter, "(objectClass=computer)");
7288           attr_array[0] = "cn";
7289           attr_array[1] = NULL;
7290         }
7291       else
7292         {
7293           strcpy(filter, "(objectClass=organizationalUnit)");
7294           attr_array[0] = "ou";
7295           attr_array[1] = NULL;
7296         }
7297
7298       while (1)
7299         {
7300           if ((rc = linklist_build(ldap_handle, dName, filter, attr_array, 
7301                                    &group_base, &group_count, 
7302                                    LDAP_SCOPE_SUBTREE)) != LDAP_SUCCESS)
7303             {
7304               break;
7305             }
7306
7307           if (group_count == 0)
7308             break;
7309
7310           pPtr = group_base;
7311
7312           while(pPtr)
7313             {
7314               if (!strcasecmp(pPtr->attribute, "cn"))
7315                 {
7316                   sprintf(new_cn, "cn=%s", pPtr->value);
7317                   if (i == 0)
7318                     sprintf(temp, "%s,%s", orphans_other_ou, dn_path);
7319                   if (i == 1)
7320                     sprintf(temp, "%s,%s", orphans_machines_ou, dn_path);
7321                   count = 1;
7322
7323                   while (1)
7324                     {
7325                       rc = ldap_rename_s(ldap_handle, pPtr->dn, new_cn, temp,
7326                                          TRUE, NULL, NULL);
7327                       if (rc == LDAP_ALREADY_EXISTS)
7328                         {
7329                           sprintf(new_cn, "cn=%s_%d", pPtr->value, count);
7330                           ++count;
7331                         }
7332                       else
7333                         break;
7334                     }
7335                 }
7336               else if (!strcasecmp(pPtr->attribute, "ou"))
7337                 {
7338                   rc = ldap_delete_s(ldap_handle, pPtr->dn);
7339                 }
7340
7341               pPtr = pPtr->next;
7342             }
7343
7344           linklist_free(group_base);
7345           group_base = NULL;
7346           group_count = 0;
7347         }
7348     }
7349
7350   return(0);
7351 }
7352
7353 int get_machine_ou(LDAP *ldap_handle, char *dn_path, char *member, 
7354                    char *machine_ou, char *NewMachineName)
7355 {
7356   LK_ENTRY  *group_base;
7357   int  group_count;
7358   int  i;
7359   char filter[128];
7360   char *attr_array[3];
7361   char cn[256];
7362   char dn[256];
7363   char temp[256];
7364   char *pPtr;
7365   int   rc;
7366
7367   strcpy(NewMachineName, member);
7368   rc = moira_connect();
7369   rc = GetMachineName(NewMachineName);
7370   moira_disconnect();
7371
7372   if (strlen(NewMachineName) == 0)
7373     {
7374       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7375               member);
7376       return(1);
7377     }
7378
7379   pPtr = NULL;
7380   pPtr = strchr(NewMachineName, '.');
7381
7382   if (pPtr != NULL)
7383     (*pPtr) = '\0';
7384
7385   group_base = NULL;
7386   group_count = 0;
7387   sprintf(filter, "(sAMAccountName=%s$)", NewMachineName);
7388   attr_array[0] = "cn";
7389   attr_array[1] = NULL;
7390   sprintf(temp, "%s", dn_path);
7391
7392   if ((rc = linklist_build(ldap_handle, temp, filter, attr_array, 
7393                            &group_base, &group_count, 
7394                            LDAP_SCOPE_SUBTREE)) != 0)
7395     {
7396       com_err(whoami, 0, "Unable to process machine %s : %s",
7397               member, ldap_err2string(rc));
7398       return(1);
7399     }
7400
7401   if (group_count != 1)
7402     {
7403       com_err(whoami, 0, 
7404               "Unable to process machine %s : machine not found in AD",
7405               NewMachineName);
7406       return(1);
7407     }
7408
7409   strcpy(dn, group_base->dn);
7410   strcpy(cn, group_base->value);
7411
7412   for (i = 0; i < (int)strlen(dn); i++)
7413     dn[i] = tolower(dn[i]);
7414
7415   for (i = 0; i < (int)strlen(cn); i++)
7416     cn[i] = tolower(cn[i]);
7417
7418   linklist_free(group_base);
7419   pPtr = NULL;
7420   pPtr = strstr(dn, cn);
7421
7422   if (pPtr == NULL)
7423     {
7424       com_err(whoami, 0, "Unable to process machine %s",
7425               member);
7426       return(1);
7427     }
7428
7429   pPtr += strlen(cn) + 1;
7430   strcpy(machine_ou, pPtr);
7431   pPtr = NULL;
7432   pPtr = strstr(machine_ou, "dc=");
7433
7434   if (pPtr == NULL)
7435     {
7436       com_err(whoami, 0, "Unable to process machine %s",
7437               member);
7438       return(1);
7439     }
7440
7441   --pPtr;
7442   (*pPtr) = '\0';
7443
7444   return(0);
7445 }
7446
7447 int machine_move_to_ou(LDAP *ldap_handle, char * dn_path, 
7448                        char *MoiraMachineName, char *DestinationOu)
7449 {
7450   char        NewCn[128];
7451   char        OldDn[512];
7452   char        MachineName[128];
7453   char        filter[128];
7454   char        *attr_array[3];
7455   char        NewOu[256];
7456   char        *cPtr = NULL;
7457   int         group_count;
7458   long        rc;
7459   LK_ENTRY    *group_base;
7460
7461   group_count = 0;
7462   group_base = NULL;
7463   
7464   strcpy(MachineName, MoiraMachineName);
7465   rc = GetMachineName(MachineName);
7466
7467   if (strlen(MachineName) == 0)
7468     {
7469       com_err(whoami, 0, "Unable to find alais for machine %s in Moira", 
7470               MoiraMachineName);
7471       return(1);
7472     }
7473   
7474   cPtr = strchr(MachineName, '.');
7475
7476   if (cPtr != NULL)
7477     (*cPtr) = '\0';
7478
7479   sprintf(filter, "(sAMAccountName=%s$)", MachineName);
7480   attr_array[0] = "sAMAccountName";
7481   attr_array[1] = NULL;
7482
7483   if ((rc = linklist_build(ldap_handle, dn_path, filter, attr_array, 
7484                            &group_base, 
7485                            &group_count, LDAP_SCOPE_SUBTREE)) != 0)
7486     {
7487       com_err(whoami, 0, "Unable to process machine %s : %s",
7488               MoiraMachineName, ldap_err2string(rc));
7489       return(1);
7490     }
7491   
7492   if (group_count == 1)
7493     strcpy(OldDn, group_base->dn);
7494
7495   linklist_free(group_base);
7496   group_base = NULL;
7497
7498   if (group_count != 1)
7499     {
7500       com_err(whoami, 0, "Unable to find machine %s in AD: %s", 
7501               MoiraMachineName);
7502       return(1);
7503     }
7504
7505   sprintf(NewOu, "%s,%s", DestinationOu, dn_path);
7506   cPtr = strchr(OldDn, ',');
7507
7508   if (cPtr != NULL)
7509     {
7510       ++cPtr;
7511       if (!strcasecmp(cPtr, NewOu))
7512         return(0);
7513     }
7514
7515   sprintf(NewCn, "CN=%s", MachineName);
7516   rc = ldap_rename_s(ldap_handle, OldDn, NewCn, NewOu, TRUE, NULL, NULL);
7517
7518   return(rc);
7519 }
7520
7521 int machine_check(LDAP *ldap_handle, char *dn_path, char *machine_name)
7522 {
7523   char    Name[128];
7524   char    *pPtr;
7525   int     rc;
7526   
7527   memset(Name, '\0', sizeof(Name));
7528   strcpy(Name, machine_name);
7529   pPtr = NULL;
7530   pPtr = strchr(Name, '.');
7531
7532   if (pPtr != NULL)
7533     (*pPtr) = '\0';
7534
7535   strcat(Name, "$");
7536   return(!(rc = checkADname(ldap_handle, dn_path, Name)));
7537 }
7538
7539 int machine_get_moira_container(LDAP *ldap_handle, char *dn_path, 
7540                                 char *machine_name, char *container_name)
7541 {
7542   int     rc;
7543   char    *av[2];
7544   char    *call_args[2];
7545   
7546   av[0] = machine_name;
7547   call_args[0] = (char *)container_name;
7548   rc = mr_query("get_machine_to_container_map", 1, av, 
7549                 machine_GetMoiraContainer, call_args);
7550   return(rc);
7551 }
7552
7553 int machine_GetMoiraContainer(int ac, char **av, void *ptr)
7554 {
7555   char **call_args;
7556   
7557   call_args = ptr;
7558   strcpy(call_args[0], av[1]);
7559   return(0);
7560 }
7561
7562 int Moira_container_group_create(char **after)
7563 {
7564   long rc;
7565   char GroupName[64];
7566   char *argv[20];
7567   
7568   memset(GroupName, '\0', sizeof(GroupName));
7569   rc = Moira_groupname_create(GroupName, after[CONTAINER_NAME], 
7570                               after[CONTAINER_ROWID]);
7571   if (rc)
7572     return rc;
7573   
7574   argv[L_NAME] = GroupName;
7575   argv[L_ACTIVE] = "1";
7576   argv[L_PUBLIC] = "0";
7577   argv[L_HIDDEN] = "0";
7578   argv[L_MAILLIST] = "0";
7579   argv[L_GROUP] = "1";
7580   argv[L_GID] = UNIQUE_GID;
7581   argv[L_NFSGROUP] = "0";
7582   argv[L_MAILMAN] = "0";
7583   argv[L_MAILMAN_SERVER] = "[NONE]";
7584   argv[L_DESC] = "auto created container group";
7585   argv[L_ACE_TYPE] = "USER";
7586   argv[L_MEMACE_TYPE] = "USER";
7587   argv[L_ACE_NAME] = "sms";
7588   argv[L_MEMACE_NAME] = "sms";
7589
7590   if (rc = mr_query("add_list", 15, argv, NULL, NULL))
7591     {
7592       com_err(whoami, 0, 
7593               "Unable to create container group %s for container %s: %s",
7594               GroupName, after[CONTAINER_NAME], error_message(rc));
7595     }
7596
7597   Moira_setContainerGroup(after[CONTAINER_NAME], GroupName);
7598   Moira_addGroupToParent(after[CONTAINER_NAME], GroupName);
7599   
7600   return(rc);
7601 }
7602
7603 int Moira_container_group_update(char **before, char **after)
7604 {
7605   long rc;
7606   char BeforeGroupName[64];
7607   char AfterGroupName[64];
7608   char *argv[20];
7609   
7610   if (!strcasecmp(after[CONTAINER_NAME], before[CONTAINER_NAME]))
7611     return(0);
7612
7613   memset(BeforeGroupName, '\0', sizeof(BeforeGroupName));
7614   Moira_getGroupName(after[CONTAINER_NAME], BeforeGroupName, 0);
7615   if (strlen(BeforeGroupName) == 0)
7616     return(0);
7617
7618   memset(AfterGroupName, '\0', sizeof(AfterGroupName));
7619   rc = Moira_groupname_create(AfterGroupName, after[CONTAINER_NAME], 
7620                               after[CONTAINER_ROWID]);
7621   if (rc)
7622     return rc;
7623
7624   if (strcasecmp(BeforeGroupName, AfterGroupName))
7625     {
7626       argv[L_NAME] = BeforeGroupName;
7627       argv[L_NAME + 1] = AfterGroupName;
7628       argv[L_ACTIVE + 1] = "1";
7629       argv[L_PUBLIC + 1] = "0";
7630       argv[L_HIDDEN + 1] = "0";
7631       argv[L_MAILLIST + 1] = "0";
7632       argv[L_GROUP + 1] = "1";
7633       argv[L_GID + 1] = UNIQUE_GID;
7634       argv[L_NFSGROUP + 1] = "0";
7635       argv[L_MAILMAN + 1] = "0";
7636       argv[L_MAILMAN_SERVER + 1] = "[NONE]";
7637       argv[L_DESC + 1] = "auto created container group";
7638       argv[L_ACE_TYPE + 1] = "USER";
7639       argv[L_MEMACE_TYPE + 1] = "USER";
7640       argv[L_ACE_NAME + 1] = "sms";
7641       argv[L_MEMACE_NAME + 1] = "sms";
7642       
7643       if (rc = mr_query("update_list", 16, argv, NULL, NULL))
7644         {
7645           com_err(whoami, 0, 
7646                   "Unable to rename container group from %s to %s: %s",
7647                   BeforeGroupName, AfterGroupName, error_message(rc));
7648         }
7649     }
7650   
7651   return(rc);
7652 }
7653
7654 int Moira_container_group_delete(char **before)
7655 {
7656   long rc = 0;
7657   char *argv[13];
7658   char GroupName[64];
7659   char ParentGroupName[64];
7660   
7661   memset(ParentGroupName, '\0', sizeof(ParentGroupName));
7662   Moira_getGroupName(before[CONTAINER_NAME], ParentGroupName, 1);
7663
7664   memset(GroupName, '\0', sizeof(GroupName));
7665
7666   if (strcmp(before[CONTAINER_GROUP_NAME], "[none]"))
7667     strcpy(GroupName, before[CONTAINER_GROUP_NAME]);
7668   
7669   if ((strlen(ParentGroupName) != 0) && (strlen(GroupName) != 0))
7670     {
7671       argv[0] = ParentGroupName;
7672       argv[1] = "LIST";
7673       argv[2] = GroupName;
7674
7675       if (rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL))
7676         {
7677           com_err(whoami, 0, 
7678                   "Unable to delete container group %s from list: %s",
7679                   GroupName, ParentGroupName, error_message(rc));
7680         }
7681     }
7682   
7683   if (strlen(GroupName) != 0)
7684     {
7685       argv[0] = GroupName;
7686
7687       if (rc = mr_query("delete_list", 1, argv, NULL, NULL))
7688         {
7689           com_err(whoami, 0, "Unable to delete container group %s : %s",
7690                   GroupName, error_message(rc));
7691         }
7692     }
7693   
7694   return(rc);
7695 }
7696
7697 int Moira_groupname_create(char *GroupName, char *ContainerName,
7698                            char *ContainerRowID)
7699 {
7700   char *ptr;
7701   char *ptr1;
7702   char temp[64];
7703   char newGroupName[64];
7704   char tempGroupName[64];
7705   char tempgname[64];
7706   char *argv[1];
7707   int  i;
7708   long rc;
7709
7710   strcpy(temp, ContainerName);
7711   
7712   ptr1 = strrchr(temp, '/');
7713
7714   if (ptr1 != NULL)
7715   {
7716     *ptr1 = '\0';
7717     ptr = ++ptr1;
7718     ptr1 = strrchr(temp, '/');
7719
7720     if (ptr1 != NULL)
7721     {
7722         sprintf(tempgname, "%s-%s", ++ptr1, ptr);
7723     }
7724     else
7725         strcpy(tempgname, ptr);
7726   }
7727   else
7728     strcpy(tempgname, temp);
7729
7730   if (strlen(tempgname) > 25)
7731     tempgname[25] ='\0';
7732
7733   sprintf(newGroupName, "cnt-%s", tempgname);
7734
7735   /* change everything to lower case */
7736   ptr = newGroupName;
7737
7738   while (*ptr)
7739     {
7740       if (isupper(*ptr))
7741         *ptr = tolower(*ptr);
7742
7743       if (*ptr == ' ')
7744         *ptr = '-';
7745
7746       ptr++;
7747     }
7748
7749   strcpy(tempGroupName, newGroupName);
7750   i = (int)'0';
7751
7752   /* append 0-9 then a-z if a duplicate is found */
7753   while(1)
7754     {
7755       argv[0] = newGroupName;
7756
7757       if (rc = mr_query("get_list_info", 1, argv, NULL, NULL))
7758         {
7759           if (rc == MR_NO_MATCH)
7760             break;
7761           com_err(whoami, 0, "Moira error while creating group name for "
7762                   "container %s : %s", ContainerName, error_message(rc));
7763           return rc;
7764         }
7765
7766       sprintf(newGroupName, "%s-%c", tempGroupName, i);
7767
7768       if (i == (int)'z')
7769         {
7770           com_err(whoami, 0, "Unable to find a unique group name for "
7771                   "container %s: too many duplicate container names",
7772                   ContainerName);
7773           return 1;
7774         }
7775
7776       if (i == '9')
7777         i = 'a';
7778       else
7779         i++;
7780     }
7781
7782   strcpy(GroupName, newGroupName);
7783   return(0);
7784 }
7785
7786 int Moira_setContainerGroup(char *origContainerName, char *GroupName)
7787 {
7788   long rc;
7789   char *argv[3];
7790   
7791   argv[0] = origContainerName;
7792   argv[1] = GroupName;
7793   
7794   if ((rc = mr_query("set_container_list", 2, argv, NULL, NULL)))
7795     {
7796       com_err(whoami, 0, 
7797               "Unable to set container group %s in container %s: %s",
7798               GroupName, origContainerName, error_message(rc));
7799     }
7800   
7801   return(0);
7802 }
7803
7804 int Moira_addGroupToParent(char *origContainerName, char *GroupName)
7805  {
7806    char ContainerName[64];
7807    char ParentGroupName[64];
7808    char *argv[3];
7809    long rc;
7810
7811    strcpy(ContainerName, origContainerName);
7812    
7813    Moira_getGroupName(ContainerName, ParentGroupName, 1);
7814
7815    /* top-level container */
7816    if (strlen(ParentGroupName) == 0)
7817      return(0);
7818    
7819    argv[0] = ParentGroupName;
7820    argv[1] = "LIST";
7821    argv[2] = GroupName;
7822
7823    if ((rc = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
7824      {
7825        com_err(whoami, 0, 
7826                "Unable to add container group %s to parent group %s: %s",
7827                GroupName, ParentGroupName, error_message(rc));
7828      }
7829    
7830    return(0);
7831  }
7832
7833 int Moira_getContainerGroup(int ac, char **av, void *ptr)
7834 {
7835   char **call_args;
7836   
7837   call_args = ptr;
7838   strcpy(call_args[0], av[1]);
7839
7840   return(0);
7841 }
7842
7843 int Moira_getGroupName(char *origContainerName, char *GroupName,
7844                        int ParentFlag)
7845 {
7846   char ContainerName[64];
7847   char *argv[3];
7848   char *call_args[3];
7849   char *ptr;
7850   long rc;
7851
7852   strcpy(ContainerName, origContainerName);
7853
7854   if (ParentFlag)
7855     {
7856       ptr = strrchr(ContainerName, '/');
7857
7858       if (ptr != NULL)
7859         (*ptr) = '\0';
7860       else
7861         return(0);
7862     }
7863
7864   argv[0] = ContainerName;
7865   argv[1] = NULL;
7866   call_args[0] = GroupName;
7867   call_args[1] = NULL;
7868
7869   if (!(rc = mr_query("get_container_list", 1, argv, Moira_getContainerGroup,
7870                       call_args)))
7871     {
7872       if (strlen(GroupName) != 0)
7873         return(0);
7874     }
7875
7876   if (rc)
7877     com_err(whoami, 0, "Unable to get container group from container %s: %s",
7878             ContainerName, error_message(rc));
7879   else
7880     com_err(whoami, 0, "Unable to get container group from container %s",
7881             ContainerName);
7882   
7883   return(0);
7884 }
7885
7886 int Moira_process_machine_container_group(char *MachineName, char* GroupName, 
7887                                           int DeleteMachine)
7888 {
7889   char *argv[3];
7890   long rc;
7891   
7892   if (strcmp(GroupName, "[none]") == 0)
7893     return 0;
7894
7895   argv[0] = GroupName;
7896   argv[1] = "MACHINE";
7897   argv[2] = MachineName;
7898
7899   if (!DeleteMachine)
7900     rc = mr_query("add_member_to_list", 3, argv, NULL, NULL);
7901   else
7902     rc = mr_query("delete_member_from_list", 3, argv, NULL, NULL);
7903
7904   if (rc)
7905     {
7906       com_err(whoami, 0, "Unable to add machine %s to container group%s: %s",
7907               MachineName, GroupName, error_message(rc));
7908     }
7909
7910   return(0);
7911 }
7912
7913 int GetMachineName(char *MachineName)
7914 {
7915   char    *args[2];
7916   char    NewMachineName[1024];
7917   char    *szDot;
7918   int     rc = 0;
7919   int     i;
7920   DWORD   dwLen = 0;
7921   char    *call_args[2];
7922   
7923   // If the address happens to be in the top-level MIT domain, great!
7924   strcpy(NewMachineName, MachineName);
7925
7926   for (i = 0; i < (int)strlen(NewMachineName); i++)
7927     NewMachineName[i] = toupper(NewMachineName[i]);
7928
7929   szDot = strchr(NewMachineName,'.');
7930
7931   if ((szDot) && (!strcasecmp(szDot+1, DOMAIN_SUFFIX)))
7932     {
7933       return(0);
7934     }
7935   
7936   // If not, see if it has a Moira alias in the top-level MIT domain.
7937   memset(NewMachineName, '\0', sizeof(NewMachineName));
7938   args[0] = "*";
7939   args[1] = MachineName;
7940   call_args[0] = NewMachineName;
7941   call_args[1] = NULL;
7942
7943   if (rc = mr_query("get_hostalias", 2, args, ProcessMachineName, call_args))
7944     {
7945       com_err(whoami, 0, "Unable to resolve machine name %s : %s",
7946               MachineName, error_message(rc));
7947       strcpy(MachineName, "");
7948       return(0);
7949     }
7950   
7951   if (strlen(NewMachineName) != 0)
7952     strcpy(MachineName, NewMachineName);
7953   else
7954     strcpy(MachineName, "");
7955
7956   return(0);
7957 }
7958
7959 int ProcessMachineName(int ac, char **av, void *ptr)
7960 {
7961   char    **call_args;
7962   char    MachineName[1024];
7963   char    *szDot;
7964   int     i;
7965   
7966   call_args = ptr;
7967
7968   if (strlen(call_args[0]) == 0)
7969     {
7970       strcpy(MachineName, av[0]);
7971
7972       for (i = 0; i < (int)strlen(MachineName); i++)
7973         MachineName[i] = toupper(MachineName[i]);
7974
7975       szDot = strchr(MachineName,'.');
7976
7977         if ((szDot) && (!strcasecmp(szDot+1,DOMAIN_SUFFIX)))
7978           {
7979             strcpy(call_args[0], MachineName);
7980           }
7981     }
7982
7983   return(0);
7984 }
7985
7986 void SwitchSFU(LDAPMod **mods, int *UseSFU30, int n)
7987 {
7988   int i;
7989   
7990   if (*UseSFU30)
7991     {
7992       for (i = 0; i < n; i++)
7993         {
7994           if (!strcmp(mods[i]->mod_type, "msSFU30UidNumber"))
7995             mods[i]->mod_type = "uidNumber";
7996         }
7997
7998       (*UseSFU30) = 0;
7999     }
8000   else
8001     {
8002       for (i = 0; i < n; i++)
8003         {
8004           if (!strcmp(mods[i]->mod_type, "uidNumber"))
8005             mods[i]->mod_type = "msSFU30UidNumber";
8006         }
8007
8008       (*UseSFU30) = 1;
8009     }
8010 }
8011
8012 int SetHomeDirectory(LDAP *ldap_handle, char *user_name, 
8013                      char *DistinguishedName,
8014                      char *WinHomeDir, char *WinProfileDir,
8015                      char **homedir_v, char **winProfile_v,
8016                      char **drives_v, LDAPMod **mods, 
8017                      int OpType, int n)
8018 {
8019   char **hp;
8020   char cWeight[3];
8021   char cPath[1024];
8022   char path[1024];
8023   char winPath[1024];
8024   char winProfile[1024];
8025   char homeDrive[8];
8026   char homedir[1024];
8027   char apple_homedir[1024];
8028   char *apple_homedir_v[] = {NULL, NULL};
8029   int  last_weight;
8030   int  i;
8031   int  rc;
8032   LDAPMod *DelMods[20];
8033   
8034   memset(homeDrive, '\0', sizeof(homeDrive));
8035   memset(path, '\0', sizeof(path));
8036   memset(winPath, '\0', sizeof(winPath));
8037   memset(winProfile, '\0', sizeof(winProfile));
8038   hp = NULL;
8039
8040   if(!ActiveDirectory) 
8041     {
8042       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
8043         {
8044           memset(cWeight, 0, sizeof(cWeight));
8045           memset(cPath, 0, sizeof(cPath));
8046           last_weight = 1000;
8047           i = 0;
8048           
8049           while (hp[i] != NULL)
8050             {
8051               if (sscanf(hp[i], "%*s %s", cPath))
8052                 {
8053                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
8054                     {
8055                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
8056                         {
8057                           if (atoi(cWeight) < last_weight)
8058                             {
8059                               strcpy(path, cPath);
8060                               last_weight = (int)atoi(cWeight);
8061                             }
8062                         }
8063                       else 
8064                         strcpy(path, cPath);
8065                     }
8066                 }
8067               ++i;
8068             }
8069           
8070           if (strlen(path))
8071             {
8072               if (!strnicmp(path, AFS, strlen(AFS)))
8073                 {
8074                   sprintf(homedir, "%s", path);
8075                   sprintf(apple_homedir, "%s/MacData", path);
8076                   homedir_v[0] = homedir;
8077                   apple_homedir_v[0] = apple_homedir;
8078                   ADD_ATTR("homeDirectory", homedir_v, OpType);
8079                   ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8080                            OpType);
8081                 }
8082             }
8083           else
8084             {
8085               if(user_name[0] && user_name[1]) 
8086                 {
8087                   sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", 
8088                           user_name[0], user_name[1], user_name);
8089                   sprintf(apple_homedir, "%s/MacData", homedir);
8090                   homedir_v[0] = "NONE";
8091                   apple_homedir_v[0] = "NONE";
8092                   ADD_ATTR("homeDirectory", homedir_v, OpType);
8093                   ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8094                            OpType);
8095                 }
8096             }
8097         }
8098       else
8099         {
8100           if(user_name[0] && user_name[1]) 
8101             {
8102               sprintf(homedir, "/afs/athena.mit.edu/user/%c/%c/%s", 
8103                       user_name[0], user_name[1], user_name);
8104               sprintf(apple_homedir, "%s/MacData", homedir);
8105               homedir_v[0] = "NONE";
8106               apple_homedir_v[0] = "NONE";
8107               ADD_ATTR("homeDirectory", homedir_v, OpType);
8108               ADD_ATTR("apple-user-homeDirectory", apple_homedir_v, 
8109                        OpType);
8110             }
8111         }
8112       return(n);
8113     }
8114       
8115   if ((!strcasecmp(WinHomeDir, "[afs]")) || 
8116       (!strcasecmp(WinProfileDir, "[afs]")))
8117     {
8118       if ((hp = hes_resolve(user_name, "filsys")) != NULL)
8119         {
8120           memset(cWeight, 0, sizeof(cWeight));
8121           memset(cPath, 0, sizeof(cPath));
8122           last_weight = 1000;
8123           i = 0;
8124
8125           while (hp[i] != NULL)
8126             {
8127               if (sscanf(hp[i], "%*s %s", cPath))
8128                 {
8129                   if (strnicmp(cPath, AFS, strlen(AFS)) == 0)
8130                     {
8131                       if (sscanf(hp[i], "%*s %*s %*s %*s %s", cWeight))
8132                         {
8133                           if (atoi(cWeight) < last_weight)
8134                             {
8135                               strcpy(path, cPath);
8136                               last_weight = (int)atoi(cWeight);
8137                             }
8138                         }
8139                       else 
8140                         strcpy(path, cPath);
8141                     }
8142                 }
8143               ++i;
8144             }
8145
8146           if (strlen(path))
8147             {
8148               if (!strnicmp(path, AFS, strlen(AFS)))
8149                 {
8150                   AfsToWinAfs(path, winPath);
8151                   strcpy(winProfile, winPath);
8152                   strcat(winProfile, "\\.winprofile");
8153                 }
8154             }
8155         }
8156       else
8157         return(n);
8158     }
8159
8160     if ((!strcasecmp(WinHomeDir, "[dfs]")) || 
8161         (!strcasecmp(WinProfileDir, "[dfs]")))
8162     {
8163       sprintf(path, "\\\\%s\\dfs\\profiles\\%c\\%s", ldap_domain, 
8164               user_name[0], user_name);
8165
8166       if (!strcasecmp(WinProfileDir, "[dfs]"))
8167         {
8168           strcpy(winProfile, path);
8169           strcat(winProfile, "\\.winprofile");
8170         }
8171
8172       if (!strcasecmp(WinHomeDir, "[dfs]"))
8173         strcpy(winPath, path);
8174     }
8175     
8176     if (hp != NULL)
8177       {
8178         i = 0;
8179         while (hp[i])
8180           {
8181             free(hp[i]);
8182             i++;
8183           }
8184       }
8185     
8186     if (!strcasecmp(WinHomeDir, "[local]"))
8187       memset(winPath, '\0', sizeof(winPath));
8188     else if (!strcasecmp(WinHomeDir, "[afs]") || 
8189              !strcasecmp(WinHomeDir, "[dfs]"))
8190       {
8191         strcpy(homeDrive, "H:");
8192       }
8193     else
8194       {
8195         strcpy(winPath, WinHomeDir);
8196         if (!strncmp(WinHomeDir, "\\\\", 2))
8197           {
8198             strcpy(homeDrive, "H:");
8199           }        
8200       }
8201     
8202     // nothing needs to be done if WinProfileDir is [afs].
8203     if (!strcasecmp(WinProfileDir, "[local]"))
8204       memset(winProfile, '\0', sizeof(winProfile));
8205     else if (strcasecmp(WinProfileDir, "[afs]") && 
8206              strcasecmp(WinProfileDir, "[dfs]"))
8207       {
8208         strcpy(winProfile, WinProfileDir);
8209       }
8210     
8211     if (strlen(winProfile) != 0)
8212       {
8213         if (winProfile[strlen(winProfile) - 1] == '\\')
8214           winProfile[strlen(winProfile) - 1] = '\0';
8215       }
8216
8217     if (strlen(winPath) != 0)
8218       {
8219         if (winPath[strlen(winPath) - 1] == '\\')
8220           winPath[strlen(winPath) - 1] = '\0';
8221       }
8222     
8223     if ((winProfile[1] == ':') && (strlen(winProfile) == 2))
8224       strcat(winProfile, "\\");
8225
8226     if ((winPath[1] == ':') && (strlen(winPath) == 2))
8227       strcat(winPath, "\\");
8228     
8229     if (strlen(winPath) == 0)
8230       {
8231         if (OpType == LDAP_MOD_REPLACE)
8232           {
8233             i = 0;
8234             DEL_ATTR("homeDirectory", LDAP_MOD_DELETE);
8235             DelMods[i] = NULL;
8236             //unset homeDirectory attribute for user.
8237             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8238             free(DelMods[0]);
8239           }
8240       }
8241     else
8242       {
8243         homedir_v[0] = strdup(winPath);
8244         ADD_ATTR("homeDirectory", homedir_v, OpType);
8245       }
8246     
8247     if (strlen(winProfile) == 0)
8248       {
8249         if (OpType == LDAP_MOD_REPLACE)
8250           {
8251             i = 0;
8252             DEL_ATTR("profilePath", LDAP_MOD_DELETE);
8253             DelMods[i] = NULL;
8254             //unset profilePate attribute for user.
8255             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8256             free(DelMods[0]);
8257           }
8258       }
8259     else
8260       {
8261         winProfile_v[0] = strdup(winProfile);
8262         ADD_ATTR("profilePath", winProfile_v, OpType);
8263       }
8264     
8265     if (strlen(homeDrive) == 0)
8266       {
8267         if (OpType == LDAP_MOD_REPLACE)
8268           {
8269             i = 0;
8270             DEL_ATTR("homeDrive", LDAP_MOD_DELETE);
8271             DelMods[i] = NULL;
8272             //unset homeDrive attribute for user
8273             rc = ldap_modify_s(ldap_handle, DistinguishedName, DelMods);
8274             free(DelMods[0]);
8275           }
8276       }
8277     else
8278       {
8279         drives_v[0] = strdup(homeDrive);
8280         ADD_ATTR("homeDrive", drives_v, OpType);
8281       }
8282
8283     return(n);
8284 }
8285
8286 int attribute_update(LDAP *ldap_handle, char *distinguished_name, 
8287                      char *attribute_value, char *attribute, char *user_name)
8288 {
8289   char      *mod_v[] = {NULL, NULL};
8290   LDAPMod   *DelMods[20];
8291   LDAPMod   *mods[20];
8292   int       n;
8293   int       i;
8294   int       rc;
8295   
8296   if (strlen(attribute_value) == 0)
8297     {
8298       i = 0;
8299       DEL_ATTR(attribute, LDAP_MOD_DELETE);
8300       DelMods[i] = NULL;
8301       rc = ldap_modify_s(ldap_handle, distinguished_name, DelMods);
8302       free(DelMods[0]);
8303     }
8304   else
8305     {
8306       n = 0;
8307       mod_v[0] = attribute_value;
8308       ADD_ATTR(attribute, mod_v, LDAP_MOD_REPLACE);
8309       mods[n] = NULL;
8310
8311       if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8312                               mods)) != LDAP_SUCCESS)
8313         {
8314           free(mods[0]);
8315           n = 0;
8316           mod_v[0] = attribute_value;
8317           ADD_ATTR(attribute, mod_v, LDAP_MOD_ADD);
8318           mods[n] = NULL;
8319
8320           if ((rc = ldap_modify_s(ldap_handle, distinguished_name, 
8321                                   mods)) != LDAP_SUCCESS)
8322             {
8323               com_err(whoami, 0, "Unable to change the %s attribute for %s "
8324                       "in the AD : %s",
8325                       attribute, user_name, ldap_err2string(rc));
8326             }
8327         }
8328
8329       free(mods[0]);
8330     }
8331   
8332   return(rc);
8333 }
8334
8335 void StringTrim(char *StringToTrim)
8336 {
8337   char *t, *s;
8338   char *save;
8339
8340   save = strdup(StringToTrim);
8341
8342   s = save;
8343
8344   while (isspace(*s))
8345     s++;
8346
8347   /* skip to end of string */
8348   if (*s == '\0')
8349     {
8350       if (*save)
8351         *save = '\0';
8352       strcpy(StringToTrim, save);
8353       return;
8354     }
8355   
8356   for (t = s; *t; t++)
8357     continue;
8358
8359   while (t > s)
8360     {
8361       --t;
8362       if (!isspace(*t))
8363         {
8364           t++;
8365           break;
8366         }
8367     }
8368
8369   if (*t)
8370     *t = '\0';
8371   
8372   strcpy(StringToTrim, s);
8373   return;
8374 }
8375
8376 int ReadConfigFile(char *DomainName)
8377 {
8378     int     Count;
8379     int     i;
8380     int     k;
8381     char    temp[256];
8382     char    temp1[256];
8383     FILE    *fptr;
8384
8385     Count = 0;
8386
8387     sprintf(temp, "%s%s.cfg", CFG_PATH, DomainName);
8388
8389     if ((fptr = fopen(temp, "r")) != NULL)
8390       {
8391         while (fgets(temp, sizeof(temp), fptr) != 0)
8392           {
8393             for (i = 0; i < (int)strlen(temp); i++)
8394               temp[i] = toupper(temp[i]);
8395
8396             if (temp[strlen(temp) - 1] == '\n')
8397               temp[strlen(temp) - 1] = '\0';
8398
8399             StringTrim(temp);
8400
8401             if (strlen(temp) == 0)
8402               continue;
8403
8404             if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8405               {
8406                 if (strlen(temp) > (strlen(DOMAIN)))
8407                   {
8408                     strcpy(ldap_domain, &temp[strlen(DOMAIN)]);
8409                     StringTrim(ldap_domain);
8410                   }
8411               }
8412             else if (!strncmp(temp, REALM, strlen(REALM)))
8413               {
8414                 if (strlen(temp) > (strlen(REALM)))
8415                   {
8416                     strcpy(ldap_realm, &temp[strlen(REALM)]);
8417                     StringTrim(ldap_realm);
8418                   }
8419               }
8420             else if (!strncmp(temp, PORT, strlen(PORT)))
8421               {
8422                 if (strlen(temp) > (strlen(PORT)))
8423                   {
8424                     strcpy(ldap_port, &temp[strlen(PORT)]);
8425                     StringTrim(ldap_port);
8426                   }
8427               }
8428             else if (!strncmp(temp, PRINCIPALNAME, strlen(PRINCIPALNAME)))
8429               {
8430                 if (strlen(temp) > (strlen(PRINCIPALNAME)))
8431                   {
8432                     strcpy(PrincipalName, &temp[strlen(PRINCIPALNAME)]);
8433                     StringTrim(PrincipalName);
8434                   }
8435               }
8436             else if (!strncmp(temp, SERVER, strlen(SERVER)))
8437               {
8438                 if (strlen(temp) > (strlen(SERVER)))
8439                   {
8440                     ServerList[Count] = calloc(1, 256);
8441                     strcpy(ServerList[Count], &temp[strlen(SERVER)]);
8442                     StringTrim(ServerList[Count]);
8443                     ++Count;
8444                   }
8445               }
8446             else if (!strncmp(temp, MSSFU, strlen(MSSFU)))
8447               {
8448                 if (strlen(temp) > (strlen(MSSFU)))
8449                   {
8450                     strcpy(temp1, &temp[strlen(MSSFU)]);
8451                     StringTrim(temp1);
8452                     if (!strcmp(temp1, SFUTYPE))
8453                       UseSFU30 = 1;
8454                   }
8455               }
8456             else if (!strncmp(temp, GROUP_SUFFIX, strlen(GROUP_SUFFIX)))
8457               {
8458                 if (strlen(temp) > (strlen(GROUP_SUFFIX)))
8459                   {
8460                     strcpy(temp1, &temp[strlen(GROUP_SUFFIX)]);
8461                     StringTrim(temp1);
8462                     if (!strcasecmp(temp1, "NO")) 
8463                       {
8464                         UseGroupSuffix = 0;
8465                         memset(group_suffix, '\0', sizeof(group_suffix));
8466                       }
8467                   }
8468               }
8469             else if (!strncmp(temp, GROUP_TYPE, strlen(GROUP_TYPE)))
8470               {
8471                 if (strlen(temp) > (strlen(GROUP_TYPE)))
8472                   {
8473                     strcpy(temp1, &temp[strlen(GROUP_TYPE)]);
8474                     StringTrim(temp1);
8475                     if (!strcasecmp(temp1, "UNIVERSAL")) 
8476                       UseGroupUniversal = 1;
8477                   }
8478               }
8479             else if (!strncmp(temp, SET_GROUP_ACE, strlen(SET_GROUP_ACE)))
8480               {
8481                 if (strlen(temp) > (strlen(SET_GROUP_ACE)))
8482                   {
8483                     strcpy(temp1, &temp[strlen(SET_GROUP_ACE)]);
8484                     StringTrim(temp1);
8485                     if (!strcasecmp(temp1, "NO"))
8486                       SetGroupAce = 0;
8487                   }
8488               }
8489             else if (!strncmp(temp, SET_PASSWORD, strlen(SET_PASSWORD)))
8490               {
8491                 if (strlen(temp) > (strlen(SET_PASSWORD)))
8492                   {
8493                     strcpy(temp1, &temp[strlen(SET_PASSWORD)]);
8494                     StringTrim(temp1);
8495                     if (!strcasecmp(temp1, "NO"))
8496                       SetPassword = 0;
8497                   }
8498               }
8499             else if (!strncmp(temp, EXCHANGE, strlen(EXCHANGE)))
8500               {
8501                 if (strlen(temp) > (strlen(EXCHANGE)))
8502                   {
8503                     strcpy(temp1, &temp[strlen(EXCHANGE)]);
8504                     StringTrim(temp1);
8505                     if (!strcasecmp(temp1, "YES"))
8506                       Exchange = 1;
8507                   }
8508               }
8509             else if (!strncmp(temp, PROCESS_MACHINE_CONTAINER, 
8510                               strlen(PROCESS_MACHINE_CONTAINER)))
8511               {
8512                 if (strlen(temp) > (strlen(PROCESS_MACHINE_CONTAINER)))
8513                   {
8514                     strcpy(temp1, &temp[strlen(PROCESS_MACHINE_CONTAINER)]);
8515                     StringTrim(temp1);
8516                     if (!strcasecmp(temp1, "NO"))
8517                       ProcessMachineContainer = 0;
8518                   }
8519               }
8520             else if (!strncmp(temp, ACTIVE_DIRECTORY, 
8521                               strlen(ACTIVE_DIRECTORY)))
8522               {
8523                 if (strlen(temp) > (strlen(ACTIVE_DIRECTORY)))
8524                   {
8525                     strcpy(temp1, &temp[strlen(ACTIVE_DIRECTORY)]);
8526                     StringTrim(temp1);
8527                     if (!strcasecmp(temp1, "NO"))
8528                       ActiveDirectory = 0;
8529                   }
8530               }
8531             else
8532               {
8533                 if (strlen(ldap_domain) != 0)
8534                   {
8535                     memset(ldap_domain, '\0', sizeof(ldap_domain));
8536                     break;
8537                   }
8538
8539                 if (strlen(temp) != 0)
8540                   strcpy(ldap_domain, temp);
8541               }
8542           }
8543         fclose(fptr);
8544       }
8545     
8546     if (strlen(ldap_domain) == 0)
8547       {
8548       strcpy(ldap_domain, DomainName);
8549       }
8550
8551     if (Count == 0)
8552         return(0);
8553
8554     for (i = 0; i < Count; i++)
8555       {
8556         if (ServerList[i] != 0)
8557           {
8558             for (k = 0; k < (int)strlen(ServerList[i]); k++)
8559               ServerList[i][k] = toupper(ServerList[i][k]);
8560           }
8561       }
8562     
8563     return(0);
8564 }
8565
8566 int ReadDomainList()
8567 {
8568   int     Count;
8569   int     i;
8570   char    temp[128];
8571   char    temp1[128];
8572   FILE    *fptr;
8573   unsigned char c[11];
8574   unsigned char stuff[256];
8575   int     rc;
8576   int     ok;
8577
8578   Count = 0;
8579   sprintf(temp, "%s%s", CFG_PATH, WINADCFG);
8580
8581   if ((fptr = fopen(temp, "r")) != NULL)
8582     {
8583       while (fgets(temp, sizeof(temp), fptr) != 0)
8584         {
8585           for (i = 0; i < (int)strlen(temp); i++)
8586             temp[i] = toupper(temp[i]);
8587
8588           if (temp[strlen(temp) - 1] == '\n')
8589             temp[strlen(temp) - 1] = '\0';
8590
8591           StringTrim(temp);
8592
8593           if (strlen(temp) == 0)
8594             continue;
8595
8596           if (!strncmp(temp, DOMAIN, strlen(DOMAIN)))
8597             {
8598               if (strlen(temp) > (strlen(DOMAIN)))
8599                 {
8600                   strcpy(temp1, &temp[strlen(DOMAIN)]);
8601                   StringTrim(temp1);
8602                   strcpy(temp, temp1);
8603                 }
8604             }
8605           
8606           strcpy(DomainNames[Count], temp);
8607           StringTrim(DomainNames[Count]);
8608           ++Count;
8609         }
8610
8611       fclose(fptr);
8612     }
8613
8614   if (Count == 0)
8615     {
8616       critical_alert("incremental", "%s", "ldap.incr cannot run due to a "
8617                      "configuration error in ldap.cfg");
8618       return(1);
8619     }
8620   
8621   return(0);
8622 }
8623
8624 int email_isvalid(const char *address) {
8625   int        count = 0;
8626   const char *c, *domain;
8627   static char *rfc822_specials = "()<>@,;:\\\"[]";
8628
8629   if(address[strlen(address) - 1] == '.') 
8630     return 0;
8631     
8632   /* first we validate the name portion (name@domain) */
8633   for (c = address;  *c;  c++) {
8634     if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == 
8635                        '\"')) {
8636       while (*++c) {
8637         if (*c == '\"') 
8638           break;
8639         if (*c == '\\' && (*++c == ' ')) 
8640           continue;
8641         if (*c <= ' ' || *c >= 127) 
8642           return 0;
8643       }
8644
8645       if (!*c++) 
8646         return 0;
8647       if (*c == '@') 
8648         break;
8649       if (*c != '.') 
8650         return 0;
8651       continue;
8652     }
8653
8654     if (*c == '@') 
8655       break;
8656     if (*c <= ' ' || *c >= 127) 
8657       return 0;
8658     if (strchr(rfc822_specials, *c)) 
8659       return 0;
8660   }
8661
8662   if (c == address || *(c - 1) == '.') 
8663     return 0;
8664
8665   /* next we validate the domain portion (name@domain) */
8666   if (!*(domain = ++c)) return 0;
8667   do {
8668     if (*c == '.') {
8669       if (c == domain || *(c - 1) == '.') 
8670         return 0;
8671       count++;
8672     }
8673     if (*c <= ' ' || *c >= 127) 
8674       return 0;
8675     if (strchr(rfc822_specials, *c)) 
8676       return 0;
8677   } while (*++c);
8678
8679   return (count >= 1);
8680 }
8681
8682 int find_homeMDB(LDAP *ldap_handle, char *dn_path, char **homeMDB, 
8683              char **homeServerName) 
8684 {
8685   LK_ENTRY *group_base;
8686   LK_ENTRY *sub_group_base;
8687   LK_ENTRY *gPtr;
8688   LK_ENTRY *sub_gPtr;
8689   int      group_count;
8690   int      sub_group_count;
8691   char     filter[1024];
8692   char     sub_filter[1024];
8693   char     search_path[1024];
8694   char     range[1024];
8695   char     *attr_array[3];
8696   char     *s;
8697   int      homeMDB_count = -1;
8698   int      rc;
8699   int      i;
8700   int      mdbbl_count;
8701   int      rangeStep = 1500;
8702   int      rangeLow = 0;
8703   int      rangeHigh = rangeLow + (rangeStep - 1);
8704   int      isLast = 0;
8705
8706   /* Grumble..... microsoft not making it searchable from the root *grr* */
8707
8708   memset(filter, '\0', sizeof(filter));
8709   memset(search_path, '\0', sizeof(search_path));
8710   
8711   sprintf(filter, "(objectClass=msExchMDB)");
8712   sprintf(search_path, "CN=Configuration,%s", dn_path);
8713   attr_array[0] = "distinguishedName";
8714   attr_array[1] = NULL;
8715   
8716   group_base = NULL;
8717   group_count = 0;
8718   
8719   if ((rc = linklist_build(ldap_handle, search_path, filter, attr_array,
8720                            &group_base, &group_count, 
8721                            LDAP_SCOPE_SUBTREE)) != 0) 
8722     {
8723       com_err(whoami, 0, "Unable to find msExchMDB %s",
8724               ldap_err2string(rc));
8725       return(rc);
8726     }
8727   
8728   if (group_count) 
8729     {
8730       gPtr = group_base;
8731       
8732       while(gPtr) {
8733         if (((s = strstr(gPtr->dn, "Public")) != (char *) NULL) ||
8734             ((s = strstr(gPtr->dn, "Recover")) != (char *) NULL) || 
8735             ((s = strstr(gPtr->dn, "Reserve")) != (char *) NULL))
8736           {
8737             gPtr = gPtr->next;
8738             continue;
8739           }
8740
8741         /* 
8742          * Due to limits in active directory we need to use the LDAP
8743          * range semantics to query and return all the values in 
8744          * large lists, we will stop increasing the range when
8745          * the result count is 0.
8746          */
8747
8748         i = 0;  
8749         mdbbl_count = 0;
8750
8751         for(;;) 
8752           {
8753             memset(sub_filter, '\0', sizeof(sub_filter));
8754             memset(range, '\0', sizeof(range));
8755             sprintf(sub_filter, "(objectClass=msExchMDB)");
8756
8757             if(isLast)
8758               sprintf(range, "homeMDBBL;Range=%d-*", rangeLow);
8759             else 
8760               sprintf(range, "homeMDBBL;Range=%d-%d", rangeLow, rangeHigh);
8761
8762             attr_array[0] = range;
8763             attr_array[1] = NULL;
8764             
8765             sub_group_base = NULL;
8766             sub_group_count = 0;
8767             
8768             if ((rc = linklist_build(ldap_handle, gPtr->dn, sub_filter, 
8769                                      attr_array, &sub_group_base, 
8770                                      &sub_group_count, 
8771                                      LDAP_SCOPE_SUBTREE)) != 0) 
8772               {
8773                 com_err(whoami, 0, "Unable to find homeMDBBL %s",
8774                         ldap_err2string(rc));
8775                 return(rc);
8776               }
8777
8778             if(!sub_group_count)
8779               {
8780                 if(isLast) 
8781                   {
8782                     isLast = 0;
8783                     rangeLow = 0;
8784                     rangeHigh = rangeLow + (rangeStep - 1);
8785                     break;
8786                   }
8787                 else
8788                   isLast++;
8789               }
8790
8791             mdbbl_count += sub_group_count;
8792             rangeLow = rangeHigh + 1;
8793             rangeHigh = rangeLow + (rangeStep - 1);
8794           }
8795
8796         /* First time through, need to initialize or update the least used */
8797         
8798         com_err(whoami, 0, "Mail store %s, count %d", gPtr->dn, 
8799                 mdbbl_count);
8800
8801         if(mdbbl_count < homeMDB_count || homeMDB_count == -1) 
8802           {
8803             homeMDB_count = mdbbl_count; 
8804             *homeMDB = strdup(gPtr->dn);
8805           }
8806
8807         gPtr = gPtr->next;
8808         linklist_free(sub_group_base);
8809       }
8810     }
8811
8812   linklist_free(group_base);
8813   
8814   /* 
8815    * Ok found the server least allocated need to now query to get its
8816    * msExchHomeServerName so we can set it as a user attribute
8817    */
8818   
8819   attr_array[0] = "legacyExchangeDN";
8820   attr_array[1] = NULL; 
8821   
8822   group_count = 0;
8823   group_base = NULL;
8824   
8825   if ((rc = linklist_build(ldap_handle, *homeMDB, filter, 
8826                            attr_array, &group_base, 
8827                            &group_count, 
8828                            LDAP_SCOPE_SUBTREE)) != 0) 
8829     {
8830       com_err(whoami, 0, "Unable to find msExchHomeServerName %s",
8831               ldap_err2string(rc));
8832       return(rc);
8833     }  
8834   
8835   if(group_count) 
8836     {
8837       *homeServerName = strdup(group_base->value);
8838       if((s = strrchr(*homeServerName, '/')) != (char *) NULL) 
8839         {
8840           *s = '\0';
8841         }
8842     } 
8843
8844   linklist_free(group_base);
8845   
8846   return(rc);
8847 }
8848       
8849 char *lowercase(char *s)
8850 {
8851   char *p;
8852
8853   for (p = s; *p; p++)
8854     {
8855       if (isupper(*p))
8856         *p = tolower(*p);
8857     }
8858   return s;
8859 }
8860
8861 char *uppercase(char *s)
8862 {
8863   char *p;
8864
8865   for (p = s; *p; p++)
8866     {
8867       if (islower(*p))
8868         *p = toupper(*p);
8869     }
8870   return s;
8871 }
8872
8873 char *escape_string(char *s)
8874 {
8875   char *p, *q;
8876   char string[1024];
8877   char temp[1024];
8878   int i = 0;
8879   int spaces = 0;
8880
8881   memset(string, '\0', sizeof(string));
8882
8883   q = s;
8884
8885   /* Replace leading spaces */
8886
8887   while(isspace(*q)) {
8888     string[i++] = '\\';
8889     string[i++] = '2';
8890     string[i++] = '0';
8891     q++;
8892   }
8893
8894   /* Escape any special characters */
8895
8896   for(; *q != '\0'; q++) {
8897     if(*q == ',')
8898       string[i++] = '\\';
8899     if(*q == '+') 
8900       string[i++] = '\\';
8901     if(*q == '"') 
8902       string[i++] = '\\';
8903     if(*q == '\\') 
8904       string[i++] = '\\';
8905     if(*q == '<') 
8906       string[i++] = '\\';
8907     if(*q == '>') 
8908       string[i++] = '\\';
8909     if(*q == ';')
8910       string[i++] = '\\';
8911     if(*q == '#')
8912       string[i++] = '\\';
8913     if(*q == '=')
8914       string[i++] = '\\';
8915
8916     string[i++] = *q;
8917   }
8918
8919   return strdup(string);
8920 }
8921
8922 int save_query_info(int argc, char **argv, void *hint)
8923 {
8924   int i;
8925   char **nargv = hint;
8926
8927   for(i = 0; i < argc; i++)
8928     nargv[i] = strdup(argv[i]);
8929
8930   return MR_CONT;
8931 }
This page took 0.75479 seconds and 5 git commands to generate.