]>
Commit | Line | Data |
---|---|---|
05e17ac2 EM |
1 | /* authd/auth.c - authentication provider framework |
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" | |
46 | #include "auth.h" | |
47 | ||
05e17ac2 EM |
48 | #define NULL_PROVIDER { \ |
49 | .provider = PROVIDER_NULL, \ | |
50 | .init = NULL, \ | |
51 | .destroy = NULL, \ | |
52 | .start = NULL, \ | |
53 | .cancel = NULL, \ | |
54 | .completed = NULL, \ | |
55 | } | |
56 | ||
05e17ac2 EM |
57 | /* Providers */ |
58 | static struct auth_provider auth_providers[] = | |
59 | { | |
60 | NULL_PROVIDER, | |
05e17ac2 EM |
61 | }; |
62 | ||
63 | /* Clients waiting */ | |
64 | struct auth_client auth_clients[MAX_CLIENTS]; | |
65 | ||
66 | /* Initalise all providers */ | |
67 | void init_providers(void) | |
68 | { | |
69 | struct auth_provider *pptr; | |
70 | ||
71 | AUTH_PROVIDER_FOREACH(pptr) | |
72 | { | |
73 | if(pptr->init && !pptr->init()) | |
74 | /* Provider failed to init, time to go */ | |
75 | exit(1); | |
76 | } | |
77 | } | |
78 | ||
79 | /* Terminate all providers */ | |
f42aa1a9 | 80 | void destroy_providers(void) |
05e17ac2 EM |
81 | { |
82 | struct auth_provider *pptr; | |
83 | ||
84 | /* Cancel outstanding connections */ | |
85 | for (size_t i = 0; i < MAX_CLIENTS; i++) | |
86 | { | |
87 | if(auth_clients[i].cid) | |
88 | { | |
89 | /* TBD - is this the right thing? | |
90 | * (NOTE - this error message is designed for morons) */ | |
f42aa1a9 | 91 | reject_client(&auth_clients[i], 0, |
05e17ac2 EM |
92 | "IRC server reloading... try reconnecting in a few seconds"); |
93 | } | |
94 | } | |
95 | ||
96 | AUTH_PROVIDER_FOREACH(pptr) | |
97 | { | |
98 | if(pptr->destroy) | |
99 | pptr->destroy(); | |
100 | } | |
101 | } | |
102 | ||
103 | /* Cancel outstanding providers for a client */ | |
104 | void cancel_providers(struct auth_client *auth) | |
105 | { | |
106 | struct auth_provider *pptr; | |
107 | ||
108 | AUTH_PROVIDER_FOREACH(pptr) | |
109 | { | |
110 | if(pptr->cancel && is_provider(auth, pptr->provider)) | |
111 | /* Cancel if required */ | |
112 | pptr->cancel(auth); | |
113 | } | |
114 | } | |
115 | ||
116 | /* Provider is done */ | |
117 | void provider_done(struct auth_client *auth, provider_t provider) | |
118 | { | |
119 | struct auth_provider *pptr; | |
120 | ||
121 | unset_provider(auth, provider); | |
122 | ||
123 | if(!auth->providers) | |
124 | { | |
125 | /* No more providers, done */ | |
f42aa1a9 | 126 | accept_client(auth, 0); |
05e17ac2 EM |
127 | return; |
128 | } | |
129 | ||
130 | AUTH_PROVIDER_FOREACH(pptr) | |
131 | { | |
132 | if(pptr->completed && is_provider(auth, pptr->provider)) | |
133 | /* Notify pending clients who asked for it */ | |
134 | pptr->completed(auth, provider); | |
135 | } | |
136 | } | |
137 | ||
138 | /* Reject a client, cancel outstanding providers if any */ | |
f42aa1a9 | 139 | void reject_client(struct auth_client *auth, provider_t provider, const char *reason) |
05e17ac2 EM |
140 | { |
141 | uint16_t cid = auth->cid; | |
142 | ||
143 | rb_helper_write(authd_helper, "R %x :%s", auth->cid, reason); | |
144 | ||
f42aa1a9 EM |
145 | unset_provider(auth, provider); |
146 | ||
05e17ac2 EM |
147 | if(auth->providers) |
148 | cancel_providers(auth); | |
149 | ||
150 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
151 | } | |
152 | ||
153 | /* Accept a client, cancel outstanding providers if any */ | |
f42aa1a9 | 154 | void accept_client(struct auth_client *auth, provider_t provider) |
05e17ac2 EM |
155 | { |
156 | uint16_t cid = auth->cid; | |
157 | ||
158 | rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname); | |
159 | ||
f42aa1a9 EM |
160 | unset_provider(auth, provider); |
161 | ||
05e17ac2 EM |
162 | if(auth->providers) |
163 | cancel_providers(auth); | |
164 | ||
165 | memset(&auth_clients[cid], 0, sizeof(struct auth_client)); | |
166 | } | |
167 | ||
168 | /* Send a notice to a client */ | |
169 | void notice_client(struct auth_client *auth, const char *notice) | |
170 | { | |
171 | rb_helper_write(authd_helper, "N %x :%s", auth->cid, notice); | |
172 | } | |
173 | ||
174 | /* Begin authenticating user */ | |
175 | void start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port) | |
176 | { | |
177 | struct auth_provider *pptr; | |
178 | struct auth_client *auth; | |
179 | long lcid = strtol(cid, NULL, 16); | |
180 | ||
181 | if(lcid >= MAX_CLIENTS) | |
182 | return; | |
183 | ||
184 | auth = &auth_clients[lcid]; | |
185 | if(auth->cid != 0) | |
186 | /* Shouldn't get here */ | |
187 | return; | |
188 | ||
189 | auth->cid = (uint16_t)lcid; | |
190 | ||
191 | rb_strlcpy(auth->l_ip, l_ip, sizeof(auth->l_ip)); | |
192 | auth->l_port = (uint16_t)atoi(l_port); /* Safe cast, port shouldn't exceed 16 bits */ | |
193 | ||
194 | rb_strlcpy(auth->c_ip, c_ip, sizeof(auth->c_ip)); | |
195 | auth->c_port = (uint16_t)atoi(c_port); | |
196 | ||
197 | AUTH_PROVIDER_FOREACH(pptr) | |
198 | { | |
199 | /* Execute providers */ | |
200 | if(!pptr->start(auth)) | |
201 | { | |
202 | /* Rejected immediately */ | |
203 | cancel_providers(auth); | |
204 | return; | |
205 | } | |
206 | } | |
207 | ||
208 | /* If no providers are running, accept the client */ | |
209 | if(!auth->providers) | |
f42aa1a9 | 210 | accept_client(auth, 0); |
05e17ac2 EM |
211 | } |
212 | ||
213 | /* Callback for the initiation */ | |
214 | void handle_new_connection(int parc, char *parv[]) | |
215 | { | |
216 | if(parc < 5) | |
217 | return; | |
218 | ||
219 | start_auth(parv[1], parv[2], parv[3], parv[4], parv[5]); | |
220 | } |