/*{ ** Name: psy_dpermit - Define a permit. ** ** INTERNAL PSF call format: status = psy_dpermit(&psy_cb, sess_cb); ** ** EXTERNAL call format: status = psy_call(PSY_DPERMIT, &psy_cb, sess_cb); ** ** Description: ** Given all of the parameters necessary to CREATE/DEFINE a permit on a ** table or view, this function will store the permission in the system ** catalogs. This will include storing the query tree in the tree table, ** storing the text of the query in the iiqrytext table (really done by ** QEF), storing a row in the protect table, and issuing an "alter table" ** operation to DMF to indicate that there are permissions on the given ** table. ** ** Inputs: ** psy_cb ** .psy_qrytext Id of query text as stored in QSF. ** .psy_cols[] Array of columns on which to grant ** permission ** .psy_numcols Number of columns listed above; 0 means ** give permission on all columns ** .psy_intree QSF id of query tree representing the ** where clause in the permit ** .psy_opctl Bit map of defined operations ** .psy_opmap Bit map of permitted operations ** .psy_user Name of user who will get permission ** .psy_terminal Terminal at which permission is given ** (blank if none specified) ** .psy_timbgn Time of day at which the permission ** begins (minutes since 00:00) ** .psy_timend Time of day at which the permission ends ** (minutes since 00:00) ** .psy_daybgn Day of week at which the permission ** begins (0 = Sunday) ** .psy_dayend Day of week at which the permission ends ** (0 = Sunday) ** .psy_grant ** PSY_CPERM CREATE/DEFINE PERMIT ** .psy_tblq head of table queue ** .psy_colq head of column queue ** .psy_usrq head of user queue ** .psy_qlen length of first iiqrytext ** .psy_flags useful info ** PSY_EXCLUDE_COLUMNS user specified a list of columns to ** which privilege should not apply ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_txtid Id of query text as stored in the ** iiqrytext system relation. ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_FATAL Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** Stores text of query in iiqrytext relation, query tree in tree ** relation, row in protect relation identifying the permit. Does ** an alter table DMF operation to indicate that there are permissions ** on the table. ** ** History: ** 02-oct-85 (jeff) ** written ** 03-sep-86 (seputis) ** changed some psy_cb. to psy_cb-> ** added .db_att_id reference ** changed rdr_cb. rdr_cb-> ** 02-dec-86 (daved) ** bug fixing. check for permit on tables owned by user and not ** view. ** 29-apr-87 (stec) ** Implemented changes for GRANT statement. ** 10-may-88 (stec) ** Make changes for db procs. ** 03-oct-88 (andre) ** Modified call to pst_rgent to pass 0 as a query mode since it is ** clearly not PSQ_DESTROY ** 06-feb-89 (ralph) ** Added support for 300 attributes: ** Use DB_COL_BITS in place of DB_MAX_COLS ** Loop over domset array using DB_COL_WORDS ** 06-mar-89 (ralph) ** GRANT Enhancements, Phase 1: ** Initialize new DB_PROTECTION fields, dbp_seq and dbp_gtype ** 03-apr-89 (ralph) ** GRANT Enhancements, Phase 2: ** Use DBGR_USER when initializing dbp_gtype ** 08-may-89 (ralph) ** Initialize reserved field to blanks (was \0) ** 04-jun-89 (ralph) ** Initialize dbp_fill1 to zero ** Fix unix portability problems ** 02-nov-89 (neil) ** Alerters: Allowed privileges for events. ** 1-mar-90 (andre) ** If processing a GRANT on tables, check if ** ALL-TO-ALL or RETRIEVE-TO-ALL has already been granted, and if so, ** mark psy_mask appropriately. ** If user tried to CREATE ALL/RETRIEVE-TO-ALL, and one already exists, ** skip to the exit. ** 12-mar-90 (andre) ** set rdr_2types_mask to 0. ** 22-may-90 (teg) ** init rdr_instr to RDF_NO_INSTR ** 08-aug-90 (ralph) ** Initialize new fields in iiprotect tuple ** 14-dec-90 (ralph) ** Disallow use of GRANT by non-DBA if xORANGE ** 11-jan-90 (ralph) ** Allow user "$ingres" to use GRANT if xORANGE. ** This was done for CREATEDB (UPGRADEFE). ** 20-feb-91 (andre) ** For CREATE/DEFINE PERMIT, grantee type was stored in ** psy_cb->psy_gtype. ** 24-jun-91 (andre) ** IIPROTECT tuples for table permits will contain exactly one ** privilege. IIQRYTEXT template built for table-wide privileges ** contains a placeholder for a privilege name which will be filled in ** with each of the table-wide privileges being granted, one at a time. ** PSY_CB.psy_opmap will be set to correspond with privilege name ** stored in the IIQRYTEXT permit. ** 16-jul-91 (andre) ** responsibility for splitting permit tuples will passed on to ** qeu_cprot(). If a permit specified only one privilege, we will ** substitute the appropriate privilege name here and will not ask ** qeu_cprot() to split tuples. ** 06-aug-91 (andre) ** before proceeding to CREATE a permit on a view owned by the current ** user, we will call psy_tbl_grant_check() to ensure that this user ** may create a permit on his view. If the object is not owned by the ** current user, we will not try to verify that the user may ** CREATE/DEFINE a permit since (until the relevant FE changes are ** made) we intend to continue allowing any user with CATUPD to ** CREATE/DEFINE permits on catalogs and the dba will be allowed to ** CREATE/DEFINE permits on extended catalogs ** 11-nov-91 (rblumer) ** merged from 6.4: 26-feb-91 (andre) ** PST_QTREE was changed to store the range table as an array of ** pointers to PST_RNGENTRY structure. ** 14-feb-92 (andre) ** we will no longer have to fill in privilege name for permits ** specifying one privilege - it will be handled in respective ** grammars. ** 15-jun-92 (barbara) ** For Sybil, change interface to pst_rgent(), Star returns from ** psy_dpermit before permits get stored. ** 07-jul-92 (andre) ** DB_PROTECTION tuple will contain an indicator of how the permit was ** created, i.e. whether it was created using SQL or QUEL and if the ** former, then whether it was created using GRANT statement. Having ** this information will facilitate merging similar and identical ** permit tuples. ** 14-jul-92 (andre) ** semantics of GRANT ALL [PRIVILEGES] is different from that of ** CREATE PERMIT ALL in that the former (as dictated by SQL92) means ** "grant all privileges which the current auth id posesses WGO" ** whereas the latter (as is presently interpreted) means "grant all ** privileges that can be defined on the object" which in case of ** tables and views means SELECT, INSERT, DELETE, UPDATE. ** psy_tbl_grant_check() (function responsible for determining whether ** a user may grant specified privilege on a specified table or view) ** will have to be notified whether we are processing GRANT ALL. Its ** behaviour will change as follows: ** - if processing GRANT ALL and psy_tbl_grant_check() determines ** that the user does not possess some (but not all) of the ** privileges passed to it by the caller it will not treat it as an ** error, but will instead inform the caller of privileges that the ** user does not posess, ** - if processing GRANT ALL and psy_tbl_grant_check() determines ** that the user does not possess any of the privileges passed to ** it by the caller it will treat it as an error ** - if processing a statement other than GRANT ALL and ** psy_tbl_grant_check() determines that the user does not possess ** some of the privileges passed to it by the caller it will treat ** it as an error ** 16-jul-92 (andre) ** if a permit being created depends on some privileges, build a ** structure describing these privileges and store its address in ** rdf_cb->rdr_indep. ** 18-jul-92 (andre) ** we will no longer be telling QEF to turn off DMT_ALL_PROT or ** DMT_RETRIEVE_PRO when a user creates ALL/RETRIEVE TO ALL permit. ** QEF will figure out on its own whether PUBLIC now has RETRIEVE or ** ALL on a table/view ** 20-jul-92 (andre) ** if user specified a list of columns to which privilege(s) should ** not apply, set dbp_domset correctly ** 03-aug-92 (barbara) ** Invalidate base table infoblk from RDF cache for CREATE PERMIT ** and CREATE SEC_ALARM. ** 16-sep-92 (andre) ** privilege maps are build using bitwise ops, so care should be ** exercised when accessing it using BT*() functions ** 17-jun-93 (andre) ** changed interface of psy_secaudit() to accept PSS_SESBLK ** 5-jul-93 (robf) ** changed interface of psy_secaudit() to accept security label ** 7-jan-94 (swm) ** Bug #58635 ** Added PTR cast for qsf_owner which has changed type to PTR. ** 06-mar-96 (nanpr01) ** Move the QSF request block initialization up. because if ** pst_rgnent returns a failure status code, subsequent QSF ** calls get bad control block error. */ DB_STATUS psy_dpermit( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { RDF_CB rdf_cb; register RDR_RB *rdf_rb = &rdf_cb.rdf_rb; QSF_RCB qsf_rb; DB_STATUS status; DB_STATUS stat; DB_PROTECTION ptuple; register DB_PROTECTION *protup = &ptuple; i4 *domset = ptuple.dbp_domset; register i4 i, j; i4 err_code; PSS_RNGTAB *rngvar; PSS_USRRANGE *rngtab; PST_PROCEDURE *pnode; PST_QTREE *qtree; DB_ERROR *err_blk = &psy_cb->psy_error; i4 textlen; i4 tree_lock = 0; i4 text_lock = 0; DB_TAB_ID tabids[PST_NUMVARS]; PSQ_INDEP_OBJECTS indep_objs; PSQ_OBJPRIV obj_priv; /* space for independent DELETE */ PSQ_COLPRIV col_privs[2]; /* ** space for independent INSERT and ** UPDATE */ PST_VRMAP varmap; PSY_TBL *psy_tbl; DB_TIME_ID timeid; DB_NAME *objname; /* ** For CREATE/DEFINE PERMIT execute code below. */ /* initialize the QSF control block */ qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; rngtab = &sess_cb->pss_auxrng; /* table info is stored in the only entry in the table queue */ psy_tbl = (PSY_TBL *) psy_cb->psy_tblq.q_next; status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID, (DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL, &psy_tbl->psy_tabid, TRUE, &rngvar, (i4) 0, err_blk); if (DB_FAILURE_MACRO(status)) goto exit; /* In STAR, we do not actually store permits */ if (sess_cb->pss_distrib & DB_3_DDB_SESS) { qsf_rb.qsf_lk_state = QSO_EXLOCK; goto exit; } /* Fill in the RDF request block */ pst_rdfcb_init(&rdf_cb, sess_cb); /* The table which is receiving the permit */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, rdf_rb->rdr_tabid); /* Tell RDF we're doing a permit definition */ rdf_rb->rdr_update_op = RDR_APPEND; rdf_rb->rdr_types_mask = RDR_PROTECT; rdf_rb->rdr_qrytuple = (PTR) protup; /* initialize independent object structure */ indep_objs.psq_objs = (PSQ_OBJ *) NULL; indep_objs.psq_objprivs = (PSQ_OBJPRIV *) NULL; indep_objs.psq_colprivs = (PSQ_COLPRIV *) NULL; indep_objs.psq_grantee = &sess_cb->pss_user; rdf_rb->rdr_indep = (PTR) &indep_objs; /* ** populate the IIPROTECT tuple */ /* Zero out the template */ (VOID)MEfill(sizeof(ptuple), (u_char) 0, (PTR) protup); /* store grantee type */ protup->dbp_gtype = psy_cb->psy_gtype; /* Init reserved block */ (VOID)MEfill(sizeof(protup->dbp_reserve), (u_char) ' ', (PTR) protup->dbp_reserve); /* Init obj name */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabnm, protup->dbp_obname); /*@FIX_ME@ Where does this come from? */ protup->dbp_obstat = ' '; /* store the object type indicator */ if (psy_tbl->psy_mask & PSY_OBJ_IS_TABLE) { protup->dbp_obtype = DBOB_TABLE; } else if (psy_tbl->psy_mask & PSY_OBJ_IS_VIEW) { protup->dbp_obtype = DBOB_VIEW; } else { protup->dbp_obtype = DBOB_INDEX; } STRUCT_ASSIGN_MACRO(psy_tbl->psy_owner, protup->dbp_obown); STRUCT_ASSIGN_MACRO(sess_cb->pss_user, protup->dbp_grantor); TMnow((SYSTIME *)&timeid); protup->dbp_timestamp.db_tim_high_time = timeid.db_tim_high_time; protup->dbp_timestamp.db_tim_low_time = timeid.db_tim_low_time; /* The table on which we're giving permission */ STRUCT_ASSIGN_MACRO(psy_tbl->psy_tabid, protup->dbp_tabid); /* Beginning and ending times of day */ protup->dbp_pdbgn = psy_cb->psy_timbgn; protup->dbp_pdend = psy_cb->psy_timend; /* Beginning and ending days of week */ protup->dbp_pwbgn = psy_cb->psy_daybgn; protup->dbp_pwend = psy_cb->psy_dayend; if (psy_cb->psy_numcols != 0 && ~psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS) { /* user specified a list of columns to which privilege(s) will apply */ /* Bit map of permitted columns */ psy_fill_attmap(domset, ((i4) 0)); for (i = 0; i < psy_cb->psy_numcols; i++) { BTset((i4)psy_cb->psy_cols[i].db_att_id, (char *) domset); } } else { /* ** user specified table-wide privilege(s) or a list of columns L s.t. ** privilege(s) will apply to the entire table except for columns in L */ psy_fill_attmap(domset, ~((i4) 0)); if (psy_cb->psy_flags & PSY_EXCLUDE_COLUMNS) { /* ** exclude specified columns from the list of columns to which ** privilege(s) will apply */ for (i = 0; i < psy_cb->psy_numcols; i++) { BTclear((i4) psy_cb->psy_cols[i].db_att_id, (char *) domset); } } } if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW) { /* ** if view is owned by the current user, psy_tbl_grant_check() will ** determine if the permit can, indeed, be created; as long as we are ** preserving the kludge that allows users with CATUPD create permits on ** catalogs and DBAs to create permits on extended catalogs, we shall ** not call psy_tbl_grant_check() on view not owned by the current user, ** since it is likely to result in psy_tbl_grant_check() complaining ** about inadequate permissions */ if (!MEcmp((PTR) &rngvar->pss_ownname, (PTR) &sess_cb->pss_user, sizeof(sess_cb->pss_user))) { i4 tbl_wide_privs; PSY_COL_PRIVS col_specific_privs, *csp, indep_col_specific_privs; DB_TAB_ID indep_id; i4 indep_tbl_wide_privs; bool insuf_privs, quel_view; i4 val1, val2; /* ** build maps of table-wide and column-specific privileges for ** psy_tbl_grant_check() ** if a column list was specified with CREATE PERMIT and ** privileges specified in the statement include a set of ** privileges S s.t. for all P in S, P can only be specified as ** table-wide with GRANT statement (currently this includes ** SELECT, INSERT, DELETE), we will make ** psy_tbl_grant_check() think that privileges in S are ** table-wide. ** This will work correctly since if the view was defined over ** some objects owned by other user(s), for every P in S we ** would need table-wide privilege WGO on the underlying object. ** ** For the purposes of providing more descriptive output for ** trace point ps131, if column-list was specified, we will pass ** the map of attributes even if column-specific UPDATE was not ** specified */ if (psy_cb->psy_numcols != 0 && (psy_cb->psy_opmap & DB_REPLACE || ult_check_macro(&sess_cb->pss_trace, 3, &val1, &val2) ) ) { i4 *ip; csp = &col_specific_privs; /* ** column-specific UPDATE privilege will not be translated into ** a table-wide privilege since GRANT allows for specification ** of column-specific UPDATE privilege */ csp->psy_col_privs = psy_cb->psy_opmap & DB_REPLACE; tbl_wide_privs = psy_cb->psy_opmap & ~DB_REPLACE; /* ** if creating a permit on a set of columns and UPDATE is not ** one of the privileges named in the statement, store the ** attribute map in the first element of the attribute map list */ ip = (csp->psy_col_privs) ? csp->psy_attmap[PSY_UPDATE_ATTRMAP].map : csp->psy_attmap->map; /* copy the attribute map */ for (i = 0; i < DB_COL_WORDS; i++, ip++) { *ip = domset[i]; } } else { tbl_wide_privs = psy_cb->psy_opmap; csp = (PSY_COL_PRIVS *) NULL; } status = psy_tbl_grant_check(sess_cb, (i4) PSQ_PROT, &rngvar->pss_tabid, &tbl_wide_privs, csp, &indep_id, &indep_tbl_wide_privs, &indep_col_specific_privs, psy_cb->psy_flags, &insuf_privs, &quel_view, &psy_cb->psy_error); if (DB_FAILURE_MACRO(status)) { goto exit; } if (insuf_privs) { /* must audit failure to create a permit */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { DB_ERROR e_error; /* Must audit CREATE PERMIT failure. */ status = psy_secaudit(FALSE, sess_cb, (char *)&rngvar->pss_tabdesc->tbl_name, &rngvar->pss_tabdesc->tbl_owner, sizeof(DB_TAB_NAME), SXF_E_TABLE, I_SX2016_PROT_TAB_CREATE, SXF_A_FAIL | SXF_A_CREATE, &e_error); status = (status > E_DB_ERROR) ? status : E_DB_ERROR; } goto exit; } else if (quel_view) { goto exit; } /* ** If user is trying to grant one or more of ** INSERT/DELETE/UPDATE on his/her view whose underlying table ** or view is owned by another user, psy_tbl_grant_check() will ** return id of the underlying object along with map of ** privileges. We will convert maps of independent privileges ** into elements of independent privilege list and pass them ** along to QEF */ if ( indep_id.db_tab_base != (i4) 0 && ( indep_id.db_tab_base != rngvar->pss_tabid.db_tab_base || indep_id.db_tab_index != rngvar->pss_tabid.db_tab_index ) ) { if (indep_tbl_wide_privs & DB_DELETE) { /* ** the only expected independent table-wide privilege ** is DELETE */ obj_priv.psq_next = (PSQ_OBJPRIV *) NULL; obj_priv.psq_objtype = PSQ_OBJTYPE_IS_TABLE; obj_priv.psq_privmap = (i4) DB_DELETE; obj_priv.psq_objid.db_tab_base = indep_id.db_tab_base; obj_priv.psq_objid.db_tab_index = indep_id.db_tab_index; indep_objs.psq_objprivs = &obj_priv; } if (indep_col_specific_privs.psy_col_privs) { i4 i, j; PSQ_COLPRIV *csp; i4 *att_map, *p; i4 priv_map = 0; /* ** privilege map is built using bitwise operators, but ** here using BTnext() makes code much more palatable, ** so convert a privilege map */ if (indep_col_specific_privs.psy_col_privs & DB_APPEND) BTset(DB_APPP, (char *) &priv_map); if (indep_col_specific_privs.psy_col_privs & DB_REPLACE) BTset(DB_REPP, (char *) &priv_map); for (i = -1, csp = col_privs; (i = BTnext(i, (char *) &priv_map, BITS_IN(priv_map))) != -1; csp++ ) { csp->psq_next = indep_objs.psq_colprivs; indep_objs.psq_colprivs = csp; csp->psq_objtype = PSQ_OBJTYPE_IS_TABLE; csp->psq_tabid.db_tab_base = indep_id.db_tab_base; csp->psq_tabid.db_tab_index = indep_id.db_tab_index; switch (i) { case DB_APPP: /* INSERT privilege */ { csp->psq_privmap = (i4) DB_APPEND; att_map = indep_col_specific_privs. psy_attmap[PSY_INSERT_ATTRMAP].map; break; } case DB_REPP: { csp->psq_privmap = (i4) DB_REPLACE; att_map = indep_col_specific_privs. psy_attmap[PSY_UPDATE_ATTRMAP].map; break; } } for (p = csp->psq_attrmap, j = 0; j < DB_COL_WORDS; j++) { *p++ = *att_map++; } } } } } else { /* ** either this is a catalog and the user has CATUPD or ** this is an extended catalog and the user is the DBA; ** since we may be allowing a user to create a permit by ** circumventing the permit system, we only need to ascertain that ** this is an SQL view */ i4 issql = 0; status = psy_sqlview(rngvar, sess_cb, err_blk, &issql); if (status) { goto exit; } if (!issql) { /* can only have permits on SQL views */ psf_error(3598L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(rngvar->pss_tabname), (char *) &rngvar->pss_tabname), &rngvar->pss_tabname); status = E_DB_ERROR; goto exit; } } } /* Name of user getting permission */ STRUCT_ASSIGN_MACRO(psy_cb->psy_user, protup->dbp_owner); /* Terminal at which permission given */ STRUCT_ASSIGN_MACRO(psy_cb->psy_terminal, protup->dbp_term); /* Give RDF pointer to query tree, if any */ if (!psy_cb->psy_istree) { rdf_rb->rdr_qry_root_node = (PTR) NULL; } else { PST_VRMAP varset; i4 j; STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id); qsf_rb.qsf_lk_state = QSO_EXLOCK; status = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); goto exit; } tree_lock = qsf_rb.qsf_lk_id; pnode = (PST_PROCEDURE *) qsf_rb.qsf_root; qtree = (PST_QTREE *) pnode->pst_stmts->pst_specific.pst_tree; rdf_rb->rdr_qry_root_node = (PTR) pnode; /* check for no views in the qualification. */ (VOID)psy_varset(qtree->pst_qtree, &varset); j = BTnext(-1, (char *) &varset, BITS_IN(varset)); for ( ; j >= 0; j = BTnext(j, (char *) &varset, BITS_IN(varset))) { status = pst_rgent(sess_cb, rngtab, -1, "", PST_SHWID, (DB_TAB_NAME *) NULL, (DB_TAB_OWN *) NULL, &qtree->pst_rangetab[j]->pst_rngvar, TRUE, &rngvar, (i4) 0, err_blk); if (status) goto exit; if (rngvar->pss_tabdesc->tbl_status_mask & DMT_VIEW) { psf_error(3597L, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(rngvar->pss_tabname), (char *) &rngvar->pss_tabname), &rngvar->pss_tabname); status = E_DB_ERROR; goto exit; } } } /* Give RDF a pointer to the query text to be stored in iiqrytext */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); qsf_rb.qsf_lk_state = QSO_EXLOCK; status = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_error(E_PS0D19_QSF_INFO, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, err_blk, 0); goto exit; } text_lock = qsf_rb.qsf_lk_id; MEcopy((char *) qsf_rb.qsf_root, sizeof(i4), (char *) &textlen); rdf_rb->rdr_l_querytext = textlen; rdf_rb->rdr_querytext = ((char *) qsf_rb.qsf_root) + sizeof(i4); rdf_rb->rdr_status = (sess_cb->pss_lang == DB_SQL) ? DB_SQL : 0; /* determine if the permit specifies exactly one privilege */ if (BTcount((char *) &psy_cb->psy_opmap, BITS_IN(psy_cb->psy_opmap)) > 1) { /* ** if permit specified more than one privilege, notify QEF that it will ** have to split the permit into multiple IIPROTECT tuples */ rdf_rb->rdr_instr |= RDF_SPLIT_PERM; } else if (psy_cb->psy_opmap & DB_RETRIEVE) { /* ** if qeu_cprot() will not be splitting the permit into multiple tuples ** and RETRIEVE is the privilege mentioned in it, set the two bits ** associated with DB_RETRIEVE */ psy_cb->psy_opmap |= DB_TEST | DB_AGGREGATE; psy_cb->psy_opctl |= DB_TEST | DB_AGGREGATE; } /* Null out the DMU control block pointer, just in case */ rdf_rb->rdr_dmu_cb = (PTR) NULL; /* produce list of dependent tables */ rdf_rb->rdr_cnt_base_id = 0; if (psy_cb->psy_istree && qtree->pst_qtree) { j = 0; (VOID)psy_varset(qtree->pst_qtree, &varmap); for (i = -1; (i = BTnext(i, (char*) &varmap, PST_NUMVARS)) > -1;) { /* if this is the table that is getting the permit, ignore */ if (qtree->pst_rangetab[i]->pst_rngvar.db_tab_base != psy_tbl->psy_tabid.db_tab_base || qtree->pst_rangetab[i]->pst_rngvar.db_tab_index != psy_tbl->psy_tabid.db_tab_index ) { rdf_rb->rdr_cnt_base_id++; STRUCT_ASSIGN_MACRO(qtree->pst_rangetab[i]->pst_rngvar, tabids[j++]); } } rdf_rb->rdr_base_id = tabids; } protup->dbp_popctl = psy_cb->psy_opctl; protup->dbp_popset = psy_cb->psy_opmap; /* ** store an indication of whether this permit is being created using SQL or ** QUEL */ protup->dbp_flags = (sess_cb->pss_lang == DB_SQL) ? DBP_SQL_PERM : (i2) 0; protup->dbp_flags |= DBP_65_PLUS_PERM; /* Now let RDF do all the work of the permit definition */ status = rdf_call(RDF_UPDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { if (rdf_cb.rdf_error.err_code == E_RD0002_UNKNOWN_TBL) { (VOID) psf_error(E_PS0903_TAB_NOTFOUND, 0L, PSF_USERERR, &err_code, err_blk, 1, psf_trmwhite(sizeof(psy_tbl->psy_tabnm), (char *) &psy_tbl->psy_tabnm), &psy_tbl->psy_tabnm); } else { (VOID) psf_rdf_error(RDF_UPDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } goto exit; } /* ** Invalidate base object's infoblk from RDF cache. */ pst_rdfcb_init(&rdf_cb, sess_cb); STRUCT_ASSIGN_MACRO(psy_cb->psy_tables[0], rdf_rb->rdr_tabid); status = rdf_call(RDF_INVALIDATE, (PTR) &rdf_cb); if (DB_FAILURE_MACRO(status)) { (VOID) psf_rdf_error(RDF_INVALIDATE, &rdf_cb.rdf_error, &psy_cb->psy_error); } exit: qsf_rb.qsf_lk_state = QSO_EXLOCK; if (psy_cb->psy_istree) { /* Destroy query tree */ STRUCT_ASSIGN_MACRO(psy_cb->psy_intree, qsf_rb.qsf_obj_id); if ((qsf_rb.qsf_lk_id = tree_lock) == 0) { stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } tree_lock = qsf_rb.qsf_lk_id; } stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } tree_lock = 0; } /* Destroy query text */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); if ((qsf_rb.qsf_lk_id = text_lock) == 0) { stat = qsf_call(QSO_LOCK, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } text_lock = qsf_rb.qsf_lk_id; } stat = qsf_call(QSO_DESTROY, &qsf_rb); if (DB_FAILURE_MACRO(stat)) { (VOID) psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (!status || stat == E_DB_FATAL) status = stat; } return (status); }
/*{ ** 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: psy_group - Dispatch group identifier qrymod routines ** ** INTERNAL PSF call format: status = psy_group(&psy_cb, sess_cb); ** EXTERNAL call format: status = psy_call (PSY_GROUP,&psy_cb, sess_cb); ** ** Description: ** This procedure checks the psy_grpflag field of the PSY_CB ** to determine which qrymod processing routine to call: ** PSY_CGROUP results in call to psy_cgroup() ** PSY_AGROUP results in call to psy_agroup() ** PSY_DGROUP results in call to psy_dgroup() ** PSY_KGROUP results in call to psy_kgroup() ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_grpflag Group identifier operation ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** None. ** ** History: ** 12-mar-89 (ralph) ** written ** 20-may-89 (ralph) ** Allow multiple groups to be specified. ** 29-jul-89 (jennifer) ** Added auditing of failure to perform operation. ** 30-oct-89 (ralph) ** Use pss_ustat for authorization check. ** 10-mar-93 (markg) ** Fix bug where audit of failed group operations ** was coded incorrectly. ** 17-jun-93 (andre) ** changed interface of psy_secaudit() to accept PSS_SESBLK ** 16-aug-93 (stephenb) ** Changed call to psy_secaudit() to audit SXF_E_SECURITY instead ** of SXF_E_USER, group manipulation is a security event not a ** user event. ** 18-may-1993 (robf) ** Replaced SUPERUSER priv. ** Add security label to psy_secaudit() call ** 2-nov-93 (robf) ** Enforce MAINTAIN_USERS priv to access user groups. */ DB_STATUS psy_group( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status = E_DB_OK; i4 err_code; char dbname[DB_DB_MAXNAME]; SCF_CB scf_cb; SCF_SCI sci_list[1]; bool leave_loop = TRUE; /* This code is called for SQL only */ /* Make sure user is authorized and connected to iidbdb */ do { if (!(sess_cb->pss_ustat & DU_UMAINTAIN_USER)) { if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { DB_ERROR e_error; i4 access = 0; i4 msgid; PSY_TBL *psy_tbl = (PSY_TBL *)psy_cb->psy_tblq.q_next; /* Audit that operation rejected. */ if (psy_cb->psy_grpflag == PSY_CGROUP) { access = SXF_A_FAIL | SXF_A_CREATE; msgid = I_SX2007_GROUP_CREATE; } else if (psy_cb->psy_grpflag == PSY_AGROUP) { access = SXF_A_FAIL | SXF_A_ALTER; msgid = I_SX2008_GROUP_MEM_CREATE; } else if (psy_cb->psy_grpflag == PSY_DGROUP) { access = SXF_A_FAIL | SXF_A_ALTER; msgid = I_SX200A_GROUP_MEM_DROP; } else if (psy_cb->psy_grpflag == PSY_KGROUP) { access = SXF_A_FAIL | SXF_A_DROP; msgid = I_SX2009_GROUP_DROP; } else { err_code = E_PS0D40_INVALID_GRPID_OP; status = E_DB_SEVERE; (VOID) psf_error(E_PS0D40_INVALID_GRPID_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); break; } status = psy_secaudit(FALSE, sess_cb, (char *)&psy_tbl->psy_tabnm, (DB_OWN_NAME *)NULL, sizeof(DB_TAB_NAME), SXF_E_SECURITY, msgid, access, &e_error); } err_code = E_US18D3_6355_NOT_AUTH; (VOID) psf_error(E_US18D3_6355_NOT_AUTH, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/ALTER/DROP GROUP")-1, "CREATE/ALTER/DROP GROUP"); status = E_DB_ERROR; break; } scf_cb.scf_length = sizeof (SCF_CB); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_PSF_ID; scf_cb.scf_session = sess_cb->pss_sessid; scf_cb.scf_ptr_union.scf_sci = (SCI_LIST *) sci_list; scf_cb.scf_len_union.scf_ilength = 1; sci_list[0].sci_length = sizeof(dbname); sci_list[0].sci_code = SCI_DBNAME; sci_list[0].sci_aresult = (char *) dbname; sci_list[0].sci_rlength = NULL; status = scf_call(SCU_INFORMATION, &scf_cb); if (status != E_DB_OK) { err_code = scf_cb.scf_error.err_code; (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; break; } if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname))) { /* Session not connected to iidbdb */ err_code = E_US18D4_6356_NOT_DBDB; (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/ALTER/DROP GROUP")-1, "CREATE/ALTER/DROP GROUP"); status = E_DB_ERROR; break; } /* leave_loop has already been set to TRUE */ } while (!leave_loop); /* Select the proper routine to process this request */ if (status == E_DB_OK) switch (psy_cb->psy_grpflag) { case PSY_CGROUP: status = psy_cgroup(psy_cb, sess_cb); break; case PSY_AGROUP: status = psy_agroup(psy_cb, sess_cb); break; case PSY_DGROUP: status = psy_dgroup(psy_cb, sess_cb); break; case PSY_KGROUP: status = psy_kgroup(psy_cb, sess_cb); break; default: err_code = E_PS0D40_INVALID_GRPID_OP; status = E_DB_SEVERE; (VOID) psf_error(E_PS0D40_INVALID_GRPID_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); break; } return (status); }
/*{ ** Name: psy_alarm - Dispatch security alarm qrymod routines ** ** INTERNAL PSF call format: status = psy_alarm(&psy_cb, sess_cb); ** EXTERNAL call format: status = psy_call (PSY_ALARM, &psy_cb, sess_cb); ** ** Description: ** This procedure checks the psy_alflag field of the PSY_CB ** to determine which qrymod processing routine to call: ** PSY_CALARM results in call to psy_calarm() ** PSY_KALARM results in call to psy_kalarm() ** ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_alflag location operation ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** None. ** ** History: ** 21-sep-89 (ralph) ** written ** 29-nov-93 (robf) ** Now really call psy_calarm/psy_kalarm() */ DB_STATUS psy_alarm( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status=E_DB_OK; i4 err_code; i4 user_status; char dbname[DB_DB_MAXNAME]; SCF_CB scf_cb; SCF_SCI sci_list[2]; bool loop=FALSE; DB_SECALARM *alarm= &psy_cb->psy_tuple.psy_alarm; DB_STATUS local_status; DB_ERROR e_error; /* This code is called for SQL only */ /* ** Ensure we're connected to the iidbdb database for database/installation ** alarms, and have SECURITY privilege */ if(alarm->dba_objtype==DBOB_DATABASE) do { scf_cb.scf_length = sizeof (SCF_CB); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_PSF_ID; scf_cb.scf_session = sess_cb->pss_sessid; scf_cb.scf_ptr_union.scf_sci = (SCI_LIST *) sci_list; scf_cb.scf_len_union.scf_ilength = 1; sci_list[0].sci_code = SCI_DBNAME; sci_list[0].sci_length = sizeof(dbname); sci_list[0].sci_aresult = (char *) dbname; sci_list[0].sci_rlength = NULL; status = scf_call(SCU_INFORMATION, &scf_cb); if (status != E_DB_OK) { err_code = scf_cb.scf_error.err_code; (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; return(status); } if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname))) { /* Session not connected to iidbdb */ err_code = E_US18D4_6356_NOT_DBDB; (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/DROP SECURITY_ALARM ON DATABASE")-1, "CREATE/DROP SECURITY_ALARM ON DATABASE"); status=E_DB_ERROR; break; } if( !(sess_cb->pss_ustat & DU_USECURITY)) { err_code = E_US18D5_6357_FORM_NOT_AUTH; (VOID) psf_error(E_US18D5_6357_FORM_NOT_AUTH, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/DROP SECURITY_ALARM")-1, "CREATE/DROP SECURITY_ALARM"); status=E_DB_ERROR; break; } } while(loop); if (status!=E_DB_OK) { /* ** Audit failure */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { SXF_EVENT evtype; i4 msgid; if(alarm->dba_objtype==DBOB_DATABASE) evtype=SXF_E_DATABASE; else evtype=SXF_E_TABLE; if(psy_cb->psy_alflag&PSY_CALARM) msgid=I_SX202D_ALARM_CREATE; else msgid=I_SX202E_ALARM_DROP; local_status = psy_secaudit(FALSE, sess_cb, (char *)&alarm->dba_objname, (DB_OWN_NAME *)NULL, sizeof(alarm->dba_objname), evtype, msgid, SXF_A_CONTROL|SXF_A_FAIL, &e_error); } if(psy_cb->psy_alflag&PSY_CALARM) { /* ** Destroy query text for CREATE SECURITY_ALARM before ** returning */ DB_STATUS loc_status; QSF_RCB qsf_rb; qsf_rb.qsf_lk_state = QSO_EXLOCK; qsf_rb.qsf_type = QSFRB_CB; qsf_rb.qsf_ascii_id = QSFRB_ASCII_ID; qsf_rb.qsf_length = sizeof(qsf_rb); qsf_rb.qsf_owner = (PTR)DB_PSF_ID; qsf_rb.qsf_sid = sess_cb->pss_sessid; /* Destroy query text - lock it first */ STRUCT_ASSIGN_MACRO(psy_cb->psy_qrytext, qsf_rb.qsf_obj_id); loc_status = qsf_call(QSO_LOCK, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D18_QSF_LOCK, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } loc_status = qsf_call(QSO_DESTROY, &qsf_rb); if (loc_status != E_DB_OK) { psf_error(E_PS0D1A_QSF_DESTROY, qsf_rb.qsf_error.err_code, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); if (loc_status > status) status = loc_status; } } return status; } /* Select the proper routine to process this request */ switch (psy_cb->psy_alflag & (PSY_CALARM | PSY_KALARM)) { case PSY_CALARM: status = psy_calarm(psy_cb, sess_cb); break; case PSY_KALARM: status = psy_kalarm(psy_cb, sess_cb); break; default: status = E_DB_SEVERE; err_code = E_PS0D49_INVALID_ALARM_OP; (VOID) psf_error(E_PS0D49_INVALID_ALARM_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); break; } 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); }
/*{ ** Name: psy_user - Dispatch user qrymod routines ** ** INTERNAL PSF call format: status = psy_user(&psy_cb, sess_cb); ** EXTERNAL call format: status = psy_call (PSY_USER,&psy_cb, sess_cb); ** ** Description: ** This procedure checks the psy_usflag field of the PSY_CB ** to determine which qrymod processing routine to call: ** PSY_CUSER results in call to psy_cuser() ** PSY_AUSER results in call to psy_auser() ** PSY_KUSER results in call to psy_kuser() ** ** This procedure is called for SQL language only. ** ** Inputs: ** psy_cb ** .psy_usflag user operation ** sess_cb Pointer to session control block ** (Can be NULL) ** ** Outputs: ** psy_cb ** .psy_error Filled in if error happens ** Returns: ** E_DB_OK Function completed normally. ** E_DB_WARN Function completed with warning(s); ** E_DB_ERROR Function failed; non-catastrophic error ** E_DB_SEVERE Function failed; catastrophic error ** Exceptions: ** none ** ** Side Effects: ** None. ** ** History: ** 04-sep-89 (ralph) ** written ** 30-oct-89 (ralph) ** call qeu_audit() only if failure due to authorization check ** 11-apr-90 (jennifer) ** bug 20746 - Fix initialization of access and msgid. ** 09-dec-1992 (pholman) ** C2: change obsolete qeu_audit to be psy_secaudit. ** 06-apr-1993 (smc) ** Cast parameters to match prototypes. ** 17-jun-93 (andre) ** changed interface of psy_secaudit() to accept PSS_SESBLK ** 12-jul-93 (robf) ** check if user passwords are allowed ** 2-feb-94 (robf) ** Don't check for passwords allowed with PROFILE statements, ** profiles don't have passwords. ** 26-Oct-2004 (schka24) ** Restore security check accidently deleted with B1. */ DB_STATUS psy_user( PSY_CB *psy_cb, PSS_SESBLK *sess_cb) { DB_STATUS status, local_status; DB_ERROR e_error; i4 err_code; char dbname[DB_DB_MAXNAME]; SCF_CB scf_cb; SCF_SCI sci_list[1]; i4 access = 0; i4 msgid; PSY_USR *psy_usr = (PSY_USR *)psy_cb->psy_usrq.q_next; bool sensitive = FALSE; bool leave_loop = TRUE; /* This code is called for SQL only */ /* Make sure session is authorized and connected to iidbdb */ do { /* Ensure we're authorized to issue CREATE/ALTER/DROP USER */ if (((psy_cb->psy_usflag & ~(PSY_AUSER | PSY_USRPASS | PSY_USROLDPASS)) || (!(psy_cb->psy_usflag & PSY_USRPASS)) || (psy_cb->psy_usflag & (PSY_USREXPDATE|PSY_USRDEFPRIV)) || (STskipblank ((char *)&psy_cb->psy_apass,sizeof(psy_cb->psy_apass)) == NULL) ) && (!(sess_cb->pss_ustat & DU_UMAINTAIN_USER))) sensitive = TRUE; /* Now ALTER_AUDIT clauses - SECURITY_AUDIT */ if((psy_cb->psy_usflag & PSY_USRSECAUDIT) && !(sess_cb->pss_ustat & DU_UALTER_AUDIT)) sensitive = TRUE; /* Alter priv with SECURITY, and don't have SECURITY, is sensitive */ if ( (psy_cb->psy_usflag & (PSY_USRPRIVS|PSY_USRAPRIVS|PSY_USRDPRIVS)) && (psy_cb->psy_usprivs & DU_USECURITY) && ! (sess_cb->pss_ustat & DU_USECURITY) ) sensitive = TRUE; if(((psy_cb->psy_usflag & (PSY_APROFILE|PSY_DPROFILE|PSY_CPROFILE))) && !(sess_cb->pss_ustat & DU_UMAINTAIN_USER)) { /* ** Creating profiles is a privileged operation */ sensitive=TRUE; } if (sensitive) { /* User is not authorized to perform the requested function */ if ( Psf_srvblk->psf_capabilities & PSF_C_C2SECURE ) { if ((psy_cb->psy_usflag & (PSY_CUSER | PSY_AUSER | PSY_KUSER)) == PSY_CUSER) { access = SXF_A_FAIL | SXF_A_CREATE; msgid = I_SX200C_USER_CREATE; } else if ((psy_cb->psy_usflag & (PSY_CUSER | PSY_AUSER | PSY_KUSER)) == PSY_AUSER) { access = SXF_A_FAIL | SXF_A_ALTER; msgid = I_SX2023_USER_ALTER; } else if ((psy_cb->psy_usflag & (PSY_CUSER | PSY_AUSER | PSY_KUSER)) == PSY_KUSER) { access = SXF_A_FAIL | SXF_A_DROP; msgid = I_SX200D_USER_DROP; } else if ((psy_cb->psy_usflag & (PSY_CPROFILE | PSY_APROFILE | PSY_DPROFILE)) == PSY_CPROFILE) { access = SXF_A_FAIL | SXF_A_CREATE; msgid = I_SX272E_CREATE_PROFILE; } else if ((psy_cb->psy_usflag & (PSY_CPROFILE | PSY_APROFILE | PSY_DPROFILE)) == PSY_APROFILE) { access = SXF_A_FAIL | SXF_A_ALTER; msgid = I_SX272F_ALTER_PROFILE; } else if ((psy_cb->psy_usflag & (PSY_CPROFILE | PSY_APROFILE | PSY_DPROFILE)) == PSY_DPROFILE) { access = SXF_A_FAIL | SXF_A_DROP; msgid = I_SX2730_DROP_PROFILE; } local_status = psy_secaudit(FALSE, sess_cb, (char *)&psy_usr->psy_usrnm, (DB_OWN_NAME *)NULL, sizeof(DB_OWN_NAME), SXF_E_SECURITY, msgid, access, &e_error); } if (psy_cb->psy_usflag & PSY_AUSER) { err_code = E_US18D5_6357_FORM_NOT_AUTH; (VOID) psf_error(E_US18D5_6357_FORM_NOT_AUTH, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("ALTER USER/PROFILE")-1, "ALTER USER/PROFILE"); } else { err_code = E_US18D3_6355_NOT_AUTH; (VOID) psf_error(E_US18D3_6355_NOT_AUTH, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/DROP USER/PROFILE")-1, "CREATE/DROP USER/PROFILE"); } status = E_DB_ERROR; break; } /* Ensure we're connected to the iidbdb database */ scf_cb.scf_length = sizeof (SCF_CB); scf_cb.scf_type = SCF_CB_TYPE; scf_cb.scf_facility = DB_PSF_ID; scf_cb.scf_session = sess_cb->pss_sessid; scf_cb.scf_ptr_union.scf_sci = (SCI_LIST *) sci_list; scf_cb.scf_len_union.scf_ilength = 1; sci_list[0].sci_code = SCI_DBNAME; sci_list[0].sci_length = sizeof(dbname); sci_list[0].sci_aresult = (char *) dbname; sci_list[0].sci_rlength = NULL; status = scf_call(SCU_INFORMATION, &scf_cb); if (status != E_DB_OK) { err_code = scf_cb.scf_error.err_code; (VOID) psf_error(E_PS0D13_SCU_INFO_ERR, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); status = (status > E_DB_SEVERE) ? status : E_DB_SEVERE; return(status); } if (MEcmp((PTR)dbname, (PTR)DB_DBDB_NAME, sizeof(dbname))) { /* Session not connected to iidbdb */ err_code = E_US18D4_6356_NOT_DBDB; (VOID) psf_error(E_US18D4_6356_NOT_DBDB, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/ALTER/DROP USER/PROFILE")-1, "CREATE/ALTER/DROP USER/PROFILE"); status = E_DB_ERROR; break; } /* ** Check if passwords are allowed. */ if((sess_cb->pss_ses_flag & PSS_PASSWORD_NONE) && !(psy_cb->psy_usflag & ( PSY_KUSER| PSY_DPROFILE|PSY_APROFILE|PSY_CPROFILE)) && STskipblank((char *)&psy_cb->psy_apass, (i4)sizeof(psy_cb->psy_apass)) != NULL) { err_code=E_US18E7_6375; (VOID) psf_error(E_US18E7_6375, 0L, PSF_USERERR, &err_code, &psy_cb->psy_error, 1, sizeof("CREATE/ALTER USER WITH PASSWORD")-1, "CREATE/ALTER USER WITH PASSWORD"); status = E_DB_ERROR; break; } break; /* leave_loop has already been set to TRUE */ } while (!leave_loop); /* Select the proper routine to process this request */ if (status == E_DB_OK) switch (psy_cb->psy_usflag & (PSY_CUSER | PSY_AUSER | PSY_KUSER| PSY_CPROFILE | PSY_APROFILE | PSY_DPROFILE)) { case PSY_CUSER: status = psy_cuser(psy_cb, sess_cb); break; case PSY_AUSER: status = psy_auser(psy_cb, sess_cb); break; case PSY_KUSER: status = psy_kuser(psy_cb, sess_cb); break; case PSY_CPROFILE: status = psy_cprofile(psy_cb, sess_cb); break; case PSY_APROFILE: status = psy_aprofile(psy_cb, sess_cb); break; case PSY_DPROFILE: status = psy_kprofile(psy_cb, sess_cb); break; default: status = E_DB_SEVERE; err_code = E_PS0D46_INVALID_USER_OP; (VOID) psf_error(E_PS0D46_INVALID_USER_OP, 0L, PSF_INTERR, &err_code, &psy_cb->psy_error, 0); break; } return (status); }