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, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.cclass[0] = 0;
117 else strcpy(res.cclass, tread);
121 if(!(arg = strchr(tread, ' '))) {
126 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ident[0] = 0;
127 else strcpy(res.ident, tread);
131 if(!(arg = strchr(tread, ' '))) {
136 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.host[0] = 0;
137 else strcpy(res.host, tread);
141 if(!(arg = strchr(tread, ' '))) {
146 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ip[0] = 0;
147 else strcpy(res.ip, tread);
149 /* Read modes string. */
155 if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.modes[0] = 0;
156 else strcpy(res.modes, tread);
163 * Adds or removes a user.
165 struct iauth_client *iauth_clients = NULL;
166 unsigned int iauth_clients_size = 0;
168 void iauth_setcap(unsigned int cap) {
169 if(iauth_clients_size) return;
170 iauth_clients = iauth_malloc(sizeof(struct iauth_client) * cap);
171 iauth_clients_size = cap;
174 void iauth_addid(signed int id) {
176 if(!iauth_clients_size || id >= iauth_clients_size) return;
177 memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
178 iauth_clients[id].state_r = 1;
179 iauth_clients[id].id = id;
182 void iauth_delid(signed int id) {
184 if(!iauth_clients_size || id >= iauth_clients_size) return;
185 iauth_free(iauth_clients[id].ip);
186 iauth_free(iauth_clients[id].lo_ip);
187 iauth_free(iauth_clients[id].host);
188 iauth_free(iauth_clients[id].c_host);
189 iauth_free(iauth_clients[id].c_serv);
190 iauth_free(iauth_clients[id].nick);
191 iauth_free(iauth_clients[id].username);
192 iauth_free(iauth_clients[id].realname);
193 iauth_free(iauth_clients[id].account);
194 iauth_free(iauth_clients[id].fakehost);
195 iauth_free(iauth_clients[id].cclass);
196 iauth_free(iauth_clients[id].password);
197 iauth_free(iauth_clients[id].ident);
198 memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
201 static unsigned int loc_allow = 0;
202 static unsigned int loc_deny = 0;
203 static unsigned int def_allow = 0;
204 static unsigned int def_deny = 0;
206 void iauth_stats_report() {
207 static unsigned int stats = 0;
208 static char buffer[512];
213 iauth_query_newconf();
214 iauth_query_config("*", "loc", "Login-On-Connect handler");
215 iauth_query_config("*", "def", "Default handler");
217 if(stats < 10) goto report;
218 else if((stats % 10) == 0) goto report;
222 iauth_query_newstats();
223 sprintf(buffer, "Count: %u Allowed: %u Denied: %u", loc_allow + loc_deny, loc_allow, loc_deny);
224 iauth_query_stats("loc", buffer);
225 sprintf(buffer, "Count: %u Allowed: %u Denied: %u", def_allow + def_deny, def_allow, def_deny);
226 iauth_query_stats("def", buffer);
229 void iauth_stats_loc_allow() {
231 iauth_stats_report();
234 void iauth_stats_loc_deny() {
236 iauth_stats_report();
239 void iauth_stats_def_allow() {
241 iauth_stats_report();
244 void iauth_stats_def_deny() {
246 iauth_stats_report();
249 /* Sends a specific request to the ircd.
250 * This is a less generic but easier to use interface
251 * for the iauth_[vf]send() commands. This interface also
252 * correctly sends statistics.
255 /* Operator Notification: > :<message text> */
256 extern void iauth_query_fnotify(const char *format, ...) {
259 va_start(arg, format);
260 iauth_query_vnotify(format, arg);
263 extern void iauth_query_vnotify(const char *format, va_list list) {
264 char buffer[IAUTH_LINE + 1];
266 buffer[IAUTH_LINE] = 0;
267 sprintf(buffer, "> :");
268 vsnprintf(buffer, IAUTH_LINE - 4, format, list);
272 /* Set Debug Level: G <level> */
273 extern void iauth_query_debug(unsigned int debuglevel) {
274 iauth_fsend("G %u", debuglevel);
277 /* Set Policy Options: O <options> */
278 extern void iauth_query_policy(const char *policy) {
279 iauth_fsend("O %s", policy);
282 /* iauth Program Version: V :<version string> */
283 extern void iauth_query_version(const char *version) {
284 iauth_fsend("V :%s", version);
287 /* Start of new configuration: a */
288 extern void iauth_query_newconf() {
292 /* Configuration Information: A <hosts?> <module> :<options> */
293 extern void iauth_query_config(const char *hosts, const char *module, const char *value) {
294 iauth_fsend("A %s %s :%s", hosts, module, value);
297 /* Start of new statistics: s */
298 extern void iauth_query_newstats() {
302 /* Statistics Information: S <module> :<module information> */
303 extern void iauth_query_stats(const char *module, const char *value) {
304 iauth_fsend("S %s :%s", module, value);
307 /* Forced Username: o <id> <remoteip> <remoteport> <username> */
308 extern void iauth_query_set_username(signed int id, const char *username) {
309 if(id < 0 || id >= iauth_clients_size) return;
310 iauth_fsend("o %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
313 /* Trusted Username: U <id> <remoteip> <remoteport> <username> */
314 extern void iauth_query_trust_username(signed int id, const char *username) {
315 if(id < 0 || id >= iauth_clients_size) return;
316 iauth_fsend("U %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
319 /* Untrusted Username: u <id> <remoteip> <remoteport> <username> */
320 extern void iauth_query_distrust_username(signed int id, const char *username) {
321 if(id < 0 || id >= iauth_clients_size) return;
322 iauth_fsend("u %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
325 /* Client Hostname: N <id> <remoteip> <remoteport> <hostname> */
326 extern void iauth_query_sethost(signed int id, const char *hostname) {
327 if(id < 0 || id >= iauth_clients_size) return;
328 iauth_fsend("N %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, hostname);
331 /* Client IP Address: I <id> <currentip> <remoteport> <newip> */
332 extern void iauth_query_setip(signed int id, const char *ip) {
333 if(id < 0 || id >= iauth_clients_size) return;
334 iauth_fsend("I %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, ip);
335 iauth_free(iauth_clients[id].ip);
336 iauth_clients[id].ip = iauth_strdup(ip);
339 /* Adjust User Mode: M <id> <remoteip> <remoteport> +<mode changes> */
340 extern void iauth_query_setmodes(signed int id, const char *modes) {
341 if(id < 0 || id >= iauth_clients_size) return;
342 iauth_fsend("M %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, modes);
345 /* Challenge User: C <id> <remoteip> <remoteport> :<challenge string> */
346 extern void iauth_query_challenge(signed int id, const char *challenge) {
347 if(id < 0 || id >= iauth_clients_size) return;
348 iauth_fsend("C %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, challenge);
351 /* Quietly Kill Client: k <id> <remoteip> <remoteport> :<reason> */
352 extern void iauth_query_reject(signed int id, const char *reason) {
353 if(id < 0 || id >= iauth_clients_size) return;
354 iauth_fsend("k %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
358 /* Kill Client: K <id> <remoteip> <remoteport> :<reason> */
359 extern void iauth_query_kill(signed int id, const char *reason) {
360 if(id < 0 || id >= iauth_clients_size) return;
361 iauth_fsend("K %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
365 /* Done Checking: D <id> <remoteip> <remoteport> [class] */
366 extern void iauth_query_assign(signed int id, const char *cclass) {
367 if(id < 0 || id >= iauth_clients_size) return;
369 iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, cclass);
371 iauth_fsend("D %d %s %hu", id, iauth_clients[id].ip, iauth_clients[id].port);
375 /* Registered User: R <id> <remoteip> <remoteport> <account> [class] */
376 extern void iauth_query_register(signed int id, const char *account, const char *cclass) {
377 if(id < 0 || id >= iauth_clients_size) return;
379 iauth_fsend("D %d %s %hu %s %s", id, iauth_clients[id].ip, iauth_clients[id].port, account, cclass);
381 iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, account);