]> andersk Git - moira.git/blob - incremental/afs.c
Remove `delete_user_by_uid' since it's never been used in any logs we have,
[moira.git] / incremental / afs.c
1 /* $Header$
2  *
3  * Do AFS incremental updates
4  *
5  * Copyright (C) 1989,1992 by the Massachusetts Institute of Technology
6  * for copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <stdio.h>
11 #include <sys/types.h>
12 #include <sys/file.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include <krb.h>
17 #include <moira.h>
18 #include <moira_site.h>
19
20 #include <afs/param.h>
21 #include <afs/cellconfig.h>
22 #include <afs/venus.h>
23 #include <afs/ptclient.h>
24 #include <afs/pterror.h>
25
26 #define STOP_FILE "/moira/afs/noafs"
27 #define file_exists(file) (access((file), F_OK) == 0)
28
29 char *whoami;
30
31 /* Main stub routines */
32 int do_user();
33 int do_list();
34 int do_member();
35 int do_filesys();
36 int do_quota();
37
38 /* Support stub routines */
39 int run_cmd();
40 int add_user_lists();
41 int add_list_members();
42 int check_user();
43 int edit_group();
44 long pr_try();
45 int check_afs();
46
47 /* libprot.a routines */
48 extern long pr_Initialize();
49 extern long pr_CreateUser();
50 extern long pr_CreateGroup();
51 extern long pr_DeleteByID();
52 extern long pr_ChangeEntry();
53 extern long pr_SetFieldsEntry();
54 extern long pr_AddToGroup();
55 extern long pr_RemoveUserFromGroup();
56 extern long pr_SIdToName();
57
58 static char tbl_buf[1024];
59 static struct member {
60         int op;
61         char list[33];
62         char type[9];
63         char member[129];
64         struct member *next;
65 } *member_head = 0;
66
67 static int mr_connections=0;
68
69 main(argc, argv)
70 char **argv;
71 int argc;
72 {
73     int beforec, afterc, i;
74     char *table, **before, **after;
75
76     for (i = getdtablesize() - 1; i > 2; i--)
77       close(i);
78
79     whoami = ((whoami = strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
80
81     table = argv[1];
82     beforec = atoi(argv[2]);
83     before = &argv[4];
84     afterc = atoi(argv[3]);
85     after = &argv[4 + beforec];
86
87     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
88
89     strcpy(tbl_buf, table);
90     strcat(tbl_buf, " (");
91     for (i = 0; i < beforec; i++) {
92         if (i > 0)
93           strcat(tbl_buf, ",");
94         strcat(tbl_buf, before[i]);
95     }
96     strcat(tbl_buf, ")->(");
97     for (i = 0; i < afterc; i++) {
98         if (i > 0)
99           strcat(tbl_buf, ",");
100         strcat(tbl_buf, after[i]);
101     }
102     strcat(tbl_buf, ")");
103 #ifdef DEBUG
104     com_err(whoami, 0, "%s", tbl_buf);
105 #endif
106
107     initialize_sms_error_table();
108     initialize_krb_error_table();
109
110     if (!strcmp(table, "users")) {
111         do_user(before, beforec, after, afterc);
112     } else if (!strcmp(table, "list")) {
113         do_list(before, beforec, after, afterc);
114     } else if (!strcmp(table, "imembers")) {
115         do_member(before, beforec, after, afterc);
116     } else if (!strcmp(table, "filesys")) {
117         do_filesys(before, beforec, after, afterc);
118     } else if (!strcmp(table, "quota")) {
119         do_quota(before, beforec, after, afterc);
120     }
121     exit(0);
122 }
123
124
125 do_user(before, beforec, after, afterc)
126 char **before;
127 int beforec;
128 char **after;
129 int afterc;
130 {
131     int astate, bstate, auid, buid, code;
132     char *av[2];
133
134     auid = buid = astate = bstate = 0;
135     if (afterc > U_STATE) astate = atoi(after[U_STATE]);
136     if (beforec > U_STATE) bstate = atoi(before[U_STATE]);
137     if (afterc > U_UID) auid = atoi(after[U_UID]);
138     if (beforec > U_UID) buid = atoi(before[U_UID]);
139
140     /* We consider "half-registered" users to be active */
141     if (astate == 2) astate = 1;
142     if (bstate == 2) bstate = 1;
143
144     if (astate != 1 && bstate != 1)             /* inactive user */
145         return;
146
147     if (astate == bstate && auid == buid && 
148         !strcmp(before[U_NAME], after[U_NAME]))
149         /* No AFS related attributes have changed */
150         return;
151
152     if (astate == bstate) {
153         /* Only a modify has to be done */
154         com_err(whoami, 0, "Changing user %s (uid %d) to %s (uid %d)",
155                before[U_NAME], buid, after[U_NAME], auid);
156
157         code = pr_try(pr_ChangeEntry, before[U_NAME], after[U_NAME], auid, "");
158         if (code) {
159             critical_alert("incremental",
160                            "Couldn't change user %s (id %d) to %s (id %d): %s",
161                            before[U_NAME], buid, after[U_NAME], auid,
162                            error_message(code));
163         }
164         return;
165     }
166     if (bstate == 1) {
167         com_err(whoami, 0, "Deleting user %s (uid %d)",
168                before[U_NAME], buid);
169
170         code = pr_try(pr_DeleteByID, buid);
171         if (code && code != PRNOENT) {
172             critical_alert("incremental",
173                            "Couldn't delete user %s (id %d): %s",
174                            before[U_NAME], buid, error_message(code));
175         }
176         return;
177     }
178     if (astate == 1) {
179         com_err(whoami, 0, "%s user %s (uid %d)",
180                ((bstate != 0) ? "Reactivating" : "Creating"),
181                after[U_NAME], auid);
182         
183         code = pr_try(pr_CreateUser, after[U_NAME], &auid);
184         /* if we get PRIDEXIST, it's only an error if the username
185            doesn't match (otherwise it just means the user was deleted
186            from Moira but not AFS */
187         if (code == PRIDEXIST) {
188             char ename[255];
189             
190             if (pr_try(pr_SIdToName, auid, ename) == 0 &&
191                 !strcmp(after[U_NAME], ename))
192                 return;
193         }
194         if (code) {
195             critical_alert("incremental",
196                            "Couldn't create user %s (id %d): %s",
197                            after[U_NAME], auid, error_message(code));
198             return;
199         }
200
201         if (bstate != 0) {
202             /* Reactivating a user; get his group list */
203             code = moira_connect();
204             if (code) {
205                 critical_alert("incremental",
206                                "Error contacting Moira server to retrieve grouplist of user %s: %s",
207                                after[U_NAME], error_message(code));
208                 return;
209             }
210             av[0] = "ruser";
211             av[1] = after[U_NAME];
212             code = mr_query("get_lists_of_member", 2, av,
213                             add_user_lists, after[U_NAME]);
214             if (code && code != MR_NO_MATCH)
215                 critical_alert("incremental",
216                                "Couldn't retrieve membership of user %s: %s",
217                                after[U_NAME], error_message(code));
218             moira_disconnect();
219         }
220         return;
221     }
222 }
223
224
225 do_list(before, beforec, after, afterc)
226 char **before;
227 int beforec;
228 char **after;
229 int afterc;
230 {
231     register int agid, bgid;
232     int ahide, bhide;
233     long code, id;
234     char g1[PR_MAXNAMELEN], g2[PR_MAXNAMELEN];
235     char *av[2];
236
237     agid = bgid = 0;
238     if (beforec > L_GID && atoi(before[L_ACTIVE]) && atoi(before[L_GROUP])) {
239         bgid = atoi(before[L_GID]);
240         bhide = atoi(before[L_HIDDEN]);
241     }
242     if (afterc > L_GID && atoi(after[L_ACTIVE]) && atoi(after[L_GROUP])) {
243         agid = atoi(after[L_GID]);
244         ahide = atoi(after[L_HIDDEN]);
245     }
246
247     if (agid == 0 && bgid == 0)                 /* Not active groups */
248         return;
249
250     if (agid && bgid) {
251         if (strcmp(after[L_NAME], before[L_NAME])) {
252             /* Only a modify is required */
253             strcpy(g1, "system:");
254             strcpy(g2, "system:");
255             strcat(g1, before[L_NAME]);
256             strcat(g2, after[L_NAME]);
257
258             com_err(whoami, 0, "Changing group %s (gid %d) to %s (gid %d)",
259                    before[L_NAME], bgid, after[L_NAME], agid);
260
261             code = pr_try(pr_ChangeEntry, g1, g2, -agid, "");
262             if (code) {
263                 critical_alert("incremental",
264                                "Couldn't change group %s (id %d) to %s (id %d): %s",
265                                before[L_NAME], -bgid, after[L_NAME], -agid,
266                                error_message(code));
267             }
268         }
269         if (ahide != bhide) {
270             com_err(whoami, 0, "Making group %s (gid %d) %s",
271                    after[L_NAME], agid,
272                    (ahide ? "hidden" : "visible"));
273             code = pr_try(pr_SetFieldsEntry, -agid, PR_SF_ALLBITS,
274                           (ahide ? PRP_STATUS_ANY : PRP_GROUP_DEFAULT) >>PRIVATE_SHIFT,
275                           0 /*ngroups*/, 0 /*nusers*/);
276             if (code) {
277                 critical_alert("incremental",
278                                "Couldn't set flags of group %s: %s",
279                                after[L_NAME], error_message(code));
280             }
281         }
282         return;
283     }
284     if (bgid) {
285         com_err(whoami, 0, "Deleting group %s (gid %d)",
286                before[L_NAME], bgid);
287         code = pr_try(pr_DeleteByID, -bgid);
288         if (code && code != PRNOENT) {
289             critical_alert("incremental",
290                            "Couldn't delete group %s (id %d): %s",
291                            before[L_NAME], -bgid, error_message(code));
292         }
293         return;
294     }
295     if (agid) {
296         strcpy(g1, "system:");
297         strcat(g1, after[L_NAME]);
298         strcpy(g2, "system:administrators");
299         id = -agid;
300         com_err(whoami, 0, "Creating %s group %s (gid %d)",
301                (ahide ? "hidden" : "visible"), after[L_NAME], agid);
302         code = pr_try(pr_CreateGroup, g1, g2, &id);
303         if (code == PRIDEXIST) {
304             char ename[255];
305             
306             if (pr_try(pr_SIdToName, -agid, ename) == 0 && !strcmp(g1, ename))
307                 return;
308         }
309         if (code) {
310             critical_alert("incremental",
311                            "Couldn't create group %s (id %d): %s",
312                            after[L_NAME], id, error_message(code));
313             return;
314         }
315         if (ahide) {
316             code = pr_try(pr_SetFieldsEntry, -agid, PR_SF_ALLBITS,
317                           (ahide ? PRP_STATUS_ANY : PRP_GROUP_DEFAULT) >>PRIVATE_SHIFT,
318                           0 /*ngroups*/, 0 /*nusers*/);
319             if (code) {
320                 critical_alert("incremental",
321                                "Couldn't set flags of group %s: %s",
322                                after[L_NAME], error_message(code));
323             }
324         }
325
326         /* We need to make sure the group is properly populated */
327         if (beforec < L_ACTIVE) return;
328
329         code = moira_connect();
330         if (code) {
331             critical_alert("incremental",
332                            "Error contacting Moira server to resolve %s: %s",
333                            after[L_NAME], error_message(code));
334             return;
335         }
336         av[0] = after[L_NAME];
337         code = mr_query("get_end_members_of_list", 1, av,
338                         add_list_members, after[L_NAME]);
339         if (code)
340             critical_alert("incremental",
341                            "Couldn't retrieve full membership of list %s: %s",
342                            after[L_NAME], error_message(code));
343         moira_disconnect();
344         return;
345     }
346 }
347
348
349     
350 #define LM_EXTRA_ACTIVE   (LM_END)
351 #define LM_EXTRA_PUBLIC   (LM_END+1)
352 #define LM_EXTRA_HIDDEN   (LM_END+2)
353 #define LM_EXTRA_MAILLIST (LM_END+3)
354 #define LM_EXTRA_GROUP    (LM_END+4)
355 #define LM_EXTRA_GID      (LM_END+5)
356 #define LM_EXTRA_END      (LM_END+6)
357
358 do_member(before, beforec, after, afterc)
359 char **before;
360 int beforec;
361 char **after;
362 int afterc;
363 {
364     int code;
365     char *p;
366
367     if (afterc) {
368         if (afterc < LM_EXTRA_END) {
369             return;
370         } else
371           if (!atoi(after[LM_EXTRA_ACTIVE]) || !atoi(after[LM_EXTRA_GROUP]))
372             return;
373         
374         edit_group(1, after[LM_LIST], after[LM_TYPE], after[LM_MEMBER]);
375     } else if (beforec) {
376         if (beforec < LM_EXTRA_END) {
377             return;
378         } else
379           if (!atoi(before[LM_EXTRA_ACTIVE]) || !atoi(before[LM_EXTRA_GROUP]))
380             return;
381         edit_group(0, before[LM_LIST], before[LM_TYPE], before[LM_MEMBER]);
382     }
383 }
384
385
386 do_filesys(before, beforec, after, afterc)
387 char **before;
388 int beforec;
389 char **after;
390 int afterc;
391 {
392     char cmd[1024];
393     int acreate, atype, bcreate, btype;
394
395     if (afterc < FS_CREATE) {
396         atype = acreate = 0;
397     } else {
398         atype = !strcmp(after[FS_TYPE], "AFS");
399         acreate = atoi(after[FS_CREATE]);
400     }
401
402     if (beforec < FS_CREATE) {
403         if (acreate == 0 || atype == 0) return;
404
405         /* new locker creation */
406         sprintf(cmd, "%s/perl -I%s %s/afs_create.pl %s %s %s %s %s %s",
407                 BIN_DIR, BIN_DIR, BIN_DIR,
408                 after[FS_NAME], after[FS_L_TYPE], after[FS_MACHINE],
409                 after[FS_PACK], after[FS_OWNER], after[FS_OWNERS]);
410         run_cmd(cmd);
411         return;
412     }
413     
414     btype = !strcmp(before[FS_TYPE], "AFS");
415     bcreate = atoi(before[FS_CREATE]);
416     if (afterc < FS_CREATE) {
417         if (btype && bcreate)
418             critical_alert("incremental",
419                            "Cannot delete AFS filesystem %s: Operation not supported",
420                            before[FS_NAME]);
421         return;
422     }
423
424     if (!acreate)
425         return;
426
427     /* Are we dealing with AFS lockers (could be type ERR lockers) */
428     if (!atype && !btype)
429         if (strcmp(before[FS_TYPE], "ERR") || strcmp(after[FS_TYPE], "ERR"))
430             return;
431                                                     
432     /* By now, we know we are simply changing AFS filesystem attributes.
433      * Operations supported:
434      *    Name change:  rename/remount
435      *    Path change:  remount
436      *    Type change:  ERR<-->AFS
437      */
438
439 #if 0
440     if (strcmp(before[FS_OWNER], after[FS_OWNER]) ||
441         strcmp(before[FS_OWNERS], after[FS_OWNERS]))
442     {
443         critical_alert("incremental",
444                        "Cannot change ownership of filesystem %s: Operation not yet supported",
445                        after[FS_NAME]);
446     }
447 #endif
448
449     sprintf(cmd, "%s/perl -I%s %s/afs_rename.pl %s %s %s %s %s %s %s %s %s %s",
450             BIN_DIR, BIN_DIR, BIN_DIR,
451             before[FS_NAME], before[FS_MACHINE], before[FS_TYPE],
452             before[FS_L_TYPE], before[FS_PACK],
453             after[FS_NAME], after[FS_MACHINE], after[FS_TYPE],
454             after[FS_L_TYPE], after[FS_PACK]);
455     run_cmd(cmd);
456 }
457
458
459 do_quota(before, beforec, after, afterc)
460 char **before;
461 int beforec;
462 char **after;
463 int afterc;
464 {
465     char cmd[1024];
466
467     if (afterc < Q_DIRECTORY || strcmp("ANY", after[Q_TYPE]) ||
468         strncmp("/afs/", after[Q_DIRECTORY], 5))
469         return;
470
471     sprintf(cmd, "%s/perl -I%s %s/afs_quota.pl %s %s",
472             BIN_DIR, BIN_DIR, BIN_DIR,
473             after[Q_DIRECTORY], after[Q_QUOTA]);
474     run_cmd(cmd);
475     return;
476 }
477
478
479 run_cmd(cmd)
480 char *cmd;
481 {
482     int success=0, tries=0;
483
484     check_afs();
485     
486     while (success == 0 && tries < 2) {
487         if (tries++)
488             sleep(90);
489         com_err(whoami, 0, "Executing command: %s", cmd);
490         if (system(cmd) == 0)
491             success++;
492     }
493     if (!success)
494         critical_alert("incremental", "failed command: %s", cmd);
495 }
496
497
498 add_user_lists(ac, av, user)
499     int ac;
500     char *av[];
501     char *user;
502 {
503     if (atoi(av[L_ACTIVE]) && atoi(av[L_GROUP]))        /* active group ? */
504         edit_group(1, av[L_NAME], "USER", user);
505     return 0;
506 }
507
508
509 add_list_members(ac, av, group)
510     int ac;
511     char *av[];
512     char *group;
513 {
514     edit_group(1, group, av[0], av[1]);
515     return 0;
516 }
517
518
519 check_user(ac, av, ustate)
520     int ac;
521     char *av[];
522     int *ustate;
523 {
524     *ustate = atoi(av[U_STATE]);
525     return 0;
526 }
527
528
529 edit_group(op, group, type, member)
530     int op;
531     char *group;
532     char *type;
533     char *member;
534 {
535     char *p = 0;
536     char buf[PR_MAXNAMELEN];
537     int code, ustate;
538     static char local_realm[REALM_SZ+1] = "";
539     struct member *m;
540
541     /* The following KERBEROS code allows for the use of entities
542      * user@foreign_cell.
543      */
544     if (!local_realm[0])
545         krb_get_lrealm(local_realm, 1);
546     if (!strcmp(type, "KERBEROS")) {
547         p = strchr(member, '@');
548         if (p && !strcasecmp(p+1, local_realm))
549             *p = 0;
550     } else if (strcmp(type, "USER"))
551         return;                                 /* invalid type */
552
553     /* Cannot risk doing another query during a callback */
554     /* We could do this simply for type USER, but eventually this may also
555      * dynamically add KERBEROS types to the prdb, and we will need to do
556      * a query to look up the uid of the null-instance user */
557     if (mr_connections) {
558         m = (struct member *)malloc(sizeof(struct member));
559         if (!m) {
560             critical_alert("incremental", "Out of memory");
561             exit(1);
562         }
563         m->op = op;
564         strcpy(m->list, group);
565         strcpy(m->type, type);
566         strcpy(m->member, member);
567         m->next = member_head;
568         member_head = m;
569         return;
570     }
571
572     strcpy(buf, "system:");
573     strcat(buf, group);
574     com_err(whoami, 0, "%s %s %s group %s",
575            (op ? "Adding" : "Removing"), member,
576            (op ? "to" : "from"), group);
577     code = 0;
578     code=pr_try(op ? pr_AddToGroup : pr_RemoveUserFromGroup, member, buf);
579     if (code) {
580         if (op==1 && code == PRIDEXIST) return; /* Already added */
581
582         if (code == PRNOENT) {                  /* Something is missing */
583             if (op==0) return;                  /* Already deleted */
584             if (!strcmp(type, "KERBEROS"))      /* Special instances; ok */
585                 return;
586
587             /* Check whether the member being added is an active user */
588             code = moira_connect();
589             if (!code) code = mr_query("get_user_by_login", 1, &member,
590                                        check_user, (char *)&ustate);
591             if (code) {
592                 critical_alert("incremental",
593                                "Error contacting Moira server to lookup user %s: %s",
594                                member, error_message(code));
595             }
596
597             /* We don't use moira_disconnect()
598              * because we may already be in the routine.
599              */
600             mr_disconnect();
601             mr_connections--;
602
603             if (!code && ustate!=1 && ustate!=2) return; /* inactive user */
604             code = PRNOENT;
605         }
606
607         critical_alert("incremental",
608                        "Couldn't %s %s %s %s: %s",
609                        op ? "add" : "remove", member,
610                        op ? "to" : "from", buf,
611                        error_message(code));
612     }
613 }
614
615
616 long pr_try(fn, a1, a2, a3, a4, a5, a6, a7, a8)
617     long (*fn)();
618     char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
619 {
620     static int initd=0;
621     register long code;
622     register int tries = 0;
623 #ifdef DEBUG
624     char fname[64];
625 #endif
626
627     check_afs();
628
629     if (initd) {
630         code=pr_Initialize(0, AFSCONF_CLIENTNAME, 0);
631     } else {
632         code = 0;
633         initd = 1;
634     }
635     if (!code) code=pr_Initialize(1, AFSCONF_CLIENTNAME, 0);
636     if (code) {
637         critical_alert("incremental", "Couldn't initialize libprot: %s",
638                        error_message(code));
639         return;
640     }
641
642     sleep(1);                                   /* give ptserver room */
643
644     while (code = (*fn)(a1, a2, a3, a4, a5, a6, a7, a8)) {
645 #ifdef DEBUG
646         long t;
647         t = time(0);
648         if (fn == pr_AddToGroup) strcpy(fname, "pr_AddToGroup");
649         else if (fn == pr_RemoveUserFromGroup)
650             strcpy(fname, "pr_RemoveUserFromGroup");
651         else if (fn == pr_CreateUser) strcpy(fname, "pr_CreateUser");
652         else if (fn == pr_CreateGroup) strcpy(fname, "pr_CreateGroup");
653         else if (fn == pr_DeleteByID) strcpy(fname, "pr_DeleteByID");
654         else if (fn == pr_ChangeEntry) strcpy(fname, "pr_ChangeEntry");
655         else if (fn == pr_SetFieldsEntry) strcpy(fname, "pr_SetFieldsEntry");
656         else if (fn == pr_AddToGroup) strcpy(fname, "pr_AddToGroup");
657         else
658             sprintf(fname, "pr_??? (0x%08x)", (long)fn);
659
660         com_err(whoami, code, "- %s failed (try %d @%u)", fname, tries+1, t);
661 #endif
662         if (++tries > 2) break;         /* 3 tries */
663         
664         if (code == UNOQUORUM) sleep(90);
665         else sleep(15);
666
667         /* Re-initialize the prdb connection */
668         code=pr_Initialize(0, AFSCONF_CLIENTNAME, 0);
669         if (!code) code=pr_Initialize(1, AFSCONF_CLIENTNAME, 0);
670         if (code) {
671             critical_alert("incremental", "Couldn't re-initialize libprot: %s",
672                            error_message(code));
673             initd = 0;                          /* we lost */
674             break;
675         }
676     }
677     return code;
678 }
679
680
681 check_afs()
682 {
683     int i;
684     
685     for (i=0; file_exists(STOP_FILE); i++) {
686         if (i > 30) {
687             critical_alert("incremental",
688                            "AFS incremental failed (%s exists): %s",
689                            STOP_FILE, tbl_buf);
690             exit(1);
691         }
692         sleep(60);
693     }
694 }
695
696
697 moira_connect()
698 {
699     static char hostname[64];
700     long code;
701
702     if (!mr_connections++) {
703         gethostname(hostname, sizeof(hostname));
704         code = mr_connect(hostname);
705         if (!code) code = mr_auth("afs.incr");
706         return code;    
707     }
708     return 0;
709 }
710
711 moira_disconnect()
712 {
713     struct member *m;
714     
715     if (!--mr_connections) {
716         mr_disconnect();
717         while(m = member_head) {
718             edit_group(m->op, m->list, m->type, m->member);
719             member_head = m->next;
720             free(m);
721         }
722     }
723     return 0;
724 }
This page took 0.092876 seconds and 5 git commands to generate.