Add stub of TRP client test program, trpc.
[trust_router.git] / tr / tr_trp.c
1 #include <fcntl.h>
2 #include <event2/event.h>
3 #include <talloc.h>
4 #include <errno.h>
5 #include <unistd.h>
6
7 #include <gsscon.h>
8 #include <tr_rp.h>
9 #include <tr_config.h>
10 #include <tr_event.h>
11 #include <tr_debug.h>
12 #include <tr_trp.h>
13
14 /* hold a trps instance and a config manager */
15 struct tr_trps_event_cookie {
16   TRPS_INSTANCE *trps;
17   TR_CFG_MGR *cfg_mgr;
18 };
19
20 /********** Ersatz TRPC implementation **********/
21 TRPC_INSTANCE *trpc_create (TALLOC_CTX *mem_ctx)
22 {
23   return talloc_zero(mem_ctx, TRPC_INSTANCE);
24 }
25
26 void trpc_destroy (TRPC_INSTANCE *trpc)
27 {
28   if (trpc)
29     talloc_free(trpc);
30 }
31
32 /* Connect to a TRP server */
33 int trpc_open_connection (TRPC_INSTANCE *trpc, 
34                           char *server,
35                           unsigned int port,
36                           gss_ctx_id_t *gssctx)
37 {
38   int err = 0;
39   int conn = -1;
40   unsigned int use_port = 0;
41
42   if (0 == port)
43     use_port = TRP_PORT;
44   else 
45     use_port = port;
46
47   tr_debug("trpc_open_connection: opening GSS connection to %s:%d", server, use_port);
48   err = gsscon_connect(server, use_port, "trustrouter", &conn, gssctx);
49
50   if (!err)
51     return conn;
52   else
53     return -1;
54 }
55
56
57 /* simple function, based on tidc_send_req */
58 int trpc_send_msg (TRPC_INSTANCE *trpc, 
59                    int conn, 
60                    gss_ctx_id_t gssctx,
61                    const char *msg_content,
62                    int *resp_handler(),
63                    void *cookie)
64 {
65   char *resp_buf=NULL;
66   size_t resp_buflen=0;
67   int err=0;
68   int rc=0;
69
70   /* Send the request over the connection */
71   if (err = gsscon_write_encrypted_token (conn,
72                                           gssctx,
73                                           msg_content, 
74                                           strlen(msg_content))) {
75     tr_err( "trpc_send_msg: Error sending message over connection.\n");
76     goto error;
77   }
78
79   /* Read the response from the connection */
80   if (err = gsscon_read_encrypted_token(conn, gssctx, &resp_buf, &resp_buflen)) {
81     if (resp_buf)
82       free(resp_buf);
83     goto error;
84   }
85
86   tr_debug( "trpc_send_msg: Response Received (%u bytes).\n", (unsigned) resp_buflen);
87   tr_debug( "%s\n", resp_buf);
88
89   if (resp_handler)
90     /* Call the caller's response function */
91     (*resp_handler)(trpc, resp_buf, cookie);
92   goto cleanup;
93
94  error:
95   rc = -1;
96  cleanup:
97   if (resp_buf)
98     free(resp_buf);
99   return rc;
100 }
101
102
103 /********** Ersatz TRPS implementation **********/
104 TRPS_INSTANCE *trps_create (TALLOC_CTX *mem_ctx)
105 {
106   return talloc_zero(mem_ctx, TRPS_INSTANCE);
107 }
108
109 void trps_destroy (TRPS_INSTANCE *trps)
110 {
111   if (trps)
112     talloc_free(trps);
113 }
114
115 static int trps_listen (TRPS_INSTANCE *trps, int port) 
116 {
117     int rc = 0;
118     int conn = -1;
119     int optval = 1;
120
121     union {
122       struct sockaddr_storage storage;
123       struct sockaddr_in in4;
124     } addr;
125
126     struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
127
128     saddr->sin_port = htons (port);
129     saddr->sin_family = AF_INET;
130     saddr->sin_addr.s_addr = INADDR_ANY;
131
132     if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
133       return conn;
134
135     setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
136
137     if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
138       return rc;
139
140     if (0 > (rc = listen(conn, 512)))
141       return rc;
142
143     tr_debug("trps_listen: TRP Server listening on port %d", port);
144     return conn;
145 }
146
147 #if 0
148
149 /* returns EACCES if authorization is denied */
150 static int trps_auth_cb(gss_name_t clientName, gss_buffer_t displayName,
151                         void *data)
152 {
153   TRPS_INSTANCE *inst = (TRPS_INSTANCE *)data;
154   TR_NAME name ={(char *) displayName->value,
155                  displayName->length};
156   int result=0;
157
158   if (0!=inst->auth_handler(clientName, &name, inst->cookie)) {
159     tr_debug("trps_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
160     result=EACCES; /* denied */
161   }
162
163   return result;
164 }
165
166 /* returns 0 on authorization success, 1 on failure, or -1 in case of error */
167 static int trps_auth_connection (TRPS_INSTANCE *inst,
168                                  int conn,
169                                  gss_ctx_id_t *gssctx)
170 {
171   int rc = 0;
172   int auth, autherr = 0;
173   gss_buffer_desc nameBuffer = {0, NULL};
174   char *name = 0;
175   int nameLen = 0;
176
177   nameLen = asprintf(&name, "trustrouter@%s", inst->hostname);
178   nameBuffer.length = nameLen;
179   nameBuffer.value = name;
180   
181   if (rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, trps_auth_cb, inst)) {
182     tr_debug("trps_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
183     return -1;
184   }
185
186   if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) {
187     tr_debug("trps_auth_connection: Error from gsscon_authorize, rc = %d, autherr = %d.", 
188             rc, autherr);
189     return -1;
190   }
191
192   if (auth)
193     tr_debug("trps_auth_connection: Connection authenticated, conn = %d.", conn);
194   else
195     tr_debug("trps_auth_connection: Authentication failed, conn %d.", conn);
196
197   return !auth;
198 }
199 #endif
200
201 static int tr_trps_req_handler (TRPS_INSTANCE *trps,
202                                 TRP_REQ *orig_req, 
203                                 TRP_RESP *resp,
204                                 void *tr_in)
205 {
206   if (orig_req != NULL) 
207     free(orig_req);
208   return -1; /* not handling anything right now */
209 }
210
211 static void trps_handle_connection (TRPS_INSTANCE *trps, int conn)
212 {
213   return;
214 }
215
216 static int tr_trps_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
217                                void *cookie_in)
218 {
219   TR_RP_CLIENT *rp;
220   struct tr_trps_event_cookie *cookie=(struct tr_trps_event_cookie *)cookie_in;
221   TRPS_INSTANCE *trps = cookie->trps;
222   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
223
224   tr_debug("tr_trps_gss_handler()");
225
226   if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) {
227     tr_debug("tr_trps_gss_handler: Bad parameters.");
228     return -1;
229   }
230   
231   /* look up the RP client matching the GSS name */
232   if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)))) {
233     tr_debug("tr_trps_gss_handler: Unknown GSS name %s", gss_name->buf);
234     return -1;
235   }
236
237   trps->rp_gss = rp;
238   tr_debug("Client's GSS Name: %s", gss_name->buf);
239
240   return 0;
241 }
242
243
244 static int trps_get_listener(TRPS_INSTANCE *trps,
245                              TRPS_REQ_FUNC *req_handler,
246                              trps_auth_func *auth_handler,
247                              const char *hostname,
248                              unsigned int port,
249                              void *cookie)
250 {
251   int listen = -1;
252
253   if (0 > (listen = trps_listen(trps, port))) {
254     char errbuf[256];
255     if (0 == strerror_r(errno, errbuf, 256)) {
256       tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf);
257     } else {
258       tr_debug("trps_get_listener: Unknown error openining port %d.", port);
259     }
260   } 
261
262   if (listen > 0) {
263     /* opening port succeeded */
264     tr_debug("trps_get_listener: Opened port %d.", port);
265     
266     /* make this socket non-blocking */
267     if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
268       tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
269       close(listen);
270       listen=-1;
271     }
272   }
273
274   if (listen > 0) {
275     /* store the caller's request handler & cookie */
276     trps->req_handler = req_handler;
277     trps->auth_handler = auth_handler;
278     trps->hostname = talloc_strdup(trps, hostname);
279     trps->port = port;
280     trps->cookie = cookie;
281   }
282
283   return listen;
284 }
285
286
287 /* Accept and process a connection on a port opened with trps_get_listener() */
288 int trps_accept(TRPS_INSTANCE *trps, int listen)
289 {
290   int conn=-1;
291
292   conn = accept(listen, NULL, NULL);
293
294   if (0 > conn) {
295     perror("Error from TRP Server accept()");
296     return 1;
297   }
298
299   /* does not fork, handles request in main process */
300   trps_handle_connection(trps, conn);
301   write(conn, "TRP Online\n", strlen("TRP Online\n"));
302   close(conn);
303   return 0;
304 }
305
306
307 /********** Event Handling **********/
308
309 /* called when a connection to the TRPS port is received */
310 static void tr_trps_event_cb(int listener, short event, void *arg)
311 {
312   TRPS_INSTANCE *trps = (TRPS_INSTANCE *)arg;
313
314   if (0==(event & EV_READ))
315     tr_debug("tr_trps_event_cb: unexpected event on TRPS socket (event=0x%X)", event);
316   else 
317     trps_accept(trps, listener);
318 }
319
320
321 /* Configure the trps instance and set up its event handler.
322  * Returns 0 on success, nonzero on failure. Fills in
323  * *trps_event (which should be allocated by caller). */
324 int tr_trps_event_init(struct event_base *base,
325                        TRPS_INSTANCE *trps,
326                        TR_CFG_MGR *cfg_mgr,
327                        struct tr_socket_event *trps_ev)
328 {
329   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
330   struct tr_trps_event_cookie *cookie;
331   int retval=0;
332
333   if (trps_ev == NULL) {
334     tr_debug("tr_trps_event_init: Null trps_ev.");
335     retval=1;
336     goto cleanup;
337   }
338
339   /* Create the cookie for callbacks. It is part of the trps context, so it will
340    * be cleaned up when trps is freed by talloc_free. */
341   cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
342   if (cookie == NULL) {
343     tr_debug("tr_trps_event_init: Unable to allocate cookie.");
344     retval=1;
345     goto cleanup;
346   }
347   cookie->trps=trps;
348   cookie->cfg_mgr=cfg_mgr;
349   talloc_steal(trps, cookie);
350
351   /* get a trps listener */
352   trps_ev->sock_fd=trps_get_listener(trps,
353                                      tr_trps_req_handler,
354                                      tr_trps_gss_handler,
355                                      cfg_mgr->active->internal->hostname,
356                                      cfg_mgr->active->internal->trps_port,
357                                      (void *)cookie);
358   if (trps_ev->sock_fd < 0) {
359     tr_crit("Error opening TRP server socket.");
360     retval=1;
361     goto cleanup;
362   }
363
364   /* and its event */
365   trps_ev->ev=event_new(base,
366                         trps_ev->sock_fd,
367                         EV_READ|EV_PERSIST,
368                         tr_trps_event_cb,
369                         (void *)trps);
370   event_add(trps_ev->ev, NULL);
371
372 cleanup:
373   talloc_free(tmp_ctx);
374   return retval;
375 }