2 * Written by David Herrmann.
3 * Dedicated to the Public Domain.
12 #include <sys/types.h>
13 #include <sys/socket.h>
18 /* File which is spawned on a query. */
19 char *iauth_scriptfile = NULL;
21 const struct iauth_result *iauth_query(struct iauth_client *cli) {
22 static struct iauth_result res;
23 static char buffer[IAUTH_DATALEN * 5 + 5];
25 signed int fds[2], ret;
27 char portbuf[6], portbuf2[6];
31 memset(&res, 0, sizeof(res));
32 memset(portbuf, 0, 6);
33 memset(portbuf2, 0, 6);
34 if(!iauth_scriptfile) return &res;
35 if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
36 iauth_flog(IAUTH_WARNING, "socketpair() failed; errno = '%d'.", errno);
44 iauth_flog(IAUTH_WARNING, "fork() failed; errno = '%d'.", errno);
50 * Close the parents socket. Spawn the DB process with the socket
52 * When done, close the socket and exit the child.
53 * We directly fork() again to prevent zombies.
57 if(cpid < 0) exit(EXIT_FAILURE);
58 if(cpid != 0) exit(EXIT_SUCCESS);
61 parv = iauth_malloc(sizeof(char*) * ISIZE);
62 parv[0] = iauth_scriptfile;
63 parv[1] = cli->ip?cli->ip:&c;
64 snprintf(portbuf, 5, "%hu", cli->port);
66 parv[3] = cli->lo_ip?cli->lo_ip:&c;
67 snprintf(portbuf2, 5, "%hu", cli->lo_port);
69 parv[5] = cli->host?cli->host:&c;
70 parv[6] = cli->c_host?cli->c_host:&c;
71 parv[7] = cli->c_serv?cli->c_serv:&c;
72 parv[8] = cli->nick?cli->nick:&c;
73 parv[9] = cli->username?cli->username:&c;
74 parv[10] = cli->realname?cli->realname:&c;
75 parv[11] = cli->account?cli->account:&c;
76 parv[12] = cli->fakehost?cli->fakehost:&c;
77 parv[13] = cli->cclass?cli->cclass:&c;
78 parv[14] = cli->password?cli->password:&c;
79 parv[15] = cli->ident?cli->ident:&c;
80 parv[16] = iauth_servname;
81 parv[ISIZE - 1] = NULL;
84 if(dup2(fds[1], 1) != -1) {
85 execvp(iauth_scriptfile, parv);
86 iauth_flog(IAUTH_WARNING, "execvp() failed; errno = '%d'.", errno);
88 else iauth_flog(IAUTH_WARNING, "dup2() failed; errno = '%d'.", errno);
94 /* We are the parent. Read on the file descriptor until it is closed. */
97 /* Wait for client. The client directly forked again, so this should
99 * This whole mechanism prevents zombies.
104 if((ret = read(fds[0], buffer, sizeof(buffer))) < 1) {
108 buffer[sizeof(buffer) - 1] = 0;
111 if(!(arg = strchr(tread, ' '))) {
116 if(strcmp(tread, "error") == 0) {
117 strcpy(res.cclass, "error");
119 if(!(arg = strchr(tread, '%'))) {
125 strcpy(res.str, tread);
128 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.cclass[0] = 0;
129 else strcpy(res.cclass, tread);
133 if(!(arg = strchr(tread, ' '))) {
138 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ident[0] = 0;
139 else strcpy(res.ident, tread);
143 if(!(arg = strchr(tread, ' '))) {
148 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.host[0] = 0;
149 else strcpy(res.host, tread);
153 if(!(arg = strchr(tread, ' '))) {
158 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ip[0] = 0;
159 else strcpy(res.ip, tread);
161 /* Read modes string. */
163 if(!(arg = strchr(tread, '%'))) {
168 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.modes[0] = 0;
169 else strcpy(res.modes, tread);
176 * Adds or removes a user.
178 struct iauth_client *iauth_clients = NULL;
179 unsigned int iauth_clients_size = 0;
181 void iauth_setcap(unsigned int cap) {
182 if(iauth_clients_size) return;
183 iauth_clients = iauth_malloc(sizeof(struct iauth_client) * cap);
184 iauth_clients_size = cap;
187 void iauth_addid(signed int id) {
189 if(!iauth_clients_size || id >= iauth_clients_size) return;
190 memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
191 iauth_clients[id].state_r = 1;
192 iauth_clients[id].id = id;
195 void iauth_delid(signed int id) {
197 if(!iauth_clients_size || id >= iauth_clients_size) return;
198 iauth_free(iauth_clients[id].ip);
199 iauth_free(iauth_clients[id].lo_ip);
200 iauth_free(iauth_clients[id].host);
201 iauth_free(iauth_clients[id].c_host);
202 iauth_free(iauth_clients[id].c_serv);
203 iauth_free(iauth_clients[id].nick);
204 iauth_free(iauth_clients[id].username);
205 iauth_free(iauth_clients[id].realname);
206 iauth_free(iauth_clients[id].account);
207 iauth_free(iauth_clients[id].fakehost);
208 iauth_free(iauth_clients[id].cclass);
209 iauth_free(iauth_clients[id].password);
210 iauth_free(iauth_clients[id].ident);
211 memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
214 static unsigned int loc_allow = 0;
215 static unsigned int loc_deny = 0;
216 static unsigned int def_allow = 0;
217 static unsigned int def_deny = 0;
219 void iauth_stats_report() {
220 static unsigned int stats = 0;
221 static char buffer[512];
226 iauth_query_newconf();
227 iauth_query_config("*", "loc", "Login-On-Connect handler");
228 iauth_query_config("*", "def", "Default handler");
230 if(stats < 10) goto report;
231 else if((stats % 10) == 0) goto report;
235 iauth_query_newstats();
236 sprintf(buffer, "Count: %u Allowed: %u Denied: %u", loc_allow + loc_deny, loc_allow, loc_deny);
237 iauth_query_stats("loc", buffer);
238 sprintf(buffer, "Count: %u Allowed: %u Denied: %u", def_allow + def_deny, def_allow, def_deny);
239 iauth_query_stats("def", buffer);
242 void iauth_stats_loc_allow() {
244 iauth_stats_report();
247 void iauth_stats_loc_deny() {
249 iauth_stats_report();
252 void iauth_stats_def_allow() {
254 iauth_stats_report();
257 void iauth_stats_def_deny() {
259 iauth_stats_report();
262 /* Sends a specific request to the ircd.
263 * This is a less generic but easier to use interface
264 * for the iauth_[vf]send() commands. This interface also
265 * correctly sends statistics.
268 /* Operator Notification: > :<message text> */
269 extern void iauth_query_fnotify(const char *format, ...) {
272 va_start(arg, format);
273 iauth_query_vnotify(format, arg);
276 extern void iauth_query_vnotify(const char *format, va_list list) {
277 char buffer[IAUTH_LINE + 1];
279 buffer[IAUTH_LINE] = 0;
280 sprintf(buffer, "> :");
281 vsnprintf(buffer, IAUTH_LINE - 4, format, list);
285 /* Set Debug Level: G <level> */
286 extern void iauth_query_debug(unsigned int debuglevel) {
287 iauth_fsend("G %u", debuglevel);
290 /* Set Policy Options: O <options> */
291 extern void iauth_query_policy(const char *policy) {
292 iauth_fsend("O %s", policy);
295 /* iauth Program Version: V :<version string> */
296 extern void iauth_query_version(const char *version) {
297 iauth_fsend("V :%s", version);
300 /* Start of new configuration: a */
301 extern void iauth_query_newconf() {
305 /* Configuration Information: A <hosts?> <module> :<options> */
306 extern void iauth_query_config(const char *hosts, const char *module, const char *value) {
307 iauth_fsend("A %s %s :%s", hosts, module, value);
310 /* Start of new statistics: s */
311 extern void iauth_query_newstats() {
315 /* Statistics Information: S <module> :<module information> */
316 extern void iauth_query_stats(const char *module, const char *value) {
317 iauth_fsend("S %s :%s", module, value);
320 /* Forced Username: o <id> <remoteip> <remoteport> <username> */
321 extern void iauth_query_set_username(signed int id, const char *username) {
322 if(id < 0 || id >= iauth_clients_size) return;
323 iauth_fsend("o %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
326 /* Trusted Username: U <id> <remoteip> <remoteport> <username> */
327 extern void iauth_query_trust_username(signed int id, const char *username) {
328 if(id < 0 || id >= iauth_clients_size) return;
329 iauth_fsend("U %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
332 /* Untrusted Username: u <id> <remoteip> <remoteport> <username> */
333 extern void iauth_query_distrust_username(signed int id, const char *username) {
334 if(id < 0 || id >= iauth_clients_size) return;
335 iauth_fsend("u %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
338 /* Client Hostname: N <id> <remoteip> <remoteport> <hostname> */
339 extern void iauth_query_sethost(signed int id, const char *hostname) {
340 if(id < 0 || id >= iauth_clients_size) return;
341 iauth_fsend("N %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, hostname);
344 /* Client IP Address: I <id> <currentip> <remoteport> <newip> */
345 extern void iauth_query_setip(signed int id, const char *ip) {
346 if(id < 0 || id >= iauth_clients_size) return;
347 iauth_fsend("I %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, ip);
348 iauth_free(iauth_clients[id].ip);
349 iauth_clients[id].ip = iauth_strdup(ip);
352 /* Adjust User Mode: M <id> <remoteip> <remoteport> +<mode changes> */
353 extern void iauth_query_setmodes(signed int id, const char *modes) {
354 if(id < 0 || id >= iauth_clients_size) return;
355 iauth_fsend("M %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, modes);
358 /* Challenge User: C <id> <remoteip> <remoteport> :<challenge string> */
359 extern void iauth_query_challenge(signed int id, const char *challenge) {
360 if(id < 0 || id >= iauth_clients_size) return;
361 iauth_fsend("C %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, challenge);
364 /* Quietly Kill Client: k <id> <remoteip> <remoteport> :<reason> */
365 extern void iauth_query_reject(signed int id, const char *reason) {
366 if(id < 0 || id >= iauth_clients_size) return;
367 iauth_fsend("k %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
371 /* Kill Client: K <id> <remoteip> <remoteport> :<reason> */
372 extern void iauth_query_kill(signed int id, const char *reason) {
373 if(id < 0 || id >= iauth_clients_size) return;
374 iauth_fsend("K %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
378 /* Done Checking: D <id> <remoteip> <remoteport> [class] */
379 extern void iauth_query_assign(signed int id, const char *cclass) {
380 if(id < 0 || id >= iauth_clients_size) return;
382 iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, cclass);
384 iauth_fsend("D %d %s %hu", id, iauth_clients[id].ip, iauth_clients[id].port);
388 /* Registered User: R <id> <remoteip> <remoteport> <account> [class] */
389 extern void iauth_query_register(signed int id, const char *account, const char *cclass) {
390 if(id < 0 || id >= iauth_clients_size) return;
392 iauth_fsend("D %d %s %hu %s %s", id, iauth_clients[id].ip, iauth_clients[id].port, account, cclass);
394 iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, account);