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