]>
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); |
8b4544c9 | 70 | load_provider(&ident_provider); |
05e17ac2 EM |
71 | } |
72 | ||
73 | /* Terminate all providers */ | |
f42aa1a9 | 74 | void destroy_providers(void) |
05e17ac2 | 75 | { |
99e53867 EM |
76 | rb_dlink_node *ptr; |
77 | struct auth_provider *provider; | |
05e17ac2 EM |
78 | |
79 | /* Cancel outstanding connections */ | |
80 | for (size_t i = 0; i < MAX_CLIENTS; i++) | |
81 | { | |
82 | if(auth_clients[i].cid) | |
83 | { | |
84 | /* TBD - is this the right thing? | |
85 | * (NOTE - this error message is designed for morons) */ | |
f42aa1a9 | 86 | reject_client(&auth_clients[i], 0, |
05e17ac2 EM |
87 | "IRC server reloading... try reconnecting in a few seconds"); |
88 | } | |
89 | } | |
90 | ||
99e53867 | 91 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 92 | { |
99e53867 EM |
93 | provider = ptr->data; |
94 | ||
95 | if(provider->destroy) | |
96 | provider->destroy(); | |
05e17ac2 EM |
97 | } |
98 | } | |
99 | ||
100 | /* Cancel outstanding providers for a client */ | |
101 | void cancel_providers(struct auth_client *auth) | |
102 | { | |
99e53867 EM |
103 | rb_dlink_node *ptr; |
104 | struct auth_provider *provider; | |
05e17ac2 | 105 | |
99e53867 | 106 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 107 | { |
99e53867 EM |
108 | provider = ptr->data; |
109 | ||
110 | if(provider->cancel && is_provider(auth, provider->id)) | |
05e17ac2 | 111 | /* Cancel if required */ |
99e53867 | 112 | provider->cancel(auth); |
05e17ac2 EM |
113 | } |
114 | } | |
115 | ||
116 | /* Provider is done */ | |
99e53867 | 117 | void provider_done(struct auth_client *auth, provider_t id) |
05e17ac2 | 118 | { |
99e53867 EM |
119 | rb_dlink_node *ptr; |
120 | struct auth_provider *provider; | |
05e17ac2 | 121 | |
99e53867 | 122 | unset_provider(auth, id); |
05e17ac2 EM |
123 | |
124 | if(!auth->providers) | |
125 | { | |
126 | /* No more providers, done */ | |
f42aa1a9 | 127 | accept_client(auth, 0); |
05e17ac2 EM |
128 | return; |
129 | } | |
130 | ||
99e53867 | 131 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 132 | { |
99e53867 EM |
133 | provider = ptr->data; |
134 | ||
135 | if(provider->completed && is_provider(auth, provider->id)) | |
05e17ac2 | 136 | /* Notify pending clients who asked for it */ |
99e53867 | 137 | provider->completed(auth, id); |
05e17ac2 EM |
138 | } |
139 | } | |
140 | ||
141 | /* Reject a client, cancel outstanding providers if any */ | |
99e53867 | 142 | void reject_client(struct auth_client *auth, provider_t id, const char *reason) |
05e17ac2 EM |
143 | { |
144 | uint16_t cid = auth->cid; | |
df32819e | 145 | char reject; |
05e17ac2 | 146 | |
df32819e EM |
147 | switch(id) |
148 | { | |
149 | case PROVIDER_RDNS: | |
150 | reject = 'D'; | |
151 | break; | |
152 | case PROVIDER_IDENT: | |
153 | reject = 'I'; | |
154 | break; | |
155 | case PROVIDER_BLACKLIST: | |
156 | reject = 'B'; | |
157 | break; | |
158 | case PROVIDER_NULL: | |
159 | default: | |
160 | reject = 'N'; | |
161 | break; | |
162 | } | |
163 | ||
164 | rb_helper_write(authd_helper, "R %x %c :%s", auth->cid, reject, reason); | |
05e17ac2 | 165 | |
99e53867 | 166 | unset_provider(auth, id); |
f42aa1a9 | 167 | |
05e17ac2 EM |
168 | if(auth->providers) |
169 | cancel_providers(auth); | |
170 | ||
171 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
172 | } | |
173 | ||
174 | /* Accept a client, cancel outstanding providers if any */ | |
99e53867 | 175 | void accept_client(struct auth_client *auth, provider_t id) |
05e17ac2 EM |
176 | { |
177 | uint16_t cid = auth->cid; | |
178 | ||
179 | rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname); | |
180 | ||
99e53867 | 181 | unset_provider(auth, id); |
f42aa1a9 | 182 | |
05e17ac2 EM |
183 | if(auth->providers) |
184 | cancel_providers(auth); | |
185 | ||
186 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
187 | } | |
188 | ||
189 | /* Send a notice to a client */ | |
190 | void notice_client(struct auth_client *auth, const char *notice) | |
191 | { | |
192 | rb_helper_write(authd_helper, "N %x :%s", auth->cid, notice); | |
193 | } | |
194 | ||
195 | /* Begin authenticating user */ | |
b74739c2 | 196 | static void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port) |
05e17ac2 | 197 | { |
99e53867 EM |
198 | rb_dlink_node *ptr; |
199 | struct auth_provider *provider; | |
05e17ac2 EM |
200 | struct auth_client *auth; |
201 | long lcid = strtol(cid, NULL, 16); | |
202 | ||
203 | if(lcid >= MAX_CLIENTS) | |
204 | return; | |
205 | ||
206 | auth = &auth_clients[lcid]; | |
207 | if(auth->cid != 0) | |
208 | /* Shouldn't get here */ | |
209 | return; | |
210 | ||
211 | auth->cid = (uint16_t)lcid; | |
212 | ||
b74739c2 EM |
213 | (void)rb_inet_pton_sock(l_ip, (struct sockaddr *)&auth->l_addr); |
214 | #ifdef RB_IPV6 | |
215 | if(GET_SS_FAMILY(&auth->l_addr) == AF_INET6) | |
216 | ((struct sockaddr_in6 *)&auth->l_addr)->sin6_port = htons(atoi(l_ip)); | |
217 | else | |
218 | #endif | |
219 | ((struct sockaddr_in *)&auth->l_addr)->sin_port = htons(atoi(l_ip)); | |
220 | ||
221 | (void)rb_inet_pton_sock(c_ip, (struct sockaddr *)&auth->c_addr); | |
222 | #ifdef RB_IPV6 | |
223 | if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6) | |
224 | ((struct sockaddr_in6 *)&auth->c_addr)->sin6_port = htons(atoi(c_ip)); | |
225 | else | |
226 | #endif | |
227 | ((struct sockaddr_in *)&auth->c_addr)->sin_port = htons(atoi(c_ip)); | |
05e17ac2 | 228 | |
05e17ac2 | 229 | |
99e53867 | 230 | RB_DLINK_FOREACH(ptr, auth_providers.head) |
05e17ac2 | 231 | { |
99e53867 EM |
232 | provider = ptr->data; |
233 | ||
05e17ac2 | 234 | /* Execute providers */ |
99e53867 | 235 | if(!provider->start(auth)) |
05e17ac2 EM |
236 | { |
237 | /* Rejected immediately */ | |
238 | cancel_providers(auth); | |
239 | return; | |
240 | } | |
241 | } | |
242 | ||
243 | /* If no providers are running, accept the client */ | |
244 | if(!auth->providers) | |
f42aa1a9 | 245 | accept_client(auth, 0); |
05e17ac2 EM |
246 | } |
247 | ||
248 | /* Callback for the initiation */ | |
249 | void handle_new_connection(int parc, char *parv[]) | |
250 | { | |
f169fc88 | 251 | if(parc < 7) |
05e17ac2 EM |
252 | return; |
253 | ||
5bfc606f | 254 | start_auth(parv[1], parv[2], parv[3], parv[4], parv[5]); |
05e17ac2 | 255 | } |