1: # include <ingres.h> 2: # include <aux.h> 3: # include <catalog.h> 4: # include <access.h> 5: # include <tree.h> 6: # include <symbol.h> 7: # include <lock.h> 8: # include <pv.h> 9: # include <func.h> 10: # include "qrymod.h" 11: # include <sccs.h> 12: # include <errors.h> 13: 14: SCCSID(@(#)d_prot.c 8.3 2/8/85) 15: 16: 17: 18: /* 19: ** D_PROT -- define protection constraint 20: ** 21: ** A protection constraint as partially defined by the last tree 22: ** defined by d_tree is defined. 23: ** 24: ** The stuff that comes through the pipe as parameters is complex. 25: ** It comes as a sequence of strings: 26: ** # The operation set, already encoded in the parser into a 27: ** bit map. If the PRO_RETR permission is set, the PRO_TEST 28: ** and PRO_AGGR permissions will also be set. 29: ** # The relation name. 30: ** # The relation owner. 31: ** # The user name. This must be a user name as specified in 32: ** the 'users' file, or the keyword 'all', meaning all users. 33: ** # The terminal id. Must be a string of the form 'ttyx' or 34: ** the keyword 'all'. 35: ** # The starting time of day, as minutes-since-midnight. 36: ** # The ending time of day. 37: ** # The starting day-of-week, with 0 = Sunday. 38: ** # The ending dow. 39: ** 40: ** The domain reference set is build automatically from the 41: ** target list of the tree. Thus, the target list must exist, 42: ** but it is not inserted into the tree. The target list must 43: ** be a flat sequence of RESDOM nodes with VAR nodes hanging 44: ** of the rhs; also, the VAR nodes must all be for Qt.qt_resvar. 45: ** If there is no target list on the tree, the set of all var- 46: ** iables is assumed. 47: ** 48: ** The relstat field in the relation relation is updated to 49: ** reflect any changes. 50: ** 51: ** It only makes sense for the DBA to execute this command. 52: ** 53: ** If there is one of the special cases 54: ** permit all to all 55: ** permit retrieve to all 56: ** it is caught, and the effect is achieved by diddling 57: ** relstat bits instead of inserting into the protect catalog. 58: ** 59: ** Parameters: 60: ** none 61: ** 62: ** Returns: 63: ** none 64: ** 65: ** Side Effects: 66: ** Activity in 'protect' and 'relation' catalogs. 67: ** 68: ** Trace Flags: 69: ** 59 70: */ 71: 72: extern struct admin Admin; 73: extern DESC Prodes; 74: extern DESC Reldes; 75: 76: extern d_prot(), null_fn(); 77: extern short tTqm[80]; 78: 79: struct fn_def DefProFn = 80: { 81: "DPROT", 82: d_prot, 83: null_fn, 84: null_fn, 85: NULL, 86: 0, 87: tTqm, 88: 80, 89: 'Q', 90: 0 91: }; 92: 93: d_prot(pc, pv) 94: int pc; 95: PARM *pv; 96: { 97: struct protect protup; 98: struct tup_id protid; 99: struct protect prokey; 100: struct protect proxtup; 101: char buf[30]; 102: char ubuf[MAXLINE + 1]; 103: register int i; 104: auto short ix; 105: int treeid; 106: register QTREE *t; 107: QTREE *root; 108: register char *p; 109: struct relation reltup; 110: struct relation relkey; 111: struct tup_id reltid; 112: int relstat; 113: int all_pro; 114: 115: /* 116: ** Fill in the protection tuple with the information 117: ** from the parser, validating as we go. 118: ** 119: ** Also, determine if we have a PERMIT xx to ALL 120: ** with no further qualification case. The variable 121: ** 'all_pro' is set to reflect this. 122: */ 123: 124: clr_tuple(&Prodes, &protup); 125: all_pro = TRUE; 126: 127: /* read operation set */ 128: if (pv->pv_type != PV_INT) 129: syserr("d_prot: opset"); 130: protup.proopset = pv->pv_val.pv_int; 131: if ((protup.proopset & PRO_RETR) != 0) 132: protup.proopset |= PRO_TEST | PRO_AGGR; 133: pv++; 134: 135: /* read relation name */ 136: if (pv->pv_type != PV_STR) 137: syserr("d_prot: relid"); 138: pmove(pv->pv_val.pv_str, protup.prorelid, MAXNAME, ' '); 139: pv++; 140: 141: /* read relation owner */ 142: if (pv->pv_type != PV_STR) 143: syserr("d_prot: relid"); 144: bmove(pv->pv_val.pv_str, protup.prorelown, 2); 145: pv++; 146: 147: /* read user name */ 148: if (pv->pv_type != PV_STR) 149: syserr("d_prot: user"); 150: if (sequal(pv->pv_val.pv_str, "all")) 151: bmove(" ", protup.prouser, 2); 152: else 153: { 154: /* look up user in 'users' file */ 155: if (getnuser(pv->pv_val.pv_str, ubuf)) 156: qmerror(BADUSRNAME, -1, Qt.qt_resvar, pv->pv_val.pv_str, 0); 157: for (p = ubuf; *p != ':' && *p != 0; p++) 158: continue; 159: bmove(++p, protup.prouser, 2); 160: if (p[0] == ':' || p[1] == ':' || p[2] != ':') 161: syserr("d_prot: users %s", ubuf); 162: all_pro = FALSE; 163: } 164: pv++; 165: 166: /* read terminal id */ 167: if (pv->pv_type != PV_STR) 168: syserr("d_prot: user"); 169: if (sequal(pv->pv_val.pv_str, "all")) 170: pmove("", protup.proterm, sizeof protup.proterm, ' '); 171: else 172: { 173: pmove(pv->pv_val.pv_str, protup.proterm, sizeof protup.proterm, ' '); 174: if (!isttyname(pv->pv_val.pv_str)) 175: qmerror(BADTERM, -1, Qt.qt_resvar, pv->pv_val.pv_str, 0); 176: all_pro = FALSE; 177: } 178: pv++; 179: 180: /* read starting time of day */ 181: if (pv->pv_type != PV_INT) 182: syserr("d_prot: btod"); 183: protup.protodbgn = pv->pv_val.pv_int; 184: if (pv->pv_val.pv_int > 0) 185: all_pro = FALSE; 186: pv++; 187: 188: /* read ending time of day */ 189: if (pv->pv_type != PV_INT) 190: syserr("d_prot: etod"); 191: protup.protodend = pv->pv_val.pv_int; 192: if (pv->pv_val.pv_int < 24 * 60 - 1) 193: all_pro = FALSE; 194: pv++; 195: 196: /* read beginning day of week */ 197: if (pv->pv_type != PV_STR) 198: syserr("d_prot: bdow"); 199: i = cvt_dow(pv->pv_val.pv_str); 200: if (i < 0) 201: qmerror(BADDOW, -1, Qt.qt_resvar, pv->pv_val.pv_str, 0); /* bad dow */ 202: protup.prodowbgn = i; 203: if (i > 0) 204: all_pro = FALSE; 205: pv++; 206: 207: /* read ending day of week */ 208: if (pv->pv_type != PV_STR) 209: syserr("d_prot: edow"); 210: i = cvt_dow(pv->pv_val.pv_str); 211: if (i < 0) 212: qmerror(BADDOW, -1, Qt.qt_resvar, pv->pv_val.pv_str, 0); /* bad dow */ 213: protup.prodowend = i; 214: if (i < 6) 215: all_pro = FALSE; 216: pv++; 217: 218: /* 219: ** Check for valid tree: 220: ** There must be a tree defined, and all variables 221: ** referenced must be owned by the current user; this 222: ** is because you could otherwise get at data by 223: ** mentioning it in a permit statement; see protect.c 224: ** for a better explanation of this. 225: */ 226: 227: if (pv->pv_type != PV_QTREE) 228: syserr("d_prot: tree"); 229: root = (QTREE *) pv->pv_val.pv_qtree; 230: pv++; 231: 232: for (i = 0; i < MAXVAR + 1; i++) 233: { 234: if (Qt.qt_rangev[i].rngvdesc == NULL) 235: continue; 236: if (!bequal(Qt.qt_rangev[i].rngvdesc->reldum.relowner, Usercode, UCODE_SZ)) 237: qmerror(OWNEDNOT, -1, i, 0); 238: } 239: 240: /* test for dba */ 241: if (!bequal(Usercode, Admin.adhdr.adowner, UCODE_SZ)) 242: qmerror(NOTDBA, -1, Qt.qt_resvar, 0); 243: 244: /* get domain reference set from target list */ 245: /* (also, find the TREE node) */ 246: t = root->left; 247: if (t->sym.type == TREE) 248: { 249: for (i = 0; i < 8; i++) 250: protup.prodomset[i] = -1; 251: } 252: else 253: { 254: for (i = 0; i < 8; i++) 255: protup.prodomset[i] = 0; 256: for (; t->sym.type != TREE; t = t->left) 257: { 258: if (t->right->sym.type != VAR || 259: t->sym.type != RESDOM || 260: t->right->sym.value.sym_var.varno != Qt.qt_resvar) 261: syserr("d_prot: garbage tree"); 262: lsetbit(t->right->sym.value.sym_var.attno, protup.prodomset); 263: } 264: all_pro = FALSE; 265: } 266: 267: /* trim off the target list, since it isn't used again */ 268: root->left = t; 269: 270: /* 271: ** Check out the target relation. 272: ** We first save the varno of the relation which is 273: ** getting the permit stuff. Also, we check to see 274: ** that the relation mentioned is a base relation, 275: ** and not a view, since that tuple would never do 276: ** anything anyway. Finally, we clear the Qt.qt_resvar 277: ** so that it does not get output to the tree catalog. 278: ** This would result in a 'syserr' when we tried to 279: ** read it. 280: */ 281: 282: protup.proresvar = Qt.qt_resvar; 283: # ifdef xQTR3 284: if (Qt.qt_resvar < 0) 285: syserr("d_prot: Rv %d", Qt.qt_resvar); 286: # endif 287: if (bitset(S_VIEW, Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relstat)) 288: qmerror(NOTREALREL, -1, Qt.qt_resvar, 0); /* is a view */ 289: 290: /* clear the (unused) Qt.qt_qmode */ 291: # ifdef xQTR3 292: if (Qt.qt_qmode != mdPROT) 293: syserr("d_prot: Qt.qt_qmode %d", Qt.qt_qmode); 294: # endif 295: Qt.qt_qmode = -1; 296: 297: /* 298: ** Check for PERMIT xx to ALL case. 299: ** The relstat bits will be adjusted as necessary 300: ** to reflect these special cases. 301: ** 302: ** This is actually a little tricky, since we cannot 303: ** afford to turn off any permissions. If we already 304: ** have some form of PERMIT xx to ALL access, we must 305: ** leave it. 306: */ 307: 308: relstat = Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relstat; 309: if (all_pro && (protup.proopset & PRO_RETR) != 0) 310: { 311: if (protup.proopset == -1) 312: relstat &= ~S_PROTALL; 313: else 314: { 315: relstat &= ~S_PROTRET; 316: if ((protup.proopset & ~(PRO_RETR|PRO_AGGR|PRO_TEST)) != 0) 317: { 318: /* some special case: still insert prot tuple */ 319: all_pro = FALSE; 320: } 321: } 322: } 323: else 324: all_pro = FALSE; 325: 326: /* see if we are adding any tuples */ 327: if (!all_pro) 328: relstat |= S_PROTUPS; 329: 330: /* 331: ** Change relstat field in relation catalog if changed 332: */ 333: 334: if (relstat != Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relstat) 335: { 336: opencatalog("relation", OR_WRITE); 337: setkey(&Reldes, &relkey, Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relid, RELID); 338: setkey(&Reldes, &relkey, Qt.qt_rangev[Qt.qt_resvar].rngvdesc->reldum.relowner, RELOWNER); 339: i = getequal(&Reldes, &relkey, &reltup, &reltid); 340: if (i != 0) 341: syserr("d_prot: geteq %d", i); 342: reltup.relstat = relstat; 343: i = replace(&Reldes, &reltid, &reltup, FALSE); 344: if (i != 0) 345: syserr("d_prot: repl %d", i); 346: if (noclose(&Reldes) != 0) 347: syserr("d_prot: noclose(rel)"); 348: } 349: 350: Qt.qt_resvar = -1; 351: 352: if (!all_pro) 353: { 354: /* 355: ** Output the created tuple to the protection catalog 356: ** after making other internal adjustments and deter- 357: ** mining a unique sequence number (with the protect 358: ** catalog locked). 359: */ 360: 361: if (root->right->sym.type != QLEND) 362: protup.protree = puttree(root, protup.prorelid, protup.prorelown, mdPROT); 363: else 364: protup.protree = -1; 365: 366: /* compute unique permission id */ 367: opencatalog("protect", OR_WRITE); 368: setrll(A_SLP, Prodes.reltid.ltid, M_EXCL); 369: setkey(&Prodes, &prokey, protup.prorelid, PRORELID); 370: setkey(&Prodes, &prokey, protup.prorelown, PRORELOWN); 371: for (ix = 2; ; ix++) 372: { 373: setkey(&Prodes, &prokey, &ix, PROPERMID); 374: i = getequal(&Prodes, &prokey, &proxtup, &protid); 375: if (i < 0) 376: syserr("d_prot: geteq"); 377: else if (i > 0) 378: break; 379: } 380: protup.propermid = ix; 381: 382: /* do actual insert */ 383: i = insert(&Prodes, &protid, &protup, FALSE); 384: if (i < 0) 385: syserr("d_prot: insert"); 386: if (noclose(&Prodes) != 0) 387: syserr("d_prot: noclose(pro)"); 388: 389: /* clear the lock */ 390: unlrl(Prodes.reltid.ltid); 391: } 392: } 393: /* 394: ** CVT_DOW -- convert day of week 395: ** 396: ** Converts the day of the week from string form to a number. 397: ** 398: ** Parameters: 399: ** sdow -- dow in string form. 400: ** 401: ** Returns: 402: ** 0 -> 6 -- the encoded day of the week. 403: ** -1 -- error. 404: ** 405: ** Side Effects: 406: ** none 407: ** 408: ** Defines: 409: ** Dowlist -- a mapping from day of week to number. 410: ** cvt_dow 411: ** 412: ** Called By: 413: ** d_prot 414: */ 415: 416: struct downame 417: { 418: char *dow_name; 419: int dow_num; 420: }; 421: 422: struct downame Dowlist[] = 423: { 424: "sun", 0, 425: "sunday", 0, 426: "mon", 1, 427: "monday", 1, 428: "tue", 2, 429: "tues", 2, 430: "tuesday", 2, 431: "wed", 3, 432: "wednesday", 3, 433: "thu", 4, 434: "thurs", 4, 435: "thursday", 4, 436: "fri", 5, 437: "friday", 5, 438: "sat", 6, 439: "saturday", 6, 440: NULL 441: }; 442: 443: cvt_dow(sdow) 444: char *sdow; 445: { 446: register struct downame *d; 447: register char *s; 448: 449: s = sdow; 450: 451: for (d = Dowlist; d->dow_name != NULL; d++) 452: if (sequal(d->dow_name, s)) 453: return (d->dow_num); 454: return (-1); 455: } 456: /* 457: ** ISTTYNAME -- "is a legal terminal name" predicate 458: ** 459: ** Returns TRUE if the argument is a legal terminal name, 460: ** otherwise FALSE. 461: ** 462: ** It may make sense to have this routine check if the given 463: ** file name really exists. 464: ** 465: ** WARNING: 466: ** This routine may be installation-dependent! 467: ** 468: ** Parameters: 469: ** n -- the name to check. 470: ** 471: ** Returns: 472: ** TRUE -- n is a legal tty name at this installation. 473: ** FALSE -- otherwise. 474: ** 475: ** Side Effects: 476: ** none 477: ** 478: ** History: 479: ** 8/1/79 (eric) -- written. 480: */ 481: 482: 483: isttyname(n) 484: register char *n; 485: { 486: return (sequal(n, "console") || bequal(n, "tty", 3)); 487: }