]>
Commit | Line | Data |
---|---|---|
0f95a274 | 1 | /* authd/provider.c - authentication provider framework |
05e17ac2 EM |
2 | * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me> |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice is present in all copies. | |
7 | * | |
8 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
9 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
10 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
11 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
12 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
13 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
14 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
15 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
16 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
17 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
18 | * POSSIBILITY OF SUCH DAMAGE. | |
19 | */ | |
20 | ||
21 | /* So the basic design here is to have "authentication providers" that do | |
22 | * things like query ident and blacklists and even open proxies. | |
23 | * | |
24 | * Providers are registered statically in the struct auth_providers array. You will | |
25 | * probably want to add an item to the provider_t enum also. | |
26 | * | |
27 | * Providers can either return failure immediately, immediate acceptance, or | |
28 | * do work in the background (calling set_provider to signal this). | |
29 | * | |
30 | * It is up to providers to keep their own state on clients if they need to. | |
31 | * | |
32 | * All providers must implement at a minimum a perform_provider function. You | |
33 | * don't have to implement the others if you don't need them. | |
34 | * | |
35 | * Providers may kick clients off by rejecting them. Upon rejection, all | |
36 | * providers are cancelled. They can also unconditionally accept them. | |
37 | * | |
f42aa1a9 EM |
38 | * When a provider is done and is neutral on accepting/rejecting a client, it |
39 | * should call provider_done. Do NOT call this if you have accepted or rejected | |
40 | * the client. | |
05e17ac2 EM |
41 | * |
42 | * --Elizafox, 9 March 2016 | |
43 | */ | |
44 | ||
45 | #include "authd.h" | |
0f95a274 | 46 | #include "provider.h" |
05e17ac2 | 47 | |
99e53867 | 48 | rb_dlink_list auth_providers; |
05e17ac2 EM |
49 | |
50 | /* Clients waiting */ | |
51 | struct auth_client auth_clients[MAX_CLIENTS]; | |
52 | ||
99e53867 EM |
53 | /* Load a provider */ |
54 | void load_provider(struct auth_provider *provider) | |
55 | { | |
56 | provider->init(); | |
57 | rb_dlinkAdd(provider, &provider->node, &auth_providers); | |
58 | } | |
59 | ||
60 | void unload_provider(struct auth_provider *provider) | |
61 | { | |
62 | provider->destroy(); | |
63 | rb_dlinkDelete(&provider->node, &auth_providers); | |
64 | } | |
65 | ||
05e17ac2 EM |
66 | /* Initalise all providers */ |
67 | void init_providers(void) | |
68 | { | |
18764319 | 69 | load_provider(&rdns_provider); |
05e17ac2 EM |
70 | } |
71 | ||
72 | /* Terminate all providers */ | |
f42aa1a9 | 73 | void destroy_providers(void) |
05e17ac2 | 74 | { |
99e53867 EM |
75 | rb_dlink_node *ptr; |
76 | struct auth_provider *provider; | |
05e17ac2 EM |
77 | |
78 | /* Cancel outstanding connections */ | |
79 | for (size_t i = 0; i < MAX_CLIENTS; i++) | |
80 | { | |
81 | if(auth_clients[i].cid) | |
82 | { | |
83 | /* TBD - is this the right thing? | |
84 | * (NOTE - this error message is designed for morons) */ | |
f42aa1a9 | 85 | reject_client(&auth_clients[i], 0, |
05e17ac2 EM |
86 | "IRC server reloading... try reconnecting in a few seconds"); |
87 | } | |
88 | } | |
89 | ||
99e53867 | 90 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 91 | { |
99e53867 EM |
92 | provider = ptr->data; |
93 | ||
94 | if(provider->destroy) | |
95 | provider->destroy(); | |
05e17ac2 EM |
96 | } |
97 | } | |
98 | ||
99 | /* Cancel outstanding providers for a client */ | |
100 | void cancel_providers(struct auth_client *auth) | |
101 | { | |
99e53867 EM |
102 | rb_dlink_node *ptr; |
103 | struct auth_provider *provider; | |
05e17ac2 | 104 | |
99e53867 | 105 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 106 | { |
99e53867 EM |
107 | provider = ptr->data; |
108 | ||
109 | if(provider->cancel && is_provider(auth, provider->id)) | |
05e17ac2 | 110 | /* Cancel if required */ |
99e53867 | 111 | provider->cancel(auth); |
05e17ac2 EM |
112 | } |
113 | } | |
114 | ||
115 | /* Provider is done */ | |
99e53867 | 116 | void provider_done(struct auth_client *auth, provider_t id) |
05e17ac2 | 117 | { |
99e53867 EM |
118 | rb_dlink_node *ptr; |
119 | struct auth_provider *provider; | |
05e17ac2 | 120 | |
99e53867 | 121 | unset_provider(auth, id); |
05e17ac2 EM |
122 | |
123 | if(!auth->providers) | |
124 | { | |
125 | /* No more providers, done */ | |
f42aa1a9 | 126 | accept_client(auth, 0); |
05e17ac2 EM |
127 | return; |
128 | } | |
129 | ||
99e53867 | 130 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 131 | { |
99e53867 EM |
132 | provider = ptr->data; |
133 | ||
134 | if(provider->completed && is_provider(auth, provider->id)) | |
05e17ac2 | 135 | /* Notify pending clients who asked for it */ |
99e53867 | 136 | provider->completed(auth, id); |
05e17ac2 EM |
137 | } |
138 | } | |
139 | ||
140 | /* Reject a client, cancel outstanding providers if any */ | |
99e53867 | 141 | void reject_client(struct auth_client *auth, provider_t id, const char *reason) |
05e17ac2 EM |
142 | { |
143 | uint16_t cid = auth->cid; | |
144 | ||
145 | rb_helper_write(authd_helper, "R %x :%s", auth->cid, reason); | |
146 | ||
99e53867 | 147 | unset_provider(auth, id); |
f42aa1a9 | 148 | |
05e17ac2 EM |
149 | if(auth->providers) |
150 | cancel_providers(auth); | |
151 | ||
152 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
153 | } | |
154 | ||
155 | /* Accept a client, cancel outstanding providers if any */ | |
99e53867 | 156 | void accept_client(struct auth_client *auth, provider_t id) |
05e17ac2 EM |
157 | { |
158 | uint16_t cid = auth->cid; | |
159 | ||
160 | rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname); | |
161 | ||
99e53867 | 162 | unset_provider(auth, id); |
f42aa1a9 | 163 | |
05e17ac2 EM |
164 | if(auth->providers) |
165 | cancel_providers(auth); | |
166 | ||
167 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
168 | } | |
169 | ||
170 | /* Send a notice to a client */ | |
171 | void notice_client(struct auth_client *auth, const char *notice) | |
172 | { | |
173 | rb_helper_write(authd_helper, "N %x :%s", auth->cid, notice); | |
174 | } | |
175 | ||
176 | /* Begin authenticating user */ | |
b74739c2 | 177 | static void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port) |
05e17ac2 | 178 | { |
99e53867 EM |
179 | rb_dlink_node *ptr; |
180 | struct auth_provider *provider; | |
05e17ac2 EM |
181 | struct auth_client *auth; |
182 | long lcid = strtol(cid, NULL, 16); | |
183 | ||
184 | if(lcid >= MAX_CLIENTS) | |
185 | return; | |
186 | ||
187 | auth = &auth_clients[lcid]; | |
188 | if(auth->cid != 0) | |
189 | /* Shouldn't get here */ | |
190 | return; | |
191 | ||
192 | auth->cid = (uint16_t)lcid; | |
193 | ||
b74739c2 EM |
194 | (void)rb_inet_pton_sock(l_ip, (struct sockaddr *)&auth->l_addr); |
195 | #ifdef RB_IPV6 | |
196 | if(GET_SS_FAMILY(&auth->l_addr) == AF_INET6) | |
197 | ((struct sockaddr_in6 *)&auth->l_addr)->sin6_port = htons(atoi(l_ip)); | |
198 | else | |
199 | #endif | |
200 | ((struct sockaddr_in *)&auth->l_addr)->sin_port = htons(atoi(l_ip)); | |
201 | ||
202 | (void)rb_inet_pton_sock(c_ip, (struct sockaddr *)&auth->c_addr); | |
203 | #ifdef RB_IPV6 | |
204 | if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6) | |
205 | ((struct sockaddr_in6 *)&auth->c_addr)->sin6_port = htons(atoi(c_ip)); | |
206 | else | |
207 | #endif | |
208 | ((struct sockaddr_in *)&auth->c_addr)->sin_port = htons(atoi(c_ip)); | |
05e17ac2 | 209 | |
05e17ac2 | 210 | |
99e53867 | 211 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 212 | { |
99e53867 EM |
213 | provider = ptr->data; |
214 | ||
05e17ac2 | 215 | /* Execute providers */ |
99e53867 | 216 | if(!provider->start(auth)) |
05e17ac2 EM |
217 | { |
218 | /* Rejected immediately */ | |
219 | cancel_providers(auth); | |
220 | return; | |
221 | } | |
222 | } | |
223 | ||
224 | /* If no providers are running, accept the client */ | |
225 | if(!auth->providers) | |
f42aa1a9 | 226 | accept_client(auth, 0); |
05e17ac2 EM |
227 | } |
228 | ||
229 | /* Callback for the initiation */ | |
230 | void handle_new_connection(int parc, char *parv[]) | |
231 | { | |
f169fc88 | 232 | if(parc < 7) |
05e17ac2 EM |
233 | return; |
234 | ||
5bfc606f | 235 | start_auth(parv[1], parv[2], parv[3], parv[4], parv[5]); |
05e17ac2 | 236 | } |