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