|
|
1.1 root 1: # include <ingres.h>
2: # include <aux.h>
3: # include <catalog.h>
4: # include <symbol.h>
5: # include <tree.h>
6: # include "qrymod.h"
7: # include <sccs.h>
8: # include <errors.h>
9:
10: SCCSID(@(#)protect.c 8.4 4/15/85)
11:
12: /*
13: ** PROTECT -- protection algorithm
14: **
15: ** This module performs the INGRES protection algorithm, as
16: ** presented in Stonebraker & Rubinstein, "The INGRES Protection
17: ** System", with a few modifications.
18: **
19: ** The basic algorithm is as follows:
20: **
21: ** The algorithm is applied once to each variable used in the
22: ** query. Each variable has an initial check performed to
23: ** determine applicability -- if the current user owns the
24: ** relation, or if the relation is specially marked as being
25: ** "all access to everyone", then the algorithm is skipped,
26: ** thereby having effectively no restriction.
27: **
28: ** The set of all such variables is computed in 'protect',
29: ** and then 'dopro' is called to process each of those. This
30: ** is so the protection algorithm does not get applied recursively
31: ** to constraints which define more than one variable. Notice
32: ** that this could in itself be a protection violation, if it
33: ** were acceptable to reference a relation you do not own in a
34: ** PERMIT statement.
35: **
36: ** The effective query mode for this variable is then computed.
37: ** This is the same as the query mode of the whole query if
38: ** the variable in question is the result variable, otherwise
39: ** it is "retrieve" mode.
40: **
41: ** The next step is to scan the query tree and create sets of
42: ** domains referenced. Four sets are created:
43: ** uset -- the set of domains updated (actually,
44: ** referenced in the target list -- on a
45: ** retrieve, this will be the set of domains
46: ** retrieved to the user).
47: ** rset -- the set of domains retrieved in some
48: ** context other than the left hand side of
49: ** an equal sign.
50: ** aset -- the set of domains aggregated. This only
51: ** includes domains aggregated with a simple
52: ** aggregate (not an aggregate function) with
53: ** no qualification, since it may be possible
54: ** to come up with too much information other-
55: ** wise.
56: ** qset -- the set of domains retrieved for use in
57: ** a qualification, but never stored. This
58: ** includes domains in a qualification of an
59: ** aggregate or aggregate function.
60: ** For more details of domains in each of these sets, look at
61: ** the routine 'makedset'.
62: **
63: ** If we had a retrieve operation in the first place, we will
64: ** then merge 'uset' into 'rset' and clear 'uset', so that
65: ** now 'uset' only contains domains which are actually updated,
66: ** and 'rset' contains all domains which are retrieved.
67: **
68: ** Now that we know what is referenced, we can scan the protection
69: ** catalog. We scan the entire catalog once for each variable
70: ** mentioned in the query (except as already taken care of as
71: ** described above).
72: **
73: ** We must create a set of all operations on this variable which
74: ** are not yet resolved, that is, for which no PERMIT statements
75: ** which qualify have been issued. We store this set in the
76: ** variable "noperm". As PERMIT statements are found, bits will
77: ** be cleared. If the variable is not zero by the end of the
78: ** scan of the protection catalog, then we reject the query,
79: ** saying that we don't have permission -- giving us default
80: ** to deny.
81: **
82: ** For each tuple in the protection catalog for this relation,
83: ** we call "proappl" to see if it applies to this query. This
84: ** routine checks the user, terminal, time of day, and so forth
85: ** (in fact, everything which is query-independent) and tells
86: ** whether this tuple might apply.
87: **
88: ** If the tuple passes this initial check, we then do the query-
89: ** dependent checking. This amounts to calling "prochk" once
90: ** for each operation (and domain set) in the query. What we
91: ** get back is a set of operations which this tuple applies to.
92: ** If zero, the tuple doesn't apply at all; otherwise, it
93: ** applies to at least one operation. If it applies to some-
94: ** thing, we call it "interesting".
95: **
96: ** For "interesting" tuples, we now get the corresponding
97: ** qualification (if one exists), and disjoin it to a set of
98: ** protection constraints held in "pqual". Also, we mark
99: ** any operations we found as having been done, by clearing
100: ** bits in "noperm".
101: **
102: ** When we have completed scanning the protection catalog,
103: ** we check "noperm". If it is non-zero, then we have some
104: ** operation for which a PERMIT statement has not been issued,
105: ** and we issue an error message. If this variable is ok,
106: ** then we go on and try the next variable.
107: **
108: ** When all variables have been accounted for, we check to
109: ** see if we have any qualifications collected from the
110: ** protection algorithm. If so, we conjoin them to the
111: ** query tree.
112: **
113: ** Finally, we return the root of the modified tree. This
114: ** tree is guaranteed to have no authorization violations,
115: ** and may be run as a regular query.
116: **
117: ** Parameters:
118: ** root -- the root of the tree.
119: **
120: ** Returns:
121: ** The root of the modified and authorized tree.
122: **
123: ** Side Effects:
124: ** A possible non-local return on access violation.
125: **
126: ** Trace Flags:
127: ** 50 - 59
128: */
129:
130: int Proopmap[MAXPROQM + 1] =
131: {
132: PRO_RETR, /* 0 -- mdRETTERM */
133: PRO_RETR, /* 1 -- mdRETR */
134: PRO_APP, /* 2 -- mdAPP */
135: PRO_REPL, /* 3 -- mdREPL */
136: PRO_DEL, /* 4 -- mdDEL */
137: };
138:
139: extern QTREE Prodes;
140: extern char Terminal[];
141: extern QTREE *gettree();
142:
143:
144: QTREE *
145: protect(root)
146: QTREE *root;
147: {
148: register QTREE *r;
149: register int i;
150: register int vn;
151: register DESC *d;
152: int qmode;
153: int varset;
154:
155: r = root;
156:
157: # ifdef xQTR1
158: tTfp(50, -1, "\n->PROTECT\n\n");
159: # endif
160:
161: varset = 0;
162:
163: /*
164: ** Scan the range table and create a set of all variables
165: ** which are 'interesting', that is, on which the protectin
166: ** algorithm should be performed.
167: */
168:
169: for (vn = 0; vn < MAXVAR + 1; vn++)
170: {
171: if (!Qt.qt_rangev[vn].rngvmark)
172: continue;
173: d = Qt.qt_rangev[vn].rngvdesc;
174: if (d == NULL)
175: syserr("null desc vn=%d", vn);
176:
177: /* if owner, accept any query */
178: if (bequal(d->reldum.relowner, Usercode, UCODE_SZ))
179: continue;
180:
181: /* check for "no restriction" bit asserted (= clear) */
182: if (!bitset(S_PROTALL, d->reldum.relstat))
183: continue;
184: if (!bitset(S_PROTRET, d->reldum.relstat) &&
185: (Qt.qt_qmode == mdRETR || Qt.qt_qmode == mdRET_UNI))
186: continue;
187:
188: varset |= 1 << vn;
189: }
190:
191: /*
192: ** For each variable specified in varset (that is, for each
193: ** variable in the initial query), do the real algorithm.
194: */
195:
196: for (vn = 0; vn < MAXVAR + 1; vn++)
197: {
198: if ((varset & (1 << vn)) == 0)
199: continue;
200: d = Qt.qt_rangev[vn].rngvdesc;
201:
202: # ifdef xQTR1
203: if (tTf(50, 1))
204: printf("\nvn=%d: %.12s\n", vn, d->reldum.relid);
205: # endif
206:
207: /*
208: ** Determine the query mode for this variable. This
209: ** is not the query mode of the original query,
210: ** unless the variable is the result variable.
211: */
212:
213: qmode = Qt.qt_qmode;
214: if (vn != Qt.qt_resvar || qmode == mdRET_UNI)
215: qmode = mdRETTERM;
216:
217: # ifdef xQTR3
218: if (qmode == 1 || qmode > 4 || qmode < 0)
219: syserr("protect: bad qmode %d", qmode);
220: # endif
221:
222: /* do the interesting part of the algorithm */
223: dopro(vn, r, qmode, NULL);
224: }
225:
226: /* return the (authorized) tree */
227: # ifdef xQTR1
228: if (tTf(50, 15))
229: treepr(r, "PROTECT->");
230: # endif
231: return (r);
232: }
233: /*
234: ** DOPRO -- actually do the protection algorithm
235: **
236: ** This is the guts of it, broken off because it must be called
237: ** recursively on aggregates. The algorithm is as discussed
238: ** in the module header.
239: **
240: ** Parameters:
241: ** varno -- the variable number of interest.
242: ** root -- the root of the tree to modify.
243: ** qmode -- the effective query mode for this relation.
244: ** byset -- if non-NULL, a set of domains passed back
245: ** which gets bound out of the aggregate func,
246: ** in other words, the by list.
247: **
248: ** Returns:
249: ** none
250: **
251: ** Side Effects:
252: ** The tree pointed at by 'root' gets modified.
253: ** Quite possibly 'Qt.qt_rangev' and 'Qt.qt_remap' get clobbered.
254: **
255: ** Called By:
256: ** protect
257: ** makedset -- on aggregates and aggregate functions.
258: **
259: ** Trace Flags:
260: ** 51
261: */
262:
263: dopro(varno, root, qmode, byset)
264: int varno;
265: QTREE *root;
266: int qmode;
267: int byset[8];
268: {
269: int qset[8];
270: int uset[8];
271: int aset[8];
272: int rset[8];
273: int zeros[8];
274: QTREE *p;
275: QTREE *pqual;
276: register int i;
277: register int vn;
278: register QTREE *t;
279: int noperm;
280: int noqual;
281: struct protect prokey, protup;
282: struct tup_id lotid, hitid;
283: struct qvect
284: {
285: QTREE *q_qual;
286: int q_mode;
287: };
288: struct qvect quals[4];
289: int j;
290: extern QTREE *norml();
291: extern QTREE *tree();
292: extern QTREE *trimqlend();
293:
294:
295: t = root;
296: vn = varno;
297:
298: /* create domain usage sets */
299: for (i = 0; i < 8; i++)
300: {
301: zeros[i] = uset[i] = rset[i] = qset[i] = aset[i] = 0;
302: if (byset != NULL)
303: byset[i] = 0;
304: }
305:
306: /*
307: ** Create domain usage set for target list side. There are
308: ** two general cases: this is the root of the tree, or this
309: ** is the head of an aggregate.
310: */
311:
312: switch (t->sym.type)
313: {
314: case AGHEAD:
315: /*
316: ** An aggregate head falls into two classes: simple
317: ** aggregate and aggregate function. In an aggregate
318: ** function, care must be taken to bind the variables
319: ** in the by-list outside of the aggregate. We use
320: ** 'rset' as a temporary here.
321: */
322:
323: if (t->left->sym.type == BYHEAD)
324: {
325: /* make by-list set */
326: makedset(vn, t->left->left, NULL, rset, aset, qset);
327:
328: /* merge by-list set into qualification set */
329: for (i = 0; i < 8; i++)
330: {
331: if (byset != NULL)
332: byset[i] |= rset[i];
333: qset[i] |= rset[i];
334: rset[i] = 0;
335: }
336:
337: /* make aggregate list set */
338: makedset(vn, t->left->right->right, NULL, rset, aset, qset);
339: }
340: else
341: {
342: /* simple aggregate */
343: # ifdef xQTR3
344: if (t->left->sym.type != AOP)
345: syserr("dopro: AGHEAD->left %d", t->left->sym.type);
346: # endif
347:
348: /* check for qualification */
349: if (t->right->sym.type == QLEND)
350: {
351: /* simple, unqualified aggregate */
352: makedset(vn, t->left->right, NULL, aset, aset, qset);
353: }
354: else
355: {
356: # ifdef xQTR3
357: if (t->right->sym.type != AND)
358: syserr("dopro: AND=%d", t->right->sym.type);
359: # endif
360: makedset(vn, t->left->right, NULL, rset, aset, qset);
361: }
362: }
363: break;
364:
365: case ROOT:
366: makedset(vn, t->left, uset, rset, aset, qset);
367: break;
368: }
369:
370: /* scan qualification */
371: makedset(vn, t->right, NULL, qset, aset, qset);
372:
373: /* if retrieval, drop the 'update' set */
374: /* if delete or append, force an apparent update */
375: switch (qmode)
376: {
377: case mdRETTERM:
378: for (i = 0; i < 8; i++)
379: uset[i] = 0;
380: break;
381:
382: case mdDEL:
383: case mdAPP:
384: for (i = 0; i < 8; i++)
385: uset[i] = -1;
386: break;
387: }
388:
389: # ifdef xQTR1
390: if (tTf(51, 2))
391: {
392: printf("qmode %d\n", qmode);
393: pr_set(uset, "uset");
394: pr_set(rset, "rset");
395: pr_set(aset, "aset");
396: pr_set(qset, "qset");
397: }
398: # endif
399:
400: /* create a bit map of all referenced operations */
401: noperm = 0;
402: if (!bequal(uset, zeros, sizeof zeros))
403: noperm |= Proopmap[qmode];
404: if (!bequal(rset, zeros, sizeof zeros))
405: noperm |= PRO_RETR;
406: if (!bequal(aset, zeros, sizeof zeros))
407: noperm |= PRO_AGGR;
408: if (!bequal(qset, zeros, sizeof zeros))
409: noperm |= PRO_TEST;
410:
411: /* if no operation, something is wrong */
412: /* not nessasarily, consider a var that only occurs in an aggregate */
413: /* if (noperm == 0)
414: syserr("protect: no oper"); */
415:
416: /* initialize qualification portion */
417: for (i = 0; i < 4; )
418: quals[i++].q_qual = NULL;
419: noqual = FALSE;
420:
421: /* check the protection catalog */
422: opencatalog("protect", OR_READ);
423: setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relid, PRORELID);
424: setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relowner, PRORELOWN);
425: find(&Prodes, EXACTKEY, &lotid, &hitid, &prokey);
426:
427: while ((i = get(&Prodes, &lotid, &hitid, &protup, TRUE)) == 0)
428: {
429: if (kcompare(&Prodes, &prokey, &protup) != 0)
430: continue;
431:
432: # ifdef xQTR2
433: if (tTf(51, 4))
434: {
435: printf("PROTECT: ");
436: printup(&Prodes, &protup);
437: }
438: # endif
439:
440: /* check if this is the correct user, terminal, etc */
441: if (!proappl(&protup))
442: continue;
443:
444: /* alright, let's check the operation */
445: i = 0;
446: if (qmode != mdRETTERM)
447: i = quals[0].q_mode = prochk(Proopmap[qmode], uset, &protup);
448: i |= quals[1].q_mode = prochk(PRO_RETR, rset, &protup);
449: i |= quals[2].q_mode = prochk(PRO_AGGR, aset, &protup);
450: i |= quals[3].q_mode = prochk(PRO_TEST, qset, &protup);
451:
452: # ifdef xQTR2
453: if (tTf(51, 5))
454: printf("Satisfies operations %o\n", i);
455: # endif
456:
457: /* see if this tuple is "interesting" */
458: if (i == 0)
459: continue;
460:
461: /* it is! get the qualification (if any) */
462: if (protup.protree >= 0)
463: {
464: p = gettree(Qt.qt_rangev[vn].rngvdesc->reldum.relid,
465: Qt.qt_rangev[vn].rngvdesc->reldum.relowner,
466: mdPROT, protup.protree, FALSE);
467: # ifdef xQTR2
468: if (tTf(51, 6))
469: treepr(p, "Protection Clause");
470: # endif
471: p = trimqlend(p->right);
472: # ifdef xQTR3
473: /* check for a non-null qualification */
474: if (p == NULL)
475: syserr("protect: null tree");
476: # endif
477:
478: /* translate to the interesting variable */
479: j = protup.proresvar;
480: if (Qt.qt_remap[j] >= 0)
481: j = Qt.qt_remap[j];
482: mergevar(j, varno, p);
483:
484: /* disjoin the protection qual to real qual */
485: for (j = 0; j < 4; j++)
486: {
487: if (quals[j].q_mode == 0)
488: continue;
489: if (quals[j].q_qual == NULL)
490: quals[j].q_qual = p;
491: else
492: quals[j].q_qual = tree(quals[j].q_qual, p, OR, 0);
493: }
494: }
495: else
496: noqual = TRUE;
497:
498: /* mark this operation as having been handled */
499: noperm &= ~i;
500: }
501:
502: /* test 'get' return code */
503: if (i < 0)
504: syserr("protect: get");
505:
506: # ifdef xQTR1
507: if (tTf(51, 12))
508: printf("No perm on %o\n", noperm);
509: # endif
510:
511: /* see if no tuples applied for some operation */
512: if (noperm != 0)
513: qmerror(PVIOL, Qt.qt_qmode, vn, 0);
514:
515: /* see if we want to modify the query at all */
516: if (!noqual)
517: {
518: /* conjoin the qualification */
519: pqual = NULL;
520: for (i = 0; i < 4; i++)
521: if (quals[i].q_qual != NULL)
522: if (pqual == NULL)
523: pqual = quals[i].q_qual;
524: else
525: pqual = tree(pqual, quals[i].q_qual, AND, 0);
526: pqual = tree(pqual, tree(NULL, NULL, QLEND, 0), AND, 0);
527: appqual(pqual, t);
528:
529: /* normalize the tree */
530: t->right = norml(trimqlend(t->right));
531: }
532: }
533: /*
534: ** MAKEDSET -- make domain reference sets
535: **
536: ** This routine creates some sets which reflect the usage of
537: ** domains for a particular variable.
538: **
539: ** The interesting nodes are 'case' labels in the large
540: ** switch statement which comprises most of the code. To
541: ** describe briefly:
542: **
543: ** VAR nodes are easy: if they are for the current variable,
544: ** set the bit corresponding to the domain in the
545: ** 'retrieval' set. They can have no descendents,
546: ** so just return.
547: ** RESDOM nodes are also easy: they can be handled the same,
548: ** but the bit is set in the 'update' set instead.
549: ** AGHEAD nodes signal the beginning of an aggregate or
550: ** aggregate function. In this case, we scan the
551: ** qualification first (noting that RESDOM and VAR
552: ** nodes are processed as 'qualification' sets
553: ** instead of 'retrieval' or 'update' sets). Then,
554: ** if the aggregate has a WHERE clause or a BY list,
555: ** we treat it as a retrieve; otherwise, we call our-
556: ** selves recursively treating VAR nodes as 'aggregate'
557: ** types rather than 'retrieve' types.
558: ** BYHEAD nodes signal the beginning of a BY list. The left
559: ** subtree (the actual BY-list) is processed with
560: ** RESDOM nodes ignored (since they are pseudo-domains
561: ** anyhow) and VAR nodes mapped into the 'qualification'
562: ** set. Then we check the right subtree (which better
563: ** begin with an AOP node!) and continue processing.
564: ** AOP nodes must have a null left subtree, so we just drop
565: ** to the right subtree and iterate. Notice that we
566: ** do NOT map VAR nodes into the 'aggregate' set for
567: ** this node, since this has already been done by the
568: ** AGHEAD node; also, this aggregate might be counted
569: ** as a retrieve operation instead of an aggregate
570: ** operation (as far as the protection system is con-
571: ** cerned) -- this has been handled by the AGHEAD
572: ** node.
573: ** All other nodes are processed recursively along both edges.
574: **
575: ** Parameters:
576: ** vn -- the variable number that we are currently
577: ** interested in.
578: ** tree -- the root of the tree to scan. Notice that this
579: ** will in general be only one half of the tree --
580: ** makedset will be called once for the target
581: ** list and once for the qualification, with
582: ** different sets for the following parameters.
583: ** uset -- adjusted to be the set of all domains
584: ** updated.
585: ** rset -- adjusted to be the set of all domains
586: ** retrieved implicitly, that is, on the right-
587: ** hand-side of an assignment operator.
588: ** aset -- adjusted to be the set of all domains
589: ** aggregated. Notice that this set is not
590: ** adjusted explicitly, but rather is passed
591: ** to recursive incarnations of this routine
592: ** as 'rset'.
593: ** qset -- adjusted to be the set of domains retrieved
594: ** implicitly in a qualification. Like 'aset',
595: ** this is passed as 'rset' to recursive
596: ** incarnations.
597: **
598: ** Returns:
599: ** none
600: **
601: ** Side Effects:
602: ** none
603: **
604: ** Called By:
605: ** protect() -- in two places.
606: **
607: ** Trace Flags:
608: ** 53
609: **
610: */
611:
612: makedset(vn, tree, uset, rset, aset, qset)
613: int vn;
614: QTREE *tree;
615: int uset[8];
616: int rset[8];
617: int aset[8];
618: int qset[8];
619: {
620: register QTREE *t;
621: register int i;
622: int byset[8];
623:
624: t = tree;
625:
626: # ifdef xQTR1
627: if (tTf(53, 0))
628: {
629: printf("->makedset\n");
630: pr_set(uset, "uset");
631: pr_set(rset, "rset");
632: pr_set(aset, "aset");
633: pr_set(qset, "qset");
634: }
635: # endif
636:
637: while (t != NULL)
638: {
639: switch (t->sym.type)
640: {
641: case VAR:
642: if (t->sym.value.sym_var.varno == vn)
643: lsetbit(t->sym.value.sym_var.attno, rset);
644: break;
645:
646: case AGHEAD:
647: /* do protection on qualification */
648: dopro(vn, t, -1, byset);
649:
650: /* merge by-list set into qualification set */
651: for (i = 0; i < 8; i++)
652: qset[i] |= byset[i];
653:
654: break;
655:
656: case BYHEAD:
657: case AOP:
658: syserr("makedset: node %d", t->sym.type);
659:
660: case RESDOM:
661: if (t->sym.value.sym_resdom.resno == 0)
662: {
663: /* tid -- ignore right subtree (and this node) */
664: t = t->left;
665: continue;
666: }
667: if (uset != NULL)
668: lsetbit(t->sym.value.sym_resdom.resno, uset);
669: /* explicit fall-through to "default" case */
670:
671: default:
672: /* handle left subtree (recursively) */
673: makedset(vn, t->left, uset, rset, aset, qset);
674:
675: /* handle right subtree (iteratively) */
676: t = t->right;
677: continue;
678: }
679: break;
680: }
681:
682: # ifdef xQTR1
683: if (tTf(53, 15))
684: {
685: printf("makedset->\n");
686: pr_set(uset, "uset");
687: pr_set(rset, "rset");
688: pr_set(aset, "aset");
689: pr_set(qset, "qset");
690: }
691: # endif
692:
693: return;
694: }
695: /*
696: ** PROAPPL -- check for protection tuple applicable
697: **
698: ** A given protection catalog tuple is checked in a query-
699: ** independent way for applicability.
700: **
701: ** This routine checks such environmental constraints as the
702: ** user, the terminal, and the time of day. The code is
703: ** fairly straightforward, just take a look.
704: **
705: ** One note: the user and terminal codes contained in the
706: ** protection catalog are blank to mean 'any value' of the
707: ** corresponding field.
708: **
709: ** Parameters:
710: ** protup -- the protection tuple to compare against.
711: **
712: ** Returns:
713: ** TRUE -- this tuple applies to the current environment.
714: ** FALSE -- this tuple does not apply.
715: **
716: ** Side Effects:
717: ** none (unless you include trashing the static vector
718: ** returned by localtime).
719: **
720: ** Called By:
721: ** protect()
722: **
723: ** Trace Flags:
724: ** 54
725: */
726:
727: proappl(protup)
728: struct protect *protup;
729: {
730: register struct protect *p;
731: int tvect[2];
732: register int *tt;
733: extern int *localtime();
734: register int mtime;
735:
736: p = protup;
737:
738: /* check for correct user [insert clique code here] */
739: if (!bequal(" ", p->prouser, 2))
740: {
741: if (!bequal(p->prouser, Usercode, UCODE_SZ))
742: {
743: # ifdef xQTR2
744: if (tTf(54, 0))
745: printf(" ~user\n");
746: # endif
747: return (FALSE);
748: }
749: }
750:
751: /* check for correct terminal */
752: if (p->proterm[0] != ' ')
753: {
754: if (!sequal(p->proterm, Terminal))
755: {
756: # ifdef xQTR2
757: if (tTf(54, 0))
758: printf(" ~term\n");
759: # endif
760: return (FALSE);
761: }
762: }
763:
764: /* check for correct time of day & week */
765: time(tvect);
766: tt = localtime(tvect);
767: mtime = tt[2] * 60 + tt[1];
768:
769: if (p->protodbgn > mtime || p->protodend < mtime)
770: {
771: # ifdef xQTR2
772: if (tTf(54, 0))
773: printf(" ~tod\n");
774: # endif
775: return (FALSE);
776: }
777: if (p->prodowbgn > tt[6] || p->prodowend < tt[6])
778: {
779: # ifdef xQTR2
780: if (tTf(54, 0))
781: printf(" ~dow\n");
782: # endif
783: return (FALSE);
784: }
785:
786: /* hasn't failed yet -- I guess it's ok */
787: return (TRUE);
788: }
789: /*
790: ** PROCHK -- query-dependent protection tuple check
791: **
792: ** This routine does the query-dependent part of checking
793: ** the validity of a protection tuple. Unlike proappl,
794: ** which looked at aspects of the environment but not the
795: ** query being run, this routine assumes that the environ-
796: ** ment is ok, and checks that if it applies to this tuple.
797: **
798: ** Two things are checked. The first is if this tuple applies
799: ** to the operation in question (passed as 'inbit'). The
800: ** second is if the set of domains in the tuple contains the
801: ** set of domains in the query. If either of these fail,
802: ** the return is zero. Otherwise the return is the operation
803: ** bit. In otherwise, the return is the operation to which
804: ** this tuple applies (if any).
805: **
806: ** As a special check, the domain set is checked for all
807: ** zero. If so, no domains have been referenced for this
808: ** operation at all, and we return zero. In other words, this
809: ** tuple might apply to this operation, but since we don't
810: ** use the operation anyhow we will ignore it. It is important
811: ** to handle things in this way so that the qualification for
812: ** this tuple doesn't get appended if the variable is not
813: ** used in a particular context.
814: **
815: ** Parameters:
816: ** inbit -- the bit describing the operation to be
817: ** checked. Note that only one bit should
818: ** be set in this word, although this is
819: ** not checked.
820: ** domset -- the set of domains actually referenced
821: ** in this query for the operation described
822: ** by 'inbit'.
823: ** protup -- the tuple in question.
824: **
825: ** Returns:
826: ** The operation (if any) to which this tuple applies.
827: **
828: ** Side Effects:
829: ** none
830: **
831: ** Called By:
832: ** protect() -- in four places.
833: **
834: ** Trace Flags:
835: ** 55
836: */
837:
838: prochk(inbit, domset, protup)
839: int inbit;
840: int domset[8];
841: struct protect *protup;
842: {
843: register struct protect *p;
844: register int *d;
845: register int i;
846:
847: p = protup;
848: d = domset;
849:
850: # ifdef xQTR1
851: if (tTf(55, 0))
852: {
853: printf("->prochk, inbit=%o, proopset=%o\n", inbit, p->proopset);
854: pr_set(d, "domset");
855: pr_set(p->prodomset, "prodomset");
856: }
857: # endif
858:
859: /* check for null domain set, if so return zero */
860: for (i = 0; i < 8; i++)
861: if (d[i] != 0)
862: break;
863: if (i >= 8)
864: {
865: # ifdef xQTR2
866: tTfp(55, 15, "prochk-> null set\n");
867: # endif
868: return (0);
869: }
870:
871: /* see if this tuple applies to this operation */
872: if ((inbit & p->proopset) == 0)
873: {
874: # ifdef xQTR2
875: tTfp(55, 15, "prochk-> no op\n");
876: # endif
877: return (0);
878: }
879:
880: /* check if domains are a subset */
881: for (i = 0; i < 8; i++)
882: {
883: if ((d[i] & ~p->prodomset[i]) != 0)
884: {
885: /* failure */
886: # ifdef xQTR2
887: tTfp(55, 15, "prochk-> not subset\n");
888: # endif
889: return (0);
890: }
891: }
892:
893: /* this is hereby an "interesting" tuple */
894: # ifdef xQTR2
895: if (tTf(55, 15))
896: printf("prochk-> %d\n", inbit);
897: # endif
898: return (inbit);
899: }
900:
901: # ifdef xQTR1
902:
903: /*
904: ** PR_SET -- print set for debugging
905: **
906: ** This routine prints a 128-bit set for debugging.
907: **
908: ** Parameters:
909: ** xset -- the set to convert.
910: ** labl -- a label to print before the set.
911: **
912: ** Returns:
913: ** a pointer to the converted string.
914: **
915: ** Side Effects:
916: ** none
917: */
918:
919: pr_set(xset, labl)
920: short xset[8];
921: char *labl;
922: {
923: register short *x;
924: register int i;
925: register long *y;
926:
927: printf("\t%s: ", labl);
928: x = xset;
929: y = (long *) x;
930: if (x == NULL)
931: {
932: printf("<NULL>\n");
933: return;
934: }
935: for (i = 7; i >= 0; i--)
936: printf("%x/", x[i]);
937: printf(" <> ");
938: for (i = 0; i < 4; i++)
939: printf("/%ld", y[i]);
940: printf("\n");
941: }
942:
943: # endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.