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

Defined functions

dopro defined in line 263; used 2 times
makedset defined in line 612; used 7 times
pr_set defined in line 919; used 15 times
proappl defined in line 727; used 1 times
prochk defined in line 838; used 4 times
protect defined in line 144; used 2 times

Defined variables

Proopmap defined in line 130; used 2 times

Defined struct's

qvect defined in line 283; used 2 times
  • in line 288(2)
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1638
Valid CSS Valid XHTML 1.0 Strict