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