1 /* mod-hostserv.c - HostServ module for srvx
2 * Copyright 2012-2013 pk910, Stricted, NurPech
4 * This file is part of srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 /* Adds new section to srvx.conf:
26 "toplevel_access" "600";
30 * After you started srvx make the bot active:
31 /msg opserv bind hostserv * hostserv.*
32 /msg opserv bind hostserv help *modcmd.help
43 #define KEY_TOPLEVEL "TopLevel"
44 #define KEY_SECONDLEVEL "SecondLevel"
45 #define KEY_MANAGERS "Manager"
46 #define KEY_ASSIGNMENTS "Assignments"
47 #define KEY_ACTIVE "active"
49 static const struct message_entry msgtab[] = {
50 { "HSMSG_ACCESS_DENIED", "Access denied." },
51 { "HSMSG_ASSIGNED_FAKEHOSTS", "Assigned Fakehosts for User $b%s$b:" },
52 { "HSMSG_ASSIGNED_FAKEHOST", " $b%s.%s$b" },
53 { "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE", " $b%s.%s$b (active)" },
54 { "HSMSG_ASSIGNED_FAKEHOST_NOT_ACTIVE", "Fakehost $b%s.%s.$b is not active." },
55 { "HSMSG_ASSIGN_HOWTO", "Use $bset xxx.yyy$b to activate one of the listed fakehosts or $bset *$b to use the default fakehost." },
56 { "HSMSG_ASSIGNED_NONE", " None." },
57 { "HSMSG_MANAGED_FAKEHOSTS", "Fakehosts managed by User $b%s$b:" },
58 { "HSMSG_MANAGED_TOPLEVEL", " $b*.%s$b fakehosts: %d assignments: %d" },
59 { "HSMSG_MANAGED_TOPLEVEL_OWN", " $b*.%s$b fakehosts: %d assignments: %d (active)" },
60 { "HSMSG_MANAGED_FAKEHOST", " $b%s.%s$b assignments: %d" },
61 { "HSMSG_MANAGE_HOWTO", "Use $bview xxx.yyy$b to view more information about a fakehost group." },
62 { "HSMSG_UNKNOWN_FAKEHOST", "Fakehost $b%s.%s$b is unknown or you have no access to manage it." },
63 { "HSMSG_TOPLEVEL_FAKEHOSTS", "Fakehosts in group $b*.%s$b:" },
64 { "HSMSG_TOPLEVEL_FAKEHOST", " $b%s.%s$b assignments: %d managers: %d" },
65 { "HSMSG_TOPLEVEL_INVALID", "The name of the group you entered is invalid ($b%s$b)" },
66 { "HSMSG_MANAGERS_TOPLEVEL", "Managers of group $b*.%s$b:" },
67 { "HSMSG_MANAGERS_FAKEHOST", "Managers of group $b%s.%s$b:" },
68 { "HSMSG_MANAGERS_MANAGERS", " %s" },
69 { "HSMSG_FAKEHOST_ASSIGNMENTS", "Assignments in group $b%s.%s$b:" },
70 { "HSMSG_FAKEHOST_ASSIGNMENT", " $b%s$b (%s.%s.%s)" },
71 { "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE", " $b%s$b (%s.%s.%s) active" },
72 { "HSMSG_FAKEHOST_SET_SUCCESS", "$b%s.%s$b where set successfully." },
73 { "HSMSG_FAKEHOST_TOPLEVEL_ADDED", "Group $b%s$b successfully added." },
74 { "HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", "Group $b%s$b already exists." },
75 { "HSMSG_FAKEHOST_TOPLEVEL_DELETED", "Group $b%s$b successfully deleted." },
76 { "HSMSG_FAKEHOST_SECONDLEVEL_ADDED", "Group $b%s.%s$b successfully added." },
77 { "HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", "Group $b%s.%s$b already exists." },
78 { "HSMSG_FAKEHOST_SECONDLEVEL_DELETED", "Group $b%s.%s$b successfully deleted." },
79 { "HSMSG_MANAGER_ALREADY", "$b%s$b is already a manager of %s.%s" },
80 { "HSMSG_MANAGER_ADDED", "$b%s$b is now a manager of %s.%s" },
81 { "HSMSG_MANAGER_NOT", "$b%s$b is not a manager of %s.%s" },
82 { "HSMSG_MANAGER_DELETED", "$b%s$b is no longer a manager of %s.%s" },
83 { "HSMSG_FAKEHOST_ASSIGN_SUCCESS", "Group $b%s.%s$b was assigned successfully." },
84 { "HSMSG_FAKEHOST_UNASSIGN_SUCCESS", "Group $b%s.%s$b was unassigned successfully." },
93 int fallback_other_assignment : 1;
94 int manager_can_del_toplevel : 1;
95 int manager_can_del_secondlevel : 1;
98 const char *hostserv_module_deps[] = { NULL };
99 struct userNode *hostserv;
100 struct helpfile *hostserv_helpfile;
101 static struct module *hostserv_module;
102 static struct service *hostserv_service;
103 static struct log_type *HS_LOG;
104 static struct hs_toplevel *toplevels = NULL;
105 static struct hs_user *hostserv_users = NULL;
107 /* FAKEHOST STRUCTS */
110 struct hs_manager *managers;
111 struct hs_secondlevel *secondlevel;
112 struct hs_toplevel *next;
115 struct hs_secondlevel {
116 struct hs_toplevel *toplevel;
118 struct hs_manager *managers;
119 struct hs_assignment *assignments;
120 struct hs_secondlevel *next;
123 struct hs_assignment {
124 struct hs_secondlevel *secondlevel;
125 struct hs_user *user;
127 struct hs_assignment *next;
128 struct hs_assignment *unext; /* for hs_user */
135 struct hs_user *user;
136 struct hs_manager *next;
137 struct hs_manager *unext; /* for hs_user */
141 struct handle_info *hi;
142 struct hs_assignment *assignments;
143 struct hs_manager *managements;
144 struct hs_user *next;
147 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
148 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
149 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
150 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
151 static void hs_del_user(struct hs_user *user);
153 static void hs_free_all() {
154 struct hs_toplevel *tlfh, *next_tlfh;
155 struct hs_secondlevel *slfh, *next_slfh;
156 struct hs_assignment *assng, *next_assng;
157 struct hs_manager *manager, *next_manager;
158 struct hs_user *user, *next_user;
159 for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
160 next_tlfh = tlfh->next;
161 for(manager = tlfh->managers; manager; manager = next_manager) {
162 next_manager = manager->next;
165 for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
166 next_slfh = slfh->next;
167 for(manager = tlfh->managers; manager; manager = next_manager) {
168 next_manager = manager->next;
171 for(assng = slfh->assignments; assng; assng = next_assng) {
172 next_assng = assng->next;
175 free(slfh->fakehost);
178 free(tlfh->fakehost);
181 for(user = hostserv_users; user; user = next_user) {
182 next_user = user->next;
186 hostserv_users = NULL;
189 static struct hs_toplevel *hs_add_toplevel(const char *name) {
190 struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
191 tlfh->fakehost = strdup(name);
192 tlfh->next = toplevels;
197 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
198 //unassign all assignments
199 struct hs_secondlevel *slfh, *next_slfh;
200 struct hs_manager *manager, *next_manager;
201 for(manager = tlfh->managers; manager; manager = next_manager) {
202 next_manager = manager->next;
203 hs_del_manager(manager, 0);
205 for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
206 next_slfh = slfh->next;
207 hs_del_secondlevel(slfh, 0);
210 struct hs_toplevel *ctlfh, *last_tlfh = NULL;
211 for(ctlfh = toplevels; ctlfh; ctlfh = ctlfh->next) {
214 last_tlfh->next = ctlfh->next;
216 toplevels = ctlfh->next;
220 free(tlfh->fakehost);
224 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, const char *name) {
225 struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
226 slfh->toplevel = tlfh;
227 slfh->fakehost = strdup(name);
228 slfh->next = tlfh->secondlevel;
229 tlfh->secondlevel = slfh;
233 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
234 if(remove_from_tlfh) {
235 struct hs_secondlevel *cslfh, *prev_slfh = NULL;
236 for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
239 prev_slfh->next = slfh->next;
241 slfh->toplevel->secondlevel = slfh->next;
247 struct hs_assignment *assng, *next_assng;
248 struct hs_manager *manager, *next_manager;
249 for(manager = slfh->managers; manager; manager = next_manager) {
250 next_manager = manager->next;
251 hs_del_manager(manager, 0);
253 for(assng = slfh->assignments; assng; assng = next_assng) {
254 next_assng = assng->next;
255 hs_del_assignment(assng, 0);
257 free(slfh->fakehost);
261 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
262 struct hs_manager *manager = calloc(1, sizeof(*manager));
263 manager->user = user;
265 manager->object = tlfh;
266 manager->unext = user->managements;
267 user->managements = manager;
268 manager->next = tlfh->managers;
269 tlfh->managers = manager;
273 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
274 struct hs_manager *manager = calloc(1, sizeof(*manager));
275 manager->user = user;
277 manager->object = slfh;
278 manager->unext = user->managements;
279 user->managements = manager;
280 manager->next = slfh->managers;
281 slfh->managers = manager;
285 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
286 struct hs_manager *cmanager, *prev_manager = NULL;
287 if(remove_from_object) {
288 if(manager->type == 1) {
289 struct hs_toplevel *tlfh = manager->object;
290 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
291 if(cmanager == manager) {
293 prev_manager->next = manager->next;
295 tlfh->managers = manager->next;
298 prev_manager = cmanager;
300 } else if(manager->type == 2) {
301 struct hs_secondlevel *slfh = manager->object;
302 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
303 if(cmanager == manager) {
305 prev_manager->next = manager->next;
307 slfh->managers = manager->next;
310 prev_manager = cmanager;
315 if(remove_from_object != 2) {
316 for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
317 if(cmanager == manager) {
319 prev_manager->unext = manager->unext;
321 manager->user->managements = manager->unext;
324 prev_manager = cmanager;
326 if(manager->user->managements == NULL && manager->user->assignments == NULL)
327 hs_del_user(manager->user);
332 static void hs_activate_assignment(struct hs_user *user, struct hs_assignment *assignment) {
333 struct hs_toplevel *tlfh;
334 struct hs_secondlevel *slfh;
335 struct hs_assignment *assgn;
336 char fakehost[HOSTLEN];
338 assert((!assignment || (assignment->user == user)));
340 if(user->assignments) {
341 for(assgn = assignment->user->assignments; assgn; assgn = assgn->unext)
345 if(user->hi->fakehost) {
346 free(user->hi->fakehost);
347 user->hi->fakehost = NULL;
351 slfh = assignment->secondlevel;
352 tlfh = slfh->toplevel;
353 snprintf(fakehost, sizeof(fakehost), "$.%s.%s", slfh->fakehost, tlfh->fakehost);
354 user->hi->fakehost = strdup(fakehost);
355 assignment->active = 1;
358 apply_fakehost(assignment->user->hi, NULL);
361 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
362 struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
363 assignment->secondlevel = slfh;
364 assignment->user = user;
365 if(user->assignments == NULL)
366 assignment->active = 1;
367 assignment->next = slfh->assignments;
368 slfh->assignments = assignment;
369 assignment->unext = user->assignments;
370 user->assignments = assignment;
371 if(assignment->active) {
372 hs_activate_assignment(user, assignment);
377 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
378 struct hs_assignment *cassignment, *prev_assignment = NULL;
379 if(remove_from_slfh) {
380 for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
381 if(cassignment == assignment) {
383 prev_assignment->next = assignment->next;
385 assignment->secondlevel->assignments = assignment->next;
388 prev_assignment = cassignment;
390 prev_assignment = NULL;
392 if(remove_from_slfh != 2) {
393 prev_assignment = NULL;
394 for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
395 if(cassignment == assignment) {
397 prev_assignment->unext = assignment->unext;
399 assignment->user->assignments = assignment->unext;
402 prev_assignment = cassignment;
405 if(assignment->active) {
406 /* use another assignment - or fall back to default user host? */
408 if(hostserv_conf.fallback_other_assignment && assignment->user->assignments) {
409 /* try to find another assignment from same slfh first */
410 for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
411 if(cassignment != assignment && cassignment->user == assignment->user)
414 /* use another tlfh assignment */
416 cassignment = assignment->user->assignments;
418 hs_activate_assignment(assignment->user, cassignment);
421 if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
422 hs_del_user(assignment->user);
427 static struct hs_assignment *hs_get_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
428 struct hs_assignment *cassignment;
429 for(cassignment = slfh->assignments; cassignment; cassignment = cassignment->next) {
430 if(cassignment->user == user)
436 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
437 struct hs_user *cuser;
438 for(cuser = hostserv_users; cuser; cuser = cuser->next) {
443 cuser = calloc(1, sizeof(*cuser));
445 cuser->next = hostserv_users;
446 hostserv_users = cuser;
452 static void hs_del_user(struct hs_user *user) {
453 if(user->managements) {
454 struct hs_manager *manager, *next_manager;
455 for(manager = user->managements; manager; manager = next_manager) {
456 next_manager = manager->unext;
457 hs_del_manager(manager, 2);
460 if(user->assignments) {
461 struct hs_assignment *assng, *next_assng;
462 for(assng = user->assignments; assng; assng = next_assng) {
463 next_assng = assng->unext;
464 hs_del_assignment(assng, 2);
467 struct hs_user *cuser, *prev_user = NULL;
468 for(cuser = hostserv_users; cuser; cuser = cuser->next) {
471 prev_user->next = user->next;
473 hostserv_users = user->next;
481 /* END OF MANAGEMENT FUNCTIONS */
483 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_secondlevel *slfh) {
486 if(hi->opserv_level >= hostserv_conf.toplevel_access)
488 struct hs_user *user = hs_get_user(hi, 0);
491 struct hs_manager *manager;
493 for(manager = user->managements; manager; manager = manager->next) {
494 if(manager->type == 2 && manager->object == slfh)
499 for(manager = user->managements; manager; manager = manager->next) {
500 if(manager->type == 1 && manager->object == tlfh)
508 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
509 reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
510 struct hs_secondlevel *slfh;
511 if(!tlfh->secondlevel)
512 reply("HSMSG_ASSIGNED_NONE");
514 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
515 struct hs_manager *cmanager;
517 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
519 struct hs_assignment *assignment;
521 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
523 reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
525 reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
526 struct hs_manager *cmanager;
528 reply("HSMSG_ASSIGNED_NONE");
530 char managerBuf[351];
532 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
533 if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
534 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
537 managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
539 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
543 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
544 reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
545 struct hs_assignment *assignment;
546 for(assignment = slfh->assignments; assignment; assignment = assignment->next) {
547 reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
549 reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
550 struct hs_manager *cmanager;
552 reply("HSMSG_ASSIGNED_NONE");
554 char managerBuf[351];
556 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
557 if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
558 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
561 managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
563 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
567 static MODCMD_FUNC(cmd_view) {
568 struct handle_info *hi;
569 if(argc >= 2 && !strchr(argv[1], '.')) {
570 if (!(hi = modcmd_get_handle_info(user, argv[1])))
572 } else if(argc >= 2) {
573 if (!(hi = user->handle_info)) {
574 reply("NSMSG_MUST_AUTH");
577 char *slfh_name = argv[1];
578 char *tlfh_name = strchr(argv[1], '.');
581 if(strchr(tlfh_name, '.')) {
582 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
585 struct hs_toplevel *tlfh;
586 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
587 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
590 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
593 if(!irccasecmp(slfh_name, "*")) {
594 if(!check_management_access(hi, tlfh, NULL)) {
595 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
598 cmd_view_toplevel_information(user, cmd, tlfh);
601 struct hs_secondlevel *slfh;
602 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
603 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
605 if(!slfh || !check_management_access(hi, tlfh, slfh)) {
606 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
609 cmd_view_secondlevel_information(user, cmd, slfh);
613 if (!(hi = user->handle_info)) {
614 reply("NSMSG_MUST_AUTH");
618 struct hs_user *huser = hs_get_user(hi, 0);
619 reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
622 struct hs_assignment *assignment;
623 for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
624 reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
627 if(assigncount && huser->hi == user->handle_info)
628 reply("HSMSG_ASSIGN_HOWTO");
631 reply("HSMSG_ASSIGNED_NONE");
632 if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
633 struct hs_toplevel *tlfh;
634 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
635 struct hs_secondlevel *slfh;
636 struct hs_assignment *assignment;
637 int slfhs = 0, assignments = 0;
638 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
640 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
643 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
645 reply("HSMSG_MANAGE_HOWTO");
646 } else if(huser && huser->managements) {
647 reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
648 struct hs_manager *manager;
649 for(manager = huser->managements; manager; manager = manager->unext) {
650 if(manager->type == 1) {
651 struct hs_toplevel *tlfh = manager->object;
652 struct hs_secondlevel *slfh;
653 struct hs_assignment *assignment;
654 int slfhs = 0, assignments = 0;
655 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
657 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
660 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
663 for(manager = huser->managements; manager; manager = manager->next) {
664 if(manager->type == 2) {
665 struct hs_secondlevel *slfh = manager->object;
666 struct hs_toplevel *tlfh = slfh->toplevel;
667 //check if the user is already a manager of the tlfh
668 struct hs_manager *cmanager;
669 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
670 if(cmanager->user == huser) break;
672 if(cmanager) continue;
673 struct hs_assignment *assignment;
675 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
677 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
680 if(huser->hi == user->handle_info)
681 reply("HSMSG_MANAGE_HOWTO");
686 static MODCMD_FUNC(cmd_addhost) {
687 struct handle_info *hi;
688 struct hs_toplevel *tlfh;
689 struct hs_secondlevel *slfh;
690 if (!(hi = user->handle_info)) {
691 reply("NSMSG_MUST_AUTH");
694 char *slfh_name = argv[1];
695 char *tlfh_name = strchr(argv[1], '.');
697 reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
702 if(strchr(tlfh_name, '.')) {
703 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
706 if(!irccasecmp(slfh_name, "*")) {
707 if(!check_management_access(hi, NULL, NULL)) {
708 reply("HSMSG_ACCESS_DENIED");
711 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
712 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
715 reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
718 hs_add_toplevel(tlfh_name);
719 reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
721 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
722 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
725 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
728 if(!check_management_access(hi, tlfh, NULL)) {
729 reply("HSMSG_ACCESS_DENIED");
732 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
733 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
736 reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
739 hs_add_secondlevel(tlfh, slfh_name);
740 reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
745 static MODCMD_FUNC(cmd_delhost) {
746 struct handle_info *hi;
747 if (!(hi = user->handle_info)) {
748 reply("NSMSG_MUST_AUTH");
751 char *slfh_name = argv[1];
752 char *tlfh_name = strchr(argv[1], '.');
755 if(strchr(tlfh_name, '.')) {
756 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
759 struct hs_toplevel *tlfh;
760 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
761 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
764 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
767 if(!irccasecmp(slfh_name, "*")) {
768 if(!check_management_access(hi, (hostserv_conf.manager_can_del_toplevel ? tlfh : NULL), NULL)) { /* manager access is enough to delete whole toplevel? */
769 reply("HSMSG_ACCESS_DENIED");
772 hs_del_toplevel(tlfh);
773 reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
775 struct hs_secondlevel *slfh;
776 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
777 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
780 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
783 if(!check_management_access(hi, tlfh, (hostserv_conf.manager_can_del_secondlevel ? slfh : NULL))) {
784 reply("HSMSG_ACCESS_DENIED");
787 hs_del_secondlevel(slfh, 1);
788 reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
793 static MODCMD_FUNC(cmd_addmanager) {
794 struct handle_info *hi;
797 if(!strchr(argv[1], '.')) {
798 if (!(hi = modcmd_get_handle_info(user, argv[1])))
802 if (!(hi = modcmd_get_handle_info(user, argv[2])))
806 char *slfh_name = fakehost;
807 char *tlfh_name = strchr(fakehost, '.');
810 if(strchr(tlfh_name, '.')) {
811 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
814 struct hs_toplevel *tlfh;
815 struct hs_secondlevel *slfh = NULL;
816 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
817 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
820 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
823 if(!irccasecmp(slfh_name, "*")) {
824 if(!check_management_access(user->handle_info, tlfh, NULL)) {
825 reply("HSMSG_ACCESS_DENIED");
829 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
830 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
833 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
836 if(!check_management_access(user->handle_info, tlfh, slfh)) {
837 reply("HSMSG_ACCESS_DENIED");
841 struct hs_user *huser = hs_get_user(hi, 1);
842 struct hs_manager *manager;
844 for(manager = huser->managements; manager; manager = manager->next) {
845 if(manager->type == 2 && manager->object == slfh) {
846 reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
851 for(manager = huser->managements; manager; manager = manager->next) {
852 if(manager->type == 1 && manager->object == tlfh) {
853 reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
858 hs_add_manager_secondlevel(slfh, huser);
860 hs_add_manager_toplevel(tlfh, huser);
861 reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
867 static MODCMD_FUNC(cmd_delmanager) {
868 struct handle_info *hi;
870 if(!strchr(argv[1], '.')) {
871 if (!(hi = modcmd_get_handle_info(user, argv[1])))
875 if (!(hi = modcmd_get_handle_info(user, argv[2])))
879 char *slfh_name = fakehost;
880 char *tlfh_name = strchr(fakehost, '.');
884 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
888 if(strchr(tlfh_name, '.')) {
889 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
892 struct hs_toplevel *tlfh;
893 struct hs_secondlevel *slfh = NULL;
894 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
895 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
898 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
901 if(!irccasecmp(slfh_name, "*")) {
902 if(!check_management_access(user->handle_info, tlfh, NULL)) {
903 reply("HSMSG_ACCESS_DENIED");
907 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
908 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
911 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
914 if(!check_management_access(user->handle_info, tlfh, slfh)) {
915 reply("HSMSG_ACCESS_DENIED");
919 struct hs_user *huser = hs_get_user(hi, 0);
920 struct hs_manager *manager;
922 reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
926 for(manager = huser->managements; manager; manager = manager->next) {
927 if(manager->type == 2 && manager->object == slfh)
931 reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
935 for(manager = huser->managements; manager; manager = manager->next) {
936 if(manager->type == 1 && manager->object == tlfh)
940 reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
944 hs_del_manager(manager, 1);
945 reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
949 static MODCMD_FUNC(cmd_set) {
950 struct handle_info *hi;
951 struct hs_user *hs_user;
952 struct hs_assignment *assignment;
953 struct hs_assignment *assgn;
954 struct hs_toplevel *tlfh;
955 struct hs_secondlevel *slfh;
958 if (!(hi = user->handle_info)) {
959 reply("NSMSG_MUST_AUTH");
962 hs_user = hs_get_user(hi, 0);
964 return 0; //nothing to do here
965 if(!strcmp(argv[1], "*")) {
966 hs_activate_assignment(hs_user, NULL);
969 if(!strchr(argv[1], '.')) {
973 char *slfh_name = fakehost;
974 char *tlfh_name = strchr(fakehost, '.');
979 if(!tlfh_name || strchr(tlfh_name, '.')) {
980 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, (tlfh_name ? tlfh_name : ""));
983 for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
984 slfh = assignment->secondlevel;
985 tlfh = slfh->toplevel;
986 if(!irccasecmp(tlfh_name, tlfh->fakehost) && !irccasecmp(slfh_name, slfh->fakehost)) {
987 hs_activate_assignment(hs_user, assignment);
988 reply("HSMSG_FAKEHOST_SET_SUCCESS", slfh->fakehost, tlfh->fakehost);
992 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
997 static MODCMD_FUNC(cmd_assign) {
998 struct handle_info *hi;
1000 if(!strchr(argv[1], '.')) {
1001 if (!(hi = modcmd_get_handle_info(user, argv[1])))
1005 if (!(hi = modcmd_get_handle_info(user, argv[2])))
1009 if (!user->handle_info) {
1010 reply("NSMSG_MUST_AUTH");
1013 char *slfh_name = fakehost;
1014 char *tlfh_name = strchr(fakehost, '.');
1018 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1022 if(strchr(tlfh_name, '.')) {
1023 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1026 struct hs_toplevel *tlfh;
1027 struct hs_secondlevel *slfh;
1028 struct hs_user *hs_user = hs_get_user(hi, 1);
1029 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1030 if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
1031 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1032 if(!irccasecmp(slfh_name, slfh->fakehost)) {
1033 if(!check_management_access(user->handle_info, tlfh, slfh)) {
1034 reply("HSMSG_ACCESS_DENIED");
1037 hs_add_assignment(slfh, hs_user);
1038 reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
1044 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1048 static MODCMD_FUNC(cmd_unassign) {
1049 struct handle_info *hi;
1051 if(!strchr(argv[1], '.')) {
1052 if (!(hi = modcmd_get_handle_info(user, argv[1])))
1056 if (!(hi = modcmd_get_handle_info(user, argv[2])))
1060 if (!user->handle_info) {
1061 reply("NSMSG_MUST_AUTH");
1064 char *slfh_name = fakehost;
1065 char *tlfh_name = strchr(fakehost, '.');
1069 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1073 if(strchr(tlfh_name, '.')) {
1074 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1077 struct hs_assignment *assignment;
1078 struct hs_user *hs_user = hs_get_user(hi, 0);
1080 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1083 for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1084 if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
1085 if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
1086 if(!check_management_access(user->handle_info, assignment->secondlevel->toplevel, assignment->secondlevel)) {
1087 reply("HSMSG_ACCESS_DENIED");
1090 hs_del_assignment(assignment, 1);
1091 reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
1096 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1100 static void hostserv_conf_read(void) {
1104 str = "modules/hostserv";
1105 if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1106 log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1110 str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1111 if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
1114 hostserv_conf.nick = str;
1116 str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1117 hostserv_conf.modes = (str ? str : NULL);
1119 str = database_get_data(conf_node, "toplevel_access", RECDB_QSTRING);
1120 unsigned int toplevel_access = atoi(str);
1121 hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
1123 str = database_get_data(conf_node, "fallback_other_assignment", RECDB_QSTRING);
1124 hostserv_conf.fallback_other_assignment = (atoi(str) ? 1 : 0);
1126 str = database_get_data(conf_node, "manager_can_del_toplevel", RECDB_QSTRING);
1127 hostserv_conf.manager_can_del_toplevel = (atoi(str) ? 1 : 0);
1129 str = database_get_data(conf_node, "manager_can_del_secondlevel", RECDB_QSTRING);
1130 hostserv_conf.manager_can_del_secondlevel = (atoi(str) ? 1 : 0);
1132 /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
1133 hostserv_conf.description = (str ? str : NULL);*/
1136 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));
1137 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra));
1139 static int hostserv_saxdb_read_toplevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1140 struct record_data *rd = data;
1141 struct hs_toplevel *tlfh;
1142 struct hs_manager *managerTL;
1143 struct hs_user *user;
1144 struct dict *object;
1146 if (rd->type == RECDB_OBJECT) {
1147 dict_t db = GET_RECORD_OBJECT(rd);
1150 tlfh = hs_add_toplevel(name);
1152 if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1153 for (it = dict_first(object); it; it = iter_next(it)) {
1154 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1155 //rd = iter_data(it);
1156 /* nothing in here, yet */
1157 managerTL = hs_add_manager_toplevel(tlfh, user);
1158 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1159 managerTL->active = 1;
1161 managerTL->active = 0;
1165 if ((object = database_get_data(db, KEY_SECONDLEVEL, RECDB_OBJECT)))
1166 dict_foreach(object, hostserv_saxdb_read_secondlevel, tlfh);
1171 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1172 struct record_data *rd = data;
1173 struct hs_toplevel *tlfh = extra;
1174 struct hs_secondlevel *slfh;
1175 struct hs_manager *managerSL;
1176 struct hs_user *user;
1177 struct dict *object;
1179 if (rd->type == RECDB_OBJECT) {
1180 dict_t db = GET_RECORD_OBJECT(rd);
1183 slfh = hs_add_secondlevel(tlfh, name);
1185 if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1186 for (it = dict_first(object); it; it = iter_next(it)) {
1187 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1188 //rd = iter_data(it);
1189 /* nothing in here, yet */
1190 managerSL = hs_add_manager_secondlevel(slfh, user);
1191 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1192 managerSL->active = 1;
1194 managerSL->active = 0;
1198 if ((object = database_get_data(db, KEY_ASSIGNMENTS, RECDB_OBJECT)))
1199 dict_foreach(object, hostserv_saxdb_read_assignments, slfh);
1204 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra)) {
1205 struct record_data *rd = data;
1206 struct hs_secondlevel *slfh = extra;
1207 struct hs_user *user;
1208 struct hs_assignment *assng;
1210 if (rd->type == RECDB_OBJECT) {
1211 dict_t db = GET_RECORD_OBJECT(rd);
1213 user = hs_get_user(get_handle_info(name), 1);
1214 assng = hs_add_assignment(slfh, user);
1216 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1226 hostserv_saxdb_read(struct dict *db)
1228 struct dict *object;
1230 if ((object = database_get_data(db, KEY_TOPLEVEL, RECDB_OBJECT)))
1231 dict_foreach(object, hostserv_saxdb_read_toplevel, NULL);
1237 hostserv_saxdb_write(struct saxdb_context *ctx)
1239 struct hs_toplevel *tlfh;
1240 struct hs_secondlevel *slfh;
1241 struct hs_assignment *assng;
1242 struct hs_manager *manager;
1244 saxdb_start_record(ctx, KEY_TOPLEVEL, 1);
1245 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1246 saxdb_start_record(ctx, tlfh->fakehost, 1);
1248 saxdb_start_record(ctx, KEY_MANAGERS, 1);
1249 for(manager = tlfh->managers; manager; manager = manager->next) {
1250 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1251 //additional manager information?
1253 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1254 saxdb_end_record(ctx);
1256 saxdb_end_record(ctx);
1258 saxdb_start_record(ctx, KEY_SECONDLEVEL, 1);
1259 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1260 saxdb_start_record(ctx, slfh->fakehost, 1);
1262 saxdb_start_record(ctx, KEY_MANAGERS, 1);
1263 for(manager = slfh->managers; manager; manager = manager->next) {
1264 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1265 //additional manager information?
1267 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1268 saxdb_end_record(ctx);
1270 saxdb_end_record(ctx);
1272 saxdb_start_record(ctx, KEY_ASSIGNMENTS, 1);
1273 for(assng = slfh->assignments; assng; assng = assng->next) {
1274 saxdb_start_record(ctx, assng->user->hi->handle, 0);
1275 //additional assignment information?
1277 saxdb_write_int(ctx, KEY_ACTIVE, assng->active);
1278 saxdb_end_record(ctx);
1280 saxdb_end_record(ctx);
1282 saxdb_end_record(ctx);
1284 saxdb_end_record(ctx);
1286 saxdb_end_record(ctx);
1288 saxdb_end_record(ctx);
1294 static void hostserv_db_cleanup(void) {
1298 int hostserv_init() {
1299 HS_LOG = log_register_type("HostServ", "file:hostserv.log");
1301 const char *nick, *modes;
1302 if((nick = conf_get_data("modules/hostserv/nick", RECDB_QSTRING))) {
1303 modes = conf_get_data("modules/hostserv/modes", RECDB_QSTRING);
1304 hostserv = AddLocalUser(nick, nick, NULL, "Host Service", modes);
1305 hostserv_service = service_register(hostserv);
1306 hostserv_service->trigger = '*';
1309 conf_register_reload(hostserv_conf_read);
1310 reg_exit_func(hostserv_db_cleanup);
1311 saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
1312 hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
1313 modcmd_register(hostserv_module, "view", cmd_view, 0, MODCMD_REQUIRE_AUTHED, NULL);
1314 modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1315 modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1316 modcmd_register(hostserv_module, "set", cmd_set, 2, MODCMD_REQUIRE_AUTHED, NULL);
1317 modcmd_register(hostserv_module, "assign", cmd_assign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1318 modcmd_register(hostserv_module, "unassign", cmd_unassign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1319 modcmd_register(hostserv_module, "addhost", cmd_addhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1320 modcmd_register(hostserv_module, "delhost", cmd_delhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1321 message_register_table(msgtab);
1325 int hostserv_finalize(void) {
1329 str = "modules/hostserv";
1330 if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1331 log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1335 str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1336 if (str) hostserv_conf.nick = str;
1338 str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1339 if (str) hostserv_conf.modes = str;