Authenticate GSS context in separate thread. (Not fully working yet.)
[trust_router.git] / tr / tr_trp.c
1 #include <pthread.h>
2 #include <fcntl.h>
3 #include <event2/event.h>
4 #include <talloc.h>
5 #include <errno.h>
6 #include <unistd.h>
7
8 #include <gsscon.h>
9 #include <tr_rp.h>
10 #include <trp_internal.h>
11 #include <tr_config.h>
12 #include <tr_event.h>
13 #include <tr_debug.h>
14 #include <tr_trp.h>
15
16 /* hold a trps instance and a config manager */
17 struct tr_trps_event_cookie {
18   TRPS_INSTANCE *trps;
19   TR_CFG_MGR *cfg_mgr;
20 };
21
22
23 static int tr_trps_req_handler (TRPS_INSTANCE *trps,
24                                 TRP_REQ *orig_req, 
25                                 void *tr_in)
26 {
27   if (orig_req != NULL) 
28     free(orig_req);
29   return -1; /* not handling anything right now */
30 }
31
32
33 static int tr_trps_gss_handler(gss_name_t client_name, gss_buffer_t gss_name,
34                                void *cookie_in)
35 {
36   TR_RP_CLIENT *rp;
37   struct tr_trps_event_cookie *cookie=(struct tr_trps_event_cookie *)cookie_in;
38   TRPS_INSTANCE *trps = cookie->trps;
39   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
40   TR_NAME name={gss_name->value, gss_name->length};
41
42   tr_debug("tr_trps_gss_handler()");
43
44   if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) {
45     tr_debug("tr_trps_gss_handler: Bad parameters.");
46     return -1;
47   }
48   
49   /* look up the RP client matching the GSS name */
50   if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, &name)))) {
51     tr_debug("tr_trps_gss_handler: Unknown GSS name %.*s", name.len, name.buf);
52     return -1;
53   }
54
55   /*trps->rp_gss = rp;*/
56   tr_debug("Client's GSS Name: %.*s", name.len, name.buf);
57
58   return 0;
59 }
60
61
62 /* data passed to thread */
63 struct thread_data {
64   TRP_CONNECTION *conn;
65   TRPS_INSTANCE *trps;
66 };
67 /* thread to handle GSS connections to peers */
68 static void *tr_trps_conn_thread(void *arg)
69 {
70   struct thread_data *thread_data=talloc_get_type_abort(arg, struct thread_data);
71   TRP_CONNECTION *conn=thread_data->conn;
72   TRPS_INSTANCE *trps=thread_data->trps;
73
74   tr_debug("tr_trps_conn_thread: started");
75   /* try to establish a GSS context */
76   if (0!=trp_connection_auth(conn, trps->auth_handler, trps->cookie)) {
77     tr_notice("tr_trps_conn_thread: failed to authorize connection");
78     pthread_exit(NULL);
79   }
80   tr_notice("tr_trps_conn_thread: authorized connection");
81   return NULL;
82 }
83
84 /* called when a connection to the TRPS port is received */
85 static void tr_trps_event_cb(int listener, short event, void *arg)
86 {
87   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
88   TRPS_INSTANCE *trps = talloc_get_type_abort(arg, TRPS_INSTANCE); /* aborts on wrong type */
89   TRP_CONNECTION *conn=NULL;
90   TR_NAME *gssname=NULL;
91   char *name=NULL;
92   struct thread_data *thread_data;
93
94   if (0==(event & EV_READ)) {
95     tr_debug("tr_trps_event_cb: unexpected event on TRPS socket (event=0x%X)", event);
96   } else {
97     /* create a thread to handle this connection */
98     asprintf(&name, "trustrouter@%s", trps->hostname);
99     gssname=tr_new_name(name);
100     free(name); name=NULL;
101     conn=trp_connection_accept(tmp_ctx, listener, gssname, trps_auth_cb, NULL, trps);
102     if (conn!=NULL) {
103       /* need to monitor this fd and trigger events when read becomes possible */
104       thread_data=talloc(conn, struct thread_data);
105       if (thread_data==NULL) {
106         tr_err("tr_trps_event_cb: unable to allocate thread_data");
107         talloc_free(tmp_ctx);
108         return;
109       }
110       thread_data->conn=conn;
111       thread_data->trps=trps;
112       pthread_create(conn->thread, NULL, tr_trps_conn_thread, thread_data);
113       trps_add_connection(trps, conn); /* remember the connection */
114     }
115   }
116   talloc_free(tmp_ctx);
117 }
118
119
120 /* Configure the trps instance and set up its event handler.
121  * Returns 0 on success, nonzero on failure. Fills in
122  * *trps_event (which should be allocated by caller). */
123 int tr_trps_event_init(struct event_base *base,
124                        TRPS_INSTANCE *trps,
125                        TR_CFG_MGR *cfg_mgr,
126                        struct tr_socket_event *trps_ev)
127 {
128   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
129   struct tr_trps_event_cookie *cookie;
130   int retval=0;
131
132   if (trps_ev == NULL) {
133     tr_debug("tr_trps_event_init: Null trps_ev.");
134     retval=1;
135     goto cleanup;
136   }
137
138   /* Create the cookie for callbacks. It is part of the trps context, so it will
139    * be cleaned up when trps is freed by talloc_free. */
140   cookie=talloc(tmp_ctx, struct tr_trps_event_cookie);
141   if (cookie == NULL) {
142     tr_debug("tr_trps_event_init: Unable to allocate cookie.");
143     retval=1;
144     goto cleanup;
145   }
146   cookie->trps=trps;
147   cookie->cfg_mgr=cfg_mgr;
148   talloc_steal(trps, cookie);
149
150   /* get a trps listener */
151   trps_ev->sock_fd=trps_get_listener(trps,
152                                      tr_trps_req_handler,
153                                      tr_trps_gss_handler,
154                                      cfg_mgr->active->internal->hostname,
155                                      cfg_mgr->active->internal->trps_port,
156                                      (void *)cookie);
157   if (trps_ev->sock_fd < 0) {
158     tr_crit("Error opening TRP server socket.");
159     retval=1;
160     goto cleanup;
161   }
162
163   /* and its event */
164   trps_ev->ev=event_new(base,
165                         trps_ev->sock_fd,
166                         EV_READ|EV_PERSIST,
167                         tr_trps_event_cb,
168                         (void *)trps);
169   event_add(trps_ev->ev, NULL);
170
171 cleanup:
172   talloc_free(tmp_ctx);
173   return retval;
174 }
175