Add TRP handling events, plus change to cfg layout.
[trust_router.git] / tr / tr_tid.c
1 #include <tid_internal.h>
2 #include <tr_filter.h>
3 #include <tr_comm.h>
4 #include <tr_idp.h>
5 #include <tr_rp.h>
6 #include <tr_event.h>
7 #include <tr_debug.h>
8 #include <gsscon.h>
9 #include <tr_config.h>
10 #include <tr_tid.h>
11
12 /* Structure to hold TR instance and original request in one cookie */
13 typedef struct tr_resp_cookie {
14   TIDS_INSTANCE *tids;
15   TID_REQ *orig_req;
16 } TR_RESP_COOKIE;
17
18 /* hold a tids instance and a config manager */
19 struct tr_tids_event_cookie {
20   TIDS_INSTANCE *tids;
21   TR_CFG_MGR *cfg_mgr;
22 };
23
24
25 static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc, 
26                                   TID_REQ *req,
27                                   TID_RESP *resp, 
28                                   void *resp_cookie)
29 {
30   tr_debug("tr_tidc_resp_handler: Response received (conn = %d)! Realm = %s, Community = %s.", ((TR_RESP_COOKIE *)resp_cookie)->orig_req->conn, resp->realm->buf, resp->comm->buf);
31   req->resp_rcvd = 1;
32
33   /* TBD -- handle concatentation of multiple responses to single req */
34   tids_send_response(((TR_RESP_COOKIE *)resp_cookie)->tids, 
35                      ((TR_RESP_COOKIE *)resp_cookie)->orig_req, 
36                      resp);
37   
38   return;
39 }
40
41 static int tr_tids_req_handler (TIDS_INSTANCE *tids,
42                                 TID_REQ *orig_req, 
43                                 TID_RESP *resp,
44                                 void *cookie_in)
45 {
46   TIDC_INSTANCE *tidc = NULL;
47   TR_RESP_COOKIE resp_cookie;
48   TR_AAA_SERVER *aaa_servers = NULL;
49   TR_NAME *apc = NULL;
50   TID_REQ *fwd_req = NULL;
51   TR_COMM *cfg_comm = NULL;
52   TR_COMM *cfg_apc = NULL;
53   int oaction = TR_FILTER_ACTION_REJECT;
54   int rc = 0;
55   time_t expiration_interval;
56   struct tr_tids_event_cookie *cookie=(struct tr_tids_event_cookie *)cookie_in;
57   TR_CFG_MGR *cfg_mgr=cookie->cfg_mgr;
58
59   if ((!tids) || (!orig_req) || (!resp)) {
60     tr_debug("tr_tids_req_handler: Bad parameters");
61     return -1;
62   }
63
64   tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn, 
65            orig_req->realm->buf, orig_req->comm->buf);
66   tids->req_count++;
67
68   /* Duplicate the request, so we can modify and forward it */
69   if (NULL == (fwd_req = tid_dup_req(orig_req))) {
70     tr_debug("tr_tids_req_handler: Unable to duplicate request.");
71     return -1;
72   }
73
74   if (NULL == (cfg_comm = tr_comm_lookup(cfg_mgr->active->comms, orig_req->comm))) {
75     tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf);
76     tids_send_err_response(tids, orig_req, "Unknown community");
77     return -1;
78   }
79
80   /* Check that the rp_realm matches the filter for the GSS name that 
81    * was received. */
82
83   if ((!tids->rp_gss) || 
84       (!tids->rp_gss->filter)) {
85     tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
86     tids_send_err_response(tids, orig_req, "No GSS name for request");
87     return -1;
88   }
89
90   if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm,
91                                                             tids->rp_gss->filter,
92                                                             orig_req->cons,
93                                                            &fwd_req->cons,
94                                                            &oaction)) ||
95       (TR_FILTER_ACTION_REJECT == oaction)) {
96     tr_notice("tr_tids_req_handler: RP realm (%s) does not match RP Realm filter for GSS name", orig_req->rp_realm->buf);
97     tids_send_err_response(tids, orig_req, "RP Realm filter error");
98     return -1;
99   }
100   /* Check that the rp_realm is a member of the community in the request */
101   if (NULL == (tr_find_comm_rp(cfg_comm, orig_req->rp_realm))) {
102     tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
103     tids_send_err_response(tids, orig_req, "RP COI membership error");
104     return -1;
105   }
106
107   /* Map the comm in the request from a COI to an APC, if needed */
108   if (TR_COMM_COI == cfg_comm->type) {
109     tr_debug("tr_tids_req_handler: Community was a COI, switching.");
110     /* TBD -- In theory there can be more than one?  How would that work? */
111     if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) {
112       tr_notice("No valid APC for COI %s.", orig_req->comm->buf);
113       tids_send_err_response(tids, orig_req, "No valid APC for community");
114       return -1;
115     }
116     apc = tr_dup_name(cfg_comm->apcs->id);
117
118     /* Check that the APC is configured */
119     if (NULL == (cfg_apc = tr_comm_lookup(cfg_mgr->active->comms, apc))) {
120       tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf);
121       tids_send_err_response(tids, orig_req, "Unknown APC");
122       return -1;
123     }
124
125     fwd_req->comm = apc;
126     fwd_req->orig_coi = orig_req->comm;
127
128     /* Check that rp_realm is a  member of this APC */
129     if (NULL == (tr_find_comm_rp(cfg_apc, orig_req->rp_realm))) {
130       tr_notice("tr_tids_req_hander: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
131       tids_send_err_response(tids, orig_req, "RP APC membership error");
132       return -1;
133     }
134   }
135
136   /* Find the AAA server(s) for this request */
137   if (NULL == (aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->idp_realms, 
138                                                       orig_req->realm, 
139                                                       orig_req->comm))) {
140     tr_debug("tr_tids_req_handler: No AAA Servers for realm %s, defaulting.", orig_req->realm->buf);
141     if (NULL == (aaa_servers = tr_default_server_lookup (cfg_mgr->active->default_servers,
142                                                          orig_req->comm))) {
143       tr_notice("tr_tids_req_handler: No default AAA servers, discarded.");
144       tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm");
145       return -1;
146     }
147   } else {
148     /* if we aren't defaulting, check idp coi and apc membership */
149     if (NULL == (tr_find_comm_idp(cfg_comm, fwd_req->realm))) {
150       tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, orig_req->comm->buf);
151       tids_send_err_response(tids, orig_req, "IDP community membership error");
152       return -1;
153     }
154     if ( cfg_apc && (NULL == (tr_find_comm_idp(cfg_apc, fwd_req->realm)))) {
155       tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, orig_req->comm->buf);
156       tids_send_err_response(tids, orig_req, "IDP APC membership error");
157       return -1;
158     }
159   }
160
161   /* send a TID request to the AAA server(s), and get the answer(s) */
162   /* TBD -- Handle multiple servers */
163
164   if (cfg_apc)
165     expiration_interval = cfg_apc->expiration_interval;
166   else expiration_interval = cfg_comm->expiration_interval;
167   if (fwd_req->expiration_interval)
168     fwd_req->expiration_interval =  (expiration_interval < fwd_req->expiration_interval) ? expiration_interval : fwd_req->expiration_interval;
169   else fwd_req->expiration_interval = expiration_interval;
170   /* Create a TID client instance */
171   if (NULL == (tidc = tidc_create())) {
172     tr_crit("tr_tids_req_hander: Unable to allocate TIDC instance.");
173     tids_send_err_response(tids, orig_req, "Memory allocation failure");
174     return -1;
175   }
176   /* Use the DH parameters from the original request */
177   /* TBD -- this needs to be fixed when we handle more than one req per conn */
178   tidc->client_dh = orig_req->tidc_dh;
179
180   /* Save information about this request for the response */
181   resp_cookie.tids = tids;
182   resp_cookie.orig_req = orig_req;
183
184   /* Set-up TID connection */
185   if (-1 == (fwd_req->conn = tidc_open_connection(tidc, 
186                                                   aaa_servers->hostname->buf,
187                                                   TID_PORT,
188                                                  &(fwd_req->gssctx)))) {
189     tr_notice("tr_tids_req_handler: Error in tidc_open_connection.");
190     tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS");
191     return -1;
192   };
193
194   /* Send a TID request */
195   if (0 > (rc = tidc_fwd_request(tidc, fwd_req, &tr_tidc_resp_handler, (void *)&resp_cookie))) {
196     tr_notice("Error from tidc_fwd_request, rc = %d.", rc);
197     tids_send_err_response(tids, orig_req, "Can't forward request to next hop TIDS");
198     tid_req_free(orig_req);
199     return -1;
200   }
201     
202   tid_req_free(orig_req);
203   return 0;
204 }
205
206 static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
207                                void *data)
208 {
209   TR_RP_CLIENT *rp;
210   struct tr_tids_event_cookie *cookie=(struct tr_tids_event_cookie *)data;
211   TIDS_INSTANCE *tids = cookie->tids;
212   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
213
214   if ((!client_name) || (!gss_name) || (!tids) || (!cfg_mgr)) {
215     tr_debug("tr_tidc_gss_handler: Bad parameters.");
216     return -1;
217   }
218
219   /* look up the RP client matching the GSS name */
220   if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)))) {
221     tr_debug("tr_tids_gss_handler: Unknown GSS name %s", gss_name->buf);
222     return -1;
223   }
224
225   /* Store the rp client */
226   tids->rp_gss = rp;
227   tr_debug("Client's GSS Name: %s", gss_name->buf);
228
229   return 0;
230 }
231
232
233 /***** TIDS event handling *****/
234
235 /* called when a connection to the TIDS port is received */
236 static void tr_tids_event_cb(int listener, short event, void *arg)
237 {
238   TIDS_INSTANCE *tids = (TIDS_INSTANCE *)arg;
239
240   if (0==(event & EV_READ))
241     tr_debug("tr_tids_event_cb: unexpected event on TIDS socket (event=0x%X)", event);
242   else 
243     tids_accept(tids, listener);
244 }
245
246 /* Configure the tids instance and set up its event handler.
247  * Returns 0 on success, nonzero on failure. Fills in
248  * *tids_event (which should be allocated by caller). */
249 int tr_tids_event_init(struct event_base *base,
250                        TIDS_INSTANCE *tids,
251                        TR_CFG_MGR *cfg_mgr,
252                        struct tr_socket_event *tids_ev)
253 {
254   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
255   struct tr_tids_event_cookie *cookie=NULL;
256   int retval=0;
257
258   if (tids_ev == NULL) {
259     tr_debug("tr_tids_event_init: Null tids_ev.");
260     retval=1;
261     goto cleanup;
262   }
263
264   /* Create the cookie for callbacks. We'll put it in the tids context, so it will
265    * be cleaned up when tids is freed by talloc_free. */
266   cookie=talloc(tmp_ctx, struct tr_tids_event_cookie);
267   if (cookie == NULL) {
268     tr_debug("tr_tids_event_init: Unable to allocate cookie.");
269     retval=1;
270     goto cleanup;
271   }
272   cookie->tids=tids;
273   cookie->cfg_mgr=cfg_mgr;
274   talloc_steal(tids, cookie);
275
276   /* get a tids listener */
277   tids_ev->sock_fd=tids_get_listener(tids,
278                                      tr_tids_req_handler,
279                                      tr_tids_gss_handler,
280                                      cfg_mgr->active->internal->hostname,
281                                      cfg_mgr->active->internal->tids_port,
282                                      (void *)cookie);
283   if (tids_ev->sock_fd < 0) {
284     tr_crit("Error opening TID server socket.");
285     retval=1;
286     goto cleanup;
287   }
288
289   /* and its event */
290   tids_ev->ev=event_new(base,
291                         tids_ev->sock_fd,
292                         EV_READ|EV_PERSIST,
293                         tr_tids_event_cb,
294                         (void *)tids);
295   event_add(tids_ev->ev, NULL);
296
297 cleanup:
298   talloc_free(tmp_ctx);
299   return retval;
300 }