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