]> andersk Git - moira.git/blob - server/increment.pc
Don't disallow proxy'ed users from accessing queries with a capacl of
[moira.git] / server / increment.pc
1 /* $Id$
2  *
3  * Deal with incremental updates
4  *
5  * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include "mr_server.h"
12 #include "query.h"
13 #include "qrtn.h"
14
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 EXEC SQL INCLUDE sqlca;
22
23 RCSID("$Header$");
24
25 extern char *whoami;
26 extern char *table_name[];
27 extern int num_tables;
28
29 int inc_pid = 0;
30 int inc_running = 0;
31 time_t inc_started;
32
33 #define MAXARGC 15
34
35 EXEC SQL WHENEVER SQLERROR DO dbmserr();
36
37 EXEC SQL BEGIN DECLARE SECTION;
38 /* structures to save before args */
39 static char *before[MAXARGC];
40 static int beforec;
41 static enum tables beforetable;
42
43 /* structures to save after args */
44 static char *after[MAXARGC];
45 static int afterc;
46 EXEC SQL END DECLARE SECTION;
47
48 /* structures to save entire sets of incremental changes */
49 struct save_queue *incremental_sq = NULL;
50 struct save_queue *incremental_exec = NULL;
51 struct iupdate {
52   char *table;
53   int beforec;
54   char **before;
55   int afterc;
56   char **after;
57   char *service;
58 };
59
60 void next_incremental(void);
61 char **copy_argv(char **argv, int argc);
62 void free_argv(char **argv, int argc);
63 int table_num(char *table);
64
65 void incremental_init(void)
66 {
67   int i;
68
69   if (!incremental_sq)
70     incremental_sq = sq_create();
71   if (!incremental_exec)
72     incremental_exec = sq_create();
73
74   for (i = 0; i < MAXARGC; i++)
75     {
76       before[i] = xmalloc(MAX_FIELD_WIDTH);
77       after[i] = xmalloc(MAX_FIELD_WIDTH);
78     }
79 }
80
81
82 /* record the state of a table row before it is changed */
83
84 void incremental_before(enum tables table, char *qual, char **argv)
85 {
86   EXEC SQL BEGIN DECLARE SECTION;
87   int id;
88   EXEC SQL END DECLARE SECTION;
89
90   char *name, *name2;
91
92   beforetable = table;
93
94   switch (table)
95     {
96     case USERS_TABLE:
97       sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
98               "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
99               "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
100       dosql(before);
101       beforec = 11;
102       break;
103     case MACHINE_TABLE:
104       sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
105               "WHERE %s", qual);
106       dosql(before);
107       beforec = 3;
108       break;
109     case CLUSTERS_TABLE:
110       sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
111               "c.clu_id FROM clusters c WHERE %s", qual);
112       dosql(before);
113       beforec = 4;
114       break;
115     case CONTAINERS_TABLE:
116       sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
117               "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
118               "WHERE %s", qual);
119       dosql(before);
120       beforec = 8;
121       name = xmalloc(0);
122       id = atoi(before[5]);
123       if (!strncmp(before[4], "USER", 4))
124         {
125           id_to_name(id, USERS_TABLE, &name);
126           strcpy(before[5], name);
127         }
128       else if (!strncmp(before[4], "LIST", 4))
129         {
130           id_to_name(id, LIST_TABLE, &name);
131           strcpy(before[5], name);
132         }
133       else if (!strncmp(before[4], "KERBEROS", 8))
134         {
135           id_to_name(id, STRINGS_TABLE, &name);
136           strcpy(before[5], name);
137         }
138       id = atoi(before[7]);
139       id_to_name(id, LIST_TABLE, &name);
140       strcpy(before[7], name);
141       break;
142     case MCMAP_TABLE:
143       strcpy(before[0], argv[0]);
144       strcpy(before[1], argv[1]);
145       beforec = 2;
146       break;
147     case MCNTMAP_TABLE:
148       strcpy(before[0], argv[0]);
149       strcpy(before[1], argv[1]);
150       name_to_id(before[0], MACHINE_TABLE, &id);
151       sprintf(before[2], "%d", id);
152       name_to_id(before[1], CONTAINERS_TABLE, &id);
153       sprintf(before[3], "%d", id);
154       name = xmalloc(0);
155       EXEC SQL SELECT list_id INTO :before[4] FROM containers
156         WHERE cnt_id = :id;
157       id = atoi(before[4]);
158       id_to_name(id, LIST_TABLE, &name);
159       strcpy(before[4], name);
160       beforec = 5;
161       break;
162     case SVC_TABLE:
163       strcpy(before[0], argv[0]);
164       strcpy(before[1], argv[1]);
165       strcpy(before[2], argv[2]);
166       beforec = 3;
167       break;
168     case FILESYS_TABLE:
169       sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
170               "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
171               "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
172               "WHERE %s", qual);
173       dosql(before);
174       name = xmalloc(0);
175       id = atoi(before[2]);
176       id_to_name(id, MACHINE_TABLE, &name);
177       strcpy(before[2], name);
178       id = atoi(before[7]);
179       id_to_name(id, USERS_TABLE, &name);
180       strcpy(before[7], name);
181       id = atoi(before[8]);
182       id_to_name(id, LIST_TABLE, &name);
183       strcpy(before[8], name);
184       free(name);
185       beforec = 12;
186       break;
187     case QUOTA_TABLE:
188       strcpy(before[0], "?");
189       strcpy(before[1], argv[1]);
190       strcpy(before[2], "?");
191       sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
192               "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
193       dosql(&(before[3]));
194       strcpy(before[2], argv[1]);
195       beforec = 5;
196       break;
197     case LIST_TABLE:
198       sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
199               "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
200               "l.description, l.list_id FROM list l WHERE %s", qual);
201       dosql(before);
202       beforec = 11;
203       break;
204     case IMEMBERS_TABLE:
205       id = (int) argv[0];
206       sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
207               "grouplist, gid FROM list WHERE list_id = %d", id);
208       dosql(&(before[3]));
209       name = xmalloc(0);
210       id_to_name(id, LIST_TABLE, &name);
211       name2 = xmalloc(0);
212       strcpy(before[0], name);
213       strcpy(before[1], argv[1]);
214       id = (int) argv[2];
215       beforec = 10;
216       if (!strcmp(before[1], "USER"))
217         {
218           id_to_name(id, USERS_TABLE, &name2);
219           EXEC SQL SELECT status, users_id INTO :before[9], :before[11] 
220             FROM users WHERE users_id = :id;
221           EXEC SQL SELECT list_id INTO :before[10] FROM list
222             WHERE name = :name;
223           beforec = 12;
224       }
225       else if (!strcmp(before[1], "LIST"))
226         {
227           id_to_name(id, LIST_TABLE, &name2);
228           EXEC SQL SELECT list_id INTO :before[9] FROM list
229             WHERE name = :name;
230           sprintf(before[10], "%d", id);
231           beforec = 11;
232         }
233       else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
234         {
235           id_to_name(id, STRINGS_TABLE, &name2);
236           EXEC SQL SELECT list_id INTO :before[9] FROM list
237             WHERE name = :name;
238         }
239       else if (!strcmp(before[1], "MACHINE"))
240         {
241           id_to_name(id, MACHINE_TABLE, &name2);
242           EXEC SQL SELECT list_id INTO :before[9] FROM list
243             WHERE name = :name;
244           sprintf(before[10], "%d", id);
245           beforec = 11;
246         }
247       strcpy(before[2], name2);
248       free(name);
249       free(name2);
250       break;
251     default:
252         /*
253         com_err(whoami, 0, "requested incremental on unexpected table `%s'",
254                 table_name[table]);
255         */
256       break;
257     }
258 }
259
260
261 void incremental_clear_before(void)
262 {
263   beforec = 0;
264 }
265
266
267 /* add an element to the incremental queue for the changed row */
268
269 void incremental_after(enum tables table, char *qual, char **argv)
270 {
271   char *name, *name2;
272   EXEC SQL BEGIN DECLARE SECTION;
273   int id; 
274   EXEC SQL END DECLARE SECTION;
275   struct iupdate *iu;
276
277   switch (table)
278     {
279     case USERS_TABLE:
280       sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
281               "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
282               "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
283       dosql(after);
284       afterc = 11;
285       break;
286     case MACHINE_TABLE:
287       sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
288               "WHERE %s", qual);
289       dosql(after);
290       afterc = 3;
291       break;
292     case CLUSTERS_TABLE:
293       sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
294               "c.clu_id FROM clusters c WHERE %s", qual);
295       dosql(after);
296       afterc = 4;
297       break;
298     case CONTAINERS_TABLE:
299       sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
300               "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
301               "WHERE %s", qual);
302       dosql(after);
303       afterc = 8;
304       name = xmalloc(0);
305       id = atoi(after[5]);
306       if (!strncmp(after[4], "USER", 4))
307         {
308           id_to_name(id, USERS_TABLE, &name);
309           strcpy(after[5], name);
310         }
311       else if (!strncmp(after[4], "LIST", 4))
312         {
313           id_to_name(id, LIST_TABLE, &name);
314           strcpy(after[5], name);
315         }
316       else if (!strncmp(after[4], "KERBEROS", 8))
317         {
318           id_to_name(id, STRINGS_TABLE, &name);
319           strcpy(after[5], name);
320         }
321       id = atoi(after[7]);
322       id_to_name(id, LIST_TABLE, &name);
323       strcpy(after[7], name);
324       break;
325     case MCMAP_TABLE:
326       strcpy(after[0], argv[0]);
327       strcpy(after[1], argv[1]);
328       afterc = 2;
329       break;
330     case MCNTMAP_TABLE:
331       strcpy(after[0], argv[0]);
332       strcpy(after[1], argv[1]);
333       name_to_id(after[0], MACHINE_TABLE, &id);
334       sprintf(after[2], "%d", id);
335       name_to_id(after[1], CONTAINERS_TABLE, &id);
336       sprintf(after[3], "%d", id);
337       name = xmalloc(0);
338       EXEC SQL SELECT list_id INTO :after[4] FROM containers
339         WHERE cnt_id = :id;
340       id = atoi(after[4]);
341       id_to_name(id, LIST_TABLE, &name);
342       strcpy(after[4], name);
343       afterc = 5;
344       break;
345     case SVC_TABLE:
346       strcpy(after[0], argv[0]);
347       strcpy(after[1], argv[1]);
348       strcpy(after[2], argv[2]);
349       afterc = 3;
350       break;
351     case FILESYS_TABLE:
352       sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
353               "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
354               "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
355               "WHERE %s", qual);
356       dosql(after);
357       name = xmalloc(0);
358       id = atoi(after[2]);
359       id_to_name(id, MACHINE_TABLE, &name);
360       strcpy(after[2], name);
361       id = atoi(after[7]);
362       id_to_name(id, USERS_TABLE, &name);
363       strcpy(after[7], name);
364       id = atoi(after[8]);
365       id_to_name(id, LIST_TABLE, &name);
366       strcpy(after[8], name);
367       free(name);
368       afterc = 12;
369       break;
370     case QUOTA_TABLE:
371       strcpy(after[0], "?");
372       strcpy(after[1], argv[1]);
373       strcpy(after[2], "?");
374       sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
375               "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
376               qual, argv[1]);
377       dosql(&(after[3]));
378       afterc = 5;
379       break;
380     case LIST_TABLE:
381       sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
382               "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
383               "l.description, l.list_id FROM list l WHERE %s", qual);
384       dosql(after);
385       afterc = 11;
386       break;
387     case IMEMBERS_TABLE:
388       id = (int) argv[0];
389       sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
390               "grouplist, gid FROM list WHERE list_id = %d", id);
391       dosql(&(after[3]));
392       name = xmalloc(0);
393       id_to_name(id, LIST_TABLE, &name);
394       name2 = xmalloc(0);
395       strcpy(after[0], name);
396       strcpy(after[1], argv[1]);
397       id = (int) argv[2];
398       afterc = 10;
399       if (!strcmp(after[1], "USER"))
400         {
401           id_to_name(id, USERS_TABLE, &name2);
402           EXEC SQL SELECT status, users_id INTO :after[9], :after[11]
403             FROM users WHERE users_id = :id;
404           EXEC SQL SELECT list_id INTO :after[10] FROM list
405             WHERE name = :name;
406           afterc = 12;
407         }
408       else if (!strcmp(after[1], "LIST"))
409         {
410           id_to_name(id, LIST_TABLE, &name2);
411           EXEC SQL SELECT list_id INTO :after[9] FROM list
412             WHERE name = :name;
413           sprintf(after[10], "%d", id);
414           afterc = 11;
415         }
416       else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
417         {
418           id_to_name(id, STRINGS_TABLE, &name2);
419           EXEC SQL SELECT list_id INTO :after[9] FROM list
420             WHERE name = :name;
421         }
422       else if (!strcmp(after[1], "MACHINE"))
423         {
424           id_to_name(id, MACHINE_TABLE, &name2);
425           EXEC SQL SELECT list_id INTO :after[9] FROM list
426             WHERE name = :name;
427           sprintf(after[10], "%d", id);
428           afterc = 11;
429         }
430       strcpy(after[2], name2);
431       free(name);
432       free(name2);
433       break;
434     case NO_TABLE:
435       afterc = 0;
436       table = beforetable;
437       break;
438     default:
439         /*
440         com_err(whoami, 0, "requested incremental on unexpected table `%s'",
441                 table_name[table]);
442         */
443       break;
444     }
445
446   iu = xmalloc(sizeof(struct iupdate));
447   iu->table = table_name[table];
448   iu->beforec = beforec;
449   iu->before = copy_argv(before, beforec);
450   iu->afterc = afterc;
451   iu->after = copy_argv(after, afterc);
452   sq_save_data(incremental_sq, iu);
453 }
454
455 void incremental_clear_after(void)
456 {
457   incremental_after(NO_TABLE, NULL, NULL);
458 }
459
460
461 /* Called when the current transaction is committed to start any queued
462  * incremental updates.  This caches the update table the first time it
463  * is called.
464  */
465
466 struct inc_cache {
467   struct inc_cache *next;
468   char *table, *service;
469 };
470
471
472 void incremental_update(void)
473 {
474   static int inited = 0;
475   static struct inc_cache *cache;
476   struct inc_cache *c;
477   EXEC SQL BEGIN DECLARE SECTION;
478   char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
479   EXEC SQL END DECLARE SECTION;
480   struct iupdate *iu, *iu_save;
481
482   if (!inited)
483     {
484       inited++;
485
486       EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
487         FROM incremental;
488       EXEC SQL OPEN inc;
489       while (1)
490         {
491           EXEC SQL FETCH inc INTO :tab, :serv;
492           if (sqlca.sqlcode)
493             break;
494           c = xmalloc(sizeof(struct inc_cache));
495           c->next = cache;
496           c->table = xstrdup(strtrim(tab));
497           c->service = xstrdup(strtrim(serv));
498           cache = c;
499         }
500       EXEC SQL CLOSE inc;
501       EXEC SQL COMMIT WORK;
502     }
503
504   while (sq_remove_data(incremental_sq, &iu))
505     {
506       for (c = cache; c; c = c->next)
507         {
508           if (!strcmp(c->table, iu->table))
509             {
510               iu->service = c->service;
511               iu_save = xmalloc(sizeof(struct iupdate));
512               iu_save->service = iu->service;
513               iu_save->table = iu->table;
514               iu_save->beforec = iu->beforec;
515               iu_save->afterc = iu->afterc;
516               iu_save->before = copy_argv(iu->before, iu->beforec);
517               iu_save->after = copy_argv(iu->after, iu->afterc);
518               sq_save_data(incremental_exec, iu_save);
519             }
520         }
521       if (!c)
522         {
523           free_argv(iu->before, iu->beforec);
524           free_argv(iu->after, iu->afterc);
525           free(iu);
526         }
527     }
528   if (inc_running == 0)
529     next_incremental();
530 }
531
532 /* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
533    We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
534    this function so proc will pass it through without reading it. */
535
536 #ifndef _PROC_
537 void next_incremental(void)
538 {
539   struct iupdate *iu;
540   char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
541   int i;
542   sigset_t sigs;
543
544   if (!incremental_exec)
545     incremental_init();
546
547   if (sq_empty(incremental_exec) ||
548       (inc_running && now - inc_started < INC_TIMEOUT))
549     return;
550
551   if (inc_running)
552     com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
553
554   sq_remove_data(incremental_exec, &iu);
555   argv[1] = iu->table;
556   sprintf(cbefore, "%d", iu->beforec);
557   argv[2] = cbefore;
558   sprintf(cafter, "%d", iu->afterc);
559   argv[3] = cafter;
560   for (i = 0; i < iu->beforec; i++)
561     argv[4 + i] = iu->before[i];
562   for (i = 0; i < iu->afterc; i++)
563     argv[4 + iu->beforec + i] = iu->after[i];
564
565   sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
566   argv[0] = prog;
567   argv[4 + iu->beforec + iu->afterc] = 0;
568
569   sigemptyset(&sigs);
570   sigaddset(&sigs, SIGCHLD);
571   sigprocmask(SIG_BLOCK, &sigs, NULL);
572   inc_pid = vfork();
573   switch (inc_pid)
574     {
575     case 0:
576       execv(prog, argv);
577       _exit(1);
578     case -1:
579       com_err(whoami, 0, "Failed to start incremental update");
580       break;
581     default:
582       inc_running = 1;
583       inc_started = now;
584     }
585   sigprocmask(SIG_UNBLOCK, &sigs, NULL);
586
587   free_argv(iu->before, iu->beforec);
588   free_argv(iu->after, iu->afterc);
589   free(iu);
590 }
591 #endif
592
593 /* Called when the current transaction is aborted to throw away any queued
594  * incremental updates
595  */
596
597 void incremental_flush(void)
598 {
599   struct iupdate *iu;
600
601   while (sq_get_data(incremental_sq, &iu))
602     {
603       free_argv(iu->before, iu->beforec);
604       free_argv(iu->after, iu->afterc);
605       free(iu);
606     }
607   sq_destroy(incremental_sq);
608   incremental_sq = sq_create();
609 }
610
611
612 char **copy_argv(char **argv, int argc)
613 {
614   char **ret = xmalloc(sizeof(char *) * argc);
615   while (--argc >= 0)
616     ret[argc] = xstrdup(strtrim(argv[argc]));
617   return ret;
618 }
619
620 void free_argv(char **argv, int argc)
621 {
622   while (--argc >= 0)
623     free(argv[argc]);
624   free(argv);
625 }
626
627 int table_num(char *name)
628 {
629   int i;
630
631   for (i = num_tables - 1; i; i--)
632     {
633       if (!strcmp(table_name[i], name))
634         break;
635     }
636
637   return i; /* 0 = "none" if no match */
638 }
This page took 0.088749 seconds and 5 git commands to generate.