Authenticate GSS context in separate thread. (Not fully working yet.)
[trust_router.git] / trp / trps.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_event.h>
10 #include <tr_debug.h>
11 #include <trp_internal.h>
12
13
14 TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx)
15 {
16   TRPS_INSTANCE *trps=talloc(mem_ctx, TRPS_INSTANCE);
17   if (trps!=NULL)  {
18     trps->hostname=NULL;
19     trps->port=0;
20     trps->cookie=NULL;
21     trps->conn=NULL;
22     trps->mq=tr_mq_new(trps);
23     if (trps->mq==NULL) {
24       /* failed to allocate mq */
25       talloc_free(trps);
26       trps=NULL;
27     }
28   }
29   return trps;
30 }
31
32 void trps_free (TRPS_INSTANCE *trps)
33 {
34   if (trps!=NULL)
35     talloc_free(trps);
36 }
37
38 /* stand-in for a function that finds the connection for a particular peer */
39 #if 0
40 static TRP_CONNECTION *trps_find_connection(TRPS_INSTANCE *trps)
41 {
42   return trps->conn;
43 }
44 #endif
45
46 void trps_add_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *new)
47 {
48   if (trps->conn==NULL)
49     trps->conn=new;
50   else
51     trp_connection_append(trps->conn, new);
52
53   talloc_steal(trps, new);
54 }
55
56 int trps_send_msg (TRPS_INSTANCE *trps,
57                    int conn,
58                    gss_ctx_id_t gssctx,
59                    const char *msg_content)
60 {
61   int err=0;
62   int rc=0;
63
64   /* Send the request over the connection */
65   if (err = gsscon_write_encrypted_token (conn,
66                                           gssctx,
67                                           msg_content, 
68                                           strlen(msg_content))) {
69     tr_err( "trps_send_msg: Error sending message over connection.\n");
70     rc = -1;
71   }
72
73   return rc;
74 }
75
76 static int trps_listen (TRPS_INSTANCE *trps, int port) 
77 {
78     int rc = 0;
79     int conn = -1;
80     int optval = 1;
81
82     union {
83       struct sockaddr_storage storage;
84       struct sockaddr_in in4;
85     } addr;
86
87     struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
88
89     saddr->sin_port = htons (port);
90     saddr->sin_family = AF_INET;
91     saddr->sin_addr.s_addr = INADDR_ANY;
92
93     if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
94       return conn;
95
96     setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
97
98     if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
99       return rc;
100
101     if (0 > (rc = listen(conn, 512)))
102       return rc;
103
104     tr_debug("trps_listen: TRP Server listening on port %d", port);
105     return conn;
106 }
107
108 /* returns EACCES if authorization is denied */
109 int trps_auth_cb(gss_name_t clientName, gss_buffer_t displayName, void *data)
110 {
111   TRPS_INSTANCE *inst = (TRPS_INSTANCE *)data;
112   int result=0;
113
114   if (0!=inst->auth_handler(clientName, displayName, inst->cookie)) {
115     tr_debug("trps_auth_cb: client '%.*s' denied authorization.", displayName->length, displayName->value);
116     result=EACCES; /* denied */
117   }
118
119   return result;
120 }
121
122 #if 0
123 static int trps_read_message (TRPS_INSTANCE *trps, int conn, gss_ctx_id_t *gssctx, char **msg)
124 {
125   int err;
126   char *buf;
127   size_t buflen = 0;
128
129   if (err = gsscon_read_encrypted_token(conn, *gssctx, &buf, &buflen)) {
130     if (buf)
131       free(buf);
132     return -1;
133   }
134
135   tr_debug("trps_read_request(): Request Received, %u bytes.", (unsigned) buflen);
136   tr_debug("trps_read_request(): %.*s", buflen, buf);
137
138   *msg=talloc_strndup(NULL, buf, buflen); /* no context owns this! */
139   free(buf);
140   return buflen;
141 }
142 #endif
143
144 int trps_get_listener(TRPS_INSTANCE *trps,
145                       TRP_REQ_FUNC req_handler,
146                       TRP_AUTH_FUNC auth_handler,
147                       const char *hostname,
148                       unsigned int port,
149                       void *cookie)
150 {
151   int listen = -1;
152
153   if (0 > (listen = trps_listen(trps, port))) {
154     char errbuf[256];
155     if (0 == strerror_r(errno, errbuf, 256)) {
156       tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf);
157     } else {
158       tr_debug("trps_get_listener: Unknown error openining port %d.", port);
159     }
160   } 
161
162   if (listen > 0) {
163     /* opening port succeeded */
164     tr_debug("trps_get_listener: Opened port %d.", port);
165     
166     /* make this socket non-blocking */
167     if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
168       tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
169       close(listen);
170       listen=-1;
171     }
172   }
173
174   if (listen > 0) {
175     /* store the caller's request handler & cookie */
176     trps->req_handler = req_handler;
177     trps->auth_handler = auth_handler;
178     trps->hostname = talloc_strdup(trps, hostname);
179     trps->port = port;
180     trps->cookie = cookie;
181   }
182
183   return listen;
184 }
185
186 /* old cruft */
187 #if 0
188 static gss_ctx_id_t trps_establish_gss_context (TRPS_INSTANCE *trps, int conn)
189 {
190   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
191   gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT;
192   char *msg_rec=NULL;
193   int msg_len = 0;
194   int rc=0;
195
196   if (trps_auth_connection(trps, conn, &gssctx))
197     tr_notice("trps_establish_gss_context: Error authorizing TID Server connection.");
198   else:
199     tr_notice("trps_establish_gss_context: Connection authorized!");
200   return gssctx;
201
202   msg_len = trps_read_message(trps, conn, &gssctx, &msg_rec);
203   talloc_steal(tmp_ctx, msg_rec); /* get this in our context */
204   if (0 > msg_len) {
205     tr_debug("trps_handle_connection: Error from trps_read_message()");
206     goto cleanup;
207   }
208   
209   tr_debug("trps_handle_connection: msg_len=%d", msg_len);
210   reply=talloc_asprintf(tmp_ctx, "TRPS heard: %.*s", msg_len, msg_rec);
211   if (0 > (rc = trps_send_msg(trps, conn, gssctx, reply))) {
212     tr_debug("trps_handle_connection: Error from trps_send_message(), rc = %d.", rc);
213   }
214
215 cleanup:
216   talloc_free(tmp_ctx);
217   return conn;
218 }
219 #endif