## Manager and Client Illustrations

Most of the application-specific server code is contained in sample_manager.c. Since generic client tasks are so simple, the whole client is contained in sample_client.c.

/****************************************************************************/

/* [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 <stdio.h>

#include <malloc.h>

#include <time.h>

#include <pthread.h>

#include <errno.h>

#include <unistd.h>

#include <signal.h>

#include <sys/param.h>
#include <dce/nbase.h>

#include <dce/dce.h>

#include <dce/dce_cf.h>

#include <dce/dce_error.h>

#include <dce/rpc.h>

#include <dce/sec_login.h>

#include <dce/keymgmt.h>

#include <dce/uuid.h>

#include <dce/exc_handling.h>

#include <dce/dce_msg.h>

#include <dce/dbif.h>

#include <dce/aclif.h>

#include <dce/dceacl.h>

#include <dce/pgo.h>
#include <dce/dcesvcmsg.h>

#include <dce/svcremote.h>
#include "dcesmpsvc.h"

#include "dcesmpmsg.h"

#include "dcesmpmac.h"
#include "sample.h"

#include "sample_db.h"

#include "sample_bind.h"

#include "sample_server.h"
void sample_call(rpc_binding_handle_t,

idl_long_int *,

error_status_t *);
void sample_get_text(rpc_binding_handle_t,

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. */

idl_long_int *status,

error_status_t *remote_status)

{
extern uuid_t sample_acl_mgr_uuid, sample_acl_uuid;

boolean32 authorized = 0;

/****************************************************************************/

/* We have to explicitly initialize the remote status value; */

/* otherwise, if no error occurs in the transmission (which */

/* would cause the runtime to assign an error value to this */

/* variable), its value will be whatever it happened to be */

/* when the RPC was made by the client... */

*remote_status = rpc_s_ok;
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Entering sample_call()..."));
/* Check whether client is authorized or not... */

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Calling dce_acl_is_client_authorized()..."));

dce_acl_is_client_authorized(

binding, /* Client's binding handle. */

&sample_acl_mgr_uuid, /* ACL manager type UUID. */

&sample_acl_uuid, /* The ACL UUID. */

NULL, /* Pointer to owner's UUID. */

NULL, /* Pointer to owner's group's UUID. */

sec_acl_perm_read, /* The desired privileges. */

&authorized, /* Will be TRUE or FALSE on return. */

remote_status);
if (*remote_status != error_status_ok)

{

print_manager_error("dce_acl_is_client_authorized()",

*remote_status);

return;

}

if (authorized)

{

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Call authorized"));
/* HERE'S WHERE WE SHOULD ACTUALLY DO SOMETHING! */
*status = error_status_ok;

}

else

{

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Call not authorized"));
/* Return no_permissions status to client... */

*status = no_permissions;

}
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Successfully exiting sample_call()"));
}
/******

*

* sample_get_text -- Extracts and returns an object's text information.

*

*

* Called from the client using its "object-bound" handle.

*

******/

void sample_get_text(

rpc_binding_handle_t h, /* Client binding handle passed into the */

/* server stub. sec_acl_bind() is used to */

/* create this handle. */

uuid_t object_uuid, /* Desired object's UUID. */

idl_char text[TEXT_SIZE], /* To return extracted text information. */

idl_long_int *status,

error_status_t *remote_st /* To return status. */

)

{
/* 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()..."));

dce_db_fetch_by_uuid(db_object, &object_uuid, (void *)&data, remote_st);

if (*remote_st != error_status_ok)

{

dce_svc_printf(OBJECT_NOT_FOUND_MSG);

return;

}
/* Copy the text, if any, into the return parameter... */

if (data.s_data.message)

{

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Text exists"));

strcpy(text, data.s_data.message);

}

else

{

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"No text"));

strcpy(text, "-No text-");

}
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Recovered text == %s", data.s_data.message));

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Message == %s", text));
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Successfully exiting sample_get_text()"));
}

/******

*

* sample_put_text -- Puts some text information "into" an object.

*

*

* Not called from anywhere.

*

******/
void sample_put_text(

rpc_binding_handle_t h, /* Client binding handle passed into the */

/* server stub. sec_acl_bind() is used to */

/* create this handle. */

uuid_t object_uuid, /* Desired object's UUID. */

idl_char text[TEXT_SIZE], /* Text information to put. */

idl_long_int *status,

error_status_t *remote_st /* To return status. */

)

{
/* Our backing store data type. For a full explanation, see the */

/* body of sample_resolve_by_name(), in sample_server.c. See also */

/* the contents of sample_db.idl. */

sample_data_t data;
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Entering sample_put_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()..."));

dce_db_fetch_by_uuid(db_object, &object_uuid, (void *)&data, remote_st);

if (*remote_st != error_status_ok)

{

dce_svc_printf(OBJECT_NOT_FOUND_MSG);

return;

}
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug8,

"Storing text in object database"));
/* Now insert the text and stick it back in the backing store... */

strcpy(data.s_data.message, text);

DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Calling dce_db_store_by_uuid()..."));

dce_db_store_by_uuid(db_object, &object_uuid, (void *)&data, remote_st);
DCE_SVC_DEBUG((smp_svc_handle, smp_s_manager, svc_c_debug6,

"Successfully exiting sample_put_text()"));
}
/******

*

* print_manager_error-- Manager version. Prints text associated with bad

* status code.

*

*

******/

void

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.c -- Client of "sample" interface. */

/* */

/* */

/* */

/* -77 cols- */

/****************************************************************************/
#include <stdio.h>

#include <string.h>

#include <dce/dce_error.h>

#include <dce/nbase.h>

#include <dce/rpc.h>

#include <dce/dce_msg.h>

#include <dce/dbif.h>

#include <dce/dce.h>

#include <dce/dce_cf.h>

#include <dce/dcesvcmsg.h>

#include <dce/svcremote.h>

#include <dce/sec_login.h>

#include <dce/pgo.h>

#include <dce/secidmap.h>
#include "sample.h"

#include "sample_bind.h"

/* Data structure for holding object entry names... */

typedef struct {

unsigned32 count;

unsigned_char_t *name[1];

} objectname_vector_t;

/* ANSI-C style prototypes for functions private to this module... */
int do_client_command_line(int,

char **,

unsigned32 *,

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[]

)

{

rpc_ns_handle_t import_context; /* Context for importing bindings. */

rpc_binding_handle_t binding_h; /* Our binding handle. */

error_status_t status; /* For DCE library error returns. */

error_status_t rpc_remote_status; /* For remote error returns. */

idl_long_int rpc_status; /* Application-returned status from */

/* remote calls. */

unsigned_char_t *string_binding; /* For string binding conversions. */

unsigned_char_t *server_princ_name;

handle_t object_handle; /* For binding we get through junction. */

uuid_t object_uuid, mgr_uuid; /* Various UUIDs. */

unsigned_char_t *u_string; /* For converting UUIDs to strings. */

objectname_vector_t objectname_vector; /* For entry names read from */

/* command line. */

unsigned32 kill_server = FALSE; /* TRUE => invoker requested "kill */

/* server" option. */

idl_char server_message[TEXT_SIZE]; /* For message string returned */

/* from the server to us. */

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 environment*/

/* variable RPC_DEFAULT_ENTRY are used to determine the entry */

/* to import from... */

fprintf(stdout,

"sample_client: Calling rpc_ns_binding_import_begin()...\n");

rpc_ns_binding_import_begin(

rpc_c_ns_syntax_default,

NULL, /* Use the RPC_DEFAULT_ENTRY. */

sample_v1_0_c_ifspec,

NULL,

&import_context,

&status);

if (status != rpc_s_ok)

{

print_error("rpc_ns_binding_import_begin()", status);

exit(1);

}
/* Import the first server (we could iterate here, but we'll just */

/* take the first one)... */

fprintf(stdout,

"sample_client: Calling rpc_ns_binding_import_next()...\n");

rpc_ns_binding_import_next(import_context, &binding_h, &status);

if (status != rpc_s_ok)

{

print_error("rpc_ns_binding_import_next()", status);

exit(1);

}
/* Free the import context... */

fprintf(stdout,

"sample_client: Calling rpc_ns_binding_import_done()...\n");

rpc_ns_binding_import_done(&import_context, &status);

if (status != rpc_s_ok)

{

print_error("rpc_ns_binding_import_done()", status);

exit(1);

}
/* Resolve the partial binding... */

fprintf(stdout,

"sample_client: Calling rpc_ep_resolve_binding()...\n");

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()...\n");

rpc_binding_to_string_binding(binding_h, &string_binding, &status);

if (status != rpc_s_ok)

{

print_error("rpc_binding_to_string_binding()", status);

exit(1);

}
/* Print it... */

fprintf(stdout,

"sample_client: Imported resolved binding == %s\n",

string_binding);
/* Free the string binding space... */

fprintf(stdout, "sample_client: Calling rpc_string_free()...\n");

rpc_string_free(&string_binding, &status);

if (status != rpc_s_ok)

{

print_error("rpc_string_free()", status);

exit(1);

}
/* Find out what the server's principal name is... */

fprintf(stdout,

"sample_client: Calling rpc_mgmt_inq_server_princ_name()...\n");

rpc_mgmt_inq_server_princ_name(binding_h,

rpc_c_authn_dce_secret,

&server_princ_name,

&status);

if (status != rpc_s_ok)

{

print_error("rpc_mgmt_inq_server_princ_name()", status);

}

fprintf(stdout, "sample_client: Principal name returned == %s\n",

server_princ_name);
/* And now find out if it's a valid member of our sample_servers */

/* group... */

fprintf(stdout, "sample_client: Calling is_valid_principal()...\n");

if (is_valid_principal(server_princ_name, (unsigned_char_t *)SGROUP, &status))

{

fprintf(stdout,

"sample_client: Calling rpc_binding_set_auth_info()...\n");

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);
}

if (status != rpc_s_ok)

{

print_error("rpc_binding_set_auth_info()", status);

exit(1);

}
/********************************************************************/

/* Everything's okay, so do some remote stuff. There are currently */

/* two possibilities: Either stop the server via the remote mgmt */

/* interface, or actually bind to an object and call a couple of */

/* remote operations. */
/* First alternative: Kill the server via the mgmt interface... */

if (kill_server)

{

fprintf(stdout,

"sample_client: Kill server option enacted...\n");

fprintf(stdout,

"sample_client: Calling rpc_ep_resolve_binding()...\n");

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);

}
fprintf(stdout,

"sample_client: Calling rpc_mgmt_stop_server_listening()...\n");

rpc_mgmt_stop_server_listening(binding_h, &status);

if (status != rpc_s_ok)

{

print_error("rpc_mgmt_stop_server_listening()", status);

exit(1);

}
fprintf(stdout, "sample_client: Server successfully killed.\n\n");
}

/* Second alternative: Do remote operations... */

else

{

/* This is a local call... */

fprintf(stdout,

"sample_client: Remote call option enacted...\n");

fprintf(stdout,

"sample_client: Preparing to bind to object %s\n",

(char *)objectname_vector.name[0]);

fprintf(stdout,

"sample_client: Calling bind_to_object()...\n");

bind_to_object(

(unsigned_char_t *)objectname_vector.name[0],

/* ...Name of object to bind to. */

NULL, /* Interface spec "hint". */

NULL, /* Object UUID "hint". */

&object_handle, /* Here's where binding will be. */

&object_uuid, /* Here's where object UUID will be. */

&mgr_uuid, /* Type manager UUID will be here. */

&entry_name, /* Full entry name returned here. */

&object_name, /* "Unresolved", i.e. object name. */

&status);

if (status != error_status_ok)

{

fprintf(stdout, "Can't bind to object %s\n",

objectname_vector.name[0]);

return;

}
/* Display the binding, just for fun... */

fprintf(stdout, "View object %s:\n",

(char *)objectname_vector.name[0]);

fprintf(stdout, " Via junction: %s\n Object name: %s\n",

entry_name, object_name);
/* Convert to string form... */

fprintf(stdout,

"sample_client: Calling rpc_binding_to_string_binding()...\n");

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: %s\n", string_binding);
/* Now convert the type manager UUID to a string... */

fprintf(stdout, "sample_client: Calling uuid_to_string()...\n");

uuid_to_string(&mgr_uuid, &u_string, &status);

if (status != uuid_s_ok)

{

print_error("uuid_from_string()", status);

exit(1);

}
/* Show it... */

fprintf(stdout, " Manager Type UUID: %s\n", u_string);
/* Convert the object UUID to string form... */

fprintf(stdout, "sample_client: Calling uuid_to_string()...\n");

uuid_to_string(&object_uuid, &u_string, &status);

if (status != uuid_s_ok)

{

print_error("uuid_to_string()", status);

exit(1);

}
/* And show it... */

fprintf(stdout, " Object UUID: %s\n", u_string);
/* Now free the space... */

rpc_string_free(&string_binding, &status);

if (status != rpc_s_ok)

{

print_error("rpc_string_free()", status);

exit(1);

}

rpc_string_free(&u_string, &status);

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()...\n");

sample_get_text(object_handle,

object_uuid,

server_message,

&rpc_status,

&rpc_remote_status);

fprintf(stdout, " Object Text: %s\n", server_message);
/* Call the sample_call() operation... */

/* First, get rid of the object UUID... */

rpc_binding_set_object(

binding_h,

NULL,

&status);

if (status != error_status_ok)

{

print_error("rpc_binding_set_object()", status);

return;

}
/* Then display the binding... */

/* Convert to string form... */

fprintf(stdout,

"sample_client: Calling rpc_binding_to_string_binding()...\n");

rpc_binding_to_string_binding(binding_h, &string_binding, &status);

if (status != rpc_s_ok)

{

print_error("rpc_binding_to_string_binding()", status);

exit(1);

}
/* Show it... */

fprintf(stdout,

"sample_client: Binding about to be used == %s\n",

string_binding);
/* 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()...\n");

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.\n\n");
}
fprintf(stdout, "sample_client: Calling rpc_string_free()...\n");

rpc_string_free(&server_princ_name, &status);

if (status != rpc_s_ok)

{

print_error("rpc_string_free()", status);

exit(1);

}
}

/******

*

* do_client_command_line -- Get and interpret arguments and options from

* the command line, and do other setup related to the

* command line's contents.

*

* Called from main().

*

******/
int do_client_command_line(

int argc,

char *argv[],

unsigned32 *kill_server,

objectname_vector_t *objectname_vector

)

{

unsigned32 status;
/* 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. It is possible that the object name is not a namespace */

/* entry (for example, I suppose, if it's the management object, */

/* whatever its name is). That is when things get interesting, be- */

/* cause the application in effect implements a junction located */

/* at its server entry in the namespace, and clients are supposed */

/* to be able to bind to objects under the junction. Essentially */

/* this is done as follows. The client tries to bind to the over- */

/* qualified CDS entry formed by concatenating the specified */

/* object name to the server entry name; it ends up getting a */

/* partial binding to (what else?) the server; and it then makes a */

/* call to the remote bind operation with that binding, ostensibly */

/* to get the object UUID of the object whose name was specified */

/* (to bind to) when the client was invoked. These objects are */

/* held in a backing store database. The remote call makes its way */

/* by the familiar procedure to the server; the name_to_object() */

/* routine then simply looks up the desired object UUID by accessing*/

/* the name-indexed backing store. When the remote call completes, */

/* the client finds itself with a full binding and the desired */

/* object UUID. It is pointed out below that remote calls */

/* are not routed by object UUID, so this is actually useless in */

/* regard to further operations, and can be discarded. Whether */

/* this is the way things ought to be I'm not sure. */

/* */

/* If the object binding option is specified, the following things */

/* should happen: */

/* */

/* 1. The message "View object <object_name_specified>" is */

/* displayed. */

/* */

/* 2. The message "Via junction: <server_entry> */

/* Object name: <object_name>" */

/* is displayed. */

/* */

/* 3. The message "Binding: <full_binding_to_object>" is */

/* displayed. */

/* */

/* 4. The message "Manager Type ID: <manager_UUID_string>" is */

/* displayed. */

/* */

/* 5. The message "Object ID: <object_UUID_string>" is */

/* displayed. */

/* */

/* 6. The message "Object Text: <text_string>" is displayed. */

/* */

/* 7. --And this should be followed by some serviceability */

/* informational (soon to be debug) messages, from the server. */

/* */

/* ...This is all assuming, of course, that no errors occur. */
fprintf(stdout, "sample_client: Entering do_client_command_line()...\n");
if (argc < 2)

{

fprintf(stdout, "\n Usage:\n");

fprintf(stdout, " %s {<object_name> | kill}\n\n", argv[0]);

fprintf(stdout, "Note that the client imports via RPC_DEFAULT_ENTRY!\n\n");

exit(1);

}
if ((argc == 2) && !strcmp("kill", argv[1]))

{

fprintf(stdout, "sample_client: Kill server option selected.\n");

*kill_server = TRUE;

}

else

{

fprintf(stdout, "sample_client: Remote call option selected.\n");
/* Get the list of object entry names from the command */

/* line... */

objectname_vector->count = 1;

objectname_vector->name[0] = (unsigned_char_p_t)malloc(strlen(argv[1]));

strcpy((char *)objectname_vector->name[0], argv[1]);

fprintf(stdout,

"sample_client: objectname_vector->name == %s\n",

objectname_vector->name[0]);

}
return 0;

}

/******

*

*

* 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, /* Full name of principal to test. */

unsigned_char_t *group, /* Group we want principal to be in. */

unsigned32 *status)

{
unsigned_char_t *local_name; /* For principal's local name. */

char *cell_name; /* Local cell name. */

sec_rgy_handle_t rhandle; /* Local registry binding. */

boolean32 is_valid; /* To hold result of registry call. */
fprintf(stdout, "sample_client: Entering is_valid_principal()...\n");

fprintf(stdout, "sample_client: Initial principal name == %s\n", princ_name);

fprintf(stdout, "sample_client: Initial group name == %s\n", group);
/* Find out the local cell name... */

fprintf(stdout, "sample_client: Calling dce_cf_get_cell_name()...\n");

dce_cf_get_cell_name(&cell_name, status);

if (*status != dce_cf_st_ok)

{

print_error("dce_cf_get_cell_name()", *status);

return 0;

}
/* Now bind to the local cell registry... */

fprintf(stdout, "sample_client: Calling sec_rgy_site_open()...\n");

sec_rgy_site_open(cell_name, &rhandle, status);

if (*status != error_status_ok)

{

free(cell_name);

print_error("sec_rgy_site_open()", *status);

return 0;

}
/* Free the cellname string space... */

free(cell_name);

if (*status != rpc_s_ok)

{

print_error("free()", *status);

return 0;

}
/* Get the specified principal's local (cell-relative) name... */

local_name = malloc(strlen((char *)princ_name));
fprintf(stdout, "sample_client: Calling sec_id_parse_name()...\n");

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. */

status);

if (*status != error_status_ok)

{

free(local_name);

print_error("sec_id_parse_name()", *status);

return 0;

}

else

{

fprintf(stdout,

"sample_client: Full principal name == %s\n",

princ_name);

fprintf(stdout,

"sample_client: Local principal name == %s\n",

local_name);

}
/* And finally, find out from the registry whether that principal */

/* is a valid member of the specified group... */

fprintf(stdout, "sample_client: Calling sec_rgy_pgo_is_member()...\n");

is_valid = sec_rgy_pgo_is_member(rhandle,

sec_rgy_domain_group,

group,

local_name,

status);

if (*status != error_status_ok)

{

free(local_name);

print_error("sec_rgy_pgo_is_member()", *status);

return 0;

}
/* Free the principal name string area... */

free(local_name);

return(is_valid);
}

/******

*

* 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(). */

rpc_binding_handle_t *binding_h, /* Binding will be returned here. */

uuid_t *object_uuid, /* Object's object UUID will be returned here. */

uuid_t *mgr_type_uuid, /* Object's type manager UUID will be returned here. */

unsigned_char_t **entry_name, /* Full entry name (?) will be returned here. */

unsigned_char_t **residual, /* Unresolved (?) name part returned here. */

error_status_t *status)

{
unsigned_char_p_t resolved_name = NULL; /* To hold resolved part of */

/* object name. */

rpc_ns_handle_t import_context; /* For NSI import operations. */

unsigned_char_t *uuid_string; / * Not used. */

unsigned_char_t *string_binding; / * Not used. */
fprintf(stdout, "sample_client: Entering bind_to_object()...\n");
/* Attempt to resolve the entry (i.e., object) name we were */

/* given. The idea is that we are feeding this routine an over- */

/* qualified name, which it will be able to resolve only to a */

/* certain depth. What's left should be only a simple name, i.e. of */

/* the object we want to bind to... */

fprintf(stdout, "sample_client: Object name == %s\n", object_name);

fprintf(stdout, "sample_client: Calling rpc_ns_entry_inq_resolution()...\n");

rpc_ns_entry_inq_resolution(

rpc_c_ns_syntax_dce, / * Syntax for object_name. */

object_name, / * Entry name to be resolved. */

&resolved_name, / * Pointer to resolved name returned here. */

residual, / * Pointer to unresolved name part returned here. */

status);

if ( *status != rpc_s_ok)

{

print_error("rpc_ns_entry_inq_resolution()", *status);

}

/* 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...\n");
/* Make the object name the "residual"... */

*residual = (unsigned_char_t *)malloc(strlen((char *)object_name));

strcpy((char *) *residual, (char *)object_name);
/* Try importing from the RPC_DEFAULT_ENTRY, with interface */

/* and object UUID specified, if any were given to us */

/* (which they weren't in the original call made from */

/* main())... */

fprintf(stdout, "sample_client: Calling rpc_ns_binding_import_begin()...\n");

rpc_ns_binding_import_begin(

rpc_c_ns_syntax_default,

NULL,

if_hint,

id_hint,

&import_context,

status);
/* If that didn't succeed, we're at a loss... */

if ( *status != rpc_s_ok)

{

print_error("rpc_ns_binding_import_begin()", *status);

return;

}

fprintf(stdout, "sample_client: Found object.\n");

}
/* We either resolved the name completely, or we resolved every- */

/* thing but the simple object name part. But if the latter is */

/* the case, that's the same thing for us as having a full entry */

/* name to import from, since the whole point of this exercise is */

/* that the object part of the name isn't in the namespace in the */

/* the first place. So... */
/* Import a binding... */

else if ( *status == rpc_s_partial_results || *status == error_status_ok)

{

fprintf(stdout, "sample_client: Binding to resolved name...\n");

fprintf(stdout, "sample_client: Calling rpc_ns_binding_import_begin()...\n");

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. */

id_hint, /* Object UUID we were originally given. */

&import_context,

status);
/* If this has failed, one possible reason is that we sup- */

/* plied an id_hint and this wasn't in the junction. We */

/* could try to import with the nil-UUID at this point and */

/* then put the id_hint into the returned binding. That */

/* way, we would succeed if the correct UUID was in the */

/* endpoint map. For now, though, we'll just fail. */

/* [--original note] */

/* */

/* Well, it's hard to see what sense the above makes when */

/* the only way this function is ever called is with a */

/* null interface... */

if ( *status != error_status_ok)

{

print_error("rpc_ns_binding_import_begin()", *status);

return;

}
}
fprintf(stdout, "sample_client: Calling rpc_ns_binding_import_next()...\n");

rpc_ns_binding_import_next(

import_context,

(rpc_binding_handle_t *)binding_h,

status);

if ( *status != error_status_ok)

{

print_error("rpc_ns_binding_import_next()", *status);

return;

}
fprintf(stdout, "sample_client: Calling rpc_ns_binding_import_done()...\n");

rpc_ns_binding_import_done(&import_context, status);

if ( *status != error_status_ok)

{

print_error("rpc_ns_binding_import_done()", *status);

return;

}
/* We succeeded in importing a (partial) binding. Presumably the */

/* name we successfully used is in resolved_name, but for some */

/* reason he wants to make the following call to get that name. */

/* Note that this is only for the purpose of returning the name */

/* to the caller; we have no further use for it here... */

fprintf(stdout, "sample_client: Imported partial binding.\n");

fprintf(stdout, "sample_client: Calling rpc_ns_binding_inq_entry_name()...\n");

rpc_ns_binding_inq_entry_name(

(rpc_binding_handle_t) *binding_h,

rpc_c_ns_syntax_default,

entry_name,

status);

if ( *status != error_status_ok)

{

print_error("rpc_ns_binding_inq_entry_name()", *status);

return;

}
/* Note that at this point, we can only assume that the server */

/* has put at least one object UUID in the endpoint map and */

/* the name space. If id_hint was null, we got one of the object */

/* UUIDs from the namespace at random. If id_hint was supplied, */

/* we either got that UUID or failed. If no UUIDs were exported, */

/* then the binding contains none, so when we make the call */

/* we are only guaranteed to get to some server that supports */

/* the sample_bind interface on the bound-to host. It may */

/* well be the wrong one, in which case we will now fail... */
/* This is the "remote binding interface" call. What we are hoping */

/* to get from it is the object UUID of the object whose name is */

/* pretending (via a junction) to be in the namespace. These */

/* things, not being in the namespace, are held in a backing store */

/* database maintained by the server... */

fprintf(stdout, "sample_client: Calling [remote] rs_bind_to_object()...\n");

rs_bind_to_object(

*binding_h, /* The partial binding we just got. */

*residual, /* The backing store "key", i.e. object name. */

object_uuid, /* To return the object UUID. */

mgr_type_uuid, /* To return the type manager UUID. */

status);

if ( *status != error_status_ok)

{

print_error("rs_bind_to_object()", *status);

return;

}
/* The binding handle is now fully bound. Our request for the */

/* object 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 */

/* replace it with any type manager UUID returned from the server… */

fprintf(stdout, "sample_client: Fully bound to object.\n");

/* fprintf(stdout, "sample_client: Calling rpc_binding_set_object()...\n");

rpc_binding_set_object(

(rpc_binding_handle_t) *binding_h,

mgr_type_uuid,

status);

if ( *status != error_status_ok)

{

print_error("rpc_binding_set_object()", *status);

return;

}

*/

fprintf(stdout, "sample_client: Calling rpc_string_free()...\n");

rpc_string_free(&resolved_name, status);

if ( *status != error_status_ok)

{

print_error("rpc_string_free()", *status);

return;

}
}
/******

*

* print_error-- Client version. Prints text associated with bad status code.

*

*

*

******/
void

print_error(char *caller, /* 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);

fprintf(stderr," Client: %s: %s\n", caller, error_string);

}

##