|
|
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.