3 * Do AFS incremental updates
5 * Copyright (C) 1989,1992 by the Massachusetts Institute of Technology
6 * for copying and distribution information, please see the file
11 #include <moira_site.h>
12 #include <moira_schema.h>
16 #include <sys/resource.h>
17 #include <sys/types.h>
18 #include <sys/utsname.h>
26 #include <afs/param.h>
27 #include <afs/cellconfig.h>
28 #include <afs/venus.h>
29 #include <afs/ptclient.h>
30 #include <afs/pterror.h>
32 /* Cheesy test for determining AFS more recent than 3.4a */
33 #ifndef AFSCONF_CLIENTNAME
34 #include <afs/dirpath.h>
35 #define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
38 #define STOP_FILE "/moira/afs/noafs"
39 #define file_exists(file) (access((file), F_OK) == 0)
43 /* Main stub routines */
44 void do_user(char **before, int beforec, char **after, int afterc);
45 void do_list(char **before, int beforec, char **after, int afterc);
46 void do_member(char **before, int beforec, char **after, int afterc);
47 void do_filesys(char **before, int beforec, char **after, int afterc);
48 void do_quota(char **before, int beforec, char **after, int afterc);
50 /* Support stub routines */
51 void run_cmd(char *cmd);
52 int add_user_lists(int ac, char **av, void *user);
53 int add_list_members(int ac, char **av, void *group);
54 int check_user(int ac, char **av, void *ustate);
55 void edit_group(int op, char *group, char *type, char *member);
58 int moira_connect(void);
59 int moira_disconnect(void);
61 /* libprot.a routines */
62 extern long pr_Initialize();
63 extern long pr_CreateUser();
64 extern long pr_CreateGroup();
65 extern long pr_DeleteByID();
66 extern long pr_ChangeEntry();
67 extern long pr_SetFieldsEntry();
68 extern long pr_AddToGroup();
69 extern long pr_RemoveUserFromGroup();
70 extern long pr_SIdToName();
72 static char tbl_buf[1024];
73 static struct member {
75 char list[LIST_NAME_SIZE];
76 char type[IMEMBERS_MEMBER_TYPE_SIZE];
77 char member[MAX_FIELD_WIDTH];
79 } *member_head = NULL;
81 static int mr_connections = 0;
83 int main(int argc, char **argv)
85 int beforec, afterc, i;
86 char *table, **before, **after;
89 getrlimit(RLIMIT_NOFILE, &rl);
90 for (i = rl.rlim_cur; i > 2; i--)
93 whoami = ((whoami = strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
96 beforec = atoi(argv[2]);
98 afterc = atoi(argv[3]);
99 after = &argv[4 + beforec];
101 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
103 strcpy(tbl_buf, table);
104 strcat(tbl_buf, " (");
105 for (i = 0; i < beforec; i++)
108 strcat(tbl_buf, ",");
109 strcat(tbl_buf, before[i]);
111 strcat(tbl_buf, ")->(");
112 for (i = 0; i < afterc; i++)
115 strcat(tbl_buf, ",");
116 strcat(tbl_buf, after[i]);
118 strcat(tbl_buf, ")");
120 initialize_sms_error_table();
121 initialize_krb_error_table();
123 if (!strcmp(table, "users"))
124 do_user(before, beforec, after, afterc);
125 else if (!strcmp(table, "list"))
126 do_list(before, beforec, after, afterc);
127 else if (!strcmp(table, "imembers"))
128 do_member(before, beforec, after, afterc);
129 else if (!strcmp(table, "filesys"))
130 do_filesys(before, beforec, after, afterc);
131 else if (!strcmp(table, "quota"))
132 do_quota(before, beforec, after, afterc);
138 void do_user(char **before, int beforec, char **after, int afterc)
140 int astate, bstate, auid, buid, code;
143 auid = buid = astate = bstate = 0;
144 if (afterc > U_STATE)
145 astate = atoi(after[U_STATE]);
146 if (beforec > U_STATE)
147 bstate = atoi(before[U_STATE]);
149 auid = atoi(after[U_UID]);
151 buid = atoi(before[U_UID]);
153 /* We consider "half-registered" users to be active */
159 if (astate != 1 && bstate != 1) /* inactive user */
162 if (astate == bstate && auid == buid &&
163 !strcmp(before[U_NAME], after[U_NAME]))
164 /* No AFS related attributes have changed */
167 if (astate == bstate)
169 /* Only a modify has to be done */
170 com_err(whoami, 0, "Changing user %s (uid %d) to %s (uid %d)",
171 before[U_NAME], buid, after[U_NAME], auid);
173 code = pr_try(pr_ChangeEntry, before[U_NAME], after[U_NAME], auid, "");
176 critical_alert("incremental",
177 "Couldn't change user %s (id %d) to %s (id %d): %s",
178 before[U_NAME], buid, after[U_NAME], auid,
179 error_message(code));
185 com_err(whoami, 0, "Deleting user %s (uid %d)",
186 before[U_NAME], buid);
188 code = pr_try(pr_DeleteByID, buid);
189 if (code && code != PRNOENT)
191 critical_alert("incremental", "Couldn't delete user %s (id %d): %s",
192 before[U_NAME], buid, error_message(code));
198 com_err(whoami, 0, "%s user %s (uid %d)",
199 ((bstate != 0) ? "Reactivating" : "Creating"),
200 after[U_NAME], auid);
202 code = pr_try(pr_CreateUser, after[U_NAME], &auid);
203 /* if we get PRIDEXIST, it's only an error if the username
204 doesn't match (otherwise it just means the user was deleted
205 from Moira but not AFS */
206 if (code == PRIDEXIST)
208 char ename[PR_MAXNAMELEN];
210 if (pr_try(pr_SIdToName, auid, ename) == 0 &&
211 !strcmp(after[U_NAME], ename))
216 critical_alert("incremental", "Couldn't create user %s (id %d): %s",
217 after[U_NAME], auid, error_message(code));
223 /* Reactivating a user; get his group list */
224 code = moira_connect();
227 critical_alert("incremental", "Error contacting Moira server "
228 "to retrieve grouplist of user %s: %s",
229 after[U_NAME], error_message(code));
233 av[1] = after[U_NAME];
234 code = mr_query("get_lists_of_member", 2, av, add_user_lists,
236 if (code && code != MR_NO_MATCH)
238 critical_alert("incremental",
239 "Couldn't retrieve membership of user %s: %s",
240 after[U_NAME], error_message(code));
249 void do_list(char **before, int beforec, char **after, int afterc)
254 char g1[PR_MAXNAMELEN], g2[PR_MAXNAMELEN];
258 if (beforec > L_GID && atoi(before[L_ACTIVE]) && atoi(before[L_GROUP]))
260 bgid = atoi(before[L_GID]);
261 bhide = atoi(before[L_HIDDEN]);
263 if (afterc > L_GID && atoi(after[L_ACTIVE]) && atoi(after[L_GROUP]))
265 agid = atoi(after[L_GID]);
266 ahide = atoi(after[L_HIDDEN]);
269 if (agid == 0 && bgid == 0) /* Not active groups */
274 if (strcmp(after[L_NAME], before[L_NAME]))
276 /* Only a modify is required */
277 strcpy(g1, "system:");
278 strcpy(g2, "system:");
279 strcat(g1, before[L_NAME]);
280 strcat(g2, after[L_NAME]);
282 com_err(whoami, 0, "Changing group %s (gid %d) to %s (gid %d)",
283 before[L_NAME], bgid, after[L_NAME], agid);
285 code = pr_try(pr_ChangeEntry, g1, g2, -agid, "");
288 critical_alert("incremental", "Couldn't change group %s (id %d) "
289 "to %s (id %d): %s", before[L_NAME], -bgid,
290 after[L_NAME], -agid, error_message(code));
295 com_err(whoami, 0, "Making group %s (gid %d) %s", after[L_NAME],
296 agid, (ahide ? "hidden" : "visible"));
297 code = pr_try(pr_SetFieldsEntry, -agid, PR_SF_ALLBITS,
298 (ahide ? PRP_STATUS_ANY : PRP_GROUP_DEFAULT) >>
299 PRIVATE_SHIFT, 0 /*ngroups*/, 0 /*nusers*/);
302 critical_alert("incremental",
303 "Couldn't set flags of group %s: %s",
304 after[L_NAME], error_message(code));
311 com_err(whoami, 0, "Deleting group %s (gid %d)", before[L_NAME], bgid);
312 code = pr_try(pr_DeleteByID, -bgid);
313 if (code && code != PRNOENT)
315 critical_alert("incremental",
316 "Couldn't delete group %s (id %d): %s",
317 before[L_NAME], -bgid, error_message(code));
323 strcpy(g1, "system:");
324 strcat(g1, after[L_NAME]);
325 strcpy(g2, "system:administrators");
327 com_err(whoami, 0, "Creating %s group %s (gid %d)",
328 (ahide ? "hidden" : "visible"), after[L_NAME], agid);
329 code = pr_try(pr_CreateGroup, g1, g2, &id);
330 if (code == PRIDEXIST)
332 char ename[PR_MAXNAMELEN];
334 if (pr_try(pr_SIdToName, -agid, ename) == 0 && !strcmp(g1, ename))
339 critical_alert("incremental", "Couldn't create group %s (id %d): %s",
340 after[L_NAME], id, error_message(code));
345 code = pr_try(pr_SetFieldsEntry, -agid, PR_SF_ALLBITS,
346 (ahide ? PRP_STATUS_ANY : PRP_GROUP_DEFAULT) >>
347 PRIVATE_SHIFT, 0 /*ngroups*/, 0 /*nusers*/);
350 critical_alert("incremental",
351 "Couldn't set flags of group %s: %s",
352 after[L_NAME], error_message(code));
356 /* We need to make sure the group is properly populated */
357 if (beforec < L_ACTIVE)
360 code = moira_connect();
363 critical_alert("incremental",
364 "Error contacting Moira server to resolve %s: %s",
365 after[L_NAME], error_message(code));
368 av[0] = after[L_NAME];
369 code = mr_query("get_end_members_of_list", 1, av,
370 add_list_members, after[L_NAME]);
373 critical_alert("incremental",
374 "Couldn't retrieve full membership of list %s: %s",
375 after[L_NAME], error_message(code));
384 #define LM_EXTRA_ACTIVE (LM_END)
385 #define LM_EXTRA_PUBLIC (LM_END+1)
386 #define LM_EXTRA_HIDDEN (LM_END+2)
387 #define LM_EXTRA_MAILLIST (LM_END+3)
388 #define LM_EXTRA_GROUP (LM_END+4)
389 #define LM_EXTRA_GID (LM_END+5)
390 #define LM_EXTRA_END (LM_END+6)
392 void do_member(char **before, int beforec, char **after, int afterc)
396 if (afterc < LM_EXTRA_END)
400 if (!atoi(after[LM_EXTRA_ACTIVE]) || !atoi(after[LM_EXTRA_GROUP]))
404 edit_group(1, after[LM_LIST], after[LM_TYPE], after[LM_MEMBER]);
408 if (beforec < LM_EXTRA_END)
412 if (!atoi(before[LM_EXTRA_ACTIVE]) || !atoi(before[LM_EXTRA_GROUP]))
415 edit_group(0, before[LM_LIST], before[LM_TYPE], before[LM_MEMBER]);
420 void do_filesys(char **before, int beforec, char **after, int afterc)
423 int acreate, atype, bcreate, btype;
425 if (afterc < FS_CREATE)
429 atype = !strcmp(after[FS_TYPE], "AFS");
430 acreate = atoi(after[FS_CREATE]);
433 if (beforec < FS_CREATE)
435 if (acreate == 0 || atype == 0)
438 /* new locker creation */
439 sprintf(cmd, "%s/perl -I%s %s/afs_create.pl %s %s %s %s %s %s",
440 BIN_DIR, BIN_DIR, BIN_DIR,
441 after[FS_NAME], after[FS_L_TYPE], after[FS_MACHINE],
442 after[FS_PACK], after[FS_OWNER], after[FS_OWNERS]);
447 btype = !strcmp(before[FS_TYPE], "AFS");
448 bcreate = atoi(before[FS_CREATE]);
449 if (afterc < FS_CREATE)
451 if (btype && bcreate)
452 critical_alert("incremental", "Cannot delete AFS filesystem %s: "
453 "Operation not supported", before[FS_NAME]);
460 /* Are we dealing with AFS lockers (could be type ERR lockers) */
461 if (!atype && !btype)
463 if (strcmp(before[FS_TYPE], "ERR") || strcmp(after[FS_TYPE], "ERR"))
467 /* By now, we know we are simply changing AFS filesystem attributes.
468 * Operations supported:
469 * Name change: rename/remount
470 * Path change: remount
471 * Type change: ERR<-->AFS
475 if (strcmp(before[FS_OWNER], after[FS_OWNER]) ||
476 strcmp(before[FS_OWNERS], after[FS_OWNERS]))
478 critical_alert("incremental",
479 "Cannot change ownership of filesystem %s: Operation not yet supported",
484 sprintf(cmd, "%s/perl -I%s %s/afs_rename.pl %s %s %s %s %s %s %s %s %s %s",
485 BIN_DIR, BIN_DIR, BIN_DIR,
486 before[FS_NAME], before[FS_MACHINE], before[FS_TYPE],
487 before[FS_L_TYPE], before[FS_PACK],
488 after[FS_NAME], after[FS_MACHINE], after[FS_TYPE],
489 after[FS_L_TYPE], after[FS_PACK]);
494 void do_quota(char **before, int beforec, char **after, int afterc)
498 if (afterc < Q_DIRECTORY || strcmp("ANY", after[Q_TYPE]) ||
499 strncmp("/afs/", after[Q_DIRECTORY], 5))
502 sprintf(cmd, "%s/perl -I%s %s/afs_quota.pl %s %s",
503 BIN_DIR, BIN_DIR, BIN_DIR,
504 after[Q_DIRECTORY], after[Q_QUOTA]);
510 void run_cmd(char *cmd)
512 int success=0, tries=0;
516 while (success == 0 && tries < 2)
520 com_err(whoami, 0, "Executing command: %s", cmd);
521 if (system(cmd) == 0)
525 critical_alert("incremental", "failed command: %s", cmd);
529 int add_user_lists(int ac, char **av, void *user)
531 if (atoi(av[L_ACTIVE]) && atoi(av[L_GROUP])) /* active group ? */
532 edit_group(1, av[L_NAME], "USER", user);
537 int add_list_members(int ac, char **av, void *group)
539 edit_group(1, group, av[0], av[1]);
543 int check_user(int ac, char **av, void *ustate)
545 *(int *)ustate = atoi(av[U_STATE]);
550 void edit_group(int op, char *group, char *type, char *member)
553 char buf[PR_MAXNAMELEN];
555 static char local_realm[REALM_SZ+1] = "";
558 /* The following KERBEROS code allows for the use of entities
562 krb_get_lrealm(local_realm, 1);
563 if (!strcmp(type, "KERBEROS"))
565 p = strchr(member, '@');
566 if (p && !strcasecmp(p+1, local_realm))
569 else if (strcmp(type, "USER"))
570 return; /* invalid type */
572 /* Cannot risk doing another query during a callback */
573 /* We could do this simply for type USER, but eventually this may also
574 * dynamically add KERBEROS types to the prdb, and we will need to do
575 * a query to look up the uid of the null-instance user */
578 m = malloc(sizeof(struct member));
581 critical_alert("incremental", "Out of memory");
585 strcpy(m->list, group);
586 strcpy(m->type, type);
587 strcpy(m->member, member);
588 m->next = member_head;
593 strcpy(buf, "system:");
595 com_err(whoami, 0, "%s %s %s group %s", (op ? "Adding" : "Removing"), member,
596 (op ? "to" : "from"), group);
597 code = pr_try(op ? pr_AddToGroup : pr_RemoveUserFromGroup, member, buf);
600 if (op==1 && code == PRIDEXIST)
601 return; /* Already added */
604 { /* Something is missing */
606 return; /* Already deleted */
607 if (!strcmp(type, "KERBEROS")) /* Special instances; ok */
610 /* Check whether the member being added is an active user */
611 code = moira_connect();
614 code = mr_query("get_user_by_login", 1, &member,
615 check_user, (char *) &ustate);
619 critical_alert("incremental", "Error contacting Moira server "
620 "to lookup user %s: %s", member,
621 error_message(code));
624 /* We don't use moira_disconnect()
625 * because we may already be in the routine.
630 if (!code && ustate!=1 && ustate!=2)
631 return; /* inactive user */
635 critical_alert("incremental", "Couldn't %s %s %s %s: %s",
636 op ? "add" : "remove", member,
637 op ? "to" : "from", buf,
638 error_message(code));
643 long pr_try(long (*fn)(), char *a1, char *a2, char *a3, char *a4, char *a5,
644 char *a6, char *a7, char *a8)
646 static int initd = 0;
653 code = pr_Initialize(0, AFSCONF_CLIENTNAME, 0);
660 code = pr_Initialize(1, AFSCONF_CLIENTNAME, 0);
663 critical_alert("incremental", "Couldn't initialize libprot: %s",
664 error_message(code));
668 sleep(1); /* give ptserver room */
670 while ((code = (*fn)(a1, a2, a3, a4, a5, a6, a7, a8)))
675 if (code == UNOQUORUM)
677 else if (code == PRPERM)
678 system("/bin/athena/aklog");
682 /* Re-initialize the prdb connection */
683 code = pr_Initialize(0, AFSCONF_CLIENTNAME, 0);
685 code = pr_Initialize(1, AFSCONF_CLIENTNAME, 0);
688 critical_alert("incremental", "Couldn't re-initialize libprot: %s",
689 error_message(code));
690 initd = 0; /* we lost */
702 for (i = 0; file_exists(STOP_FILE); i++)
706 critical_alert("incremental",
707 "AFS incremental failed (%s exists): %s",
716 int moira_connect(void)
720 if (!mr_connections++)
724 code = mr_connect(uts.nodename);
726 code = mr_krb5_auth("afs.incr");
732 int moira_disconnect(void)
736 if (!--mr_connections)
739 while ((m = member_head))
741 edit_group(m->op, m->list, m->type, m->member);
742 member_head = m->next;