II_EXTERN II_VOID IIapi_loadNSColumns ( IIAPI_STMTHNDL *stmtHndl, IIAPI_GETCOLPARM *getColParm, IIAPI_GCN_REQ_TUPLE *tuple ) { IIAPI_DESCRIPTOR *descr; IIAPI_DATAVALUE *value; API_PARSE *parse = (API_PARSE *)stmtHndl->sh_queryText; char buffer[ API_NS_MAX_LEN ]; char *str, *val[ 3 ]; u_i2 len; IIAPI_TRACE( IIAPI_TR_VERBOSE ) ( "IIapi_loadNSColumns: %d columns starting at %d, %d total columns\n", (II_LONG)stmtHndl->sh_colFetch, (II_LONG)stmtHndl->sh_colIndex, (II_LONG)stmtHndl->sh_colCount ); /* ** Some columns are combined in the returned ** GCN value field. Break out the combinded ** columns for reference below. We don't ** expect to overflow the buffer, but just ** in case we truncate the input. */ if ( tuple->gcn_val.gcn_l_item > (sizeof( buffer ) - 1) ) tuple->gcn_val.gcn_value[ sizeof( buffer ) - 1 ] = EOS; gcu_words( tuple->gcn_val.gcn_value, buffer, val, ',', 3 ); descr = &stmtHndl->sh_colDescriptor[ stmtHndl->sh_colIndex ]; value = &getColParm->gc_columnData[ (getColParm->gc_rowsReturned * getColParm->gc_columnCount) + getColParm->gc_columnCount - stmtHndl->sh_colFetch ]; for( ; stmtHndl->sh_colFetch; stmtHndl->sh_colFetch--, stmtHndl->sh_colIndex++, descr++, value++ ) { /* ** Figure out which piece of of the tuple ** satisfies the current column depending ** on which object type is being accessed. */ switch( parse->object ) { case API_KW_NODE : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Network address */ str = val[0]; break; case 3 : /* Protocol */ str = val[1]; break; case 4 : /* Listen address */ str = val[2]; break; } break; case API_KW_LOGIN : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Login */ str = val[0]; break; } break; case API_KW_ATTR : switch( stmtHndl->sh_colIndex ) { case 0 : /* Type */ str = (parse->type == API_KW_GLOBAL) ? glob_type : priv_type; break; case 1 : /* Vnode */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Attribute Name */ str = val[0]; break; case 3 : /* Attribute Value */ str = val[1]; break; } break; case API_KW_SERVER : switch( stmtHndl->sh_colIndex ) { case 0 : /* Server type */ str = tuple->gcn_type.gcn_value; break; case 1 : /* Object */ str = tuple->gcn_obj.gcn_value; break; case 2 : /* Address */ str = val[0]; break; } break; } /* ** We should always get a valid string, ** but provide a default just in case. ** Strings are silently truncated if too ** long since we don't expect truncation ** to occur (except for the type column, ** in which case silent truncation is ** desired). */ if ( ! str ) str = err_str; len = STlength( str ); value->dv_null = FALSE; switch( descr->ds_dataType ) { case IIAPI_CHA_TYPE : len = min( len, descr->ds_length ); value->dv_length = len; MEcopy( (PTR)str, len, value->dv_value ); break; case IIAPI_VCH_TYPE : len = min( len, descr->ds_length - sizeof( len ) ); value->dv_length = sizeof( len ) + len; MEcopy( (PTR)&len, sizeof( len ), value->dv_value ); MEcopy( (PTR)str, len, (PTR)((char *)value->dv_value + sizeof( len )) ); break; default : /* ** Should not happen. */ value->dv_null = TRUE; value->dv_length = 0; break; } } return; }
STATUS gca_ns_resolve( char *target, char *user, char *password, char *rem_user, char *rem_pass, GCA_RQCB *rqcb ) { #ifdef GCF_EMBEDDED_GCN GCA_RQNS *ns = &rqcb->ns; GCN_RESOLVE_CB *grcb; char uid[ GC_USERNAME_MAX + 1 ]; char *puid = uid; char empty[ 1 ] = { '\0' }; STATUS status; i4 i; /* ** Allocate the embedded Name Server interface control block ** and save it in the request control block to provide storage ** for the resolved values. */ if ( ! rqcb->grcb && ! (rqcb->grcb = gca_alloc(sizeof(GCN_RESOLVE_CB))) ) return( E_GC0013_ASSFL_MEM ); grcb = (GCN_RESOLVE_CB *)rqcb->grcb; /* ** Default local username and password if required. ** Only use the provided info if both a username and ** password are provided. */ IDname( &puid ); STzapblank( uid, uid ); if ( ! user ) user = empty; if ( ! password ) password = empty; if ( ! user[0] || ! password[ 0 ] ) { user = uid; password = empty; } /* ** Validate username and password if attempt is ** made to change the user's ID. This would ** normally be done in the Name Server GCA_LISTEN. */ if ( user != uid && STcompare( user, uid ) ) { CL_ERR_DESC sys_err; status = GCusrpwd( user, password, &sys_err ); if ( status != OK ) return( status ); } /* ** Setup input parameters to Name Database interface. */ STcopy( target, grcb->target ); STcopy( user, grcb->user ); if ( rem_user && rem_pass ) { /* ** Use the requested remote username and password. */ grcb->gca_message_type = GCN_NS_2_RESOLVE; STcopy( rem_user, grcb->user_in ); STcopy( rem_pass, grcb->passwd_in ); } else { /* ** Use the local username and password. */ grcb->gca_message_type = GCN_NS_RESOLVE; STcopy( user, grcb->user_in ); STcopy( password, grcb->passwd_in ); } /* ** Call embedded Name Server to resolve the target. */ if ( (status = gcn_rslv_parse( grcb )) == OK && (status = gcn_rslv_server( grcb )) == OK && (status = gcn_rslv_node( grcb )) == OK && (status = gcn_rslv_login( grcb )) == OK ) { #ifdef WIN16 gcpasswd_prompt(grcb->user_out, grcb->passwd_out, grcb->vnode); #endif /* WIN16 */ /* ** Return resolved info. The new partner ID should ** have the vnode removed, but still retain the server ** class. We use the grcb as static storage to rebuild ** the partner ID from the dbname and class components. */ ns->svr_class = grcb->class ? grcb->class : ""; ns->username = grcb->user_out ? grcb->user_out : ""; ns->password = grcb->passwd_out ? grcb->passwd_out : ""; ns->rmt_dbname = grcb->target; STprintf( grcb->target, "%s%s%s", grcb->dbname ? grcb->dbname : "", ns->svr_class[0] ? "/" : "", ns->svr_class ); for( i = 0, ns->lcl_count = grcb->catl.tupc; i < ns->lcl_count; i++ ) ns->lcl_addr[ i ] = grcb->catl.tupv[ i ]; for( i = 0, ns->rmt_count = grcb->catr.tupc; i < ns->rmt_count; i++ ) { char *pv[3]; gcu_words( grcb->catr.tupv[ i ], NULL, pv, ',', 3 ); ns->node[ i ] = pv[ 0 ]; ns->protocol[ i ] = pv[ 1 ]; ns->port[ i ] = pv[ 2 ]; } if ( ! ns->lcl_count ) status = E_GC0021_NO_PARTNER; }
bool gcn_merge_rec( GCN_QUEUE *gcn_q, bool isLogin ) { bool add_record; GCN_QUEUE *merge_q; GCN_DB_REC0 *dst; QUEUE *q; /* ** Invalid records don't get added. */ if (gcn_q->buf.gcn_tup_id == -1) return FALSE; if (gcn_q->buf.gcn_invalid) return FALSE; if ( !gcn_q->buf.gcn_uid[0]) return FALSE; if ( !gcn_q->buf.gcn_l_uid) return FALSE; if ( !gcn_q->buf.gcn_obj[0]) return FALSE; if ( !gcn_q->buf.gcn_l_obj) return FALSE; /* ** Assume a valid record that doesn't match. */ add_record = TRUE; for (q = merge_qhead.q_prev; q != &merge_qhead; q = q->q_prev) { merge_q = (GCN_QUEUE *)q; /* ** EOF of merge queue reached. */ if (merge_q->buf.gcn_tup_id == -1) break; /* ** Records marked as delete (invalid) don't get merged. Search ** the next record. */ if (gcn_q->buf.gcn_invalid) continue; /* ** Compare the uid and obj values. No match means the record can ** potentially be added. Search the next record. */ if ( STbcompare( gcn_q->buf.gcn_uid, 0, merge_q->buf.gcn_uid, 0, TRUE ) ) continue; if ( STbcompare( gcn_q->buf.gcn_obj, 0, merge_q->buf.gcn_obj, 0, TRUE ) ) continue; /* ** If this is a login file, and the uid and obj (global/private and ** vnode name) entries match, don't merge. */ if (isLogin) return FALSE; if ( gcn_q->buf.gcn_val[0] ) { char tmp1[ GCN_VAL_MAX_LEN + 1 ]; char tmp2[ GCN_VAL_MAX_LEN + 1 ]; char *pv1[ NBR_SUBFIELDS ], *pv2[ NBR_SUBFIELDS ]; i4 v1, v2; /* ** Extract sub-fields. */ v1 = gcu_words( gcn_q->buf.gcn_val, tmp1, pv1, ',', NBR_SUBFIELDS ); v2 = gcu_words( merge_q->buf.gcn_val, tmp2, pv2, ',', NBR_SUBFIELDS ); /* ** Limit comparison to requested number of sub-fields ** Make sure there are enough sub-fields for comparison. */ if ( v2 > NBR_SUBFIELDS ) v2 = NBR_SUBFIELDS; if ( v1 < v2 ) continue; /* ** Compare the sub-fields. */ while( v2-- ) { if ( *pv2[v2] && !STbcompare(pv1[v2], 0, pv2[v2], 0, TRUE) ) { add_record = FALSE; break; } } /* ** Nothing matched, so search the next record. */ if (add_record) continue; /* ** Everything matched. Don't add the record and stop ** searching. */ add_record = FALSE; break; } } /* for (q = merge_qhead.q_prev; q != &merge_qhead; q = q->q_prev) */ if (verboseArg) { if (add_record) SIprintf("Merging vnode %s\n", gcn_q->buf.gcn_obj); else SIprintf("Vnode %s rejected for merging\n"); } return add_record; }
STATUS gcn_recrypt( bool clustered, u_i1 *local_mask, char *gcn_val, bool *v1DecryptErr, bool *writeOutput) { i2 pc; char *pv[ 3 ]; STATUS status = OK; char *p; char pwd[GC_L_PASSWORD]; i2 j; bool printable; *v1DecryptErr = FALSE; pc = gcu_words( gcn_val, NULL, pv, ',', 3 ); if (pc < 2 ) pv[1] = ""; if (pc < 3 ) pv[2] = ""; if (!STcasecmp(pv[2],"V0") || (pc < 3)) status = gcn_decrypt( pv[0], pv[1], pwd ); else status = gcn_decode( pv[0],(u_i1*)local_mask, pv[1], pwd ); if (status != OK) { if (!STcasecmp(pv[2],"V1")) *v1DecryptErr = TRUE; goto end_routine; } if (!STlength(pwd)) { if (!STcasecmp(pv[2],"V1")) *v1DecryptErr = TRUE; status = FAIL; goto end_routine; } p = &pwd[0]; printable = TRUE; for (j = 0; j < STlength(pwd); j++) { if (!CMprint(p)) { printable = FALSE; break; } CMnext(p); } if (!printable) { if (!STcasecmp(pv[2],"V1")) *v1DecryptErr = TRUE; status = FAIL; goto end_routine; } if (clustered) { if (!STncasecmp("V1", pv[2], STlength(pv[2]))) *writeOutput = TRUE; status = gcu_encode( pv[0], pwd, pv[1] ); STpolycat( 5, pv[0], ",", pv[1], ",", "V0", gcn_val ); } else { status = gcn_encode( pv[0],(u_i1*)local_mask, pwd, pv[1] ); STpolycat( 5, pv[0], ",", pv[1], ",", "V1", gcn_val ); } end_routine: return status; }
static STATUS gcn_op_add ( char *msg_in, GCN_MBUF *mbout, char *user, char *gcn_type, GCN_TUP *masktup, i4 num_tuple, i4 opflags, i4 srv_flags ) { GCN_QUE_NAME *nq = NULL; i4 row_count, tup_count; STATUS status = OK; char flagbuf[ 9 ]; char valbuf[ 65 ]; char *newval = valbuf; /* ** Check that user has required privileges for operation requested. ** (These checks are bypassed if client is trusted.) */ if ( ! (opflags & GCN_OPFLAG_TRUST) ) { /* ** SERVER_CONTROL is required to add a server entry. */ if ( opflags & GCN_OPFLAG_SRV ) status = gca_chk_priv( user, GCA_PRIV_SERVER_CONTROL ); /* ** NET_ADMIN is required to add a global vnode entry. */ if ( opflags & GCN_OPFLAG_VNODE && opflags & GCN_OPFLAG_PUB ) status = gca_chk_priv( user, GCA_PRIV_NET_ADMIN ); if ( status != OK ) { gcn_error( status, NULL, user, mbout ); return( status ); } } /* Scan name list for given service class. */ if ( ! (nq = gcn_nq_find( gcn_type )) ) if ( ! (opflags & GCN_OPFLAG_SRV) ) { /* Can't find class. */ gcn_error( E_GC0100_GCN_SVRCLASS_NOTFOUND, NULL, gcn_type, mbout ); return( E_GC0100_GCN_SVRCLASS_NOTFOUND ); } else if ( ! (nq = gcn_nq_create( gcn_type )) ) { gcn_error( E_GC0121_GCN_NOMEM, NULL, gcn_type, mbout ); return( E_GC0121_GCN_NOMEM ); } /* ** Matching entries are deleted prior to adding new entries. ** When merging, only exact duplicates are deleted. Otherwise, ** matches depend on various tuple fields for different classes. */ if ( nq->gcn_transient ) { /* ** Registered servers match on listen address (value). ** UID is overloaded with formatted server flags. */ if ( ! (opflags & GCN_OPFLAG_MRG) ) masktup->obj = ""; masktup->uid = ""; CVlx( (long)srv_flags, flagbuf ); } else if ( opflags & GCN_OPFLAG_NODE ) { /* ** VNODE connection entries match on UID and VNODE (object). */ if ( ! (opflags & GCN_OPFLAG_MRG) ) masktup->val = ""; } else if ( opflags & GCN_OPFLAG_LOGIN ) { /* ** VNODE login entries match on UID and VNODE (object). ** Multiple values (merged entries) are not permitted. */ masktup->val = ""; } else if ( opflags & GCN_OPFLAG_ATTR ) { /* ** VNODE attribute entries match on UID, VNODE (object) ** and attribute name. */ if ( ! (opflags & GCN_OPFLAG_MRG) ) { /* ** Tuple value is attribute name and its value. ** Build match value to only have attribute name. */ char *pv[2]; i4 str_len = STlength( masktup->val ) + 1; if ( str_len > sizeof( valbuf ) ) { newval = (char *)MEreqmem( 0, str_len, FALSE, NULL ); if ( ! newval ) return( E_GC0121_GCN_NOMEM ); } (void)gcu_words( masktup->val, newval, pv, ',', 2 ); str_len = STlength( pv[0] ); pv[0][str_len] = ','; pv[0][str_len + 1] = '\0'; masktup->val = pv[0]; } } if ( gcn_nq_lock( nq, TRUE ) == OK ) { /* ** First delete any overlapping tuples and ** report that to the user. */ status = (row_count = gcn_nq_del( nq, masktup )) ? gcn_result( mbout, GCN_DEL, row_count ) : OK ; /* ** Insert the tuples into the name queue. */ for( row_count = tup_count = 0; status == OK && tup_count < num_tuple; tup_count++ ) { GCN_TUP tup; char buff[ 256 ]; char *login = buff; /* ** Get next tuple from user request. */ msg_in += gcu_get_str( msg_in, &gcn_type ); msg_in += gcn_get_tup( msg_in, &tup ); /* ** All tuples must have the same class. */ if ( ! gcn_type[0] ) gcn_type = IIGCn_static.svr_type; CVupper( gcn_type ); if ( STcompare( nq->gcn_type, gcn_type ) ) continue; /* ** Set user ID appropriately. */ if ( nq->gcn_transient ) tup.uid = flagbuf; else if ( opflags & GCN_OPFLAG_PUB ) tup.uid = GCN_GLOBAL_USER; else if ( ! (opflags & GCN_OPFLAG_UID) ) tup.uid = user; /* ** Login passwords are encrypted by the client ** and must be transformed into storage format. */ if ( opflags & GCN_OPFLAG_LOGIN ) { /* ** The encryption algorithm for storage produces ** a slightly longer string than the communication ** encryption. Ensure temp buffer is large enough. ** 50% larger is more than sufficient for current ** algorithm. */ i4 len = (STlength( tup.val ) * 3) / 2; if ( len >= sizeof( buff ) ) login = (char *)MEreqmem( 0, len + 1, FALSE, NULL ); if ( ! login ) status = E_GC0121_GCN_NOMEM; else { transform_login( tup.val, login ); tup.val = login; } } if ( status == OK ) { row_count += gcn_nq_add( nq, &tup ); if ( login != buff ) MEfree( (PTR)login ); } } if ( status == OK ) status = gcn_result( mbout, GCN_ADD, row_count ); else gcn_error( status, NULL, NULL, mbout ); gcn_nq_unlock( nq ); } else { status = E_GC0134_GCN_INT_NQ_ERROR; gcn_error( status, NULL, NULL, mbout ); } if ( newval != valbuf ) MEfree( (PTR)newval ); return( status ); }
static STATUS gcn_op_get ( GCN_MBUF *mbout, char *gcn_type, GCN_TUP *masktup, i4 opflags ) { GCN_QUE_NAME *nq; GCN_MBUF *mbuf; char *msg_out = NULL; char *msg_post = NULL; char *row_ptr = NULL; i4 row_count = 0; STATUS status = OK; /* ** Find desired class */ if ( ! (nq = gcn_nq_find( gcn_type )) ) if ( opflags & GCN_OPFLAG_SRV ) return( gcn_result( mbout, GCN_RET, 0 ) ); /* No servers */ else { /* Can't find class. */ gcn_error( E_GC0100_GCN_SVRCLASS_NOTFOUND, NULL, gcn_type, mbout ); return( E_GC0100_GCN_SVRCLASS_NOTFOUND ); } /* ** User ID is not applicable for registered servers. */ if ( nq->gcn_transient ) masktup->uid = ""; if ( gcn_nq_lock( nq, FALSE ) == OK ) { GCN_TUP *tupvec[ GCN_SVR_MAX ]; PTR scan_cb = NULL; i4 i, tupcount; /* ** Call gcn_nq_scan in a loop to get a batch at a time. */ do { /* Load up the next entries */ tupcount = gcn_nq_scan( nq, masktup, &scan_cb, GCN_SVR_MAX, tupvec, NULL ); /* Loop through server entries */ for( i = 0; i < tupcount; i++ ) { GCN_TUP *tup = tupvec[ i ]; GCN_TUP newtup; char buf[ 1024 ]; char *p = buf; char tmpbuf[ 128 ]; char *tmp = tmpbuf; p += gcu_put_str( p, nq->gcn_type ); newtup.uid = tup->uid; newtup.obj = tup->obj; newtup.val = tup->val; /* ** VNODE login passwords are not exposed. */ if ( opflags & GCN_OPFLAG_LOGIN ) { char *pv[2]; i4 len = STlength( tup->val ) + 1; if ( len > sizeof( tmpbuf ) && ! (tmp = (char *)MEreqmem(0, len, FALSE, NULL)) ) { gcn_nq_unlock( nq ); return( E_GC0121_GCN_NOMEM ); } (void)gcu_words( tup->val, tmp, pv, ',', 2 ); newtup.val = pv[0]; } p += gcn_put_tup( p, &newtup ); if ( tmp != tmpbuf ) MEfree( (PTR)tmp ); if ( msg_out && (p - buf) + msg_out > msg_post ) { /* ** Update the row count for this message. ** We send individual messages rather than ** continued messages hoping (in vain) that ** the client won't need to piece message ** segments back together. */ gcu_put_int( row_ptr, row_count ); mbuf->used = msg_out - mbuf->data; row_count = 0; msg_out = NULL; } if ( ! msg_out ) { mbuf = gcn_add_mbuf( mbout, TRUE, &status ); if ( status != OK ) { gcn_nq_unlock( nq ); return( status ); } mbuf->type = GCN_RESULT; msg_out = mbuf->data; msg_post = mbuf->data + mbuf->len; msg_out += gcu_put_int( msg_out, GCN_RET ); row_ptr = msg_out; msg_out += gcu_put_int( msg_out, 0 ); } MEcopy( buf, p - buf, msg_out ); msg_out += p - buf; row_count++; } } while( tupcount == GCN_SVR_MAX ); if ( ! msg_out ) status = gcn_result( mbout, GCN_RET, 0 ); else { (void)gcu_put_int( row_ptr, row_count ); mbuf->used = msg_out - mbuf->data; } gcn_nq_unlock( nq ); } else { status = E_GC0134_GCN_INT_NQ_ERROR; gcn_error( status, NULL, NULL, mbout ); } return( status ); }
static STATUS transform_login( char *ibuff, char *obuff ) { char *pv[ 2 ]; char pbuff[ 128 ], tbuff[ 128 ]; char *pwd, *tmp; i4 len; STATUS status; /* ** Isolate user ID and encrypted password. ** Ensure output buffer is large enough. ** Decrypt the password. */ if ( gcu_words( ibuff, NULL, pv, ',', 2 ) < 2 ) pv[1] = ""; len = STlength( pv[1] ); pwd = (len < sizeof( pbuff )) ? pbuff : (char *)MEreqmem( 0, len + 1, FALSE, NULL ); if ( ! pwd ) status = E_GC0121_GCN_NOMEM; else status = gcn_login( GCN_VLP_CLIENT, 0, FALSE, pv[0], pv[1], pwd ); /* ** Re-encrypt password for storage */ if ( status == OK ) { /* ** Ensure temp buffer is large enough. */ len = (STlength( pwd ) + 8) * 2; tmp = (len < sizeof( tbuff )) ? tbuff : (char *)MEreqmem( 0, len + 1, FALSE, NULL ); if ( ! tmp ) status = E_GC0121_GCN_NOMEM; else status = gcn_login( GCN_VLP_LOGIN, IIGCn_static.pwd_enc_vers, TRUE, pv[0], pwd, tmp ); } /* ** Rebuild the login tuple value. */ if ( status == OK ) { char vers[ 32 ]; STprintf( vers, "V%d", IIGCn_static.pwd_enc_vers ); STpolycat( 5, pv[0], ",", tmp, ",", vers, obuff ); } if ( pwd != pbuff ) MEfree( (PTR)pwd ); if ( tmp != tbuff ) MEfree( (PTR)tmp ); return( status ); }