示例#1
0
/*{
** 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);
}
示例#2
0
/*{
** 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);
}
示例#3
0
/*{
** 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);
} 
示例#4
0
/*{
** 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);
}
示例#5
0
/*
** 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);
}
示例#6
0
/*{
** 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);
}