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