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