/*{ ** Name: psy_qrymod - Process views, permits, and integrities ** ** Description: ** This function applies the qrymod algorithm to user queries. ** This algorithm is well-described in the specific functions ** psyview.c, psyinteg.c, and psypermit.c. It MUST be applied ** in the order: views, integrities, permits. This is because ** permits are on base tables, not on views, and we don't want ** the extra qualifications stuck on by the permit process to ** affect the integrities. ** ** Rules modifications are applied after all other query mods. ** Rules processing (in psyrules.c) may add statement trees to rule lists ** maintained in sess_cb. ** ** Inputs: ** qtree The query tree to modify ** sess_cb Current session control block ** psq_cb Calling control block ** num_joins ptr to a var containing number of joins ** in the query tree ** ** Outputs: ** qtree Can be modified by views, permits, ** and integrities ** sess_cb All kinds of miscellaneous stuff ** that is too detailed to describe here ** psq_cb ** .err_blk Filled in if an error happens ** ** *num_joins Will be incremented if any of the views ** involved in the query or any permits ** applied use joins. ** ** *resp_mask if the qmode==PSQ_VIEW will contain ** indicators of whether the view appears ** to be updateable and/or grantable view ** ** Returns: ** E_DB_OK Success ** E_DB_FATAL Failure ** Exceptions: ** none ** ** Side Effects: ** Can allocate memory ** Catalog I/O ** ** History: ** 09-jul-86 (jeff) ** Adapted from 4.0 qrymod() function ** 02-sep-86 (seputis) ** used result relation from auxiliary table since RDF ptrs are NULLed ** 18-sep-86 (daved) ** the result relation in the session cb is not always the ** same as the one found in the user range table. this is because ** the one in the range table is accurate only in an append statement. ** thus, we will now change the session cb to point to the correct ** result relation. ** 2-apr-87 (daved) ** set a pss_permit flag in the range table for each used entry. ** psy_permit will clear this flag. Psy_view will set this flag ** in all range entries that a derived from a table that still has ** this flag set, else it will clear this flag for new entries. ** We will then call psy_permit again, to catch all the new entries. ** 24-sep-87 (stec) ** Change error handling - call psf_error. ** 25-oct-87 (stec) ** Remove transaction creation, this is now done by SCF. ** 26-jan-89 (neil) ** Now also calls psy_rules to fill in rule tree. ** 08-mar-89 (neil) ** Calls psy_rules with more arguments. ** 22-jun-89 (andre) ** remove call to psy_protect() before call to psy_view() since ** psy_view() was modified to call psy_protect() before performing ** query modification on SQL views not belonging to the user. ** Additionally, &qtree will not be passed to psy_view(), since there ** is no apparent reason to do so (we no longer attempt to assign to ** the corresponding argument inside of psy_view() ) ** 24-jul-89 (jennifer) ** For each statement, indicate that audit information is NULL. ** 08-sep-89 (andre) ** recieve and pass to psy_view() and psy_permit() ptr to a var ** containing number of joins in the query tree. ** 19-sep-90 (andre) ** as a result of changes in psy_view(), we no longer need to call ** psy_permit() from psy_qrymod(). ** 13-dec-90 (ralph) ** Move reset of pss_audit to before psy_view invocation (b34903) ** 11-mar-91 (andre) ** if qmode is PSQ_VIEW, pass PSQ_RETRIEVE to psy_view(), psy_integ(), ** and psy_rules() + do not try to copy pss_usrrange to pss_auxrng ** since psy_dview() already placed the range table entries into ** pss_auxrng. ** (this is a part of fix for bug 33038) ** 07-aug-91 (andre) ** if qmode is PSQ_VIEW do NOT translate it to PSQ_RETRIEVE + ** if qmode is PSQ_VIEW do not bother calling psy_integ() and ** psy_rules() ** ** Added resp_mask to the argument list. This mask will be used to ** communicate info to the caller of psy_qrymod(). psy_qrymod() itself ** will not contribute anything to the information, instead, it will ** pass it to other functions (initially only to psy_view()) which will ** be responsible for providing the actual information. ** 30-dec-92 (andre) ** when processing a view tree in the course of processing CREATE RULE ** on a view we do NOT want to do any permit, rule, or integrity ** checking ** 04-jan-93 (andre) ** if we are processing DELETE, INSERT, or UPDATE, and a table or a ** view being updated has rules defined on it, set PSS_CHECK_RULES in ** sess_cb->pss_resrng->pss_var_mask to remind psy_view() to call ** psy_rules() ** ** since psy_dview() is going away, and psl_cview() calls psy_qrymod() ** with range variables as they were entered in the grammar, we must ** copy the range table from pss_usrrange to pss_auxrng for define VIEW ** just as we do for all other QUEL statements ** ** In most cases psy_rules() will NO LONGER be called from ** psy_qrymod(). It will be called from psy_view() when processing ** INSERT, DELETE, or UPDATE. This change was necessary because now ** rules can be defined on views, and it seemed reasonable that rule ** checking (just like privilege checking) can be driven from ** psy_view(). The once exception occurs when we are processing UPDATE ** WHERE CURRENT OF - psy_view() will simply return when presented with ** this query mode, but there may be rules that apply to this ** statement. Consequently, psy_rules() will be called from ** psy_qrymod() only when psq_qmode == PSQ_REPCURS ** 08-jan-93 (rblumer) ** set flag to bypass permission checking for dummy set-input ** range variables. ** 30-mar-93 (rblumer) ** set check_perms to false for system-generated procedures ** and for (internal) queries with PSS_NO_CHECKPERMS set. ** 01-apr-93 (andre) ** (fix for bugs 50823, 50825, and 50899) ** do not copy QUEL range table to aux. range table when processing ** REPLACE CURSOR - the entry describing the table/view over ** which the cursor has been defined has already been placed into ** pss_auxrng ** 08-apr-93 (andre) ** do not call psy_rules() explicitly for PSQ_REPCURS. psy_view() will ** now handle PSQ_REPCURS and call psy_rules() when necessary. ** 09-apr-93 (andre) ** set PSS_CHECK_RULES in the pss_var_mask corresponding to the ** table/view being updated via a cursor ** 26-apr-93 (markg) ** If the server is running C2 then initialize each range ** entry to show that it needs to be audited. ** 5-jul-93 (robf) ** If server is C2 then initialize any result range table to show ** it needs to be audited. ** 14-sep-93 (robf) ** Add QUERY_SYSCAT check, disallowing direct querying of ** base catalogs without privilege. This is done here rather than ** lower down in view/permit processing since we want to allow ** access to views on base catalogs (e.g. standard catalogs) ** to go ahead. ** 13-oct-93 (robf) ** Add <st.h> ** 25-oct-93 (stephenb) ** If the server is running C2 then also initialize the result range ** entry to show that it needs to be audited. ** 13-dec-93 (robf) ** When checking for query_syscat privilege, allow for extended ** catalogs. Some catalogs (like iistar_cdbs) have both the ** DMT_CATALOG and DMT_EXTENDED_CAT bits set. In this case we allow ** access since this priv restricts base catalogs only. ** 09-feb-94 (andre) ** fix for bug 59595: ** we also need to forego checking permits if we are parsing a ** system-generated query ** 11-jul-94 (robf) ** Restrict direct queries to table extensions the same way ** as system catalogs, i.e. to those with SELECT_SYSCAT privilege. ** The rationale for this is that info in extensions is really ** part of the base table, and to present an appropriately ** protected view of the data access should be through the base ** table, not directly at the extension. */ DB_STATUS psy_qrymod( PST_QNODE *qtree, PSS_SESBLK *sess_cb, PSQ_CB *psq_cb, PST_J_ID *num_joins, i4 *resp_mask) { PSS_RNGTAB *resrng; PSS_USRRANGE *rngtab = &sess_cb->pss_auxrng; PSF_MSTREAM *mstream = &sess_cb->pss_ostream; DB_ERROR *err_blk = &psq_cb->psq_error; i4 qmode = psq_cb->psq_mode; DB_STATUS status; i4 i; i4 check_perms = TRUE; GLOBALREF PSF_SERVBLK *Psf_srvblk; i4 err_code; bool can_query_syscat=FALSE; *resp_mask = 0L; /* init the response mask */ /* ** avoid permit checking when processing RULE trees, ** or when parsing/reparsing a system-generated procedure, ** or when parsing a system-generated query (e.g. a query to check whether ** constraints hold on existing data) */ if ((psq_cb->psq_mode == PSQ_RULE) || ( (sess_cb->pss_dbp_flags & PSS_DBPROC) && (sess_cb->pss_dbp_flags & PSS_SYSTEM_GENERATED)) || (psq_cb->psq_flag & PSQ_NO_CHECK_PERMS) || ( (psq_cb->psq_info != (PST_INFO *) NULL) && (psq_cb->psq_info->pst_execflags & PST_SYSTEM_GENERATED)) ) { check_perms = FALSE; } /* ** Can user directly query system catalogs ? ** Users with databse privilege QUERY_SYSCAT, or users with ** SECURITY subject privilege may directly query system cats */ if(psy_ckdbpr(psq_cb, DBPR_QUERY_SYSCAT)==E_DB_OK) can_query_syscat=TRUE; else if(sess_cb->pss_ustat&DU_USECURITY) can_query_syscat=TRUE; else can_query_syscat=FALSE; /* ** Reset pss_audit prior to calling psy_view. */ sess_cb->pss_audit = NULL; /* ** We don't want to clobber the user's view of the range table in ** the process of doing qrymod. Therefore, we will copy the user's ** range table to the auxiliary range table, and use that instead. */ /* don't need to copy range table for SQL because there are no range ** table entries that live longer than one statement ** ** REPLACE CURSOR places description of the table/view over which it is ** defined into pss_auxrng */ if ( sess_cb->pss_lang == DB_QUEL && qmode != PSQ_REPCURS) { status = pst_rgcopy(&sess_cb->pss_usrrange, rngtab, &sess_cb->pss_resrng, err_blk); if (DB_FAILURE_MACRO(status)) return (status); } for (i = 0; i < PST_NUMVARS; i++) { rngtab->pss_rngtab[i].pss_rgparent = -1; /* don't want to check permissions on ** set-input temporary tables */ if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT) rngtab->pss_rngtab[i].pss_permit = FALSE; else rngtab->pss_rngtab[i].pss_permit = check_perms; /* ** See if this is a real base catalog. ** We special case iidbcapabilities since its marked as a base ** catalog, but gets directly queried (and needs to be ** accessed by frontends) */ if(rngtab->pss_rngtab[i].pss_used && rngtab->pss_rngtab[i].pss_rgno != -1 && rngtab->pss_rngtab[i].pss_tabdesc && (( (rngtab->pss_rngtab[i].pss_tabdesc->tbl_2_status_mask&DMT_TEXTENSION) ) || ( (rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_CATALOG) && !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_VIEW) && !(rngtab->pss_rngtab[i].pss_tabdesc->tbl_status_mask&DMT_EXTENDED_CAT) && STncasecmp((char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name, "iidbcapabilities", GL_MAXNAME)!=0 )) ) { /* ** This is a base catalog. */ if(!can_query_syscat) { /* ** Error, user can't query base catalogs. */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) (VOID)psy_secaudit( FALSE, sess_cb, (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name, &rngtab->pss_rngtab[i].pss_tabdesc->tbl_owner, DB_MAXNAME, SXF_E_SECURITY, I_SX273B_QUERY_SYSCAT, (SXF_A_SELECT|SXF_A_FAIL), err_blk); (VOID) psf_error(E_PS035A_CANT_QUERY_SYSCAT, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(DB_NAME), (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name), (char*)&rngtab->pss_rngtab[i].pss_tabdesc->tbl_name); return E_DB_ERROR; } } /* ** If this is a C2 server set the PSS_DOAUDIT flag ** for this entry. */ if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE) rngtab->pss_rngtab[i].pss_var_mask |= PSS_DOAUDIT; } if (resrng = sess_cb->pss_resrng) { /* don't want to check permissions ** on set-input temporary tables */ if (rngtab->pss_rngtab[i].pss_rgtype == PST_SETINPUT) rngtab->pss_rngtab[i].pss_permit = FALSE; else rngtab->pss_rngtab[i].pss_permit = check_perms; /* ** if processing DELETE, UPDATE, INSERT, or UPDATE/REPLACE cursor, and ** there are rules defined on the view/table being updated, set ** PSS_CHECK_RULES in pss_var_mask */ if ( ( qmode == PSQ_APPEND || qmode == PSQ_DELETE || qmode == PSQ_REPLACE || qmode == PSQ_REPCURS ) && resrng->pss_tabdesc->tbl_status_mask & DMT_RULE ) { resrng->pss_var_mask |= PSS_CHECK_RULES; } /* ** If this is a C2 server set the PSS_DOAUDIT flag ** for the result table. */ if (Psf_srvblk->psf_capabilities & PSF_C_C2SECURE) rngtab->pss_rsrng.pss_var_mask |= PSS_DOAUDIT; } /* Apply view processing */ status = psy_view(mstream, qtree, rngtab, qmode, sess_cb, err_blk, num_joins, resp_mask); if (DB_FAILURE_MACRO(status)) { return (status); } /* ** do not check for existing INTEGRITIES when processing trees as a ** part of CREATE/DEFINE VIEW or CREATE RULE processing */ if (qmode != PSQ_VIEW && qmode != PSQ_RULE) { /* Apply integrity processing */ status = psy_integ(mstream, qtree, rngtab, resrng, qmode, sess_cb, &qtree, err_blk); if (DB_FAILURE_MACRO(status)) { return (status); } } return (status); }
/* ** Name psl_lm1_setlockstmnt() - perform semantic action for SETLOCKSTMNT ** production ** ** Description: ** perform semantic action for SETLOCKSTMNT production in QUEL and SQL ** grammars ** ** Input: ** sess_cb PSF session CB ** pss_distrib DB_3_DDB_SESS if distributed thread ** pss_ostream stream to be opened for memory allocation ** pss_stmt_flags PSS_SET_LOCKMODE_SESS if SET LOCKMODE SESSION ** psq_cb PSF request CB ** ** Output: ** sess_cb ** pss_ostream stream has been opened for memory allocation ** pss_object point to the root of a new QSF object ** (of type (DMC_CB *) or (QEF_RCB *)). ** psq_cb ** psq_mode set to PSQ_SLOCKMODE ** psq_error filled in if an error occurred ** ** Returns: ** E_DB_{OK, ERROR, SEVERE} ** ** Side effects: ** Opens a memory stream and allocates memory ** ** History: ** 07-mar-91 (andre) ** plagiarized from SETLOCKSTMNT production ** 17-apr-92 (barbara) ** Updated for Sybil. Distributed thread allocates QEF_RCB and ** calls QEF directly. ** 07-oct-93 (swm) ** Bug #56437 ** added PTR cast in assignment to dmc_cb->dmc_id. ** 09-oct-93 (swm) ** Bug #56437 ** Put pss_sessid into new dmc_session_id rather than dmc_id. ** 26-Feb-2001 (jenjo02) ** Set session_id in QEF_RCB; ** 11-Jun-2010 (kiria01) b123908 ** Initialise pointers after psf_mopen would have invalidated any ** prior content. */ DB_STATUS psl_lm1_setlockstmnt( PSS_SESBLK *sess_cb, PSQ_CB *psq_cb) { DB_STATUS status; i4 err_code; DMC_CB *dmc_cb; DB_ERROR err_blk; DB_STATUS tempstat; psq_cb->psq_mode = PSQ_SLOCKMODE; /* Verify the user has LOCKMODE permission */ status = psy_ckdbpr(psq_cb, (u_i4) DBPR_LOCKMODE); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(6247L, 0L, PSF_USERERR, &err_code, &psq_cb->psq_error, 0); /* ** Audit failed set lockmode */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { (VOID)psy_secaudit( FALSE, sess_cb, "LOCKMODE", (DB_OWN_NAME *)0, 8, SXF_E_RESOURCE, I_SX2741_SET_LOCKMODE, SXF_A_FAIL|SXF_A_LIMIT, &err_blk); } return(status); } /* Create control block for DMC_ALTER or QEF_CALL for set lockmode */ status = psf_mopen(sess_cb, QSO_QP_OBJ, &sess_cb->pss_ostream, &psq_cb->psq_error); if (status != E_DB_OK) return (status); sess_cb->pss_stk_freelist = NULL; if (sess_cb->pss_distrib & DB_3_DDB_SESS) { /* Distributed thread calls QEF directly */ QEF_RCB *qef_rcb; status = psf_malloc(sess_cb, &sess_cb->pss_ostream, sizeof(QEF_RCB), &sess_cb->pss_object, &psq_cb->psq_error); if (status != E_DB_OK) return (status); status = psf_mroot(sess_cb, &sess_cb->pss_ostream, sess_cb->pss_object, &psq_cb->psq_error); if (status != E_DB_OK) return (status); /* Fill in the QEF control block */ qef_rcb = (QEF_RCB *) sess_cb->pss_object; qef_rcb->qef_length = sizeof(QEF_RCB); qef_rcb->qef_type = QEFRCB_CB; qef_rcb->qef_owner = (PTR)DB_PSF_ID; qef_rcb->qef_ascii_id = QEFRCB_ASCII_ID; qef_rcb->qef_modifier = QEF_MSTRAN; qef_rcb->qef_flag = 0; qef_rcb->qef_cb = (QEF_CB *) NULL; qef_rcb->qef_sess_id = sess_cb->pss_sessid; return (E_DB_OK); } status = psf_malloc(sess_cb, &sess_cb->pss_ostream, sizeof(DMC_CB), (PTR *) &dmc_cb, &psq_cb->psq_error); if (status != E_DB_OK) return (status); status = psf_mroot(sess_cb, &sess_cb->pss_ostream, (PTR) dmc_cb, &psq_cb->psq_error); if (status != E_DB_OK) return (status); sess_cb->pss_object = (PTR) dmc_cb; dmc_cb->type = DMC_CONTROL_CB; dmc_cb->length = sizeof (DMC_CB); dmc_cb->dmc_op_type = DMC_SESSION_OP; dmc_cb->dmc_session_id = (PTR)sess_cb->pss_sessid; dmc_cb->dmc_flags_mask = DMC_SETLOCKMODE; dmc_cb->dmc_db_id = sess_cb->pss_dbid; dmc_cb->dmc_db_access_mode = dmc_cb->dmc_lock_mode = 0; /* need to allocate characteristics array with MAX_LOCKMODE_CHARS entries */ status = psf_malloc(sess_cb, &sess_cb->pss_ostream, sizeof(DMC_CHAR_ENTRY) * MAX_LOCKMODE_CHARS, (PTR *) &dmc_cb->dmc_char_array.data_address, &psq_cb->psq_error); if (status != E_DB_OK) return (status); dmc_cb->dmc_char_array.data_in_size = 0; /* ** Audit allowed to issue lockmode */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { (VOID)psy_secaudit( FALSE, sess_cb, "LOCKMODE", (DB_OWN_NAME *)0, 8, SXF_E_RESOURCE, I_SX2741_SET_LOCKMODE, SXF_A_SUCCESS|SXF_A_LIMIT, &err_blk); } return(E_DB_OK); }