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