Authenticate GSS context in separate thread. (Not fully working yet.)
[trust_router.git] / trp / trp_conn.c
1 #include <gsscon.h>
2 #include <fcntl.h>
3 #include <talloc.h>
4 #include <unistd.h>
5
6 #include <tr_debug.h>
7 #include <trp_internal.h>
8
9 int trp_connection_get_fd(TRP_CONNECTION *conn)
10 {
11   return conn->fd;
12 }
13
14 void trp_connection_set_fd(TRP_CONNECTION *conn, int fd)
15 {
16   conn->fd=fd;
17 }
18
19 TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn)
20 {
21   return conn->gssname;
22 }
23
24 void trp_connection_set_gssname(TRP_CONNECTION *conn, TR_NAME *gssname)
25 {
26   conn->gssname=gssname;
27 }
28
29 gss_ctx_id_t *trp_connection_get_gssctx(TRP_CONNECTION *conn)
30 {
31   return conn->gssctx;
32 }
33
34 void trp_connection_set_gssctx(TRP_CONNECTION *conn, gss_ctx_id_t *gssctx)
35 {
36   conn->gssctx=gssctx;
37 }
38
39 TRP_CONNECTION_STATUS trp_connection_get_status(TRP_CONNECTION *conn)
40 {
41   TRP_CONNECTION_STATUS status;
42   pthread_mutex_lock(&(conn->status_mutex));
43   status=conn->status;
44   pthread_mutex_unlock(&(conn->status_mutex));
45   return status;
46 }
47
48 void trp_connection_set_status(TRP_CONNECTION *conn, TRP_CONNECTION_STATUS status)
49 {
50   pthread_mutex_lock(&(conn->status_mutex));
51   conn->status=status;
52   pthread_mutex_unlock(&(conn->status_mutex));
53 }
54
55 pthread_t *trp_connection_get_thread(TRP_CONNECTION *conn)
56 {
57   return conn->thread;
58 }
59
60 void trp_connection_set_thread(TRP_CONNECTION *conn, pthread_t *thread)
61 {
62   conn->thread=thread;
63 }
64
65 TRP_CONNECTION *trp_connection_get_next(TRP_CONNECTION *conn)
66 {
67   return conn->next;
68 }
69
70 static void trp_connection_set_next(TRP_CONNECTION *conn, TRP_CONNECTION *next)
71 {
72   conn->next=next;
73 }
74
75 static TRP_CONNECTION *trp_connection_get_tail(TRP_CONNECTION *conn)
76 {
77   while((conn!=NULL)&&(trp_connection_get_next(conn)!=NULL))
78     conn=trp_connection_get_next(conn);
79   return conn;
80 }
81
82 void trp_connection_append(TRP_CONNECTION *conn, TRP_CONNECTION *new)
83 {
84   trp_connection_set_next(trp_connection_get_tail(conn), new);
85 }
86
87 static void trp_connection_mutex_init(TRP_CONNECTION *conn)
88 {
89   pthread_mutex_init(&(conn->status_mutex), NULL);
90 }
91
92 /* talloc destructor for a connection: ensures connection is closed, memory freed */
93 static int trp_connection_destructor(void *object)
94 {
95   TRP_CONNECTION *conn=talloc_get_type_abort(object, TRP_CONNECTION); /* aborts on wrong type */
96   if ((trp_connection_get_status(conn)!=TRP_CONNECTION_DOWN)
97      && (trp_connection_get_fd(conn)!=-1))
98     close(trp_connection_get_fd(conn));
99   if (conn->gssname!=NULL)
100     tr_free_name(conn->gssname);
101   return 0;
102 }
103
104 TRP_CONNECTION *trp_connection_new(TALLOC_CTX *mem_ctx)
105 {
106   TRP_CONNECTION *new_conn=talloc(mem_ctx, TRP_CONNECTION);
107   gss_ctx_id_t *gssctx=NULL;
108   pthread_t *thread=NULL;
109   
110
111   if (new_conn != NULL) {
112     trp_connection_set_next(new_conn, NULL);
113     trp_connection_set_fd(new_conn, -1);
114     trp_connection_set_gssctx(new_conn, NULL);
115     trp_connection_mutex_init(new_conn);
116     trp_connection_set_status(new_conn, TRP_CONNECTION_DOWN);
117     thread=talloc(new_conn, pthread_t);
118     if (thread==NULL) {
119       talloc_free(new_conn);
120       return NULL;
121     }
122     trp_connection_set_thread(new_conn, thread);
123     gssctx=talloc(new_conn, gss_ctx_id_t);
124     if (gssctx==NULL) {
125       talloc_free(new_conn);
126       return NULL;
127     }
128     trp_connection_set_gssctx(new_conn, gssctx);
129     talloc_set_destructor((void *)new_conn, trp_connection_destructor);
130   }
131   return new_conn;
132 }
133
134 void trp_connection_free(TRP_CONNECTION *conn)
135 {
136   /* TODO: shut down connection if it is still open */
137   talloc_free(conn);
138 }
139
140
141 /* returns 0 on authorization success, 1 on failure, or -1 in case of error */
142 int trp_connection_auth(TRP_CONNECTION *conn, TRP_AUTH_FUNC auth_callback, void *callback_data)
143 {
144   int rc = 0;
145   int auth, autherr = 0;
146   gss_buffer_desc nameBuffer = {0, NULL};
147   gss_ctx_id_t gssctx;
148
149   /* TODO: shouldn't really peek into TR_NAME... */
150   nameBuffer.length = trp_connection_get_gssname(conn)->len;
151   nameBuffer.value = trp_connection_get_gssname(conn)->buf;
152
153   tr_debug("trp_connection_auth: beginning passive authentication");
154   if (rc = gsscon_passive_authenticate(trp_connection_get_fd(conn), nameBuffer, &gssctx, auth_callback, callback_data)) {
155     tr_debug("trp_connection_auth: Error from gsscon_passive_authenticate(), rc = 0x%08X.", rc);
156     return -1;
157   }
158
159   tr_debug("trp_connection_auth: beginning second stage authentication");
160   if (rc = gsscon_authorize(gssctx, &auth, &autherr)) {
161     tr_debug("trp_connection_auth: Error from gsscon_authorize, rc = %d, autherr = %d.", 
162              rc, autherr);
163     return -1;
164   }
165
166   if (auth)
167     tr_debug("trp_connection_auth: Connection authenticated, fd = %d.", trp_connection_get_fd(conn));
168   else
169     tr_debug("trp_connection_auth: Authentication failed, fd = %d.", trp_connection_get_fd(conn));
170
171   return !auth;
172 }
173
174 /* Accept connection */
175 TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME *gssname, TRP_AUTH_FUNC auth_handler, TRP_REQ_FUNC req_handler,
176                                       void *cookie)
177 {
178   int conn_fd=-1;
179   TRP_CONNECTION *conn=NULL;
180
181   conn_fd = accept(listen, NULL, NULL);
182
183   if (0 > conn_fd) {
184     tr_notice("trp_connection_accept: accept() returned error.");
185     return NULL;
186   }
187   conn=trp_connection_new(mem_ctx);
188   trp_connection_set_fd(conn, conn_fd);
189   trp_connection_set_gssname(conn, gssname);
190   return conn;
191 }
192