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