Add TRP handling events, plus change to cfg layout.
[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
21 /********** Ersatz TRPS implementation **********/
22 TRPS_INSTANCE *trps_create (TALLOC_CTX *mem_ctx)
23 {
24   return talloc_zero(mem_ctx, TRPS_INSTANCE);
25 }
26
27 void trps_destroy (TRPS_INSTANCE *trps)
28 {
29   if (trps)
30     talloc_free(trps);
31 }
32
33 static int trps_listen (TRPS_INSTANCE *trps, int port) 
34 {
35     int rc = 0;
36     int conn = -1;
37     int optval = 1;
38
39     union {
40       struct sockaddr_storage storage;
41       struct sockaddr_in in4;
42     } addr;
43
44     struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
45
46     saddr->sin_port = htons (port);
47     saddr->sin_family = AF_INET;
48     saddr->sin_addr.s_addr = INADDR_ANY;
49
50     if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
51       return conn;
52
53     setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
54
55     if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
56       return rc;
57
58     if (0 > (rc = listen(conn, 512)))
59       return rc;
60
61     tr_debug("trps_listen: TRP Server listening on port %d", port);
62     return conn;
63 }
64
65 #if 0
66
67 /* returns EACCES if authorization is denied */
68 static int trps_auth_cb(gss_name_t clientName, gss_buffer_t displayName,
69                         void *data)
70 {
71   TRPS_INSTANCE *inst = (TRPS_INSTANCE *)data;
72   TR_NAME name ={(char *) displayName->value,
73                  displayName->length};
74   int result=0;
75
76   if (0!=inst->auth_handler(clientName, &name, inst->cookie)) {
77     tr_debug("trps_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
78     result=EACCES; /* denied */
79   }
80
81   return result;
82 }
83
84 /* returns 0 on authorization success, 1 on failure, or -1 in case of error */
85 static int trps_auth_connection (TRPS_INSTANCE *inst,
86                                  int conn,
87                                  gss_ctx_id_t *gssctx)
88 {
89   int rc = 0;
90   int auth, autherr = 0;
91   gss_buffer_desc nameBuffer = {0, NULL};
92   char *name = 0;
93   int nameLen = 0;
94
95   nameLen = asprintf(&name, "trustrouter@%s", inst->hostname);
96   nameBuffer.length = nameLen;
97   nameBuffer.value = name;
98   
99   if (rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, trps_auth_cb, inst)) {
100     tr_debug("trps_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
101     return -1;
102   }
103
104   if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) {
105     tr_debug("trps_auth_connection: Error from gsscon_authorize, rc = %d, autherr = %d.", 
106             rc, autherr);
107     return -1;
108   }
109
110   if (auth)
111     tr_debug("trps_auth_connection: Connection authenticated, conn = %d.", conn);
112   else
113     tr_debug("trps_auth_connection: Authentication failed, conn %d.", conn);
114
115   return !auth;
116 }
117 #endif
118
119 static int tr_trps_req_handler (TRPS_INSTANCE *trps,
120                                 TRP_REQ *orig_req, 
121                                 TRP_RESP *resp,
122                                 void *tr_in)
123 {
124   if (orig_req != NULL) 
125     free(orig_req);
126   return -1; /* not handling anything right now */
127 }
128
129 static void trps_handle_connection (TRPS_INSTANCE *trps, int conn)
130 {
131   return;
132 }
133
134 static int tr_trps_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
135                                void *cookie_in)
136 {
137   TR_RP_CLIENT *rp;
138   struct tr_trps_event_cookie *cookie=(struct tr_trps_event_cookie *)cookie_in;
139   TRPS_INSTANCE *trps = cookie->trps;
140   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
141
142   tr_debug("tr_trps_gss_handler()");
143
144   if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) {
145     tr_debug("tr_trps_gss_handler: Bad parameters.");
146     return -1;
147   }
148   
149   /* look up the RP client matching the GSS name */
150   if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)))) {
151     tr_debug("tr_trps_gss_handler: Unknown GSS name %s", gss_name->buf);
152     return -1;
153   }
154
155   trps->rp_gss = rp;
156   tr_debug("Client's GSS Name: %s", gss_name->buf);
157
158   return 0;
159 }
160
161
162 static int trps_get_listener(TRPS_INSTANCE *trps,
163                              TRPS_REQ_FUNC *req_handler,
164                              trps_auth_func *auth_handler,
165                              const char *hostname,
166                              unsigned int port,
167                              void *cookie)
168 {
169   int listen = -1;
170
171   if (0 > (listen = trps_listen(trps, port))) {
172     char errbuf[256];
173     if (0 == strerror_r(errno, errbuf, 256)) {
174       tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf);
175     } else {
176       tr_debug("trps_get_listener: Unknown error openining port %d.", port);
177     }
178   } 
179
180   if (listen > 0) {
181     /* opening port succeeded */
182     tr_debug("trps_get_listener: Opened port %d.", port);
183     
184     /* make this socket non-blocking */
185     if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
186       tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
187       close(listen);
188       listen=-1;
189     }
190   }
191
192   if (listen > 0) {
193     /* store the caller's request handler & cookie */
194     trps->req_handler = req_handler;
195     trps->auth_handler = auth_handler;
196     trps->hostname = talloc_strdup(trps, hostname);
197     trps->port = port;
198     trps->cookie = cookie;
199   }
200
201   return listen;
202 }
203
204
205 /* Accept and process a connection on a port opened with trps_get_listener() */
206 int trps_accept(TRPS_INSTANCE *trps, int listen)
207 {
208   int conn=-1;
209
210   conn = accept(listen, NULL, NULL);
211
212   if (0 > conn) {
213     perror("Error from TRP Server accept()");
214     return 1;
215   }
216
217   /* does not fork, handles request in main process */
218   trps_handle_connection(trps, conn);
219   write(conn, "TRP Online\n", strlen("TRP Online\n"));
220   close(conn);
221   return 0;
222 }
223
224
225 /********** Event Handling **********/
226
227 /* called when a connection to the TRPS port is received */
228 static void tr_trps_event_cb(int listener, short event, void *arg)
229 {
230   TRPS_INSTANCE *trps = (TRPS_INSTANCE *)arg;
231
232   if (0==(event & EV_READ))
233     tr_debug("tr_trps_event_cb: unexpected event on TRPS socket (event=0x%X)", event);
234   else 
235     trps_accept(trps, listener);
236 }
237
238
239 /* Configure the trps instance and set up its event handler.
240  * Returns 0 on success, nonzero on failure. Fills in
241  * *trps_event (which should be allocated by caller). */
242 int tr_trps_event_init(struct event_base *base,
243                        TRPS_INSTANCE *trps,
244                        TR_CFG_MGR *cfg_mgr,
245                        struct tr_socket_event *trps_ev)
246 {
247   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
248   struct tr_trps_event_cookie *cookie;
249   int retval=0;
250
251   if (trps_ev == NULL) {
252     tr_debug("tr_trps_event_init: Null trps_ev.");
253     retval=1;
254     goto cleanup;
255   }
256
257   /* Create the cookie for callbacks. It is part of the trps context, so it will
258    * be cleaned up when trps is freed by talloc_free. */
259   cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
260   if (cookie == NULL) {
261     tr_debug("tr_trps_event_init: Unable to allocate cookie.");
262     retval=1;
263     goto cleanup;
264   }
265   cookie->trps=trps;
266   cookie->cfg_mgr=cfg_mgr;
267   talloc_steal(trps, cookie);
268
269   /* get a trps listener */
270   trps_ev->sock_fd=trps_get_listener(trps,
271                                      tr_trps_req_handler,
272                                      tr_trps_gss_handler,
273                                      cfg_mgr->active->internal->hostname,
274                                      cfg_mgr->active->internal->trps_port,
275                                      (void *)cookie);
276   if (trps_ev->sock_fd < 0) {
277     tr_crit("Error opening TRP server socket.");
278     retval=1;
279     goto cleanup;
280   }
281
282   /* and its event */
283   trps_ev->ev=event_new(base,
284                         trps_ev->sock_fd,
285                         EV_READ|EV_PERSIST,
286                         tr_trps_event_cb,
287                         (void *)trps);
288   event_add(trps_ev->ev, NULL);
289
290 cleanup:
291   talloc_free(tmp_ctx);
292   return retval;
293 }