////////////////////////////////////////////////////////////
//
// Implementation of a class
// DceServer
//
// Copyright 2001
//
////////////////////////////////////////////////////////////
#include <string.h>
#include <stdio.h>
#include <dce/dce_error.h>
#include "AWait.h"
#include "DceKey.h"
#include "DceServer.h"
static
void get_key_fn( void *arg, unsigned_char_t *server_princ_name,
unsigned32 key_type, unsigned32 key_ver, void **key, unsigned32 *status);
const error_status_t rpc_e_access = 10001;
// DceServerAttributes
DceServerAttributes::DceServerAttributes():
max_exec_threads(rpc_c_listen_max_calls_default),
max_call_requests(rpc_c_protseq_max_reqs_default),
protocol_sequence((unsigned_char_t*)"ncacn_ip_tcp"),
entry_name_syntax(rpc_c_ns_syntax_default),
entry_name(0),
principal_name(0),
login_flags(sec_login_no_flags),
key_service(rpc_c_authn_dce_secret),
key_file(0),
key_file_flag(false),
key_version_number(sec_c_key_version_none), //latest
own_identity_flag(false),
annotation(0),
unexport_names_flag(false),
no_endpoint_replace_flag(false),
no_names_export_flag(false)
{
}
DceServerAttributes::DceServerAttributes(const DceServerAttributes& z):
max_exec_threads(z.max_exec_threads),
max_call_requests(z.max_call_requests),
protocol_sequence(z.protocol_sequence),
entry_name_syntax(rpc_c_ns_syntax_default),
entry_name(0),
principal_name(0),
login_flags(z.login_flags),
key_service(z.key_service),
key_file(0),
key_file_flag(z.key_file_flag),
key_version_number(z.key_version_number),
own_identity_flag(z.own_identity_flag),
id(z.id),
unexport_names_flag(z.unexport_names_flag),
no_endpoint_replace_flag(z.no_endpoint_replace_flag),
no_names_export_flag(z.no_names_export_flag)
{
set_entry_name((char*)z.entry_name);
set_principal_name((char*)z.entry_name);
use_key_file(z.key_file);
set_annotation((char*)z.annotation);
}
DceServerAttributes::~DceServerAttributes()
{
delete []entry_name;
delete []principal_name;
delete []key_file;
delete []annotation;
}
DceServerAttributes& DceServerAttributes::operator=(const DceServerAttributes& z)
{
max_exec_threads=z.max_exec_threads;
max_call_requests=z.max_call_requests;
protocol_sequence=z.protocol_sequence;
entry_name_syntax=rpc_c_ns_syntax_default;
entry_name=0;
principal_name=0;
login_flags=z.login_flags;
key_service=z.key_service;
key_file=0;
key_file_flag=z.key_file_flag;
key_version_number=z.key_version_number;
own_identity_flag=z.own_identity_flag;
id=z.id;
unexport_names_flag=z.unexport_names_flag;
no_endpoint_replace_flag=z.no_endpoint_replace_flag;
no_names_export_flag=z.no_names_export_flag;
set_entry_name((char*)z.entry_name);
set_principal_name((char*)z.principal_name);
use_key_file(z.key_file);
set_annotation((char*)z.annotation);
return *this;
}
int DceServerAttributes::set_entry_name(const char *name)
{
if(!name) return 1;
delete []entry_name; entry_name=0;
int size = strlen( name ) + 1 ;
entry_name = new unsigned_char_t[ size ];
memcpy(entry_name,name,size);
return 0;
}
int DceServerAttributes::set_principal_name(const char *name)
{
if(!name) return 1;
delete []principal_name; principal_name=0;
int size = strlen( name ) + 1 ;
principal_name = new unsigned_char_t[ size ];
memcpy(principal_name,name,size);
return 0;
}
int DceServerAttributes::use_key_file(const char *name)
{
key_file_flag=true;
if(!name) return 0;
delete []key_file; key_file=0;
key_file = new char[strlen(name) + sizeof("FILE:") + 1];
strcpy(key_file,"FILE:");
strcat(key_file,name);
return 0;
}
int DceServerAttributes::set_annotation(const char *name)
{
if(!name) return 1;
delete []annotation; annotation=0;
int size = strlen( name ) + 1 ;
annotation = new unsigned_char_t[ size ];
memcpy(annotation,name,size);
return 0;
}
// KeyManagerThread
KeyManagerThread::KeyManagerThread(DceServerAttributes& att, DceKeyManager * k):
attributes(&att),
arg(0)
{
if(k) arg=k;
else if(att.key_file_flag)
arg = att.key_file;
}
int KeyManagerThread::loop(bool& continue_loop)
{
continue_loop=false;
error_status_t s;
sec_key_mgmt_manage_key
(
attributes->key_service,
arg,
attributes->principal_name,
&s);
return 0;
}
// DceServer
DceServer::DceServer(DceServerAttributes& z, DceKeyManager * k):
status(0),
attributes(z),
key_manager(k),
login_context(0),
login_service(sec_login_auth_src_network),
key_manager_thread(z,k)
{
error_status_t s=0;
if(!attributes.entry_name)
{
status=1;
return;
}
if(attributes.id.is_nil())
linked_id.set_random();
else
linked_id=z.id;
if(linked_id.status)
{
log("can't generate random id",s);
status = 2;
return;
}
rpc_server_use_protseq(
attributes.protocol_sequence,
attributes.max_call_requests,
&s);
if(s!=rpc_s_ok)
{
log("can't register protocol sequence",s);
status = 3;
return;
}
if(!attributes.associated_id.is_nil())
{
int g=0;
error_status_t s=0;
uuid_t type_id, server_id;
g=attributes.associated_id.get_uuid_t(type_id);
if(!g) g=linked_id.get_uuid_t(server_id);
if(!g) rpc_object_set_type(&server_id,&type_id,&s);
if(g || s != rpc_s_ok)
{
status=1;
return;
}
}
if(attributes.own_identity_flag)
{
if(!attributes.principal_name)
{
status=1;
return;
}
boolean32 r=sec_login_setup_identity(
attributes.principal_name,
attributes.login_flags,
&login_context,
&s);
if(s!=error_status_ok || r!=TRUE)
{
log("can't set identity",s);
status = 4;
return;
}
DceKey key;
boolean32 reset_password=FALSE;
if(attributes.key_file_flag)
sec_key_mgmt_get_key(
attributes.key_service,
attributes.key_file,
attributes.principal_name,
attributes.key_version_number,
&key.data,
&s);
else if(key_manager)
sec_key_mgmt_get_key(
attributes.key_service,
key_manager,
attributes.principal_name,
attributes.key_version_number,
&key.data,
&s);
else
{
log("use a key file or a driver",rpc_e_access );
status=5;
return;
}
if(s!=error_status_ok)
{
log("can't get a key",s );
status=6;
return;
}
login_service=sec_login_auth_src_network;
r=sec_login_validate_identity(
login_context,
(sec_passwd_rec_t*)key.data,
&reset_password,
&login_service,
&s);
if(reset_password==TRUE)
log("password expired",s);
if(s!=error_status_ok || r!=TRUE)
{
log("can't validate a key",s);
status = 7;
return;
}
r=sec_login_certify_identity(
login_context,
&s);
if(s!=error_status_ok || r!=TRUE)
{
log("can't certify identity",s);
status = 8;
return;
}
int g=thread_control.launch(key_manager_thread);
}
// a cache can have some NULL handles
for(int j=0;j<5;++j)
{
sec_login_get_current_context(&login_context,&s);
if(s==error_status_ok && login_context!=0)
break;
}
if(s!=error_status_ok )
{
log("can't get current login context",s);
status = 9;
return;
}
// sec_login_release_context() ?
}
DceServer::~DceServer()
{
int g=0;
error_status_t s=0;
node n;
uuid_t server_id;
uuid_vector_t object_uuid_vector;
object_uuid_vector.count=1;
key_manager_thread.selfdestruct();
g=linked_id.get_uuid_t(server_id);
if(g) return;
while(!interfaces.pop(n))
{
uuid_t type_id;
DceCalleeInterface& z = n.interface;
rpc_binding_vector_t *& binding_vector = n.binding_vector;
if(! z.linked_id.is_nil())
{
g=z.linked_id.get_uuid_t(type_id);
if(g)
{
log("cleanup: can't get type id",rpc_s_ok);
continue;
}
object_uuid_vector.uuid[0]=&type_id;
}
else
object_uuid_vector.uuid[0]=&server_id;
if(attributes.unexport_names_flag)
{
rpc_ns_binding_unexport(
attributes.entry_name_syntax,
attributes.entry_name,
z.interface_handle,
&object_uuid_vector,
&s);
if(s!=rpc_s_ok)
{
log("can't unexport",s);
}
}
rpc_ep_unregister(
z.interface_handle,
binding_vector,
&object_uuid_vector,
&s);
if(s!=rpc_s_ok)
{
log("can't unregister",s);
}
if(! z.linked_id.is_nil() )
rpc_server_unregister_if(
z.interface_handle,
&type_id,
&s);
else
rpc_server_unregister_if(
z.interface_handle,
0,
&s);
if(binding_vector)
rpc_binding_vector_free(&binding_vector,&s);
if(s!=rpc_s_ok)
{
log("can't free binding",s);
}
}
if(!status)
sec_login_release_context(&login_context,&s);
thread_control.terminate();
}
int DceServer::add_typeless(rpc_binding_vector_t *& binding_vector,const DceCalleeInterface& z)
{
if(status) return 1;
if(!z.interface_is_set()) return 2;
int g=0;
error_status_t s=0;
uuid_t server_id;
uuid_vector_t object_uuid_vector;
g=linked_id.get_uuid_t(server_id);
object_uuid_vector.count=1;
object_uuid_vector.uuid[0]=&server_id;
rpc_server_register_if(
z.interface_handle,
0,
z.entry_point,
&s);
// allocates binding_vector
if(s==rpc_s_ok)
rpc_server_inq_bindings(&binding_vector,&s);
if(s==rpc_s_ok)
{
if(attributes.no_endpoint_replace_flag)
rpc_ep_register_no_replace(
z.interface_handle,
binding_vector,
&object_uuid_vector,
attributes.annotation,
&s);
else
rpc_ep_register(
z.interface_handle,
binding_vector,
&object_uuid_vector,
attributes.annotation,
&s);
}
if(s==rpc_s_ok && !attributes.no_names_export_flag)
rpc_ns_binding_export(
attributes.entry_name_syntax,
attributes.entry_name,
z.interface_handle,
binding_vector,
&object_uuid_vector,
&s);
if(s!=rpc_s_ok)
{
log("can't register interface",s);
return 3;
}
return 0;
}
int DceServer::add_typed(rpc_binding_vector_t *& binding_vector,const DceCalleeInterface& z)
{
if(status) return 1;
if(!z.interface_is_set()) return 2;
if(!attributes.associated_id.is_nil()) return 3;
int g=0;
error_status_t s=0;
uuid_t type_id, server_id;
g=z.linked_id.get_uuid_t(type_id);
if(!g) g=linked_id.get_uuid_t(server_id);
if(g) return 4;
rpc_object_set_type(&server_id,&type_id,&s);
if(s==rpc_s_ok)
rpc_server_register_if(
z.interface_handle,
&type_id,
z.entry_point,
&s);
uuid_vector_t object_uuid_vector;
object_uuid_vector.uuid[0]=&type_id;
object_uuid_vector.count=1;
// allocates binding_vector
if(s==rpc_s_ok)
rpc_server_inq_bindings(&binding_vector,&s);
if(s==rpc_s_ok)
{
if(attributes.no_endpoint_replace_flag)
rpc_ep_register_no_replace(
z.interface_handle,
binding_vector,
&object_uuid_vector,
attributes.annotation,
&s);
else
rpc_ep_register(
z.interface_handle,
binding_vector,
&object_uuid_vector,
attributes.annotation,
&s);
}
if(s==rpc_s_ok && !attributes.no_names_export_flag)
rpc_ns_binding_export(
attributes.entry_name_syntax,
attributes.entry_name,
z.interface_handle,
binding_vector,
&object_uuid_vector,
&s);
if(s!=rpc_s_ok)
{
log("can't register interface",s);
return 5;
}
return 0;
}
int DceServer::add_interface(const DceCalleeInterface& z)
{
int g=0;
node n(z);
if(z.linked_id.is_nil())
g=add_typeless(n.binding_vector,n.interface);
else
g=add_typed(n.binding_vector,n.interface);
if(!g)
interfaces.push(n);
return g;
}
int DceServer::add_authentication_service(unsigned authentication_service)
{
if(status) return 1;
error_status_t s=0;
// key file is in format FILE:<absolute path> or
// zero for a defaualt key file /krb/v5srvtab
if(key_manager)
rpc_server_register_auth_info(
attributes.principal_name,
(unsigned32)authentication_service,
get_key_fn,
this,
&s);
else if(attributes.key_file_flag)
rpc_server_register_auth_info(
attributes.principal_name,
(unsigned32)authentication_service,
0,
attributes.key_file,
&s);
else
{
log("use key file or a driver",rpc_e_access );
return 2;
}
if(s!=rpc_s_ok)
{
log("can't set authentication service",s);
return 3;
}
return 0;
}
int DceServer::launch()
{
if(status) return 1;
error_status_t s=0;
rpc_server_listen(attributes.max_exec_threads,&s);
if(s!=rpc_s_ok)
{
log("exited listen",s);
return 2;
}
return 0;
}
int DceServer::stop()
{
if(status) return 1;
error_status_t s=0;
rpc_mgmt_stop_server_listening(0,&s);
if(s!=rpc_s_ok)
return 1;
return 0;
}
int DceServer::log(const char *message, error_status_t ss)
{
dce_error_string_t error_text;
int s=0;
dce_error_inq_text(ss,error_text,&s);
if(!s)
fprintf(stdout,"%s; dce call error: %s\n",message,(char*)error_text);
else
fprintf(stdout,"%s; dce call error: %d\n",message,(int)ss);
return 0;
}
static
void get_key_fn( void *arg, unsigned_char_t *server_princ_name,
unsigned32 key_type, unsigned32 key_ver, void **key, unsigned32 *status)
{
*status=rpc_s_ok;
if(!arg)
{
*status=rpc_e_access;
return;
}
DceKeyManager * z = (DceKeyManager *)arg;
int g=z->get_key(
key,
(char*)server_princ_name,
(unsigned)key_type,
(unsigned)key_ver);
if(g) *status=rpc_e_access;
}