1/* 2 * access_server : demo DCE RPC application 3 * 4 * Jim Doyle, jrd@bu.edu 09-05-1998 5 * 6 * 7 */ 8#if HAVE_CONFIG_H 9#include <config.h> 10#endif 11 12#ifndef _POSIX_PTHREAD_SEMANTICS 13#define _POSIX_PTHREAD_SEMANTICS 1 14#endif 15 16#define getopt getopt_system 17 18#include <stdio.h> 19#include <string.h> 20#include <signal.h> 21#include <compat/dcerpc.h> 22#include <lw/base.h> 23#include "access.h" 24#include "misc.h" 25 26#undef getopt 27 28#ifdef HAVE_GETOPT_H 29#include <getopt.h> 30#endif 31 32#ifndef _WIN32 33static void wait_for_signals(); 34#endif 35 36/* 37 * 38 * A template DCE RPC server 39 * 40 * main() contains the basic calls needed to register an interface, 41 * get communications endpoints, and register the endpoints 42 * with the endpoint mapper. 43 * 44 * ReverseIt() implements the interface specified in access.idl 45 * 46 */ 47 48static void 49bind_server( 50 rpc_binding_vector_p_t * server_binding, 51 rpc_if_handle_t interface_spec, 52 char * protocol, 53 char * endpoint 54 ) 55{ 56 char * function = "n/a"; 57 unsigned32 status; 58 59 /* 60 * Prepare the server binding handle 61 * use all avail protocols (UDP and TCP). This basically allocates 62 * new sockets for us and associates the interface UUID and 63 * object UUID of with those communications endpoints. 64 */ 65 66#if 0 67 rpc_server_use_all_protseqs_if(0, interface_spec, &status); 68#else 69 if (!endpoint) 70 { 71 if (!protocol) 72 { 73 function = "rpc_server_use_all_protseqs()"; 74 rpc_server_use_all_protseqs(rpc_c_protseq_max_calls_default, &status); 75 } 76 else 77 { 78 function = "rpc_server_use_protseq()"; 79 rpc_server_use_protseq(protocol, rpc_c_protseq_max_calls_default, &status); 80 } 81 } 82 else 83 { 84 function = "rpc_server_use_protseq_ep()"; 85 rpc_server_use_protseq_ep(protocol, rpc_c_protseq_max_calls_default, endpoint, &status); 86 } 87#endif 88 89 chk_dce_err(status, function, "", 1); 90 rpc_server_inq_bindings(server_binding, &status); 91 chk_dce_err(status, "rpc_server_inq_bindings()", "", 1); 92} 93 94static void usage() 95{ 96 printf("usage: access_server [-e endpoint] [-n] [-u] [-t]\n"); 97 printf(" -e: specify endpoint\n"); 98 printf(" -n: use named pipe protocol\n"); 99 printf(" -u: use UDP protocol\n"); 100 printf(" -t: use TCP protocol (default)\n"); 101 printf("\n"); 102 exit(1); 103} 104 105int main(int argc, char *argv[]) 106{ 107 unsigned32 status; 108 rpc_binding_vector_p_t server_binding; 109 char * string_binding; 110 unsigned32 i; 111 char * protocol = NULL; 112 char * endpoint = NULL; 113 int c; 114 char * function = NULL; 115 116 /* 117 * Process the cmd line args 118 */ 119 120 while ((c = getopt(argc, argv, "e:nutl")) != EOF) 121 { 122 switch (c) 123 { 124 case 'e': 125 endpoint = optarg; 126 break; 127 case 'n': 128 protocol = PROTOCOL_NP; 129 break; 130 case 'u': 131 protocol = PROTOCOL_UDP; 132 break; 133 case 't': 134 protocol = PROTOCOL_TCP; 135 break; 136 case 'l': 137 protocol = PROTOCOL_LRPC; 138 break; 139 default: 140 usage(); 141 } 142 } 143 144 if (endpoint && !protocol) 145 { 146 printf("ERROR: protocol is required when endpoint is specified\n"); 147 exit(1); 148 } 149 150 /* 151 * Register the Interface with the local endpoint mapper (rpcd) 152 */ 153 154 printf ("Registering server.... \n"); 155 rpc_server_register_if(access_v1_0_s_ifspec, 156 NULL, 157 NULL, 158 &status); 159 chk_dce_err(status, "rpc_server_register_if()", "", 1); 160 161 printf("registered.\nPreparing binding handle...\n"); 162 163 bind_server(&server_binding, access_v1_0_s_ifspec, protocol, endpoint); 164 165 /* 166 * Register bindings with the endpoint mapper 167 */ 168 169 printf("registering bindings with endpoint mapper\n"); 170 171 rpc_ep_register(access_v1_0_s_ifspec, 172 server_binding, 173 NULL, 174 (unsigned char *)"QDA application server", 175 &status); 176 chk_dce_err(status, "rpc_ep_register()", "", 1); 177 178 printf("registered.\n"); 179 180 /* 181 * Print out the servers endpoints (TCP and UDP port numbers) 182 */ 183 184 printf ("Server's communications endpoints are:\n"); 185 186 for (i=0; i<RPC_FIELD_COUNT(server_binding); i++) 187 { 188 rpc_binding_to_string_binding(RPC_FIELD_BINDING_H(server_binding)[i], 189 (unsigned char **)&string_binding, 190 &status); 191 if (string_binding) 192 printf("\t%s\n", string_binding); 193 } 194 195#ifndef _WIN32 196 /* 197 * Start the signal waiting thread in background. This thread will 198 * Catch SIGINT and gracefully shutdown the server. 199 */ 200 201 wait_for_signals(); 202#endif 203 204 /* 205 * Begin listening for calls 206 */ 207 208 printf ("listening for calls....\n"); 209 210 DCETHREAD_TRY 211 { 212 rpc_server_listen(rpc_c_listen_max_calls_default, &status); 213 } 214 DCETHREAD_CATCH_ALL(THIS_CATCH) 215 { 216 printf ("Server stoppped listening\n"); 217 } 218 DCETHREAD_ENDTRY; 219 220 /* 221 * If we reached this point, then the server was stopped, most likely 222 * by the signal handler thread called rpc_mgmt_stop_server(). 223 * gracefully cleanup and unregister the bindings from the 224 * endpoint mapper. 225 */ 226 227#ifndef _WIN32 228 /* 229 * Kill the signal handling thread 230 */ 231 232#endif 233 234 printf ("Unregistering server from the endpoint mapper....\n"); 235 rpc_ep_unregister(access_v1_0_s_ifspec, 236 server_binding, 237 NULL, 238 &status); 239 chk_dce_err(status, "rpc_ep_unregister()", "", 0); 240 241 /* 242 * retire the binding information 243 */ 244 245 printf("Cleaning up communications endpoints...\n"); 246 rpc_server_unregister_if(access_v1_0_s_ifspec, 247 NULL, 248 &status); 249 chk_dce_err(status, "rpc_server_unregister_if()", "", 0); 250 251 exit(0); 252} 253 254 255/*========================================================================= 256 * 257 * Server implementation of ReverseIt() 258 * 259 *=========================================================================*/ 260 261void 262WhoAmI( 263 rpc_binding_handle_t h, 264 string_t* sid 265 ) 266{ 267 PACCESS_TOKEN token = NULL; 268 unsigned32 st = rpc_s_ok; 269 string_t str = NULL; 270 union 271 { 272 SID_AND_ATTRIBUTES user; 273 BYTE buffer[sizeof(SID_AND_ATTRIBUTES) + SID_MAX_SIZE]; 274 } u; 275 NTSTATUS status = 0; 276 ULONG len = 0; 277 PSTR sidstr = NULL; 278 279 rpc_binding_inq_access_token_caller( 280 h, 281 &token, 282 &st); 283 284 if (st) 285 { 286 goto error; 287 } 288 289 status = RtlQueryAccessTokenInformation( 290 token, 291 TokenUser, 292 &u.user, 293 sizeof(u), 294 &len); 295 296 if (status) 297 { 298 goto error; 299 } 300 301 status = RtlAllocateCStringFromSid( 302 &sidstr, 303 u.user.Sid); 304 305 if (status) 306 { 307 goto error; 308 } 309 310 str = rpc_ss_allocate(strlen(sidstr) + 1); 311 strcpy(str, sidstr); 312 313 *sid = str; 314 315cleanup: 316 317 RTL_FREE(&sidstr); 318 319 return; 320 321error: 322 323 *sid = NULL; 324 325 goto cleanup; 326} 327 328 329#ifndef _WIN32 330/*========================================================================= 331 * 332 * wait_for_signals() 333 * 334 * 335 * Set up the process environment to properly deal with signals. 336 * By default, we isolate all threads from receiving asynchronous 337 * signals. We create a thread that handles all async signals. 338 * The signal handling actions are handled in the handler thread. 339 * 340 * For AIX, we cant use a thread that sigwaits() on a specific signal, 341 * we use a plain old, lame old Unix signal handler. 342 * 343 *=========================================================================*/ 344 345void 346wait_for_signals() 347{ 348 sigset_t signals; 349 350 sigemptyset(&signals); 351 sigaddset(&signals, SIGINT); 352 353 dcethread_signal_to_interrupt(&signals, dcethread_self()); 354} 355 356#endif 357