This appendix builds on the rcpsimp application described in
Appendix A, A Sample Application The server is changed to be an OSF/DCE server and a gateway is used so that the Oracle Tuxedo ATMI client can communicate with the server using explicit binding and authenticated RPCs. The source files for this interactive application are distributed with the Oracle Tuxedo ATMI software development kit.
TUXDIR=<pathname of the Oracle Tuxedo root directory>
TUXCONFIG=
<pathname of your present working directory>/tuxconfig
PATH=$PATH:$TUXDIR/bin
# SVR4, Unixware
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# HPUX
SHLIB_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# RS6000
LIBPATH=$LD_LIBRARY_PATH:$TUXDIR/lib
export TUXDIR TUXCONFIG PATH LD_LIBRARY_PATH SHLIB_PATH LIBPATH
You need TUXDIR and
PATH to be able to access files in the Oracle Tuxedo ATMI directory structure and to execute Oracle Tuxedo ATMI commands. You need to set
TUXCONFIG to be able to load the configuration file. It may also be necessary to set an environment variable (for example,
LD_LIBRARY_PATH) if shared objects are being used.
Copy the rpcsimp files to the application directory:
The simp.idl file used in the earlier example will be used to build the gateway and the DCE server. However, since it is being compiled by both the DCE and Oracle Tuxedo IDL compilers, two different versions of the
simp.h header file are being generated with the same name. Additionally, we wish to use an ACF file in this example so that we can specify explicit binding for the server, but not for the client. The recommended approach is to link the IDL file to a second filename within the same directory, using one for TxRPC without binding and one for DCE/RPC with an explicit handle. In this case,
simp.idl is renamed
simpdce.idl and the associated ACF file is
simpdce.acf. The makefile creates
simpdce.idl and when the IDL compiler is executed, it also will find
simpdce.acf. Note that the ACF file is used simply to indicate that all operations in the interface will use explicit handles. Because the operations are defined in the IDL file without [handle] parameters as the first parameter, one will be added automatically to the function prototype and to the stub function calls.
•
|
<HOST> needs to be changed to the name of the host machine where the DCE server will be run. This is part of the service name that is put into the directory and follows the convention that the service name ends with _host. You may choose to get rid of the suffix entirely (if you do, the same change needs to be made in dceserver.c).
|
•
|
<SERVER_PRINCIPAL_GROUP> must be changed to the group associated with the DCE principal running the server. It is used as part of the mutual authentication.
|
•
|
The server principal group must be created by running rgy_edit as cell_admin, the server principal must be created, an account must be added for the principal with the group, and a key table must be created for the server. You must also create a principal and account for yourself to run the client. An example script to create these DCE entities is shown in Step 8: Configuring DCE.
|
dceepv.c contains the manager entry point vector used in the gateway. It is called by the Oracle Tuxedo ATMI server stub and calls the DCE client stub. The data type for the structure is defined in
simpdce.h, which is included in
dceepv.c, and it is initialized with the local functions
myto_upper() and
myto_lower(). Each of these functions simply calls
dobind() to get the binding handle that has been annotated for authenticated RPC and calls the associated client stub function.
#include <stdio.h>
#include <ctype.h>
#include "simpdce.h" /* header generated by IDL compiler */
#include <dce/rpcexc.h> /* RAISE macro */
#include <dce/dce_error.h> /* required to call dce_error_inq_text */
#include <dce/binding.h> /* binding to registry */
#include <dce/pgo.h> /* registry i/f */
#include <dce/secidmap.h> /* translate global name -> princ name */
void
checkauth(rpc_binding_handle_t handle)
{
int error_stat;
static unsigned char error_string[dce_c_error_string_len];
sec_id_pac_t *pac; /* client pac */
unsigned_char_t *server_principal_name; /* requested server principal */
unsigned32 protection_level; /* protection level */
unsigned32 authn_svc; /* authentication service */
unsigned32 authz_svc; /* authorization service */
sec_rgy_handle_t rgy_handle;
error_status_t status;
/*
* Check the authentication parameters that the client
* selected for this call.
*/
rpc_binding_inq_auth_client(
handle, /* input handle */
(rpc_authz_handle_t *)&pac, /* returned client pac */
&server_principal_name, /* returned requested server princ */
&protection_level, /* returned protection level */
&authn_svc, /* returned authentication service */
&authz_svc, /* returned authorization service */
&status);
if (status != rpc_s_ok) {
dce_error_inq_text(status, error_string, &error_stat);
fprintf(stderr, "%s %s\n", "inq_auth_client failed",
error_string);
RAISE(rpc_x_invalid_binding);
return;
}
/*
* Make sure that the caller has specified the required
* level of protection, authentication, and authorization.
*/
if (protection_level != rpc_c_protect_level_pkt_integ ||
authn_svc != rpc_c_authn_dce_secret ||
authz_svc != rpc_c_authz_dce) {
fprintf(stderr, "not authorized");
RAISE(rpc_x_invalid_binding);
return;
}
return;
}
void
to_upper(rpc_binding_handle_t handle, idl_char *str)
{
idl_char *p;
checkauth(handle);
/* Any ACL or reference monitor checking could be done here */
/* Convert to upper case */
for (p=str; *p != '\0 '; p++)
*p = toupper((int)*p);
return;
}
void
to_lower(rpc_binding_handle_t handle, idl_char *str)
{
idl_char *p;
checkauth(handle);
/* Any ACL or reference monitor checking could be done here */
/* Convert to lower case */
for (p=str; *p != '\0 '; p++)
*p = tolower((int)*p);
return;
}
dcemgr.c has the manager code for the DCE server. The
checkauth() function is a utility function to check the authentication of the client (level of protection, authentication, and authorization). Each of the operations,
to_upper and
to_lower, calls this function to validate the client and then does the operation itself. In an application using access control lists, the ACL checking would be done after the authentication checking and before the work of the operation.
•
|
<HOST> needs to be changed to the name of the host machine where the DCE server will be run. This is part of the service name that is put into the directory and follows the convention that the service names ends with _host. You may choose to get rid of the suffix entirely (if you do, the same change needs to be made in dcebind.c).
|
•
|
<DIRECTORY> needs to be set to the full pathname of the directory where you will create the server key table. The key table is created by executing the following:
|
where SERVER_PRINCIPAL is the DCE principal under which the server will be run,
PASSWORD is the password associated with the principal, and
SERVER_KEYTAB is the name of the server key table.
<PRINCIPAL> must be changed to the name of the DCE principal under which the server will be run.
The ANNOTATION can be changed to an annotation to be stored in the directory entry for the server.
dceserver.c is actually used twice in the application: once as the
main() for the DCE server and again (linked to
gwinit.c and compiled with -
DTPSVRINIT in the makefile) as the
tpsvrinit() for the DCE gateway.
When compiled with -DTCLIENT, this file generates a
main() as above but calls
tpinit() to join the Oracle Tuxedo ATMI application as a client, and calls
tpterm() before exiting. This would be used for a DCE gateway for calls coming from DCE to Oracle Tuxedo (such that the process is a DCE server and an Oracle Tuxedo ATMI client).
When compiled with -DTPSVRINIT, this file generates a
tpsvrinit() (with
argc and
argv server command-line options) for an Oracle Tuxedo server that does the following:
•
|
Calls tx_open to open any resource managers associated with the server
|
In each of these cases, the login context is established by calling establish_identity, which gets the network identity for the server, uses the server’s secret key from the key table file to unseal the identity, and sets the login context for the process. Two threads are started: one to refresh the login context just before it expires, and a second thread to periodically change the server’s secret key.
The makefile builds the executable client, gateway, and DCE server programs.
Before building the software, rpcsimp.mk must be modified to set the correct options and libraries for building the DCE server. As sent out, the makefile contains the proper settings for several platforms. Based on the platform that you are using, uncomment (delete the pound sign) in front of the correct pair of
DCECFLAGS and
DCELIBS variables, or add your own definitions for a different platform.
Briefly reviewing the makefile, the client is built in the same fashion as in Appendix A, ?$paratext>.? The DCE gateway is built by passing
simpdce.idl to
blds_dce, which builds an Oracle Tuxedo ATMI server that acts as a gateway to DCE. Also included are
gwinit.o (a version of
dceserver.c compiled with -
DTPSVRINIT),
dobind.o (to get the binding handle for the DCE server), and
dceepv.o (the manager entry point vector). Note that
-i -no_mepv is specified so that the IDL compiler does not generate its own manager entry point vector. The DCE server is built compiling
simpdce.idl with the DCE IDL compiler, and including
dceserver.o and
dcemgr.o.
2.
|
In the SERVERS section, comment out the server line by putting a pound sign ( #) at the beginning of the line. (Do not comment out the dceserver line.)
|
•
|
The SERVER_PRINCIPAL must be the same as the Oracle Tuxedo administrator identifier, because the server must be booted as the Oracle Tuxedo administrator and the server must be able to read the server key table.
|
1.
|
Log in as SERVER_PRINCIPAL (the owner of the server key table).
|
The message Server ready is displayed just before the DCE server starts listening for requests.