]> jfr.im git - solanum.git/blame - authd/auth.c
auth: minor changes
[solanum.git] / authd / auth.c
CommitLineData
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 */
58static struct auth_provider auth_providers[] =
59{
60 NULL_PROVIDER,
05e17ac2
EM
61};
62
63/* Clients waiting */
64struct auth_client auth_clients[MAX_CLIENTS];
65
66/* Initalise all providers */
67void 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 80void 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 */
104void 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 */
117void 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 139void 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 154void 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 */
169void 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 */
175void 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 */
214void 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}