OSF DCE Application Development Guide Introduction and Style Guide Revision 1.
The information contained within this document is subject to change without notice. OSF MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS MATERIAL, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. OSF shall not be liable for errors contained herein, or for any direct or indirect, incidental, special or consequential damages in connection with the furnishing, performance, or use of this material.
RESTRICTED RIGHTS NOTICE: Use, duplication, or disclosure by the Government is subject to the restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 52.2277013. RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the Government is subject to restrictions as set forth in paragraph (b)(3)(B) of the rights in Technical Data and Computer Software clause in DAR 7-104.9(a). This computer software is submitted with "restricted rights.
0− 0 Tandem Computers Incorporated 124246
Contents _____________________________ Preface . . . . . . . . . . . . . . . . . . . . . . . . . . ix Audience . . . . . . . . . . . . . . . . . . . . ix Applicability . . . . . . . . . . . . . . . . . . . ix Purpose . . . . . . . . . . . . . . . . . . ix . . . . . . . . . . . . . . . . . . x . . Document Usage Related Documents . . . . . . Typographic and Keying Conventions Problem Reporting . . . .
OSF DCE Application Development Guide—Introduction and Style Guide 1.6.2 Annotating the Binding Handle for Security . . 1.6.3 Invoking Remote Procedure Calls . . . . . . . . . . . 1-27 1-29 1.7 The Server’s Manager of RPC Requests . . . . . . . . . 1.7.1 Getting the Client’s Credentials . . . . . . . . . 1.7.2 Getting the Object’s ACL . . . . . . . . . . . 1.7.3 Making the Authorization Decision . . . . . . . . 1.7.4 Servicing the RPC Request . . . . . . . . . . 1.7.
Contents 4.3 Binding Methods . . Chapter 5. Using the DCE Name Service 5.1 . . . . . . . . . . . . . . . 4-9 . . . . . . . . . . . . . . . 5-1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-1 5-2 5-2 5-3 5-3 . . . Introduction to Using NSI . . . 5.1.1 The UUID . . . . . 5.1.2 Object UUIDs . . . . 5.1.3 Interface UUIDs . . . 5.1.4 Summary: Names and UUIDs . . . . 5.
OSF DCE Application Development Guide—Introduction and Style Guide 6.2.3 S e r v e r 6.3 Side Allocation RPC Data Types . . . . . 6.3.1 IDL to C Type Mappings 6.3.2 Character Handling . . 6.3.3 Pointers . . . . . 6.3.4 Context Handles . . 6.3.5 Arrays . . . . . 6.3.6 Structures and Unions . 6.3.7 Pipes . . . . . . 6.3.8 The transmit_as Attribute Chapter 7. Errors and Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . .............. 6-5 . . . . . . . . . . . . . . . . . . . . . . .
Contents LIST OF FIGURES Figure 1-1. The Combined Effect of IDL and the RPC Runtime . . . . . . . . . . 1-2 Figure 4-1. Information Required to Complete an RPC . . . . . . . . . . . . . 4-2 Figure 4-2. Server Binding Relationships . . . . . . . . . . . . . 4-4 . . . . Figure 4-3. Methods of Binding Management . . . . . . . . . . . . . . . Figure 5-1. How a Name Turns into an Object . . . . . . . . . . . . . . . 5-3 . . . . . . . . . .
OSF DCE Application Development Guide—Introduction and Style Guide LIST OF TABLES TABLE 2-1. Thread-Safe Calls . . . . . . . . . . . . . . . . TABLE 2-2. Cancelability State . . . . . . . . . . . . . . . . . . . . TABLE 3-1. Authentication . TABLE 4-1. Binding Semantics . . . . . . . . . . . . . . . . . - . 4 . - . . . . . . . . . . . . . . . . . . . . . 2-6 1 0 . 3-2 1 3 5-16 . . . . . . . . . . . . . . . 6-3 TABLE 6-2.
Preface The OSF DCE Application Development Guide provides information about how to TM program the application programming interfaces (APIs) provided for each OSF Distributed Computing Environment (DCE) component. Audience This guide is written for application programmers with UNIX operating system and C language experience who want to develop and write applications to run on DCE. Applicability This is Revision 1.1 of this document. It applies to the OSFTM DCE Version 1.1 offering and related updates.
OSF DCE Application Development Guide—Introduction and Style Guide Document Usage The OSF DCE Application Development Guide consists of three books, as follows: • • — Part 1. DCE Facilities — Part 2. DCE Threads — Part 3. DCE Remote Procedure Call — Part 4. DCE Distributed Time Service — Part 5. DCE Security Service • — Part 1. DCE Directory Service — Part 2. CDS Application Programming — Part 3. GDS Application Programming — Part 4.
Preface Typographic and Keying Conventions This guide uses the following typographic conventions: Bold Bold words or characters represent system elements that you must use literally, such as commands, options, and pathnames. Italic Italic words or characters represent variable values that you must supply. Constant width Examples and information that the system displays appear in constant width typeface. [] Brackets enclose optional items in format and syntax descriptions.
Chapter 1. Introduction to DCE Application Programming The majority of this first chapter consists of a fairly detailed overview of each of the separate steps that a developer usually has to perform (or have the application perform) from the beginning of coding to the end of execution of a successful DCE application. Before you begin a serious study of the contents of any part of this guide, or indeed of any other book in the DCE documentation set, you should read the Introduction to OSF DCE.
OSF DCE Application Development Guide—Introduction and Style Guide 1.1 Development Overview Most of the effort of developing a DCE application usually lies in the familiar steps of planning, writing and compiling the necessary C code, linking the result with the DCE library and other modules, and executing it (perhaps repeatedly). However, there is an important preliminary task which must be performed before you write any other code.
Introduction to DCE Application Programming RPCClient RPC Server Calling code .. . .. .. .. .. .. .. .. .. .. .. .. RPC interface Client stub RPC runtime .. . .. .. .. .. .. .. .. .. .. .. .. apparent path of data due to IDL and RPC Remote procedure .. .. . .. .. .. .. .. .. .. .. .. .. .. RPC interface Server stub RPC runtime ... . .. .. .. .. .. .. .. .. .. .. ..
OSF DCE Application Development Guide—Introduction and Style Guide Following is an overview list of all 21 steps, separated into the four main phases previously described. Each step’s numeral is followed by a / (slash) and the terms Client and/or Server to indicate whether it applies to the application’s server or client, or both. A. CLIENT and SERVER: Define the IDL interface A1/Client and Server: Generate the interface UUID A2/Client and Server: Write the .idl file A3/Client and Server: Write the .
Introduction to DCE Application Programming 1.3 DCE Application Development Tools The following DCE tools allow developers to define and manage a set of programs intended to run in a DCE environment. • Unique identification Because DCE involves the interaction of many distinct programs, operating on several processors that may be quite remote from each other, every entity (such as programs, interface definitions, and so forth) needs a unique identifier. This identifier is provided by the UUID generator.
OSF DCE Application Development Guide—Introduction and Style Guide 1.3.2 DCE Interface Definition Language As was mentioned earlier in this chapter, developing a DCE application involves writing and compiling an interface definition, which defines the application’s client/server interface. Application developers use IDL to write the interface definition. IDL is a high-level descriptive language whose syntax resembles that of ANSI C. IDL is a declarative, not a procedural, language.
Introduction to DCE Application Programming reference the application code needs to access the interface handle. The interface handle allows the application code to refer to the interface specification in calls to the RPC runtime. Runtime operations obtain required information about the interface, such as its UUID and version numbers, directly from the interface specification. You run the IDL compiler by issuing the idl command.
OSF DCE Application Development Guide—Introduction and Style Guide If a client makes a remote procedure call to a host without providing an endpoint, the dced searches its endpoint map for the endpoint of a compatible server. Upon finding a suitable endpoint, the endpoint mapper service (depending on the protocols used) forwards the call to that endpoint or returns the endpoint to the client’s runtime, which sends the call to the server at that endpoint.
Introduction to DCE Application Programming includes the following: principal create ... acl mod /.:/sec/principal/... • It is recommended that you have dced start your application by using server configuration information. It is generally better to do this by writing a dcecp script that sets up the server configuration information (the arguments to start the executable) rather than doing it with C code that calls the dced_server_create() API.
OSF DCE Application Development Guide—Introduction and Style Guide 1.4.1 Generating the Interface UUID Interfaces, like most other objects and entities in DCE, are identified by associating each one with a 128-bit universal unique identifier (UUID). An interface’s UUID serves to identify it far and wide throughout DCE. Every interface in a DCE application must have a UUID assigned to it. When you define a new interface, you must generate a UUID for it.
Introduction to DCE Application Programming a procedure in terms of their data types, access method, and call order, and declares the data type of the return value (if any). The skeletal interface definition produced by the uuidgen utility provides an interface header that contains the newly generated UUID for the interface, a version number, and a dummy string INTERFACENAME.
OSF DCE Application Development Guide—Introduction and Style Guide 1.4.4 Processing the Files with the IDL Compiler IDL’s input is an xxx.idl and (optionally) an xxx.acf file. Its default output is a header (xxx.
Introduction to DCE Application Programming • After a failure of the server it can be restarted If dced did not start the server, it cannot control it. Therefore, one of the first things your server should do is to verify that dced started it by obtaining the configuration information, as in the following: server_t *server_conf; . . . dce_server_inq_server(&server_conf, &status); if(status != error_status_ok) { . . .
OSF DCE Application Development Guide—Introduction and Style Guide • Messages do not need to be hard-coded into applications • Message routing can be better controlled The following routine shows how a server can report a status code returned from an API routine: void print_server_error( char *caller, /* Routine that received the error. */ error_status_t status) /* Status we want to print the message for.
Introduction to DCE Application Programming dce_msg_define_msg_table(smp__table, sizeof smp__table / sizeof smp__table[0], &status); if (status != error_status_ok) { print_server_error("dce_msg_define_msg_table()", status); exit(1); } dce_svc_printf(SIGN_ON_MSG); . . . DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling dce_server_sec_begin()"); 1.5.2 Setting Up the Server’s Objects The term object is a very general term that has meaning specific to each application.
OSF DCE Application Development Guide—Introduction and Style Guide . /* These are the backing store database handles: */ dce_db_handle_t db_acl, db_object, db_name; . . . /* A UUID for a sample object: */ uuid_t sample_object_uuid = {/* 00415371-f29a-1d3d-b8c8-0000c0d4de56 */ 0x00415371, 0xf29a, 0x1d3d, 0xb8, 0xc8, 0x00, 0x00, 0xc0, 0xd4, 0xde, 0x56 }; . . . uuid_create(&server_uuid, &status); .. .. ..
Introduction to DCE Application Programming 1.5.2.1 Object UUIDs in Bindings Object UUIDs are often used in the DCE RPC binding mechanism. The details of RPC binding are explained in Section 1.5.5, and more thoroughly in Chapter 4. It all comes down to this: clients import only partial bindings from the namespace. These will carry them only as far as the endpoint mapper service of the dced on the destination server’s host; it is dced’s job to resolve the binding with a dynamic endpoint.
OSF DCE Application Development Guide—Introduction and Style Guide that object UUID binding happens only once in an uninterrupted client/server session; after the partial binding is completed, communications proceed directly between the client and server. Type manager vectoring, on the other hand, occurs every time an incoming RPC contains an object UUID.
Introduction to DCE Application Programming To control access to the server’s objects, ACL managers are also set up. 1.5.4 Defining the Manager Entry Point Vectors for Each Set of Operations Manager is the DCE term for the part of a server that actually implements a set of interface operations (the remote procedures), as distinguished from the more or less generic server initialization code described here. (see sample_manager.c for an example of manager code).
OSF DCE Application Development Guide—Introduction and Style Guide The dce_server_register( ) routine affects a number of components and services in DCE including the RPC runtime, the local endpoint mapper service, and if the dce_server_c_ns_export flag is set, even the CDS namespace. The server_conf structure is obtained with a call to the dce_server_inq_server() routine and represents the configuration dced used to start the server. This contains information needed to register the server too.
Introduction to DCE Application Programming 1.5.5.2 Telling RPC Runtime What Protocol Sequences to Use The second thing registering the server does is it obtains a set of endpoints and associates them with the desired protocol sequences. Endpoints are the host’s address numbers on which the server can receive incoming calls. This begins the process of actually setting up the information that the server’s clients will need in order to bind to it.
OSF DCE Application Development Guide—Introduction and Style Guide An incoming RPC always has an interface UUID associated with it; therefore, if a server registers all of its endpoints with the interface it is offering, this will usually be sufficient for the endpoint mapper to send the incoming requests to one of the servers that offer the desired interface, even if there is more than one such server active on the machine.
Introduction to DCE Application Programming recommended way for clients and servers to find each other because it is a convenient and easy to use service built into DCE. 1.5.6 Specifying Multithreadedness The application may also spawn an additional thread for a signal handler.
OSF DCE Application Development Guide—Introduction and Style Guide The max_calls_exec parameter specifies the number of concurrent remote procedure calls the server can execute. This call normally begins a ‘‘semi-infinite’’ loop, execution of which is terminated only by one of the following events: • One of the server’s manager routines calls rpc_mgmt_stop_server_listening( ) • One of the server’s clients makes a remote call using the routine rpc_mgmt_stop_server_listening( ).
Introduction to DCE Application Programming routine: dce_server_unregister(server_handle, &status); In addition to unregistering the server’s address information from the local endpoint mapper’s database, this routine unregisters all the services (interfaces and EPVs) from the RPC runtime as well. If your application requires a partial shutdown or a particular order to the shutdown of services, you can use more specific routines such as rpc_ep_unregister( ) and dce_server_disable_service( ). 1.5.8.
OSF DCE Application Development Guide—Introduction and Style Guide 1.6.1 Importing the Binding Information from the Namespace The first important thing that the client does is to acquire a binding to the server it wants to request services from. From the client’s point of view, there are several binding choices to be made. The first choice is in regard to the binding method to be used; however, this is determined and implemented as part of the development coding process (the .acf file).
Introduction to DCE Application Programming 1.6.1.2 Determing the Entry Name To determine how the client knows the entry name to import from, the simplest method is to have the user type it in on the command line. 1.6.1.3 Binding Compatibility The protocol sequence used must be supported by both the RPC runtime and the operating system on the client’s machine.
OSF DCE Application Development Guide—Introduction and Style Guide also supply a handle to rpc_binding_set_auth_info(). its own login context when it calls There are several ways to determine the server’s principal name, as follows: • The server’s principal name could be hardcoded in the client. This is not recommended practice for reasons of robustness and flexibility. • The client can be handed the name as input from the command line when it is invoked.
Introduction to DCE Application Programming The usual practice is to pass NULL for login_context here, and thus use the default context. Note that it is the client who chooses whether or not to use authenticated RPC, as well as the level of authentication, and how much authorization information about itself to send. It is then up to the server to accept this arrangement or reject it, or to allow some limited operation with the client, or whatever else it might decide.
OSF DCE Application Development Guide—Introduction and Style Guide 1.6.3.1 The Possibility of Binding Failure Perhaps the most important thing to mention about this step is that it may not at first succeed. Remember that the client imported a partial binding to the server.
Introduction to DCE Application Programming 1.7 The Server’s Manager of RPC Requests As was explained, server threads are automatically spawned by the RPC runtime in the server manager to handle incoming remote procedure calls from clients. The number of calls that can be concurrently handled depends on the value of the max_calls_exec parameter specified in the call to rpc_server_listen(). The thread is created by the RPC runtime and begins execution in the operation requested.
OSF DCE Application Development Guide—Introduction and Style Guide • Nothing. The client chooses not to provide any authorization information. From now on, it is the server’s decision, as implemented by the developer, how to respond to the client’s requests for services and resources, depending on the security information the server has learned about it. A non-ACL-based strategy may be implemented using the client’s principal name string for lookups.
Introduction to DCE Application Programming the appropriate action. The application may choose to implement more than one type of ACL (reflecting the different kinds of objects and resources to be protected), thus resulting in several ACL type managers. Although it is up to the application to implement its own ACL storage, testing algorithms and manager types, there are certain DCE-wide design conventions that should be kept in mind and departed from only for good reason.
OSF DCE Application Development Guide—Introduction and Style Guide blocking on the call to rpc_server_listen( ) which was made earlier. If max_calls_exec was specified to be greater than 1 in that call, other threads may still be executing at this time in response to other requests that have been received from other clients. In any case, the call to rpc_server_listen() will not return until one of the server’s own management routines, or a client, makes a successful call to rpc_mgmt_stop_server_listening().
Introduction to DCE Application Programming mechanisms, so many possible ways of doing things, that it is often difficult for the programmer to decide among them. The guidelines provided by the AES/DC are limited to only one (albeit an important one) policy issue: portability. The DCE programmer is still left with many decisions about issues that do not arise in the typical local programming environment: how to use the name services, which security services to employ, how many threads to use, and so on.
OSF DCE Application Development Guide—Introduction and Style Guide The distinction between policy and style is itself somewhat vague. In general, policy refers to the things you should do in an application program. You can usually identify a policy recommendation because the words ‘‘should,’’ ‘‘must’’ or ‘‘recommended’’ appear. Style is a more general term that includes policy (hence ‘‘Style Guide’’), but that also covers a variety of other suggestions about how you might do things.
Introduction to DCE Application Programming In addition to being complex, DCE application programming involves elements that are likely to be unfamiliar to many programmers, such as remote parameter passing, name services, and distributed security services. Another goal of the Style Guide is to suggest wise uses for these tools, since many of the familiar local programming models are inadequate.
OSF DCE Application Development Guide—Introduction and Style Guide — Applications need to be as configuration and location independent as possible. In particular, this means giving careful thought to the use of name services for advertizing and finding resources. — Applications require both local and DCE identities and privileges. They should follow the recommended models for acquiring and maintaining these privileges and identities.
Chapter 2. Threads Threads as used specifically in DCE applications raise several obvious policy issues which may be summarized, roughly, as follows: • When to use multiple threads • How many threads to use • What scheduling and priority attributes to apply These issues are covered in Section 2.1. Beyond these obvious policy questions, however, threads raise a tricky issue for a programming policy guide because it is not always clear where the line between mechanism and policy lies.
OSF DCE Application Development Guide—Introduction and Style Guide must be taken and released in the same strict order. Rules like this are in not enforced by the thread programming mechanisms, and failure to follow them will not always result in program failures.
Threads On the other hand, if multiple threads are carrying out activities that may block—and this includes making RPCs to remote hosts—then multithreading will probably be beneficial. For example, multiple concurrent RPCs to several hosts may allow a local client to achieve true parallelism. Note however, that concurrent RPCs to a single server instance may not be any more efficient if the server itself cannot get any real benefit from multithreading of the manager code.
OSF DCE Application Development Guide—Introduction and Style Guide conjunction, but in practice, the interpretation of the max_calls_requests parameter is highly dependent on protocol and implementation. For example, in a connection-oriented protocol based on Berkeley sockets, the socket backlog—the number of connections which may be queued on a socket pending acceptance—typically has a value of five.
Threads These thread safety issues arise in the following two contexts for DCE applications: • Even when application code is not itself multithreaded (for example, client code that does not make any explicit pthread API calls), both client and server applications are still multithreaded as a result of threads created by the RPC runtime.
OSF DCE Application Development Guide—Introduction and Style Guide TABLE 2-1.
Threads scheduling policy (SCHED_OTHER) mitigates the effects of priority inversion by giving low-priority threads a chance to execute (and thus release held locks) even when higher-priority threads are eligible to run. • You may be able to use the global locking call pthread_lock_global_np() when calling into libraries not known to be thread safe. • Use the atfork( ) routine to keep the state of mutexes consistent across calls to fork( ). Note, however, that this routine is not considered portable.
OSF DCE Application Development Guide—Introduction and Style Guide 2.3.2 Storage for Thread Specific Data The pthread package provides the ability to allocate per-thread global storage using per-thread data keys. That is, an application can create storage that has global scope within a thread but which is private to each instance of that thread. To do this, the application creates a global data key by calling pthread_keycreate( ).
Threads *global_var = value; } /* The following routine returns the thread-specific value ... */ mytype read_global() { mytype *global_var; /* Note the extra indirection; pthread_getspecific() returns /* the address of the thread’s private instance of the /* storage... */ */ */ pthread_getspecific(key, (pthread_addr_t*)&global_var); return (*global_var); } 2.3.
OSF DCE Application Development Guide—Introduction and Style Guide 2.3.3.1 Cancelability State A thread’s cancelability state is determined by the combination of two substates: general cancelability and asynchronous cancelability. These substates can be set to either CANCEL_ON or CANCEL_OFF by calls to the routines pthread_setcancel( ) and pthread_setasynccancel( ) respectively. A thread’s cancelability state is determined by its general and asynchronous cancelability substates, as shown in Table 2-2.
Threads • During the timeslice interruption. • Within the DCE threads I/O wrappers for system calls that block.
OSF DCE Application Development Guide—Introduction and Style Guide 2.3.3.3 Cancellation Side Effects Cancellation ordinarily involves cleanup in order to leave resources in an orderly state. Any side effects of acting upon a cancellation request occur before the first cleanup routine is called. There are no side effects of acting upon a cancellation request while executing pthread_join( ).
Threads some_object.num_waiters = some_object.num_waiters + 1; /* Enter the exception handling block... TRY */ /* Test the predicate condition... while (! some_object.data_available) */ /* If the desired condition is not yet true, wait for */ /* it to become true. This next call also auto*/ /* matically releases the mutex... */ pthread_cond_wait(some_object.condition, some_object.mutex); /* Code to access data_available goes here */ <...
OSF DCE Application Development Guide—Introduction and Style Guide Cleanup routines are also invoked when the thread calls pthread_exit( ). Cleanup routines should never exit via longjmp( ) or siglongjmp( ). 2.3.3.5 Asynchronous Cancel Safety A function is said to be asynchronous cancel safe if it is written in such a way that entering the function with the cancelability state of asynchronous will not cause any invariants to be violated if cancellation should occur at any (arbitrary) instruction.
Threads Application developers must be aware of significant differences in the handling of signals between DCE threads and typical single-threaded environments. In DCE threads, some signals are handled on a per-process basis, and some are handled on a per-thread basis. This section explains the semantic details of DCE thread signal handling. A signal is said to be generated for a process or thread when the event that causes the signal first occurs.
OSF DCE Application Development Guide—Introduction and Style Guide 2.3.4.2 Synchronous Signal Handling Threads should call sigaction( ) to establish per-thread handlers for synchronous signals. The DCE Threads sigaction( ) function only modifies the signal action behavior for the calling thread and only works for synchronous signals. Threads must not use sigaction( ) for asynchronous signals. Signal handlers should be careful in the actions they perform.
Threads /* * * * * */ This is run by the signal catcher thread to handle async signals. We don’t use sigaction() here because it won’t work with async signals. Note that signals must be blocked prior to being waited for. void signal_catcher(char *arg) { sigset_t signals; int sig; sigemptyset(&signals); /* In this sample, we’ll catch only SIGINT...
OSF DCE Application Development Guide—Introduction and Style Guide 2.3.4.4 Signal Rules The following rules summarize correct signal handing practices for multithreaded programs. • Signals must be blocked prior to being waited for. The sigwait( ) routine waits for blocked (masked) signals. • In order to avoid unpredictable behavior, all asynchronous signal handling should be confined to one signal catcher thread. This may be extended to a set of signal catcher threads.
Threads handler’’ routines for an application or a library.
OSF DCE Application Development Guide—Introduction and Style Guide 2− 20 2. If cancelability state is deferred, then cancellation requests will be sent to the server where they will be handled according to the server’s setting of the cancelability state for the application thread extension (that is, the call thread) in the server. If ignored at the server, the client side would then effect the cancel upon return from the RPC, so the cancel would not be lost or incorrectly handled.
Chapter 3. Security For the purposes of the discussion in this chapter, the security services provided by DCE are assumed to consist of three elements: authentication, access control, and data protection. (The DCE Audit Service, which is also a part of DCE security, is described in the .
OSF DCE Application Development Guide—Introduction and Style Guide 3.1 The Basic Security Model At a high level, the DCE security model is as follows. Servers specify the authentication service they use (currently either none or DCE secret key). Clients request an authentication service (which may be none) when making a call. When a server specifies an authentication service, it is specifying the service it will use if authentication is requested by the client.
Security It is entirely up to the application manager code to make an access decision based on any authentication and authorization data provided by the runtime for a client. Clients specify an authorization service for each binding: either none (rpc_c_authz_none), client principal name-based authentication (rpc_c_authz_name), or DCE credentialbased authentication (rpc_c_authz_dce).
OSF DCE Application Development Guide—Introduction and Style Guide set of ACL management APIs is provided to make these tasks easier, but the work required remains nontrivial. The steps are covered in detail in Section 3.4 of this chapter. 3.3 Authentication Model The DCE authentication model is currently based on the Kerberos shared secret key protocol. In theory, the application-level interface to authentication is sufficiently abstract that an alternative authentication protocol can be implemented.
Security explicitly by clients. In the case of the server, these activities are usually carried out by the server explicitly. The reasons for this difference are one of the topics covered in the discussion that follows. 3. Authentication related RPC protocol activity is then carried out transparently by the RPC runtime during each call.
OSF DCE Application Development Guide—Introduction and Style Guide From the RPC point of view, the basic model is that servers are persistent entities in the sense that they normally perform services on behalf of more than one client principal session. This may mean that servers are persistent in time: that is, that they run for a long time, possibly for as long as the machine they are running on is up and running.
Security system access control to the key storage (typically a so-called keytab file) for the DCE principal identity used by the server. However, since servers normally also need to acquire credentials (in order to behave as clients of other services), application programmers need to think carefully about how the server identity is acquired. In general, it is not satisfactory to have servers run with credentials inherited from human logins.
OSF DCE Application Development Guide—Introduction and Style Guide The setup and validation operations are separate in order to minimize the amount of time that the application needs to maintain the principal’s key in its address space. Applications obtain the principal’s key by calling sec_key_mgmt_get_key(). The call to sec_login_validate_identity() destroys the key in place before returning. Applications should not violate the intention of this design by keeping the key in memory longer than necessary.
Security under which they run and make this the default login context. The principal name specified to rpc_binding_set_auth_info( ) establishes the principal for which Kerberos service tickets will be requested for RPCs on the binding handle. An application making RPC calls may or may not care about who the server principal is. The client may be satisfied to call any server that provides the service it wants, or the client may need to trust the server and thus require a trusted server principal identity.
OSF DCE Application Development Guide—Introduction and Style Guide randomly generated and updated frequently (as enforced by administrative policy). This means that servers do not have DCE passwords; passwords should be used for human login only. In general, the domains of human and nonhuman users should be separate. For example, a human user needs a password from a restricted domain (typable on the keyboard), hence keys tied to passwords are generally less secure than keys not tied to passwords.
Security In order to save space and to improve the readability of the text, the code shown below has been slightly edited: all status checks, and all calls to the DCE serviceability interface (to print or log status or informational messages), have been removed. 3.3.6.1 The managekey Routine The managekey( ) routine manages the server principal’s key, making sure that it never expires. /****** * * managekey -- Make sure the server principal’s key is changed before * it expires.
OSF DCE Application Development Guide—Introduction and Style Guide void server_get_identity( unsigned_char_p_t prin_name, sec_login_handle_t *login_context, unsigned_char_p_t keytab, unsigned32 *status) { /* Server principal name. /* Returns server’s login context. /* Local key file. */ */ */ pthread_t keymgr; sec_passwd_rec_t *keydata; sec_login_auth_src_t auth_src; boolean32 reset_pwd; *status = error_status_ok; /* Spin off thread to manage key for specified principal...
Security 3.3.6.3 The server_renew_identity Routine The server_renew_identity( ) routine makes sure that the server’s credentials are valid. /****** * * server_renew_identity -- Make sure that credentials are still valid, and * renew them if they are not. * * * This routine is called (with the current credentials) whenever a task * is about to be attempted that requires valid credentials. For an ex* ample, see the cleanup code in "main()" above.
OSF DCE Application Development Guide—Introduction and Style Guide status); /* Get key from local file... sec_key_mgmt_get_key(rpc_c_authn_dce_secret, keytab, prin_name, 0, (void**)&keydata, status); */ /* Validate the login context...
Security server identities, then it needs to check the returned value against the acceptable ones. The list of acceptable values must be obtained and maintained by the client by some means of its own choosing: for example, a principal name could be obtained from an environment variable. The only security issue here is that the client must be sure that the list of acceptable values is a legitimate one. For example, it must not be stored in such a way that a false server can modify it.
OSF DCE Application Development Guide—Introduction and Style Guide /* Now bind to the local cell registry... sec_rgy_site_open(cell_name, &rhandle, status); */ /* Free the cellname string space... free(cell_name); */ /* Get the specified principal’s local (cell-relative) name... local_name = malloc(strlen((char *)princ_name)); */ sec_id_parse_name(rhandle, /* Handle to the registry server. */ princ_name, /* Global (full) name of the principal. */ NULL, /* Principal’s home cell name returned here.
Security /* And now find out if it’s a valid member of our sample_servers */ /* group... */ if (is_valid_principal(server_princ_name, (unsigned_char_t *)SGROUP, &status)) { rpc_binding_set_auth_info(binding_h, server_princ_name, rpc_c_protect_level_pkt_integ, rpc_c_authn_dce_secret, NULL, rpc_c_authz_dce, &status); } 3.
OSF DCE Application Development Guide—Introduction and Style Guide The server may of course, simply be satisfied that the client is authenticated and check no further. Or the server can 3. Check that the protection level is acceptable. This too is a matter for negotiation between the client and server applications, but it is important to begin by considering the runtime’s mediation of the protection level request.
Security associated with access privileges). Since the credential-based (ACL) method is designed to provide a general solution to this problem, it is much to be preferred. ACL based access checking is described in the following sections. If the authorization service requested is acceptable, the server application makes the appropriate access tests as described in step 6. 5. Check that the server principal name specified by the client is acceptable.
OSF DCE Application Development Guide—Introduction and Style Guide rpc_authz_handle_t pac; /* Get the client’s credentials... rpc_binding_inq_auth_client(. . . &pac . . &status); */ /* If there is no authentication information, set up a set of null /* credentials...
Security There are two levels of semantics/policy to be considered here. One is the semantics of privilege attributes, for which we specify a strict (POSIX compliant) policy in the form of an access checking algorithm. This is embodied in the default access checking algorithm provided by the ACL library. The second is the semantics of permissions. Ultimately these depend on the ACL manager and the kinds of objects it protects.
OSF DCE Application Development Guide—Introduction and Style Guide Finally, principals that do not meet any of the above criteria can be authorized as any_other. The other_obj, any_other, and foreign_other types are distinguished by cells: other_obj applies to the local cell, foreign_obj applies to specified foreign cells, any_other applies to any cell. The user_obj and group_obj types have less straightforward semantics.
Security ACL library (see Section 3.4.3.2), its ACL management information will be hooked into the remote ACL implementation routines that make up the DCE ACL library. Of course, an application still must take care of the details of storing and retrieving its ACLs (though these tasks are now made much easier by the DCE backing store library routines), setting up definitions that determine how its ACLs are interpreted, and so on.
OSF DCE Application Development Guide—Introduction and Style Guide any requested operation with it. The application is thus not responsible for implementing any ACL interface operations. What the application is responsible for is the following: • Setting up the necessary ACL data types and descriptions. • Supplying a routine that resolves object names into ACL UUIDs. • Setting up persistent databases in which the ACLs can be stored and retrieved. • Initializing the ACLs for all existing objects.
Security • UUIDs to identify the objects must be created. • The ACLs themselves on the relevant objects must be created. • The ACLs must be stored, indexed by UUID, in the backing store database. Setting up an ACL manager is a matter of making these eight things happen. The sample application shows the easiest way of accomplishing this, namely by using the DCE ACL library. See in particular the routine server_acl_mgr_setup() in sample_server.c.
OSF DCE Application Development Guide—Introduction and Style Guide In the sample application, the objects’ state information is practically identical to the objects themselves, since the latter seem not to exist at all except as the information stored in the backing databases. However, this is only partly true. The sample_object object is indeed a dummy and exists only as a pretext for showing how ACLs on objects are set up and manipulated.
Security 2. Use the object UUID to retrieve the object information, which contains (among many other things) the UUID that identifies the object’s ACL (in the object UUID-indexed database). 3. Use the retrieved ACL UUID to retrieve the ACL itself (from the ACL UUIDindexed database). If the manager types match, return the ACL UUID extracted in step 2 to the caller. The caller is usually some routine in the ACL library.
OSF DCE Application Development Guide—Introduction and Style Guide there is a m_inq_if permission (permission to execute the rpc_mgmt_inq_if_ids( ) routine against the server). This permission makes sense only in the context of the server_mgmt object. A manager type identifies what set of permissions applies to a given set of objects. 3.4.3.
Security This is done by calling the application’s registered resolver routine; the library finds the right resolver routine by calling all the resolvers that have been registered with it until it gets a successful return. It finds the ACL manager type in the same way, since it calls each attempted resolver passing the manager type UUID that was registered with it. See the sample_resolve_by_name() function in the sample_server.c file. 3.4.3.
OSF DCE Application Development Guide—Introduction and Style Guide • The owner of the object • The owner’s group • The object’s ACL • The default object ACL • The default container ACL The standard header is a convenient means of keeping track of all the object’s associated UUIDs, without having to define fields for them in one’s own data structure. It is initialized by a call to the dce_db_std_header_init( ) routine. This is the only database whose data type is explicitly defined in the .
Security 3.4.3.13 ACL Manager Coding Example The following subsections contain extracts from the DCE sample application which is reprinted in full in Appendix A. The subsections below contain only the ACL manager code portions of the server application. In order to save space and to improve the readability of the text, the code shown below has been slightly edited: all status checks, and all calls to the DCE serviceability interface (to print or log status or informational messages), have been removed.
OSF DCE Application Development Guide—Introduction and Style Guide 0x001a15a9, 0x3382, 0x1d23, 0xa1, 0x6a, 0x00, 0x00, 0xc0, 0xd4, 0xde, 0x56 }; /* A UUID for a sample object: */ uuid_t sample_object_uuid = {/* 00415371-f29a-1d3d-b8c8-0000c0d4de56 */ 0x00415371, 0xf29a, 0x1d3d, 0xb8, 0xc8, 0x00, 0x00, 0xc0, 0xd4, 0xde, 0x56 }; /* The mgmt printstrings could be treated as standard for /* a standard mgmt ACL manager...
Security void server_get_local_principal_id( unsigned_char_t *p_name, uuid_t *p_id, unsigned32 *status) { char *cell_name; sec_rgy_handle_t rhandle; /* Simple principal name. /* UUID returned here. /* Status returned here. */ */ */ /* For local cell name. /* For registry server handle. */ */ /* First, get the local cell name... dce_cf_get_cell_name(&cell_name, status); */ /* Now bind to the cell’s registry...
OSF DCE Application Development Guide—Introduction and Style Guide void server_create_acl( uuid_t mgr_type_uuid, sec_acl_permset_t perms, unsigned_char_t *user, sec_acl_t *acl, uuid_t *acl_uuid, unsigned32 *status) { uuid_t u; /* /* /* /* /* /* Manager type of ACL to create. Permission set for ACL. Principal name for new entry. To return the ACL entry in. To return the ACL’s UUID in. To return status in. /* For the principal’s UUID (from the registry).
Security dce_db_handle_t db_name, /* Name-indexed store. sec_acl_t *acl, /* The ACL itself. uuid_t *acl_uuid, /* ACL UUID. uuid_t *object_uuid, /* Object UUID. unsigned_char_t *object_name, /* The name of the object. void *object_data, /* The actual object data contents. /* NOTE: NOT USED NOW. boolean32 is_container, /* Are we storing a container ACL? unsigned32 *status) /* To return status.
OSF DCE Application Development Guide—Introduction and Style Guide /* Now store the object data keyed by object UUID... if (strcmp(object_name, SAMPLE_OBJECT_NAME) == 0) strcpy(sample_data.s_data.message, "THIS IS AN OFFICIAL SAMPLE OBJECT TEXT!"); else if (strcmp(object_name, MGMT_OBJ_NAME) == 0) strcpy(sample_data.s_data.message, "THIS IS AN OFFICIAL MGMT OBJECT SAMPLE TEXT!"); else strcpy(sample_data.s_data.
Security /* == TRUE from main(). /* [out] parameters: */ dce_db_handle_t *db_acl, dce_db_handle_t *db_object, dce_db_handle_t *db_name, uuid_t *object_acl_uuid, uuid_t *mgmt_acl_uuid, unsigned32 *status) /* /* /* /* /* ACL-indexed store handle. Object-indexed store handle. Name-indexed store handle. Object ACL UUID. Mgmt ACL UUID.
OSF DCE Application Development Guide—Introduction and Style Guide db_acl, status); /* The returned backing store handle. */ /* Set the global variable that records whether we actually have /* opened the databases; this enables us to avoid calling the /* dce_db_close() routine for unopened databases, which will cause /* a core dump...
Security /********************************************************************/ /* Now register our ACL manager’s object types with the ACL /* library... */ */ /* Register for the mgmt ACL... dce_acl_register_object_type( *db_acl, /* Backing store where ACLs are to be stored. &mgmt_acl_mgr_uuid, /* Type of ACL manager: this one is /* for mgmt ACL operations; the UUID is defined /* globally at the top of this file.
OSF DCE Application Development Guide—Introduction and Style Guide /* Now register for the regular ACL... dce_acl_register_object_type( *db_acl, /* Backing store where ACLs are to be stored. &sample_acl_mgr_uuid, /* Hard-coded at the top of this /* file. sizeof sample_printstr/sizeof sample_printstr[0], /* Number /* of items in our printstring array. sample_printstr, /* An array of sec_acl_printstring_t /* structures containing the printable rep/* resentation of each specified permis/* sion set.
Security machine_principal, &machine_princ_id, status); /* Add a user entry for the machine principal to the new /* ACL... permset = ALL_MGMT_PERMS; dce_acl_obj_add_user_entry( &new_acl, permset, &machine_princ_id, status); */ */ /* By default everybody must be able to get the principal */ /* name. They should be able to ping too. So add an appro- */ /* priate unauthenticated permissions entry to the ACL...
OSF DCE Application Development Guide—Introduction and Style Guide status); /* Null the data header... bzero(&datahdr, sizeof datahdr); */ /* Store the object ACL... server_store_acl( *db_acl, /* The ACL UUID-indexed store. *db_object, /* The object UUID-indexed store. *db_name, /* The name ("residual")-indexed store. &new_acl, /* The ACL itself. object_acl_uuid, /* The object ACL UUID. &object_uuid, /* The object UUID. object_name, /* The object name.
Security /* Set up remote management authorization to use the ACL manager. /* Note that the first parameter to this call is the address of a /* management authorization callback routine, which is defined /* later in this file... rpc_mgmt_set_authorization_fn(sample_mgmt_auth, status); */ */ */ */ /* Finally, register the rdacl interface with the runtime... rpc_server_register_if( rdaclif_v1_0_s_ifspec, /* Interface to register. NULL, /* Manager type UUID.
OSF DCE Application Development Guide—Introduction and Style Guide 3.4.3.20 The server_rdacl_export Routine The server_rdacl_export( ) routine registers the remote ACL interface in the local endpoint map. /****** * * server_rdacl_export -- Make the rdacl interface available * for ACL editors. * * * Note that we don’t export to the namespace. Instead, the ACL editor * will typically bind to the server via some other entry that holds * the application-specific interface bindings.
Security /****** * * server_rdacl_cleanup -- Called at cleanup time to * unregister the rdacl interface. * * * Called from main(). * ******/ void server_rdacl_cleanup( rpc_binding_vector_t *binding_vector, uuid_vector_t *object_uuid_vector, unsigned32 *status) { /* Binding handles from RPC runtime. */ /* Server instance UUID(s). */ *status = error_status_ok; rpc_ep_unregister(rdaclif_v1_0_s_ifspec, binding_vector, object_uuid_vector, status); } 3.4.3.
OSF DCE Application Development Guide—Introduction and Style Guide boolean32 sample_mgmt_auth( rpc_binding_handle_t client_binding, /* Client’s binding, whoever he is. unsigned32 requested_mgmt_operation, /* What client is attempting to do. unsigned32 *status) { boolean32 authorized = 0; sec_acl_permset_t perm_required; unsigned_char_t *uuid_string; */ */ *status = error_status_ok; /* Discover what permission is required in order to do what the /* client is trying to do...
Security 3.4.3.23 The sample_resolve_by_name Routine The sample_resolve_by_name( ) routine derives the ACL UUID of an object from its name. /****** * * sample_resolve_by_name -- take the name of an object, and return the * UUID of the object’s ACL. * * The address of this function is passed (via the call to * server_acl_mgr_setup()) to the dce_acl_register_object_type() call. So * it gets implicitly called anytime someone tries to retrieve the ACL of * an object managed by the ACL manager we’ve set up.
OSF DCE Application Development Guide—Introduction and Style Guide { uuid_t u, *up; /* To hold the retrieved object UUID, and to /* take a pointer to it. unsigned_char_t *uuid_string; sec_acl_t retrieved_acl; */ */ /* The definition of the following is in the sample.idl file. /* /* See the "Examples" section in the dce_db_open() ref page, /* where the skeleton IDL interface for a server’s backing /* store is given.
Security break; default: *acl_uuid = dataheader.s_hdr.tagged_union.h.acl_uuid; } /* Here it might be interesting to try retrieving the ACL itself, /* and e.g seeing what its manager type is...
Chapter 4. Binding Binding is the process by which an RPC client establishes a relationship with a server that supports an interface, object, or some other resource the client is interested in. Since clients operate on server-held resources by making RPCs, you can think of binding, specifically, as creating the state required for an RPC to be made. In practice, the work of binding clients to servers normally involves name and endpoint mapping services.
OSF DCE Application Development Guide—Introduction and Style Guide • An object UUID that can optionally be used for selection among servers and/or manager routines • An interface UUID that identifies the interface to which the called routine belongs • An interface version number that defines compatibility between interface versions • An operation number that identifies a specific operation within the interface Figure 4-1.
Binding 4.1.1 Server Binding Model Figure 4-2 shows the set of relationships that a server must establish to receive remote procedure calls.
OSF DCE Application Development Guide—Introduction and Style Guide Figure 4-2. Server Binding Relationships Stub and Application Code 1. Define the EPV for each manager. Code for Interface foo Maintained by Server Runtime 2. Register the Object UUID/Type UUID associations. foo Manager A EPV A Operation 0 Operation 1 Operation 2 Object UUID Type UUID UUID 1 UUID 2 UUID A UUID A UUID 3 UUID 4 UUID B UUID B UUID 5 UUID B 3. Register the IF ID/Type UUID/EPV associations.
Binding Endpoint Map 5. Export the endpoint information. Full Binding Information Full Binding Information Full Binding Information foo 's IF ID foo 's IF ID foo 's IF ID Object UUID 1 Object UUID 2 Object UUID 3 Full Binding Information Full Binding Information foo 's IF ID foo 's IF ID Object UUID 4 Object UUID 5 Name Service 6. Export the binding information to a name service.
OSF DCE Application Development Guide—Introduction and Style Guide • An operation number Note that the server runtime itself maintains only a very limited set of relationships: interface identifier/type UUID/manager EPV and object UUIDs/type UUIDs. It is especially worth noting that the runtime maintains no relationships between the protocol-address bindings it has created and any of the other information.
Binding 4.1.3 Call Routing Once the server and client have taken all the necessary steps to set up server and client side relationships, the call mechanism can use them to construct a complete binding and call routing when the call is made. When the client makes a call with a binding that lacks an endpoint (typically the case for bindings imported from the name service), the endpoint is acquired from the endpoint mapper on the target host.
OSF DCE Application Development Guide—Introduction and Style Guide The most important issues concern the role of UUIDs in the binding model. Interface identifiers, which consist of a UUID and version number, have a well-defined and unambiguous role. But object UUIDs are somewhat overloaded by the binding model. An object UUID may be used to select bindings from the name service, to select endpoints from the endpoint mapper, and to map a call to the correct manager type within the server.
Binding This leads to two important recommendations: • Servers should export to the namespace at least one UUID as a tag for its endpoints, and should register the UUID with the endpoint map. • Servers which support multiple objects should also support the object management interface(s) discussed in Chapter 5, instead of exporting multiple object UUIDs to the namespace. 4.
OSF DCE Application Development Guide—Introduction and Style Guide • Automatic method This is the simplest method of managing the binding for remote procedure calls of an entire interface. With the automatic method, the server exports its binding information to a namespace, and the client stub automatically manages a binding for the application code. The automatic method completely hides binding management from client application code.
Binding Figure 4-3. Methods of Binding Management Automatic Method Obtain binding information and set global binding handle Client Appl.
OSF DCE Application Development Guide—Introduction and Style Guide to specific operations. Implicit binding allows the client to establish a default binding for an interface. When the [implicit_binding] attribute is applied to a data item in the ACF, then each call that does not specify an explicit binding parameter (either in the IDL or via the [explicit_binding] attribute in the ACF) uses the default binding information referenced by the implicit binding data item.
Binding the context handle. Also, the stub will not attempt to renew such a cached binding if the client-server connection fails. Even if the server is still running and the connection could be reestablished, the server will have rundown the context it is holding for the client, so that the context handle will no longer be valid.
Chapter 5. Using the DCE Name Service Correct use of the DCE RPC Name Service Interface (NSI) is essential to the operation of a distributed application, since NSI is the medium through which the application’s distributed parts must find each other. NSI works with named database entries which are hierarchically organized into subdirectories and referenced by the familiar pathname convention. 5.1 Introduction to Using NSI It is important to remember that names and objects are separate things in DCE.
OSF DCE Application Development Guide—Introduction and Style Guide How then, you might ask, are filenames represented in DCE? Here are two examples of remote filenames: /.../tinseltown.org/fs/doc/jones/app.gd/chap2.ps /.../tinseltown.org/fs/doc/tolstoy/novels/war_and_peace/chap2.ps As you may have guessed, these too are namespace entries, but the entries in this case refer to remote files, and the entry name as a whole is the remote filename.
Using the DCE Name Service As far as the DCE RPC and name service mechanisms are concerned, it is enough if a client is brought into contact with some server, as long as that server offers the service the client is looking for; in other words, as long as the server offers the interface the client wants to use. To accomplish this rendezvous, interface UUIDs are sufficient. They are also mandatory.
OSF DCE Application Development Guide—Introduction and Style Guide object object object server server . .. . .. . .. . .. . ... .. server .. ... ... ............. client client 2: make contact 3: access object binding name client 1: find object 5.
Using the DCE Name Service the following: ls -l /.../tinseltown.org/fs/doc/jones/app.gd The clerk agent program (called as a result of the user’s entering ls) will bind to the remote file server via its /.../tinseltown.org/fs DCE namespace entry, and pass to it the residual DFS entry name doc/jones/app.gd along with other parameters. The ls command behaves this way because the underlying (VFS+ layer) system calls are coded that way.
OSF DCE Application Development Guide—Introduction and Style Guide The dashed lines in the above figure show the progress of the client’s efforts to get access to the desired object, which involves acquiring a binding to the junction server, making contact with it, and passing to it the object’s name. The solid line shows the apparent direct access to the object that the client’s user seems to enjoy. The dotted lines show other possible paths of access to the other objects that the server manages.
Using the DCE Name Service applications normally access CDS through NSI. Applications can get full access to CDS, if necessary, by using the XDS interface. 5.4.1 CDSEntries NSI uses a subset of the many possible kinds of CDS entry in order to accomplish its tasks. CDS entries are characterized by the CDS attributes they have; each entry can have one or more such attributes.
OSF DCE Application Development Guide—Introduction and Style Guide group entry Contains a group attribute. profile entry Contains a profile attribute. There are no official names for hybrid entries that contain other combinations of attributes, which is perhaps another reason for not creating such entries. The general name for entries that contain any of these attributes is NSI entries, since they are a by-product and tool of the NSI DCE RPC library routines. 5.4.
Using the DCE Name Service When applications have occasion to handle OIDs, they do so directly, since the numbers do not change and should not be reused. However, for users’ convenience, CDS also maintains a file (whose name is /opt/dcelocal/etc/cds_attributes) that lists string equivalents for all the OIDs in use in a cell, in entries like the following: 1.3.22.1.1.4 RPC_Profile byte This allows users to see RPC_Profile in output, rather than the mysterious 1.3.22.1.1.4.
OSF DCE Application Development Guide—Introduction and Style Guide Client Server RPC Runtime RPC Runtime import binding export bindings CDS Namespace When a prospective client attempts to import binding information from a namespace entry that it looks up by name, the binding is checked by NSI for compatibility with the client. This is done by comparing interface UUIDs.
Using the DCE Name Service 5.6 Partial Binding and the Endpoint Mapper Binding handles imported by clients from the namespace normally contain only partial binding information. The exported binding information is sufficient to locate the DCE host daemon on the server’s host (the machine the server resides on), but it does not yet include a specific endpoint (UDP or TCP port number) for the desired service on that host.
OSF DCE Application Development Guide—Introduction and Style Guide There is an exception to this scheme. Some servers are designed to occupy well-known addresses. The DCE host daemon itself, dced, is reached in this way, making its accessibility independent of whether or not the namespace is accessible. The endpoint(s) of a well-known address do not change; they are usually specified in the application’s interface specification (contained in its .idl file).
Using the DCE Name Service Figure 5-5. Print Server Entries in Namespace ..... . .. .. .. .. . .. .. .. ... .. .. .. .. .. .. .. .. .. Client .. .. .. .. .. .. .. .. .. .. RPC .. .. .. Runtime .. .. .. .. .. .. .. .. .. .. ..2 .. .. .. .. 1 .. . ....................... . .. .... .. .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. ... .. .. .. .. .. .. .. Print .. Print Print Print .. Server .. Server Server Server .. A .. B C D .. .. .. .. .. .. .. .. .. .. .. .. .. .. 3 ? .. ..
OSF DCE Application Development Guide—Introduction and Style Guide by host machine. Since object UUIDs are generated by the uuid_create() function call (see the OSF DCE Application Development Reference ), servers can create as many of them as they need. For the print server example discussed in the previous section, the namespace entries for the servers could be set up as shown in the following figure. Figure 5-6. Print Server Name Entries with Object UUIDs ... .. . .. .. .. .. . .. .. .. ... .. .. .. ..
Using the DCE Name Service UUIDs. The following figure illustrates this. Figure 5-7. Separate Printer Name Entries Printer "Thorpe" Printer "Field" Printer "Murray" Printer "Ridler" Printer "Batey" Printer "Milford" Printer "Cotta" Printer "Tonson" . ... .. . .. .. . .. . .. .. . .. .. . .. . .. .. . . .. .. . .. .. . .. .. . .. . .. .. . .. . .. .. . .. . .. .. . ... .. .. .. .. .. .. .. Print Print Print .. Print ... Server Server Server Server .. .. B C D .. A .. .. .. .. .. .. .. .. .. .. .. .. ..
OSF DCE Application Development Guide—Introduction and Style Guide TABLE 5-1.
Using the DCE Name Service One way of avoiding unnecessary regeneration of object UUIDs would be to have a restarted server check the namespace for the presence of its previously exported object UUIDs, as demonstrated in the following code fragment. Refer to the OSF DCE Application Development Reference for further information on the function calls. have_object = false; /* Create an inquiry context for inspecting the object /* UUIDs exported to "my_entry_name"...
OSF DCE Application Development Guide—Introduction and Style Guide Whenever you want to offer more than one instance of the same interface on the same host, you must distinguish by object UUID the binding information in the name entries exported by the servers, if it is important to distinguish among the servers when binding to them.
Using the DCE Name Service By setting a namespace up this way, however, you do not necessarily restrict yourself to this one model for accessing binding information. Through the use of two other types of entry, groups and profiles, which can be superimposed on the simple object model, you can set up models where clients bind to abstractions such as services, or directly to the servers themselves. These techniques are described in the next section.
OSF DCE Application Development Guide—Introduction and Style Guide entries, depending on how the client is coded. 5.11.2 Profiles A profile entry specifies a search path or hierarchy of search paths to be followed through the namespace in order to obtain a binding to a server that offers a specified interface.
Using the DCE Name Service entries is searched. The entries in this path may themselves be other profiles, or groups, or simple entries. The search continues until either a compatible binding is found, or the entire path has been unsuccessfully traversed. 5.
OSF DCE Application Development Guide—Introduction and Style Guide Since the client in this model is looking for a specific server, imports will be done directly from the server entries. The only exception to this rule would be where two or more instances of a server were active on the same host, and it was indifferent to the client as to which one it is bound to. The entries for the multiple same-host servers then could be put into a group entry, and binding imports done from the group. 5.12.
Using the DCE Name Service 5.13 Models Based on Non-CDS Databases The three models previously described are not mutually exclusive; if the namespace is set up correctly, all three can coexist at the same time. All three of the models are implemented through the functionality of the DCE RPC name service. Although the emphasis in this discussion has been placed on the storage and retrieval of binding information, the namespace entries can be used to store additional states for objects.
OSF DCE Application Development Guide—Introduction and Style Guide cancel War_and_Peace.ps then how does the server that cancel binds to find the right job to delete? There is no guarantee that cancel will bind to the same server that happened to receive the original print request, so having each print server keep track of its own jobs would not be the answer. One way to keep track of jobs queued would be to have a dedicated job location server as part of the application.
Using the DCE Name Service • A single namespace entry for the server, which contains a binding attribute and, possibly, an object attribute. Thus, this entry contains all the binding information that is exported to the namespace by the server. • One namespace entry for each object that the server offers. Each entry contains an object attribute that contains that object’s UUID, and a group attribute that refers back to the exporting server’s namespace entry.
OSF DCE Application Development Guide—Introduction and Style Guide To create an object UUID for each object that the server intends to export. 2. rpc_server_register_if( ) To register interface(s) and EPVs with the RPC runtime. (This is also where manager types, if any, are registered.) 3. rpc_server_use_all_protseqs( ) To request bindings from the RPC runtime for each object. 4. rpc_server_inq_bindings() To get the binding handles for each object. 5.
Using the DCE Name Service UUID from the object entry, it will use that object UUID in its subsequent import through the group attribute. Thus, the object UUID will be contained in the handle structure that the client presents to the rpc_ns_binding_import_next() call, expecting it to be filled in with binding information. However, the RPC runtime always tries to match such an input object UUID with a UUID contained in the entry that the caller is trying to import from.
OSF DCE Application Development Guide—Introduction and Style Guide 5.15.2 Client Import To bind to an object managed by the server as previously described, a client performs the following series of library calls: • rpc_ns_entry_object_inq_begin() To set up an object inquiry context; the client application here specifies the name of the desired namespace object entry. • rpc_ns_entry_object_inq_next( ) To return the object UUID that the server exported to the object’s entry.
Using the DCE Name Service Since the model described here employs object entries with only group attributes and no binding or profile attributes, using the normal import routine should work fine. • rpc_ns_binding_import_next( ) To read the entry’s group attribute.
OSF DCE Application Development Guide—Introduction and Style Guide Figure 5-10. Importing from a Model That Uses Grouped Bindings . ... .. . .. . .. . .. .. . .. . .. .. . .. . . .. . .. . .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. .. . .. . .. .. . .. .. . ... .. .. ... ... ... .. Server entry .. .. .. .. .. .. .. .. Server .. .. .. ... .. A bindings .. .. .. ... .. . . .. ... .. .. .. .. .. B . . ... .. .. .. .. ... .. .. .. .. .. .. ... ... .. .. .. .. .. .. C .. .. .. .. .. Server .. .. .. .. .. .
Using the DCE Name Service such as binop, spm_library, and so on. If these entries are only being accessed by clients through profiles, their names will not be directly visible to the client anyway. But now imagine a larger organization. The administrator will want to define some naming hierarchy based on geography, organization, or other criteria. Somewhere within this hierarchy some writable directories (or parent directories) would be created, which could contain server entries, profiles, and so on.
Chapter 6. RPC Parameters The RPC mechanism attempts to provide a data model as close as possible to the familiar local call model. For example, you can pass data by reference—by passing a pointer to a data item—despite the fact that client and server do not share an address space. Nevertheless, there are significant differences in both the syntax and semantics of RPC parameter data compared with C language local call data.
OSF DCE Application Development Guide—Introduction and Style Guide Unfortunately, with a remote procedure call, there is no way to guarantee either exactly once or at-least-once call semantics. Instead, RPC provides at-most-once and idempotent semantics. When a call completes and returns to the client, then at-mostonce semantics is equivalent to exactly-once semantics, and idempotent semantics is equivalent to at-least-once.
RPC Parameters IDL also provides two execution semantic attributes of somewhat more limited use: broadcast and maybe. Broadcast semantics may be used with connectionless transports when there are multiple servers on the local network that can handle a call. The client broadcasts the call request to all servers, and completes the call with one of them. Maybe semantics provides a calling style that may be used when a call has no [out] or [in, out] parameters.
OSF DCE Application Development Guide—Introduction and Style Guide This obeys all the rules for output parameters: the address passed to the call points to valid storage, but the contents of that storage need not contain a meaningful value (in this case, need not be a valid pointer). A simple rule of thumb for output parameters is to declare a variable with one less asterisk than contained in the IDL (or RPC API) declaration and pass its address when calling the operation. 6.2.
RPC Parameters in,out parameters For reference pointers, the client application must allocate memory for the pointed-to nodes. For full pointers, on making the call, the client application must allocate memory for the pointed-to node. On return, the stub keeps track of whether each parameter is the original full pointer passed by the client, or a new pointer allocated by the server. If a pointer is unchanged, the returned data overwrites the existing pointedto node.
OSF DCE Application Development Guide—Introduction and Style Guide 6.3 RPC Data Types IDL provides both a number of primitive data types—such as various sizes of integers and floats, bytes, and booleans—as well as pointers and a variety of constructed types based on the primitive types. The use of the primitive types is quite straightforward. The only important policy issues have to do with IDL data type to C data type mappings and with character handling.
RPC Parameters . } On a 32-bit machine, your code could probably use a short safely (since that is how your implementation probably defines idl_short_int, but such usage is not portable to other machine types and is therefore not recommended. The following table shows the IDL to C type mappings for the IDL primitive types. TABLE 6-2.
OSF DCE Application Development Guide—Introduction and Style Guide __________________________________________________________________________________________ } 64-Bit Machines: unsigned long ________________________________________________________________________ TABLE 6-3.
RPC Parameters As a matter of programming style, these types have the advantage that the size of the declared data items is explicitly stated. For this reason their use in both IDL declarations and application C code is recommended. Note also that the following IDL and C typedefs are also made available by implementations a convenient portable declaration for status parameters: typedef unsigned long error_status_t; typedef idl_ulong_int error_status_t; 6.3.
OSF DCE Application Development Guide—Introduction and Style Guide One effect of this is that pointers only reference the marshalled data itself; that is, data of the size determined by the stub. For example, passing an idl_char * parameter causes the stub to marshall a single idl_char, since that is the size of the object pointed to by an idl_char *.
RPC Parameters 6.3.3.2 Pointer Types For reasons of efficiency, IDL distinguishes between reference [ref], full [ptr], and unique [unique] pointers. As we saw above, even though pointers are used by applications to pass data by reference, the lack of shared address space means that the stubs have to pass the data by value and provide the receiver with a reference to the passed data. In the simplest case, a pointer always points to the same memory: that is, its value does not change.
OSF DCE Application Development Guide—Introduction and Style Guide server. The top-level pointer is thus the address of the parameter container, and obviously, this value should not change during the course of the call. If it did, the return value would be written to some undetermined place in the client address space. Hence, the top level of [out] and [in,out] parameters have reference pointer semantics. The IDL compiler enforces this for [out] parameters by permitting only the [ref] attribute.
RPC Parameters side. However, this default behavior can be modified by applying the [reflect_deletions] attribute to the operation. In this case, the client-side stub will deallocate the pointer referent. The client and server must use the rpc_sm_* routines to allocate and free memory for this reflection of deletions to work. • For an [in,out] parameter which is a [ptr] pointer, if the server sets the parameter value to NULL, the client will no longer be able to dereference the pointer on return.
OSF DCE Application Development Guide—Introduction and Style Guide The server manager code to implement this points the client pointer to the beginning of the array and then increments it once: void ptr_test1( handle_t h, num_ptr *client_ptr, num_array client_array, error_status_t *status ) { *status = 0; *client_ptr = client_array; ++(*client_ptr); } On return, the client’s version of the pointer will point to memory that holds the second element of the array.
RPC Parameters input array and return it without incrementing the pointer. The returned pointer will now reference a copy of the original client array with all its elements. It will not, however reference the original array itself. The second pointer example illustrates passing a linked list. The .
OSF DCE Application Development Guide—Introduction and Style Guide An application must be very cautious if it attempts to use pointer parameters in a way that contradicts such semantics: for example, by returning a pointer to static global storage on the server. In such a case, the server and client versions of such storage can easily become inconsistent. A context handle, which the client must not modify, is typically what you want in such a case.
RPC Parameters number_ptr nptr; unsigned32 *nval; nptr = (number_ptr) rpc_sm_allocate(sizeof(number), status); nval = (unsigned32 *) rpc_sm_allocate(sizeof(unsigned32), status); *nval = 256; nptr->value = nval; *client_ptr = nptr; *status = error_status_ok; }; The client test code looks like this: number_ptr client_ptr = NULL; ptr_test3(binding_h, &client_ptr, &status); printf("Value = %i0, (unsigned32)* (client_ptr->value)); Note the use of [ref] pointers here.
OSF DCE Application Development Guide—Introduction and Style Guide unsigned32 *num; rpc_sm_enable_allocate(&status); num = (unsigned32*) rpc_sm_allocate(sizeof(unsigned32), &status); *num = 64; ptr_test4(binding_h, num, &status); There are so many ways to use (and misuse) IDL pointers that it would be impossible to give a complete set of examples. The section on arrays contains more pointer examples. 6.3.4 Context Handles Context handle semantics vary according to the application role.
RPC Parameters The size of the array data marshalled is determined in one of two ways. In a conformant array, the size of the array is not declared in the IDL declaration, and one of the max_is or size_is attributes is used to determine the size of the marshalled data at runtime. In a varying array, the size of the array is declared in the .idl file, but one or more of the other field attributes determines what range of elements is actually marshalled.
OSF DCE Application Development Guide—Introduction and Style Guide */ typedef struct{ unsigned32 size; unsigned32 first; unsigned32 length; [size_is(size), first_is(first), length_is(length)] char array[0..*]; }cv_struct; void array_test4( [in] handle_t handle, [in] cv_struct *cv_array, [out] error_status_t *status); The examples show clearly how field attribute variables are related to array declarations.
RPC Parameters handle_t handle, v_struct v_array, error_status_t *status ) { unsigned32 i; printf("Array test 30); for(i=v_array.first; i < v_array.first + v_array.length; i++) printf("subscript %i value %c0, i, v_array.array[i]); *status = error_status_ok; } void array_test4( handle_t handle, cv_struct *cv_array, error_status_t *status ) { unsigned32 i; printf("Array test 40); for (i = (*cv_array).first; i < (*cv_array).first + (*cv_array).length; i++) printf("subscript %i value %c0, i, (*cv_array).
OSF DCE Application Development Guide—Introduction and Style Guide The server output will look like this: Array test 1 a b Array test 2 a b c d e Array test 3 subscript 3 value subscript 4 value subscript 5 value subscript 6 value Array test 4 subscript 4 value subscript 5 value subscript 6 value subscript 7 value subscript 8 value d e f g e f g h i Note that for the last test, the declared structure contains a conformant and varying array.
RPC Parameters avoid such complications by sticking to the more straightforward array usages discussed here. However, if you find your application needs to use arrays in some more esoteric way, you should refer to the AES/DC - RPC Volume, Chapter 4, which contains a complete set of array and pointer usage rules. 6.3.6 Structures and Unions There are no important policy issues relating to structures and unions as RPC parameters.
OSF DCE Application Development Guide—Introduction and Style Guide typedef struct two_uuid_s_t { uuid_t uuid1; uuid_t uuid2; } two_uuid_t; typedef struct two_uint_s_t { unsigned32 uint1; unsigned32 uint2; } two_uint_t; typedef enum { uuids, uints } union_contents; typedef union switch (union_contents type){ case uuids: two_uint_t integers; case uints: two_uuid_t ids; } test_union_t; The resulting IDL generated C header declarations look like as follows: typedef struct two_uuid_s_t{ uuid_t uuid1; uuid_t uui
RPC Parameters application must set the type field of this structure to either of the enumeration values integers or ids. To return the union as an [out] or [in,out] parameter, the callee must similarly be sure that the value of the type field is correctly set. To discover which data type was marshalled, the recipient can check the value of the type field. The following is an example of non-encapsulated union usage. The .
OSF DCE Application Development Guide—Introduction and Style Guide 6.3.7 Pipes Pipes allow application-level optimization of bulk data transfer, by allowing the communication and processing of data to overlap. The actual data communications occur at about the same speed as arrays. However, pipes can reduce latency (how soon the application sees each ‘‘chunk’’ of data) and memory utilization.
RPC Parameters All the callback routines are placed in a single module that is linked with both client and server (in this case, for the test interface). As an alternative, the appropriate callbacks could be declared separately within the client and server modules: /* * test_xmit.c: * * The routines required to implement a [transmit_as] type. */ #include "test.h" /* The to_xmit routine must allocate all space for the transmitted * type.
OSF DCE Application Development Guide—Introduction and Style Guide /* * The from_xmit routine may not have to allocate any space for the * presented type. The presented type is always of a definite size * (conformant, varying, etc. types are not permitted), so the stub * provides an instance of the top level of the presented type. In * this case, for example, s_array points to an instance of a sparse * array.
RPC Parameters The client code to excercise the sparse array transmitted type is as follows: sparse_array_t test_array; /* Create a sparse array with only three nonzero members */ memset(test_array,0,sizeof(unsigned32)*S_ARRAY_SIZE); test_array[0] = 2; test_array[20] = 4; test_array[31] = 8; /* * When compressed, this array requires 7 32-bit integers, as opposed * 32 32-bit integers for the uncompressed array.
Chapter 7. Errors and Messaging Applications should adopt a consistent and portable error handling style. This includes methods for returning errors from remote procedure calls, generation of applicationspecific status codes, and the generation and display of error text. This chapter recommends a set of techniques for handling all of these issues. The chapter also makes recommendations about error logging for applications that choose to use the logging facilities. 7.
OSF DCE Application Development Guide—Introduction and Style Guide all errors. In this way a client need not concern itself with two or three separate error parameters, and can use a consistent error handling scheme for both API and application RPC errors. In order to return application-specific errors, such a status parameter must be part of the IDL specification of the interface. The recommended method is therefore to declare a status parameter as part of the application’s .
Errors and Messaging may be using the same message catalog names. Applications that need to guarantee a unique error number space among all DCE applications should use a registered component number obtained from OSF. This is the recommended procedure for applications that have public interfaces that are likely to be called by other applications. 7.2.
OSF DCE Application Development Guide—Introduction and Style Guide Although the two interfaces, broadly speaking, do the same general thing (that is, write messages), their functionality was designed to serve different needs, both of which occur in most distributed applications. Nevertheless, either interface can be used more or less exclusively of the other, if desired.
Errors and Messaging • Routine administrative actions should be reported as informational messages. This includes: creation, modification and deletion of tickets, threads, files, sockets, RPC endpoints, or other objects; message transfer, including name lookup, binding, and forwarding; and database maintenance, including replication or synchronization. The severity level attribute for each message can be determined according to the following criteria: • Fatal error exit (svc_c_sev_fatal_error).
OSF DCE Application Development Guide—Introduction and Style Guide table technology smp__table dce #################################################################### # Part II serviceability table smp_svc_table handle smp_svc_handle start subcomponent smp_s_server "server" smp_i_svc_server subcomponent smp_s_manager "manager" smp_i_svc_manager subcomponent smp_s_binder "binder" smp_i_svc_binder end #################################################################### # Part III # Note that defining the "
Errors and Messaging code subcomponent attributes text explanation action end 124246 no_signal_catcher smp_s_server "svc_c_sev_notice" "Spawn signal handler failed" "RPC runtime error. pthread_create() failed.
OSF DCE Application Development Guide—Introduction and Style Guide 7 −8 start code subcomponent attributes text explanation action end unexporting_from smp_s_server "svc_c_sev_notice" "Unexporting from %s" "Unexporting from CDS entry" "None required." start code subcomponent attributes text explanation action end importing_from smp_s_server "svc_c_sev_notice" "Importing from %s" "Importing from CDS entry" "None required.
Errors and Messaging 124246 start code subcomponent attributes text explanation action end server_error smp_s_server "svc_c_sev_fatal" "%s: %s" "general error message" "?" start code subcomponent attributes text explanation action end no_permissions smp_s_manager "svc_c_sev_notice" "No permissions" "Client does not have permissions for operation" "None required.
OSF DCE Application Development Guide—Introduction and Style Guide #################################################################### # Part IIIa # Messages for serviceability table # # Note that there has to be one of these for each of # the subcomponents declared in the second part of # the file (above)...
Errors and Messaging The following fragments illustrate remote error handling using a common status parameter. The .idl file for the sample interface includes the following declarations: void sample_call( [in] handle_t binding, [out] long *status, [in,out] error_status_t *remote_status); This is matched in the .
OSF DCE Application Development Guide—Introduction and Style Guide dce_acl_is_client_authorized( binding, &sample_acl_mgr_uuid, &sample_acl_uuid, NULL, NULL, sec_acl_perm_read, &authorized, remote_status); /* /* /* /* /* /* /* Client’s binding handle. ACL manager type UUID. The ACL UUID. Pointer to owner’s UUID. Pointer to owner’s group’s UUID. The desired privileges. Will be TRUE or FALSE on return.
Errors and Messaging The client making the sample_call( ) remote call can then check both RPC comm and fault status and application-specific status and display any error messages with the same code: sample_call(binding_h, &rpc_status, &rpc_remote_status); if (rpc_remote_status != error_status_ok) { print_error("sample_call()", rpc_remote_status); exit(1); } 124246 Tandem Computers Incorporated 7− 13
Chapter 8. Server Management Every DCE server requires some management. At a minimum, servers need to be started and stopped. In addition, servers usually provide generic server information such as the server principal name and an indication that the server is listening for remote calls. Servers may also permit other kinds of management operations while they are running; it is perfectly feasible to have a server reinitialize or even unregister and reregister endpoints while it is running.
OSF DCE Application Development Guide—Introduction and Style Guide Figure 8-1. Managing a Server with a Control Client Application Control Client Application Server dced_server_start(...); /*application-specific control*/ dced_server_stop(...); In addition to starting and stopping the server, dced’s management routines provide other control operations.
Server Management control, the server must provide a nondefault authorization function that gives the machine principal access. An example of such an authorization function is given in Chapter 3. • The server must register as a DCE server using the dce_server_register() call.
OSF DCE Application Development Guide—Introduction and Style Guide 3. The server can export manager initialization operations as part of its applicationspecific management interface, and have a management client perform the initialization. Options 1 and 2 have similar effects and are appropriate for most servers. Option 3 might be appropriate for a persistent server where reinitialization of the running server is a useful operation.
Appendix A. A Sample Application This chapter presents the complete code for a generic sample application that illustrates the recommended policies. The code is as generic as possible in the sense that it demonstrates things that most servers need to do. This generic server code is contained in the sample_server.c and sample_server.h modules. The application-specific portion consists of a set of simple examples to illustrate various styles of RPC data usage, including pointers, pipes, and context handles.
OSF DCE Application Development Guide—Introduction and Style Guide [ uuid(002d70b2-671b-1d24-a1da-0000c0d4de56), version(1.
A Sample Application The IDL file sample_db.idl and the ACF file sample_db.idl are required to generate a server-only stub for the database serialization routines used by the ACL manager. /****************************************************************************/ /* [27.VI.94] */ /* */ /* sample_db.
OSF DCE Application Development Guide—Introduction and Style Guide typedef struct dce_db_dataheader_s_t { uuid_t uuid; [...Object UUID.
A Sample Application [in,out] uuid_t [in,out] ); *u, error_status_t *st } /****************************************************************************/ /* [27.VI.94] */ /* */ /* sample_db.acf -- This makes the sample db interface into one that */ /* does pickling.
OSF DCE Application Development Guide—Introduction and Style Guide #define NAMELEN 20 #define DEFNAME "sample_server_entry" #define IF_ANNOTATION "Sample interface, version 1.0" /* At present we set up only two objects... /* A "well-known" residual name for the management "object": #define MGMT_OBJ_NAME "server_mgmt" /* /* A residual name for a sample object: #define SAMPLE_OBJECT_NAME "sample_object" */ */ */ */ /* Relative pathname at which to locate newly-created backing store */ /* databases.
A Sample Application /* The constants below come from aclbase.h (aclbase.idl)...
OSF DCE Application Development Guide—Introduction and Style Guide #include #include #include #include #include #include #include #include #include "dcesmpsvc.h" #include "dcesmpmsg.h" #include "dcesmpmac.h" /* sample-specific includes: #include "sample.h" #include "sample_db.h" #include "sample_bind.h" #include "sample_server.
A Sample Application void server_renew_identity(unsigned_char_p_t, sec_login_handle_t, unsigned_char_p_t, unsigned32, unsigned32 *); void server_create_dflt_acl(dce_db_handle_t, unsigned_char_t *, void(*)(), boolean32, sec_acl_t *, uuid_t *, unsigned32 *); void server_get_local_principal_id(unsigned_char_t *, uuid_t *, unsigned32 *); void server_create_acl(uuid_t, sec_acl_permset_t, unsigned_char_t *, sec_acl_t *, uuid_t *, unsigned32 *); void server_store_acl(dce_db_handle_t, dce_db_handle_t, dce_db_handle
OSF DCE Application Development Guide—Introduction and Style Guide void server_acl_mgr_close(dce_db_handle_t *, dce_db_handle_t *, dce_db_handle_t *, unsigned32 *); void server_rdacl_export(rpc_binding_vector_t *, uuid_vector_t *, unsigned32 *); void server_rdacl_cleanup(rpc_binding_vector_t *, uuid_vector_t *, unsigned32 *); void server_bind_cleanup(rpc_binding_vector_t *, uuid_vector_t *, unsigned32 *); boolean32 sample_mgmt_auth(rpc_binding_handle_t, unsigned32, unsigned32 *); dce_acl_resolve_func_t samp
A Sample Application /****************************************************************************/ /* Default routing information: #define SAMPLE_SVC_FATAL_DEFAULT_ROUTE 0 #define SAMPLE_SVC_ERROR_DEFAULT_ROUTE 1 #define SAMPLE_SVC_WARNING_DEFAULT_ROUTE 2 #define SAMPLE_SVC_NOTICE_DEFAULT_ROUTE 3 #define SAMPLE_SVC_VERBOSE_NOTICE_DEFAULT_ROUTE 4 #define MAX_DEFAULT_ROUTES 5 unsigned_char_t *default_routes[MAX_DEFAULT_ROUTES] = {"FATAL:STDERR:", "ERROR:STDERR:", "WARNING:STDERR:", "NOTICE:STDERR:", "NOTICE
OSF DCE Application Development Guide—Introduction and Style Guide int routes_G[MAX_ROUTES]; int debug_routes_G[MAX_LEVELS]; int debug_levels_G[MAX_LEVELS]; /* These two UUIDs could be treated as "well known": i.e. applications /* that use the same ACL manager for mgmt operations can use these...
A Sample Application { "r", { "w", { "d", { "c", { "t", { "x", "read", "write", "delete", "control", "test", "execute", sec_acl_perm_read sec_acl_perm_write sec_acl_perm_delete sec_acl_perm_control sec_acl_perm_test sec_acl_perm_execute }, }, }, }, }, } }; /*************** * * * main -* * * * **************/ int main( int argc, char *argv[] ) { unsigned32 status; /* For status returned from library calls. rpc_binding_vector_t *binding_vector; /* For bindings from RPC run/* time.
OSF DCE Application Development Guide—Introduction and Style Guide uuid_t server_uuid; /* The UUID that identifies this server in/* stance; i.e., the object UUID that /* identifies our server’s bindings. It is /* created by us, in create_server_uuid(), /* and goes into server_entry_ptr->id in /* make_server_entry(). It actually ends /* up being identical to the configuration /* UUID, if one is created (by calling the /* dced_server_create() routine).
A Sample Application (idl_char*)"smp", &status); if (status != error_status_ok) { print_server_error("dce_svc_register()", status); exit(1); } /* Set up in-memory serviceability message table... dce_msg_define_msg_table(smp__table, sizeof smp__table / sizeof smp__table[0], &status); if (status != error_status_ok) { print_server_error("dce_msg_define_msg_table()", status); exit(1); } */ dce_svc_printf(SIGN_ON_MSG); /* Create an object UUID for this server instance...
OSF DCE Application Development Guide—Introduction and Style Guide "Calling server_get_identity()")); server_get_identity(server_principal_name, &login_context, (unsigned_char_p_t)KEYTAB, &status); if (status != error_status_ok) { print_server_error("server_get_identity()", status); exit(1); } A− 16 /* Spin off a thread to wait for signals...
A Sample Application (dce_acl_resolve_func_t)sample_resolve_by_name, /* Our name->ACL UUID resolution /* function. sample_acl_mgr_uuid, /* UUID of our ACL manager; /* hard-coded at top of this file. sample_object_uuid, /* UUID of our sample object; /* hard-coded at top of this file. (unsigned_char_t *)SAMPLE_OBJECT_NAME, /* Name of /* our sample object. OBJ_OWNER_PERMS, /* Owner’s permissions on sample /* object. (unsigned_char_t *)SAMPLE_OWNER, /* Principal /* name of sample object owner.
OSF DCE Application Development Guide—Introduction and Style Guide goto CLEANUP_EXIT; } /* /* Start listening for calls...
A Sample Application /* Unexport server objects from namespace and from endpoint /* map... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug5, "Calling server_cleanup_objects()")); server_cleanup_objects(sample_v1_0_s_ifspec, binding_vector, &server_uuid_v, &entryname_vector, &status); if (status != error_status_ok) { print_server_error("server_cleanup_objects()", status); exit(1); } */ */ /* Unregister the remote ACL interface from the endpoint /* map...
OSF DCE Application Development Guide—Introduction and Style Guide /****** * * do_command_line -- Get and * command * command * * Returns * * Called from main(). * ******/ interpret arguments and options from the line, and do other setup related to the line’s contents. 0 if normal invocation, 1 if setup.
A Sample Application /* Set the program name for serviceability messages... */ dce_svc_set_progname(argv[0], &status); if (status != error_status_ok) { dce_error_inq_text(status, error_string, &print_status); fprintf(stdout, "dce_svc_set_progname(): %s0, error_string); exit(1); } return 0; } /****** * * server_register_get_bindings -- Register an interface: * * Set up only one type manager * Use all protocol sequences * Return the bindings * * Called from main().
OSF DCE Application Development Guide—Introduction and Style Guide /* Use all available protocol sequences... */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_server_use_all_protseqs()")); rpc_server_use_all_protseqs(rpc_c_protseq_max_reqs_default, status); if (*status != error_status_ok) { print_server_error("rpc_server_use_all_protseqs()", *status); return; } /* Get the binding handles generated by the runtime...
A Sample Application DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_string_free()")); rpc_string_free(&string_binding, status); if (*status != rpc_s_ok) { print_server_error("rpc_string_free()", *status); exit(1); } } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting server_register_get_bindings()")); } /****** * * * server_export_objects -- Set up a simple object-based binding scheme * for the server, i.e.
OSF DCE Application Development Guide—Introduction and Style Guide DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Entering server_export_objects()")); *status = error_status_ok; DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_ep_register()")); rpc_ep_register(interface, binding_vector, object_uuid_vector, annotation, status); if (*status != error_status_ok) { print_server_error("rpc_ep_register()", *status); return; } if (object_uuid_vector) { if (entryname_vector->count
A Sample Application else { dce_svc_printf(EXPORTING_TO_MSG, entryname_vector->name[0]); DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_ns_binding_export()")); rpc_ns_binding_export(rpc_c_ns_syntax_default, entryname_vector->name[0], interface, binding_vector, NULL, status); if (*status != error_status_ok) { print_server_error("rpc_ns_binding_export()", *status); return; } } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting server_export_objects()")); } /****** *
OSF DCE Application Development Guide—Introduction and Style Guide struct { unsigned32 count; uuid_t *uuid[1]; } object_uuid; int i; DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Entering server_cleanup_objects()")); *status = error_status_ok; /* Get rid of the endpoints...
A Sample Application if (*status != error_status_ok) { print_server_error("rpc_ns_binding_unexport()", *status); return; } } } else /* I.e., there is only one server instance to unexport...
OSF DCE Application Development Guide—Introduction and Style Guide KEYTAB, /* Local key file. */ (idl_char *)prin_name, /* Principal name. &status); if (status != error_status_ok) print_server_error("sec_key_mgmt_manage_key()", status); */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting managekey()")); } /****** * * server_get_identity -- Establish a new server identity with valid * credentials. This includes setting up a key * management thread. * * * Called from main().
A Sample Application /* Create a context and get the login context... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling sec_login_setup_identity()")); sec_login_setup_identity(prin_name, sec_login_no_flags, login_context, status); if (*status != error_status_ok) { print_server_error("sec_login_setup_identity()", *status); return; } */ /* Get secret key from the keytab file...
OSF DCE Application Development Guide—Introduction and Style Guide } /****** * * server_renew_identity -- Make sure that credentials are still valid, and * enew them if they are not. * * * This routine is called (with the current credentials) whenever a task * is about to be attempted that requires valid credentials. For an ex* ample, see the cleanup code in "main()" above. A valid credential will * nevertheless be considered invalid if it will expire within time_left * seconds.
A Sample Application /* Get the lifetime for the server’s Ticket-Granting-Ticket (TGT). */ /* Note that sec_login_get_expiration() returns a non-zero */ /* status for an uncertified login context. This is not */ /* an error. Hence the special error checking...
OSF DCE Application Development Guide—Introduction and Style Guide /* Validate the login context...
A Sample Application /* Create the UUID for the new ACL... *status = error_status_ok; DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling uuid_create()")); uuid_create(acl_uuid, status); if (*status != error_status_ok) { print_server_error("uuid_create()", *status); return; } */ if (is_container) sec_acl_type = 2; else sec_acl_type = 1; /* Now get the initial container’s ACL UUID. /* This is a call to sample_resolve_by_name(); see below...
OSF DCE Application Development Guide—Introduction and Style Guide /****** * * server_get_local_principal_id -- Get (from the local cell registry) the * UUID corresponding to a principal name. * * * Called from server_create_acl() and server_acl_mgr_setup(). * ******/ void server_get_local_principal_id( unsigned_char_t *p_name, uuid_t *p_id, unsigned32 *status) { char *cell_name; sec_rgy_handle_t rhandle; /* Simple principal name. /* UUID returned here. /* Status returned here.
A Sample Application status); if (*status != error_status_ok) { print_server_error("sec_rgy_pgo_name_to_id()", *status); return; } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting server_get_local_principal_id()")); } /****** * * server_create_acl -- Create an ACL with some specified set of permissions * assigned to some principal user. * * * Called from server_acl_mgr_setup().
OSF DCE Application Development Guide—Introduction and Style Guide "Calling dce_acl_obj_init()")); dce_acl_obj_init(&mgr_type_uuid, acl, status); if (*status != error_status_ok) { print_server_error("dce_acl_obj_init()", *status); return; } /* Get the specified principal’s UUID...
A Sample Application /* the objects) */ /* */ /* */ /* */ /****************************************************************************/ void server_store_acl( dce_db_handle_t db_acl, /* ACL (UUID)-indexed store. dce_db_handle_t db_object, /* Object (UUID)-indexed store. dce_db_handle_t db_name, /* Name-indexed store. sec_acl_t *acl, /* The ACL itself. uuid_t *acl_uuid, /* ACL UUID. uuid_t *object_uuid, /* Object UUID. unsigned_char_t *object_name, /* The name of the object.
OSF DCE Application Development Guide—Introduction and Style Guide print_server_error("uuid_create()", *status); return; } /* Store the default object ACL into UUID-indexed store... */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling dce_db_store_by_uuid()")); dce_db_store_by_uuid(db_acl, &def_object, acl, status); if (*status != error_status_ok) { print_server_error("dce_db_store_by_uuid()", *status); return; } /* Store the default container ACL into UUID-indexed */ /* store...
A Sample Application /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* 124246 by calling dce_db_fetch_by_uuid(). */ */ 3. Extract the ACL UUID from the correct field in the object */ data structure. */ */ ...
OSF DCE Application Development Guide—Introduction and Style Guide /* 3. Access by clients in contact with the server. This is */ /* handled by the server code itself, as described above. */ /* */ /* */ /* */ /* Note that the use of the three databases given here is necessar- */ /* ily true only of the ACL databases we are setting up here. The */ /* object data stored in databases is strictly up to the applica- */ /* tion; that is why this parameter is defined as (void *).
A Sample Application dce_db_store_by_uuid(db_object, object_uuid, (void *)&object_data, status); if (*status != error_status_ok) { print_server_error("dce_db_store_by_uuid()", *status); return; } /* Finally, store the object UUID keyed by the object ("residual") */ /* name...
OSF DCE Application Development Guide—Introduction and Style Guide void server_acl_mgr_setup( unsigned_char_t *db_acl_path, /* Pathname for databases. dce_acl_resolve_func_t resolver, /* sample_resolve_by_name. uuid_t acl_mgr_uuid, /* ACL manager UUID. uuid_t object_uuid, /* Object UUID. unsigned_char_t *object_name, /* Object name. sec_acl_permset_t owner_perms, /* Owner permission set. unsigned_char_t *owner, /* Owner name. boolean32 is_container, /* Is this a container object? /* == TRUE from main().
A Sample Application /* Build the full pathname string for the db_acl database... acl_path_string = malloc(MAX_ACL_PATH_SIZE); strcpy((char *)acl_path_string, (char *)db_acl_path); strcat((char *)acl_path_string, (char *)"/"); strncat((char *)acl_path_string, "db_acl", strlen("db_acl")); /* Find out if the database already exists...
OSF DCE Application Development Guide—Introduction and Style Guide /* For the object database, we need standard backing store headers /* to hold UUIDs for all the various ACLs... dbflags |= db_c_std_header; if (need_init) dbflags |= db_c_create; */ */ /* Now open (or create) the "db_object" store... */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling dce_db_open()")); /* Build the full pathname string for the database...
A Sample Application /* Build the full pathname string for the database... free(acl_path_string); acl_path_string = malloc(MAX_ACL_PATH_SIZE); strcpy((char *)acl_path_string, (char *)db_acl_path); strcat((char *)acl_path_string, (char *)"/"); strncat((char *)acl_path_string, "db_name", strlen("db_name")); dce_db_open( (char *)acl_path_string, /* Filename of backing store. NULL, /* Backing store "backend type" default == hash. dbflags, /* Specifies index by name.
OSF DCE Application Development Guide—Introduction and Style Guide sizeof mgmt_printstr/sizeof mgmt_printstr[0], /* Number of */ /* items in mgmt_printstr array. mgmt_printstr, /* An array of sec_acl_printstring_t struc/* tures containing the printable repre/* sentation of each specified permission. &mgmt_info, /* A single sec_acl_printstring_t contain/* ing the name and short description for /* the given ACL manager. sec_acl_perm_control, /* Permission set needed to change /* an ACL.
A Sample Application resolver, NULL, /* Application server function that gives */ /* the ACL UUID for a given object, when /* presented with that object’s name; for /* us it’s the sample_resolve_by_name() /* routine, below. /* Argument to pass to resolver routine; /* identified as the "resolver_arg" in the /* code to that function below. /* Flags -- none here.
OSF DCE Application Development Guide—Introduction and Style Guide DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_string_free()")); rpc_string_free(&uuid_string, status); if (*status != rpc_s_ok) { print_server_error("rpc_string_free()", *status); } /************************************************************/ /* For the management ACL we must add a default entry for */ /* the machine principal so dced can manage the server. */ /* Construct the name entry string...
A Sample Application /* By default everybody must be able to get the principal */ /* name. They should be able to ping too. So add an appro- */ /* priate unauthenticated permissions entry to the ACL...
OSF DCE Application Development Guide—Introduction and Style Guide if (*status != error_status_ok) { print_server_error("server_store_acl()", *status); return; } /********************************************************************/ /* Object ACL creation code... */ /* Now create the object ACL... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug5, "Calling server_create_acl()")); server_create_acl( sample_acl_mgr_uuid, /* Create an ACL with this /* manager type.
A Sample Application dce_acl_obj_free_entries(new_obj_acl, status); if (*status != error_status_ok) { print_server_error("dce_acl_obj_free_entries()", *status); return; } /* ...end of object ACL creation code. */ /********************************************************************/ } else /* ACL databases already exist; get the two ACL UUIDs... { */ /* This is a call to sample_resolve_by_name() (see below); */ /* it gives us the UUID of the ACL of the object whose */ /* name we pass it...
OSF DCE Application Development Guide—Introduction and Style Guide DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling uuid_to_string()")); uuid_to_string(mgmt_acl_uuid, &uuid_string, status); if (*status != uuid_s_ok) { print_server_error("uuid_to_string()", *status); } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug8, "String form of mgmt_acl_uuid == %s", uuid_string)); DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_string_free()")); rpc_string_free(&uuid_
A Sample Application if (*status != error_status_ok) { print_server_error("rpc_server_register_if()", *status); return; } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting server_acl_mgr_setup()")); } /****** * * server_acl_mgr_close -- Called at cleanup time to close * the three ACL databases. * * * Called from main(). * ******/ void server_acl_mgr_close( dce_db_handle_t *db_acl, dce_db_handle_t *db_object, dce_db_handle_t *db_name, unsigned32 *status) { /* ACL UUID-indexed database.
OSF DCE Application Development Guide—Introduction and Style Guide /* Close the Object UUID-indexed database... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling dce_db_close()")); dce_db_close(db_object, status); if (*status != error_status_ok) { print_server_error("dce_db_close()", *status); return; } */ /* Close the name-indexed database...
A Sample Application void server_rdacl_export( rpc_binding_vector_t *binding_vector, /* Binding handles from RPC runtime. uuid_vector_t *object_uuid_vector, /* Server instance UUID(s). unsigned32 *status) { */ */ uuid_vector_t my_uuids; DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Entering server_rdacl_export()")); *status = error_status_ok; /* Register the server’s endpoints with the rdacl interface at the /* local endpoint map...
OSF DCE Application Development Guide—Introduction and Style Guide DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Entering server_rdacl_cleanup()")); *status = error_status_ok; DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling rpc_ep_unregister()")); rpc_ep_unregister(rdaclif_v1_0_s_ifspec, binding_vector, object_uuid_vector, status); if (*status != error_status_ok) { print_server_error("rpc_ep_unregister()", *status); return; } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc
A Sample Application } DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting server_bind_cleanup()")); } /****************************************************************************/ /* End of server init and cleanup functions */ /****************************************************************************/ /****** * * signal_handler -- Thread to handle asynchronous interrupts. * * Catch and handle SIGINT and SIGTERM.
OSF DCE Application Development Guide—Introduction and Style Guide sigaddset(&signals, SIGTERM); /* Set the current signal mask... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling sigprocmask()")); sigprocmask(SIG_BLOCK, &signals, NULL); */ /* And now wait for the signals... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling sigwait()...")); while (1) { sig = sigwait(&signals); switch (sig) { case SIGINT: case SIGTERM: /* SIGNAL-SPECIFIC ACTIONS GO HERE...
A Sample Application * or our ACLs. * * * * The callback is set up by a call to rpc_mgmt_set_authorization() in * server_acl_mgr_setup(). * ******/ boolean32 sample_mgmt_auth( rpc_binding_handle_t client_binding, /* Client’s binding, whoever he is. unsigned32 requested_mgmt_operation, /* What client is attempting to do.
OSF DCE Application Development Guide—Introduction and Style Guide case rpc_c_mgmt_is_server_listen: perm_required = mgmt_perm_ping; break; case rpc_c_mgmt_stop_server_listen: perm_required = mgmt_perm_kill; break; default: /* This should never happen, but just in case...
A Sample Application DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Exiting sample_mgmt_auth()")); if (authorized) DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug8, "AUTHORIZED!")); else DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug8, "NOT AUTHORIZED!")); /* Return the result to the caller... return(authorized); */ } /****** * * sample_resolve_by_name -- take the name of an object, and return the * UUID of the object’s ACL.
OSF DCE Application Development Guide—Introduction and Style Guide dce_acl_resolve_func_t sample_resolve_by_name( handle_t h, /* Client binding handle passed into the /* server stub. sec_acl_bind() is used to /* create this handle. sec_acl_component_name_t name, /* The object whose ACL’s UUID we want. sec_acl_type_t sec_acl_type, /* The type of ACL whose UUID we want. uuid_t *manager_type, /* The object’s manager type. /* NOTE that this parameter isn’t used be/* low.
A Sample Application DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug8, "Object name == %s", name)); /* Check for non-existence of object name... if (!name || !*name) { dce_svc_printf(CANNOT_RESOLVE_NAME_MSG); return; } */ /* Get the object’s UUID, which will be the key that we will use to */ /* fetch this particular object’s data in the call following this */ /* one...
OSF DCE Application Development Guide—Introduction and Style Guide /* Using the UUID "key" that we just retrieved, get the object_data */ /* for the desired object (note that the data that one retrieves */ /* with this routine can be anything; it depends on what we are */ /* using the backing store for)...
A Sample Application /* Here it might be interesting to try retrieving the ACL itself, /* and e.g seeing what its manager type is... DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling dce_db_fetch_by_uuid()")); dce_db_fetch_by_uuid(db_acl, acl_uuid, &retrieved_acl, st); if (*st != error_status_ok) { print_server_error("dce_db_fetch_by_uuid()", *st); return(0); } */ */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug4, "Calling uuid_to_string()")); uuid_to_string(&(retrieved_acl.
OSF DCE Application Development Guide—Introduction and Style Guide { /* Return a bad status... *st = acl_s_bad_manager_type; /* And no ACL UUID...
A Sample Application void sample_bind_export( rpc_binding_vector_t *binding_vector, uuid_vector_t *uuid_vec, unsigned32 *status) { DCE_SVC_DEBUG((smp_svc_handle, smp_s_server, svc_c_debug7, "Entering sample_bind_export()")); *status = error_status_ok; /* Register sample_bind interface...
OSF DCE Application Development Guide—Introduction and Style Guide /***** * * create_server_uuid -- Create server instance UUID. * * * Called from main(), make_server_entry().
A Sample Application /***** * * print_server_error-- Server version. Prints text associated with * bad status code. * * *****/ void print_server_error( char *caller, /* Routine that received the error. error_status_t status) /* Status we want to print the message for.
OSF DCE Application Development Guide—Introduction and Style Guide A.2 Object Bind Interface /****************************************************************************/ /* [27.VI.94] */ /* */ /* sample_bind.c -- The remote binding interface implementation */ /* code. */ /* */ /* */ /* */ /* The code below is built and linked into the server object; meanwhile */ /* the sample_bind.idl file is processed and the output of that is */ /* a set of client and server stubs for the implementation.
A Sample Application #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Serviceability sams-generated header files... #include "dcesmpsvc.h" #include "dcesmpmsg.h" #include "dcesmpmac.
OSF DCE Application Development Guide—Introduction and Style Guide { dce_error_string_t error_string; int print_status; *st = error_status_ok; DCE_SVC_DEBUG((smp_svc_handle, smp_s_binder, svc_c_debug6, "Entering name_to_object()...")); if (!component || !*component) { dce_svc_printf(CANNOT_RESOLVE_NAME_MSG); return; } /* dce_db_fetch_by_name() retrieves data from the string-indexed /* backing store identified by the handle parameter, which was /* obtained from dce_db_open().
A Sample Application /****************************************************************************/ /* [27.VI.94] */ /* */ /* sample_bind.idl -*/ /* */ /* */ /* */ /* -77 cols*/ /****************************************************************************/ [ uuid(006868ca-6064-1d49-9829-0000c0d4de56), version(1.
OSF DCE Application Development Guide—Introduction and Style Guide /* [27.VI.94] */ /* */ /* sample_manager.c -- Implementation of "sample" interface. */ /* */ /* Routines in this file consist only of remote calls or routines that */ /* are internal to those calls. */ /* */ /* */ /* -77 cols*/ /****************************************************************************/ #define DCE_DEBUG #include #include #include #include #include #include #include #include
A Sample Application uuid_t, idl_char *, idl_long_int *, error_status_t *); void sample_put_text(rpc_binding_handle_t, uuid_t, idl_char *, idl_long_int *, error_status_t *); void print_manager_error(char *, error_status_t); /****** * * sample_call -- It don’t do too much right now... * * * * ******/ /****************************************************************************/ void sample_call( rpc_binding_handle_t binding, /* Client binding.
OSF DCE Application Development Guide—Introduction and Style Guide &authorized, /* Will be TRUE or FALSE on return.
A Sample Application /* Our backing store data type. For a full explanation, see the /* body of sample_resolve_by_name(), in sample_server.c. sample_data_t data; */ */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6, "Entering sample_get_text()...")); *remote_st = rpc_s_ok; /* Get the object’s data header... */ DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6, "Calling dce_db_fetch_by_uuid()...
OSF DCE Application Development Guide—Introduction and Style Guide void sample_put_text( rpc_binding_handle_t h, uuid_t object_uuid, idl_char text[TEXT_SIZE], idl_long_int *status, error_status_t *remote_st ) { /* /* /* /* /* Client binding handle passed into the server stub. sec_acl_bind() is used to create this handle. Desired object’s UUID. Text information to put. /* To return status. /* Our backing store data type.
A Sample Application print_manager_error( char *caller, /* String identifying the routine that received the error. error_status_t status) /* the status we want to print the message for. { dce_error_string_t error_string; int print_status; */ */ dce_error_inq_text(status, error_string, &print_status); dce_svc_printf(MANAGER_ERROR_MSG, caller, error_string); } /****************************************************************************/ /* [27.VI.94] */ /* */ /* sample_client.
OSF DCE Application Development Guide—Introduction and Style Guide objectname_vector_t *); boolean32 is_valid_principal(unsigned_char_t *_1, unsigned_char_t *_2, unsigned32 *_3); void bind_to_object(unsigned_char_t *, rpc_if_handle_t, uuid_t *, handle_t *, uuid_t *, uuid_t *, unsigned_char_t **, unsigned_char_t **, error_status_t *); void print_error(char *_1, error_status_t _2); extern unsigned_char_t *malloc(); #define SGROUP "sample_servers" /****** * * * main -* * ******/ int main( int argc, char *argv
A Sample Application unsigned_char_t *entry_name = NULL; /* Object entry name from */ /* bind_to_object(). */ unsigned_char_t *object_name = NULL; /* Residual object name from */ /* bind_to_object(). */ /* Process the command line... */ do_client_command_line(argc, argv, &kill_server, &objectname_vector); /* Start importing servers. Note that the contents of the environ/* ment variable RPC_DEFAULT_ENTRY are used to determine the entry /* to import from...
OSF DCE Application Development Guide—Introduction and Style Guide /* Resolve the partial binding... fprintf(stdout, "sample_client: Calling rpc_ep_resolve_binding()...0); rpc_ep_resolve_binding(binding_h, sample_v1_0_c_ifspec, &status); if (status != rpc_s_ok) { print_error("rpc_ep_resolve_binding()", status); exit(1); } */ /* Convert the binding to a readable string... */ fprintf(stdout, "sample_client: Calling rpc_binding_to_string_binding()...
A Sample Application /* And now find out if it’s a valid member of our sample_servers */ /* group... */ fprintf(stdout, "sample_client: Calling is_valid_principal()...0); if (is_valid_principal(server_princ_name, (unsigned_char_t *)SGROUP, &status)) { fprintf(stdout, "sample_client: Calling rpc_binding_set_auth_info()...
OSF DCE Application Development Guide—Introduction and Style Guide if (status != rpc_s_ok) { print_error("rpc_mgmt_stop_server_listening()", status); exit(1); } fprintf(stdout, "sample_client: Server successfully killed.0); } /* Second alternative: Do remote operations... else { /* This is a local call... fprintf(stdout, "sample_client: Remote call option enacted...0); fprintf(stdout, "sample_client: Preparing to bind to object %s0, (char *)objectname_vector.
A Sample Application /* Convert to string form... */ fprintf(stdout, "sample_client: Calling rpc_binding_to_string_binding()...0); rpc_binding_to_string_binding(object_handle, &string_binding, &status); if (status != rpc_s_ok) { print_error("rpc_binding_to_string_binding()", status); exit(1); } /* Show it... fprintf(stdout, " */ Binding: %s0, string_binding); /* Now convert the type manager UUID to a string... */ fprintf(stdout, "sample_client: Calling uuid_to_string()...
OSF DCE Application Development Guide—Introduction and Style Guide if (status != rpc_s_ok) { print_error("rpc_string_free()", status); exit(1); } /* Make call on returned handle to get object data... */ fprintf(stdout, "sample_client: Calling [remote] sample_get_text()...0); sample_get_text(object_handle, object_uuid, server_message, &rpc_status, &rpc_remote_status); fprintf(stdout, " Object Text: %s0, server_message); /* Call the sample_call() operation... /* First, get rid of the object UUID...
A Sample Application /* Free it... rpc_string_free(&string_binding, &status); if (status != rpc_s_ok) { print_error("rpc_string_free()", status); exit(1); } */ fprintf(stdout, "sample_client: Calling [remote] sample_call()...0); sample_call(binding_h, &rpc_status, &rpc_remote_status); if (rpc_remote_status != error_status_ok) { print_error("sample_call()", rpc_remote_status); exit(1); } fprintf(stdout, "sample_client: Remote call option successfully completed.
OSF DCE Application Development Guide—Introduction and Style Guide int do_client_command_line( int argc, char *argv[], unsigned32 *kill_server, objectname_vector_t *objectname_vector ) { unsigned32 status; A− 88 /* Check the command line... */ /* The "Usage" message requires some explanation. There are two /* modes for running the client: you can either specify that /* the server be killed, or you can specify a single object to /* bind to.
A Sample Application /* /* /* /* /* /* /* /* /* /* /* /* 4. The message "Manager Type ID: " is displayed. */ */ */ 5. The message "Object ID: " is dis*/ played. */ */ 6. The message "Object Text: " is displayed. */ */ 7. --And this should be followed by some serviceability in*/ formational (soon to be debug) messages, from the server. */ */ ...This is all assuming, of course, that no errors occur.
OSF DCE Application Development Guide—Introduction and Style Guide /****** * * * is_valid_principal -- Find out whether the specified principal is a * member of the group he’s supposed to be. * * ******/ boolean32 is_valid_principal( unsigned_char_t *princ_name, unsigned_char_t *group, unsigned32 *status) { unsigned_char_t *local_name; char *cell_name; sec_rgy_handle_t rhandle; boolean32 is_valid; /* Full name of principal to test. /* Group we want principal to be in.
A Sample Application sec_id_parse_name(rhandle, /* Handle to the registry server. princ_name, /* Global (full) name of the principal. NULL, /* Principal’s home cell name returned here. NULL, /* Pointer to UUID of above returned here. local_name, /* Principal local name returned here. NULL, /* Pointer to UUID of above returned here.
OSF DCE Application Development Guide—Introduction and Style Guide /****** * * bind_to_object -- Local client call to get UUID from object name. * * (The real sub-title of this saga seems to be "How to Implement * a Junction".) * * Called from main(). * ******/ void bind_to_object( unsigned_char_t *object_name, /* The name of the object we’re to bind to. rpc_if_handle_t if_hint, /* Interface specification; NULL from main(). uuid_t *id_hint, /* Presumably the object’s UUID; NULL from main().
A Sample Application /* Object name only, try default search path... [original note] */ /* (Apparently the assumption is that if we gave an incomplete */ /* name, that must mean that we were passed only a simple object */ /* name, which means that we must try to reconstruct the path to */ /* the "junction"... */ if (*status == rpc_s_incomplete_name) { fprintf(stdout, "sample_client: Object name only given, trying default search path...0); /* Make the object name the "residual"...
OSF DCE Application Development Guide—Introduction and Style Guide /* Import a binding... */ else if (*status == rpc_s_partial_results || *status == error_status_ok) { fprintf(stdout, "sample_client: Binding to resolved name...0); fprintf(stdout, "sample_client: Calling rpc_ns_binding_import_begin()...0); rpc_ns_binding_import_begin( rpc_c_ns_syntax_default, resolved_name, /* This should be a namespace leaf. */ if_hint, /* Interface we were originally given.
A Sample Application /* to the caller; we have no further use for it here... */ fprintf(stdout, "sample_client: Imported partial binding.0); fprintf(stdout, "sample_client: Calling rpc_ns_binding_inq_entry_name()...
OSF DCE Application Development Guide—Introduction and Style Guide /* /* The binding handle is now fully bound. Our request for the ob*/ /* ject UUID was really only a pretext for doing the namespace */ /* lookup and getting the binding handle completed with a server */ /* endpoint. The object UUID is not used for routing within the */ /* server. So we can now clear out any UUID set by id_hint and re- */ /* place it with any type manager UUID returned from the server...
A Sample Application A.4 Message (sams) File The sample application’s sams file, which contains definitions for various messages output by the serviceability interface routines, is as follows: ############################################################################## # [28.VI.94] # # # # smp.sams -- sams input file for generic sample program.
OSF DCE Application Development Guide—Introduction and Style Guide A− 98 start code sub-component attributes text explanation action end cleanup smp_s_server "svc_c_sev_notice" "Cleaning up" "Starting server cleanup" "None required." start code sub-component attributes text explanation action end server_exit smp_s_server "svc_c_sev_notice" "Exiting" "" "None required.
A Sample Application 124246 start code sub-component attributes text explanation action end cannot_resolve_name smp_s_server "svc_c_sev_notice" "Can’t resolve name" "ACL manager resolver failed to resolve name" "The ACL databases may be corrupt and need to be regenerated." start code sub-component attributes text explanation action end cannot_manage_keys smp_s_server "svc_c_sev_notice" "Can’t spawn key management thread." "RPC runtime error.
OSF DCE Application Development Guide—Introduction and Style Guide A− 100 start code sub-component attributes text explanation action end importing_from smp_s_server "svc_c_sev_notice" "Importing from %s" "Importing from CDS entry" "None required." start code sub-component attributes text explanation action end auth_set_client smp_s_server "svc_c_sev_notice" "Beginning client authentication setup" "" "None required.
A Sample Application start code sub-component attributes text explanation action end no_permissions smp_s_manager "svc_c_sev_notice" "No permissions" "Client does not have permissions for operation" "None required." start code sub-component attributes text explanation action end object_not_found smp_s_manager "svc_c_sev_error" "Object not found" "object was not found in UUID-indexed database" "None required.
OSF DCE Application Development Guide—Introduction and Style Guide start code text end !intable undocumented smp_i_svc_server "Sample server" start code text end !intable undocumented smp_i_svc_binder "Sample object binder" start code text end !intable undocumented smp_i_svc_manager "Sample manager" A.5 Makefile A generic Makefile suitable for building the sample code is as follows: ############################################################################## # [22.VI.
A Sample Application # # # # # # # # NOTE: The following five lines are needed on HPUX... LDFLAGS =-Wl,-Bimmediate,-Bnonfatal IDLCC=-cc_cmd ’c89 -c’ IDLCOPT=-cc_opt -D_HPUX_SOURCE CDEFS = -D_HPUX_SOURCE C = c89 # CC flags: CFLAGS = -g $(CDEFS) $(INC) # IDL compiler flags.
OSF DCE Application Development Guide—Introduction and Style Guide SVCSVCC = dcesmpsvc.c FROMSAMS = $(SVCH) $(SVCC) # IDL generated: HDR = $(IF).h DBHDR = $(IF)_db.h SHDR = $(SERVER).h CLIENTSC = $(IF)_cstub.c SERVERSC = $(IF)_sstub.c DBSC = $(IF)_db_cstub.c FROMIDL = $(HDR) $(CLIENTSC) $(SERVERSC) FROMDBIDL = $(DBHDR) $(DBSC) FROMBINDIDL = sample_bind.h sample_bind_sstub.c sample_bind_cstub.
A Sample Application # IDL generated files (.idl and .acf dependencies): $(FROMIDL): $(IF).idl $(IF).acf $(IDLC) $(IF).idl $(IFLAGS) $(FROMDBIDL): $(IF)_db.idl $(IF)_db.acf $(IDLC) $(IF)_db.idl $(IFLAGS) $(FROMBINDIDL): sample_bind.idl sample_bind.acf $(IDLC) sample_bind.idl $(NO_EPV_IFLAGS) ############################################################################## # Sams generated files (.sams dependencies): $(FROMSAMS): smp.sams $(SAMS) smp.
Index _____________________________ A accept(), 2-11 access algorithm as implemented in DCE ACL library, 3-21 standard DCE, 1-33 access control (authorization), definition of, 3-1 access control list (ACL), 1-19 defined, 3-20 retrieving an object’s, 1-32 use of in authorization, 3-20 access criteria, tests of, 3-17 ACL, 1-8 binding routine, 3-23 database, 3-24 design guidelines, 1-33 entry types, 3-22 handles, 1-32 manager, 1-19, 3-22 and DCE ACL library, 3-22 and DCE backing store library, 3-23, 3-24, 3-2
OSF DCE Application Development Guide—Introduction and Style Guide effect of on RPC calls, 3-2 how often performed, 3-2 model of in DCE, 3-4 necessity of for server access to namespace, 3-8 not requested by client, 3-2 requested by client, 3-2 service registered by servers, 3-2 service specified in client’s binding handle, 3-2 services, 1-29 setting up for, 1-28 steps involved in using, 3-3 three options for server, 3-6 three stages in, 3-4 authorization, 1-18, 3-17 absence of service acceptable to server,
Index when they should be used, 2-11 connect(), 2-11 context handles, 6-18 conversation keys, 3-4, 3-5 credentials acquisition, 3-10 anonymous, 3-19 client’s, retrieval by server, 1-31 definition of, 3-7 inheriting, 3-7 null, 3-19 revalidation, 3-10 _cstub.
OSF DCE Application Development Guide—Introduction and Style Guide E G endpoint dynamic, 1-17, 1-21 map, 1-7 mapper service, 1-21 mapping mechanism, 1-18 registering, 1-21 RPC, 1-7 stale data in map, 1-24 well-known, 1-21 ENDTRY macro, 2-12 entry point vector addresses in, 1-19 manager, 1-19 multiple, 1-19 registering, 1-20 entry types, in ACL, recommended checking order, 3-21 EPV (entry point vector), 1-18 exception handlers, 1-24 exceptions and rpc_server_listen( ), 1-34 handling interface, 1-24 signal
Index UUID, 1-4, 1-17 and incoming RPCs, 1-21 generating, 1-10 version number, 1-11, 1-19 compatibility, 1-12 interface definition language (IDL), 1-5 interface specification, 1-7 ISO_LATIN_1 character set, 6-9 ISO_MULTI_LINGUAL character set, 6-9 ISO_UCS character set, 6-9 is_valid_principal( ), 3-15 K Kerberos shared secret key protocol, 3-4 keys local copies of user keys, 3-7 maintenance of by server, 3-6 managing server key, 1-18, 3-9, 3-11 secret key, 1-18 should not be kept in program memory, 3-8 whe
OSF DCE Application Development Guide—Introduction and Style Guide N P names, difference of from objects, 5-1 namespace defined, 5-1 entry name in, importing from, 1-27 exporting binding information into, 1-26 importing binding handles from, 1-26 unexporting information from, 1-25 nonpointer type parameters, 6-4 NSI routines, 1-8 parameter semantics, 6-3 parameters full pointers, 6-4 i n , 1-6 nonpointer types, 6-4 out, 1-6 reference pointers, 6-4 permissions semantics, 3-21 permissions set, in ACL, 3-2
Index RPC runtime and, 1-27 PTGT (privilege ticket granting ticket), 3-7 pthread_cancel(), 2-7, 2-9, 2-12, 2-14 pthread_cleanup_pop(), 2-13 pthread_cleanup_push(), 2-13 pthread_cond_signal(), 2-18 pthread_cond_timedwait( ), 2-10, 2-14 pthread_cond_wait( ), 2-7, 2-10, 2-14 pthread_create( ), 1-23, 2-1, 3-11 pthread_delay_np(), 2-10 pthread_detach( ), 2-7 pthread_equal(), 2-7 pthread_exit( ), 2-14 pthread_getspecific(), 2-8 pthread_join( ), 2-7, 2-10, 2-12 pthread_keycreate(), 2-8 pthread_lock_global_np(), 2-
OSF DCE Application Development Guide—Introduction and Style Guide rpc_mgmt_inq_if_ids(), 3-28 rpc_mgmt_inq_princ_name(), 1-28 rpc_mgmt_inq_server_princ_name( ), 3-9, 3-14, 3-15 rpc_mgmt_set_authorization_fn(), 1-24 rpc_mgmt_set_authorizaton_fn( ), 8-2 rpc_mgmt_stop_server_listening(), 1-24, 1-34 rpc_network_inq_protseqs( ), 1-27 rpc_network_is_protseq_valid(), 1-27 rpc_ns_binding_export(), 1-22 rpc_ns_binding_import_begin( ), 1-26, 1-34 rpc_ns_binding_import_done(), 1-26, 1-34 rpc_ns_binding_import_next( )
Index principal identity, establishing, 1-18 recommended design of interfaces, 1-37 registering, 1-19 server instances, distinguishing, 1-21 serviceability, 1-4, 1-13, 7-4 severity level attribute, 7-5 sigaction( ), 2-15 should not be used for asynchronous signals, 2-16 siglongjmp( ), 2-14 signals and rpc_server_listen(), 1-34 asynchronous, 2-15, 2-16 blocking of, 2-15 handling of in a multithreaded environment, 2-14 masking of, 2-15 rules for handling in multithreaded programs, 2-18 semantics of, 2-15 sync
OSF DCE Application Development Guide—Introduction and Style Guide U unauthenticated access, 3-2 unexporting server namespace information, 1-25 unions, 6-23 unique pointers, 6-11 unregistered applications, 7-2 unregistering server address information, 1-25 user ACL, 3-21 user_obj ACL entry type, 3-21 ignored by DCE ACL library, 3-22 UUID, 1-16 generator, 1-5 interface, 1-17 generating, 1-10 registering, 1-20 object UUIDs and endpoint mapping, 1-22 and interface UUIDs, 1-21 type, registering, 1-20 uuidgen,