This topic includes the following sections:
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.
This topic requires knowledge about DCE, and a DCE tutorial is beyond the scope of this document. For further reading, try Guide to Writing DCE Applications by John Shirley, et. al., published by O'Reilly and Associates, Inc.
This application is an extension to the rpcsimp
application. As before, the client calls the remote procedure calls (operations) to_upper
() and to_lower
().
In this case, the RPC goes from the Oracle Tuxedo ATMI client to the DCE Gateway process that forwards the request to a DCE server. To make this example more realistic, the communications from the Gateway process to the DCE server use explicit binding instead of automatic binding and an authenticated RPC.
What follows is a procedure to build and run the example. The client can run on any platform described in Appendix A, "A Sample Application." There is no difference in building or running the client and it will not be described further in this chapter. The gateway and DCE server must run on a POSIX platform that also has DCE software installed on it. This chapter will not discuss installation or compilation of the clients on the Workstation platforms.
The sample programs work on platforms that conform to OSF/DCE software standards.
The following steps provide you with the instructions for installing, configuring, and running the sample application.
Make a directory for rpcsimp
and cd
to it:
mkdir rpcsampdir cd rpcsampdir
Note: This is suggested so you will be able to see clearly therpcsimp files you have at the start and the additional files you create along the way. Use the standard shell (/bin/sh ) or the Korn shell; do not use the C shell (csh ). |
Set and export the necessary environment variables:
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:
cp $TUXDIR/apps/rpcsimp/* .
You will be editing some of the files and making them executable, so it is best to begin with a copy of the files rather than with the originals delivered with the software.
List the files:
$ ls client.c dcebind.c dceepv.c dcemgr.c dceserver.c rpcsimp.mk simp.idl simpdce.acf ubbconfig $
(Some files that are not referenced in this section are omitted.)
The files that make up the application are described in the following sections. The client.c
, simp.idl
, and ubbconfig
files described in Appendix A, "A Sample Application," are not discussed further.
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.
In the interest of space, the source code for dcebind.c
is not included here but can be found in $TUXDIR/apps/rpcsimp
.
This file has a function, dobind
(), that does the following three things:
It gets a binding handle for the DCE server with the desired interface specification and gets the associated endpoint for a fully resolved handle.
It does some authentication of the server by getting the principal name for the server and checking the Security registry to see if the principal is a member of a specified group.
It also annotates the binding handle so that an authenticated RPC is done. The protection level is packet level integrity (mutual authentication on every call with a packet checksum
) using DCE private key authentication and DCE PAC-based authorization.
The following things need to be modified in dcebind.c
:
<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.
Example B-2 dceepv.c
#include <simpdce.h> /* header generated by IDL compiler */ #include <dce/rpcexc.h> /* RAISE macro */ static void myto_upper(rpc_binding_handle_t hdl, idl_char *str); static void myto_lower(rpc_binding_handle_t hdl, idl_char *str); /* * A manager entry point vector is defined so that we can generate * a valid DCE binding handle to go to the DCE server. * Note that the input handle to entry point functions will always * be NULL since Tuxedo TxRPC doesn't support handles. */ /* Manager entry point vector with two operations */ changecase_v1_0_epv_t changecase_v1_0_s_epv = { myto_upper, myto_lower }; int dobind(rpc_binding_handle_t *hdl); void myto_upper(rpc_binding_handle_t hdl, idl_char *str) { rpc_binding_handle_t handle; if (dobind(&handle) 0) { /* get binding handle for server */ userlog("binding failed"); RAISE(rpc_x_invalid_binding); } to_upper(handle, str); /* call DCE client stub */ } void myto_lower(rpc_binding_handle_t hdl, idl_char *str) { rpc_binding_handle_t handle; if (dobind(&handle) 0) { /* get binding handle for server */ userlog("binding failed"); RAISE(rpc_x_invalid_binding); } to_lower(handle, str); /* call DCE client stub */ }
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.
Example B-3 dcemgr.c
#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.
In the interest of space, the source code for dceserver.c
is not included here. There are several modifications needed for this file based on your environment:
<
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:
rgy_edit ktadd -p SERVER_PRINCIPAL -pw PASSWORD -f SERVER_KEYTAB q
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 without extra macro definitions, this file generates a main()
(with argc
and argv
command-line options) for a DCE server that does the following:
Registers its interfaces
Creates its server binding information and endpoints
Establishes its DCE login context for the server principal using information in the server key table
Registers its authentication information
Gets its bindings and registers the information in the endpoint map
Exports the binding information to the directory name space
Optionally, adds its name to a group in the name space
Listens for requests
Cleans up after rpc_server_listen
returns
The program could be modified to look at and use its command_line options.
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:
Establishes its DCE login for the principal using the information in the server key table
Registers its authentication information
Calls tx_open
to open any resource managers associated with the server
The program could be modified to look at and use its command-line options.
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.
Example B-4 rpcsimp.mk
CC=cc CFLAGS= TIDL=$(TUXDIR)/bin/tidl LIBTRPC=-ltrpc all: client server # Tuxedo client client: simp.h simp_cstub.o CC=$(CC) CFLAGS=$(CFLAGS) $(TUXDIR)/bin/buildclient -oclient \ -fclient.c -fsimp_cstub.o -f$(LIBTRPC) # # OMIT Tuxedo server # # Tuxedo Gateway example # Uses Tuxedo client above plus a gateway server and a DCE server # # # Alpha FLAGS/LIBS #DCECFLAGS=-D_SHARED_LIBRARIES -Dalpha -D_REENTRANT -w -I. \ -I/usr/include/dce -I$(TUXDIR)/include #DCELIBS=-ldce -lpthreads -lc_r -lmach -lm # # # HPUX FLAGS/LIBS #DCECFLAGS=-Aa -D_HPUX_SOURCE -D_REENTRANT -I. \ -I/usr/include/reentrant -I${TUXDIR}/include #DCELIBS=-Wl,-Bimmediate -Wl,-Bnonfatal -ldce -lc_r -lm # IDL=idl ALL2=client simpgw dceserver all2: $(ALL2) # TUXEDO-to-DCE Gateway simpdce.idl: simp.idl rm -f simpdce.idl ln simp.idl simpdce.idl gwinit.c: dceserver.c rm -f gwinit.c ln dceserver.c gwinit.c gwinit.o: gwinit.c $(CC) -c $(DCECFLAGS) -DTPSVRINIT gwinit.c dceepv.o: dceepv.c simpdce.h $(CC) -c $(DCECFLAGS) dceepv.c dcebind.o: dcebind.c simpdce.h $(CC) -c $(DCECFLAGS) dcebind.c simpgw: simpdce.idl gwinit.o dcebind.o dceepv.o blds_dce -i -no_mepv -o simpgw -f -g -f gwinit.o -f \ dcebind.o -f dceepv.o simpdce.idl # DCE server simpdce_sstub.o simpdce.h: simpdce.idl $(IDL) -client none -keep object simpdce.idl dceserver.o: dceserver.c simpdce.h $(CC) -c $(DCECFLAGS) dceserver.c dcemgr.o: dcemgr.c simpdce.h $(CC) -c $(DCECFLAGS) dcemgr.c dceserver: simpdce_sstub.o dceserver.o dcemgr.o $(CC) dceserver.o simpdce_sstub.o dcemgr.o -o dceserver \ $(DCELIBS) # Cleanup clean:: rm -f *.o server $(ALL2) ULOG.* TUXCONFIG rm -f stderr stdout *stub.c *.h simpdce.idl gwinit.c clobber: clean
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, "A Sample Application." 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
.
Modify the ASCII ubbconfig
configuration file as described in Appendix A, "A Sample Application." (This step is mandatory.)
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.)
Before building the software, you must modify rpcsimp.mk
to set the correct options and libraries for building the DCE server, as described above.
Build the client and server programs by running the following:
make -f rpcsimp.mk TUXDIR=$TUXDIR all2
Load the binary TUXCONFIG
configuration file by running the following:
tmloadcf -y ubbconfig
To set up DCE entities for running this example, as described earlier, you must customize (for your environment) identifiers in all capital letters.
If you already have a DCE principal for yourself, you do not need to create MYGROUP
, MYPRINCIPAL
, or the associated account.
This example assumes that the cell_admin
password is the default -dce
. (You can change this password as necessary.)
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.
Example B-5 DCE Configuration
$ dce_login cell_admin -dce- $ rgy_edit > domain group > add SERVER_PRINCIPAL_GROUP > add MYGROUP > domain principal > add SERVER_PRINCIPAL > add MYPRINCIPAL > domain account > add SERVER_PRINCIPAL -g SERVER_PRINCIPAL_GROUP -o none -pw \ SERVERPASSWORD -mp -dce- > add MYPRINCIPAL -g MYGROUP -o none -pw MYPASSWORD -mp -dce- > ktadd -p SERVER_PRINCIPAL -pw SERVERPASSWORD -f SERVER_KEYTAB > q $ chown SERVER_PRINCIPAL SERVER_KEYTAB $ chmod 0600 SERVER_KEYTAB
Log in as SERVER_PRINCIPAL
(the owner of the server key table).
Start the DCE server by running the following:
dceserver &
The message Server ready
is displayed just before the DCE server starts listening for requests.
Boot the Oracle Tuxedo ATMI application by running the following:
tmboot -y
The client program can be run by optionally specifying a string to be converted, first to uppercase, and then to lowercase:
$ client HeLlO to_upper returns: HELLO to_lower returns: hello $