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_ASSIGNED", "Group $b%s.%s$b is already assigned to the user." },
85 { "HSMSG_FAKEHOST_UNASSIGN_SUCCESS", "Group $b%s.%s$b was unassigned successfully." },
94 int fallback_other_assignment : 1;
95 int manager_can_del_toplevel : 1;
96 int manager_can_del_secondlevel : 1;
99 const char *hostserv_module_deps[] = { NULL };
100 struct userNode *hostserv;
101 struct helpfile *hostserv_helpfile;
102 static struct module *hostserv_module;
103 static struct service *hostserv_service;
104 static struct log_type *HS_LOG;
105 static struct hs_toplevel *toplevels = NULL;
106 static struct hs_user *hostserv_users = NULL;
108 /* FAKEHOST STRUCTS */
111 struct hs_manager *managers;
112 struct hs_secondlevel *secondlevel;
113 struct hs_toplevel *next;
116 struct hs_secondlevel {
117 struct hs_toplevel *toplevel;
119 struct hs_manager *managers;
120 struct hs_assignment *assignments;
121 struct hs_secondlevel *next;
124 struct hs_assignment {
125 struct hs_secondlevel *secondlevel;
126 struct hs_user *user;
128 struct hs_assignment *next;
129 struct hs_assignment *unext; /* for hs_user */
136 struct hs_user *user;
137 struct hs_manager *next;
138 struct hs_manager *unext; /* for hs_user */
142 struct handle_info *hi;
143 struct hs_assignment *assignments;
144 struct hs_manager *managements;
145 struct hs_user *next;
148 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
149 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
150 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
151 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
152 static void hs_del_user(struct hs_user *user);
154 static void hs_free_all() {
155 struct hs_toplevel *tlfh, *next_tlfh;
156 struct hs_secondlevel *slfh, *next_slfh;
157 struct hs_assignment *assng, *next_assng;
158 struct hs_manager *manager, *next_manager;
159 struct hs_user *user, *next_user;
160 for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
161 next_tlfh = tlfh->next;
162 for(manager = tlfh->managers; manager; manager = next_manager) {
163 next_manager = manager->next;
166 for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
167 next_slfh = slfh->next;
168 for(manager = tlfh->managers; manager; manager = next_manager) {
169 next_manager = manager->next;
172 for(assng = slfh->assignments; assng; assng = next_assng) {
173 next_assng = assng->next;
176 free(slfh->fakehost);
179 free(tlfh->fakehost);
182 for(user = hostserv_users; user; user = next_user) {
183 next_user = user->next;
187 hostserv_users = NULL;
190 static struct hs_toplevel *hs_add_toplevel(const char *name) {
191 struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
192 tlfh->fakehost = strdup(name);
193 tlfh->next = toplevels;
198 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
199 //unassign all assignments
200 struct hs_secondlevel *slfh, *next_slfh;
201 struct hs_manager *manager, *next_manager;
202 for(manager = tlfh->managers; manager; manager = next_manager) {
203 next_manager = manager->next;
204 hs_del_manager(manager, 0);
206 for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
207 next_slfh = slfh->next;
208 hs_del_secondlevel(slfh, 0);
211 struct hs_toplevel *ctlfh, *last_tlfh = NULL;
212 for(ctlfh = toplevels; ctlfh; ctlfh = ctlfh->next) {
215 last_tlfh->next = ctlfh->next;
217 toplevels = ctlfh->next;
221 free(tlfh->fakehost);
225 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, const char *name) {
226 struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
227 slfh->toplevel = tlfh;
228 slfh->fakehost = strdup(name);
229 slfh->next = tlfh->secondlevel;
230 tlfh->secondlevel = slfh;
234 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
235 if(remove_from_tlfh) {
236 struct hs_secondlevel *cslfh, *prev_slfh = NULL;
237 for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
240 prev_slfh->next = slfh->next;
242 slfh->toplevel->secondlevel = slfh->next;
248 struct hs_assignment *assng, *next_assng;
249 struct hs_manager *manager, *next_manager;
250 for(manager = slfh->managers; manager; manager = next_manager) {
251 next_manager = manager->next;
252 hs_del_manager(manager, 0);
254 for(assng = slfh->assignments; assng; assng = next_assng) {
255 next_assng = assng->next;
256 hs_del_assignment(assng, 0);
258 free(slfh->fakehost);
262 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
263 struct hs_manager *manager = calloc(1, sizeof(*manager));
264 manager->user = user;
266 manager->object = tlfh;
267 manager->unext = user->managements;
268 user->managements = manager;
269 manager->next = tlfh->managers;
270 tlfh->managers = manager;
274 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
275 struct hs_manager *manager = calloc(1, sizeof(*manager));
276 manager->user = user;
278 manager->object = slfh;
279 manager->unext = user->managements;
280 user->managements = manager;
281 manager->next = slfh->managers;
282 slfh->managers = manager;
286 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
287 struct hs_manager *cmanager, *prev_manager = NULL;
288 if(remove_from_object) {
289 if(manager->type == 1) {
290 struct hs_toplevel *tlfh = manager->object;
291 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
292 if(cmanager == manager) {
294 prev_manager->next = manager->next;
296 tlfh->managers = manager->next;
299 prev_manager = cmanager;
301 } else if(manager->type == 2) {
302 struct hs_secondlevel *slfh = manager->object;
303 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
304 if(cmanager == manager) {
306 prev_manager->next = manager->next;
308 slfh->managers = manager->next;
311 prev_manager = cmanager;
316 if(remove_from_object != 2) {
317 for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
318 if(cmanager == manager) {
320 prev_manager->unext = manager->unext;
322 manager->user->managements = manager->unext;
325 prev_manager = cmanager;
327 if(manager->user->managements == NULL && manager->user->assignments == NULL)
328 hs_del_user(manager->user);
333 static void hs_activate_assignment(struct hs_user *user, struct hs_assignment *assignment) {
334 struct hs_toplevel *tlfh;
335 struct hs_secondlevel *slfh;
336 struct hs_assignment *assgn;
337 char fakehost[HOSTLEN];
339 assert((!assignment || (assignment->user == user)));
341 if(user->assignments) {
342 for(assgn = assignment->user->assignments; assgn; assgn = assgn->unext)
346 if(user->hi->fakehost) {
347 free(user->hi->fakehost);
348 user->hi->fakehost = NULL;
352 slfh = assignment->secondlevel;
353 tlfh = slfh->toplevel;
354 snprintf(fakehost, sizeof(fakehost), "$.%s.%s", slfh->fakehost, tlfh->fakehost);
355 user->hi->fakehost = strdup(fakehost);
356 assignment->active = 1;
359 apply_fakehost(assignment->user->hi, NULL);
362 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
363 struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
364 assignment->secondlevel = slfh;
365 assignment->user = user;
366 if(user->assignments == NULL)
367 assignment->active = 1;
368 assignment->next = slfh->assignments;
369 slfh->assignments = assignment;
370 assignment->unext = user->assignments;
371 user->assignments = assignment;
372 if(assignment->active) {
373 hs_activate_assignment(user, assignment);
378 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
379 struct hs_assignment *cassignment, *prev_assignment = NULL;
380 if(remove_from_slfh) {
381 for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
382 if(cassignment == assignment) {
384 prev_assignment->next = assignment->next;
386 assignment->secondlevel->assignments = assignment->next;
389 prev_assignment = cassignment;
391 prev_assignment = NULL;
393 if(remove_from_slfh != 2) {
394 prev_assignment = NULL;
395 for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
396 if(cassignment == assignment) {
398 prev_assignment->unext = assignment->unext;
400 assignment->user->assignments = assignment->unext;
403 prev_assignment = cassignment;
406 if(assignment->active) {
407 /* use another assignment - or fall back to default user host? */
409 if(hostserv_conf.fallback_other_assignment && assignment->user->assignments) {
410 /* try to find another assignment from same slfh first */
411 for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
412 if(cassignment != assignment && cassignment->user == assignment->user)
415 /* use another tlfh assignment */
417 cassignment = assignment->user->assignments;
419 hs_activate_assignment(assignment->user, cassignment);
422 if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
423 hs_del_user(assignment->user);
428 static struct hs_assignment *hs_get_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
429 struct hs_assignment *cassignment;
430 for(cassignment = slfh->assignments; cassignment; cassignment = cassignment->next) {
431 if(cassignment->user == user)
437 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
438 struct hs_user *cuser;
439 for(cuser = hostserv_users; cuser; cuser = cuser->next) {
444 cuser = calloc(1, sizeof(*cuser));
446 cuser->next = hostserv_users;
447 hostserv_users = cuser;
453 static void hs_del_user(struct hs_user *user) {
454 if(user->managements) {
455 struct hs_manager *manager, *next_manager;
456 for(manager = user->managements; manager; manager = next_manager) {
457 next_manager = manager->unext;
458 hs_del_manager(manager, 2);
461 if(user->assignments) {
462 struct hs_assignment *assng, *next_assng;
463 for(assng = user->assignments; assng; assng = next_assng) {
464 next_assng = assng->unext;
465 hs_del_assignment(assng, 2);
468 struct hs_user *cuser, *prev_user = NULL;
469 for(cuser = hostserv_users; cuser; cuser = cuser->next) {
472 prev_user->next = user->next;
474 hostserv_users = user->next;
482 /* END OF MANAGEMENT FUNCTIONS */
484 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_secondlevel *slfh) {
487 if(hi->opserv_level >= hostserv_conf.toplevel_access)
489 struct hs_user *user = hs_get_user(hi, 0);
492 struct hs_manager *manager;
494 for(manager = user->managements; manager; manager = manager->next) {
495 if(manager->type == 2 && manager->object == slfh)
500 for(manager = user->managements; manager; manager = manager->next) {
501 if(manager->type == 1 && manager->object == tlfh)
509 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
510 reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
511 struct hs_secondlevel *slfh;
512 if(!tlfh->secondlevel)
513 reply("HSMSG_ASSIGNED_NONE");
515 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
516 struct hs_manager *cmanager;
518 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
520 struct hs_assignment *assignment;
522 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
524 reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
526 reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
527 struct hs_manager *cmanager;
529 reply("HSMSG_ASSIGNED_NONE");
531 char managerBuf[351];
533 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
534 if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
535 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
538 managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
540 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
544 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
545 reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
546 struct hs_assignment *assignment;
547 for(assignment = slfh->assignments; assignment; assignment = assignment->next) {
548 reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
550 reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
551 struct hs_manager *cmanager;
553 reply("HSMSG_ASSIGNED_NONE");
555 char managerBuf[351];
557 for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
558 if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
559 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
562 managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
564 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
568 static MODCMD_FUNC(cmd_view) {
569 struct handle_info *hi;
570 if(argc >= 2 && !strchr(argv[1], '.')) {
571 if (!(hi = modcmd_get_handle_info(user, argv[1])))
573 } else if(argc >= 2) {
574 if (!(hi = user->handle_info)) {
575 reply("NSMSG_MUST_AUTH");
578 char *slfh_name = argv[1];
579 char *tlfh_name = strchr(argv[1], '.');
582 if(strchr(tlfh_name, '.')) {
583 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
586 struct hs_toplevel *tlfh;
587 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
588 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
591 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
594 if(!irccasecmp(slfh_name, "*")) {
595 if(!check_management_access(hi, tlfh, NULL)) {
596 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
599 cmd_view_toplevel_information(user, cmd, tlfh);
602 struct hs_secondlevel *slfh;
603 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
604 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
606 if(!slfh || !check_management_access(hi, tlfh, slfh)) {
607 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
610 cmd_view_secondlevel_information(user, cmd, slfh);
614 if (!(hi = user->handle_info)) {
615 reply("NSMSG_MUST_AUTH");
619 struct hs_user *huser = hs_get_user(hi, 0);
620 reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
623 struct hs_assignment *assignment;
624 for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
625 reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
628 if(assigncount && huser->hi == user->handle_info)
629 reply("HSMSG_ASSIGN_HOWTO");
632 reply("HSMSG_ASSIGNED_NONE");
633 if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
634 struct hs_toplevel *tlfh;
635 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
636 struct hs_secondlevel *slfh;
637 struct hs_assignment *assignment;
638 int slfhs = 0, assignments = 0;
639 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
641 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
644 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
646 reply("HSMSG_MANAGE_HOWTO");
647 } else if(huser && huser->managements) {
648 reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
649 struct hs_manager *manager;
650 for(manager = huser->managements; manager; manager = manager->unext) {
651 if(manager->type == 1) {
652 struct hs_toplevel *tlfh = manager->object;
653 struct hs_secondlevel *slfh;
654 struct hs_assignment *assignment;
655 int slfhs = 0, assignments = 0;
656 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
658 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
661 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
664 for(manager = huser->managements; manager; manager = manager->next) {
665 if(manager->type == 2) {
666 struct hs_secondlevel *slfh = manager->object;
667 struct hs_toplevel *tlfh = slfh->toplevel;
668 //check if the user is already a manager of the tlfh
669 struct hs_manager *cmanager;
670 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
671 if(cmanager->user == huser) break;
673 if(cmanager) continue;
674 struct hs_assignment *assignment;
676 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
678 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
681 if(huser->hi == user->handle_info)
682 reply("HSMSG_MANAGE_HOWTO");
687 static MODCMD_FUNC(cmd_addhost) {
688 struct handle_info *hi;
689 struct hs_toplevel *tlfh;
690 struct hs_secondlevel *slfh;
691 if (!(hi = user->handle_info)) {
692 reply("NSMSG_MUST_AUTH");
695 char *slfh_name = argv[1];
696 char *tlfh_name = strchr(argv[1], '.');
698 reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
703 if(strchr(tlfh_name, '.')) {
704 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
707 if(!irccasecmp(slfh_name, "*")) {
708 if(!check_management_access(hi, NULL, NULL)) {
709 reply("HSMSG_ACCESS_DENIED");
712 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
713 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
716 reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
719 hs_add_toplevel(tlfh_name);
720 reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
722 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
723 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
726 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
729 if(!check_management_access(hi, tlfh, NULL)) {
730 reply("HSMSG_ACCESS_DENIED");
733 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
734 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
737 reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
740 hs_add_secondlevel(tlfh, slfh_name);
741 reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
746 static MODCMD_FUNC(cmd_delhost) {
747 struct handle_info *hi;
748 if (!(hi = user->handle_info)) {
749 reply("NSMSG_MUST_AUTH");
752 char *slfh_name = argv[1];
753 char *tlfh_name = strchr(argv[1], '.');
756 if(strchr(tlfh_name, '.')) {
757 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
760 struct hs_toplevel *tlfh;
761 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
762 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
765 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
768 if(!irccasecmp(slfh_name, "*")) {
769 if(!check_management_access(hi, (hostserv_conf.manager_can_del_toplevel ? tlfh : NULL), NULL)) { /* manager access is enough to delete whole toplevel? */
770 reply("HSMSG_ACCESS_DENIED");
773 hs_del_toplevel(tlfh);
774 reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
776 struct hs_secondlevel *slfh;
777 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
778 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
781 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
784 if(!check_management_access(hi, tlfh, (hostserv_conf.manager_can_del_secondlevel ? slfh : NULL))) {
785 reply("HSMSG_ACCESS_DENIED");
788 hs_del_secondlevel(slfh, 1);
789 reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
794 static MODCMD_FUNC(cmd_addmanager) {
795 struct handle_info *hi;
798 if(!strchr(argv[1], '.')) {
799 if (!(hi = modcmd_get_handle_info(user, argv[1])))
803 if (!(hi = modcmd_get_handle_info(user, argv[2])))
807 char *slfh_name = fakehost;
808 char *tlfh_name = strchr(fakehost, '.');
811 if(strchr(tlfh_name, '.')) {
812 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
815 struct hs_toplevel *tlfh;
816 struct hs_secondlevel *slfh = NULL;
817 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
818 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
821 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
824 if(!irccasecmp(slfh_name, "*")) {
825 if(!check_management_access(user->handle_info, tlfh, NULL)) {
826 reply("HSMSG_ACCESS_DENIED");
830 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
831 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
834 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
837 if(!check_management_access(user->handle_info, tlfh, slfh)) {
838 reply("HSMSG_ACCESS_DENIED");
842 struct hs_user *huser = hs_get_user(hi, 1);
843 struct hs_manager *manager;
845 for(manager = huser->managements; manager; manager = manager->next) {
846 if(manager->type == 2 && manager->object == slfh) {
847 reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
852 for(manager = huser->managements; manager; manager = manager->next) {
853 if(manager->type == 1 && manager->object == tlfh) {
854 reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
859 hs_add_manager_secondlevel(slfh, huser);
861 hs_add_manager_toplevel(tlfh, huser);
862 reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
868 static MODCMD_FUNC(cmd_delmanager) {
869 struct handle_info *hi;
871 if(!strchr(argv[1], '.')) {
872 if (!(hi = modcmd_get_handle_info(user, argv[1])))
876 if (!(hi = modcmd_get_handle_info(user, argv[2])))
880 char *slfh_name = fakehost;
881 char *tlfh_name = strchr(fakehost, '.');
885 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
889 if(strchr(tlfh_name, '.')) {
890 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
893 struct hs_toplevel *tlfh;
894 struct hs_secondlevel *slfh = NULL;
895 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
896 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
899 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
902 if(!irccasecmp(slfh_name, "*")) {
903 if(!check_management_access(user->handle_info, tlfh, NULL)) {
904 reply("HSMSG_ACCESS_DENIED");
908 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
909 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
912 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
915 if(!check_management_access(user->handle_info, tlfh, slfh)) {
916 reply("HSMSG_ACCESS_DENIED");
920 struct hs_user *huser = hs_get_user(hi, 0);
921 struct hs_manager *manager;
923 reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
927 for(manager = huser->managements; manager; manager = manager->next) {
928 if(manager->type == 2 && manager->object == slfh)
932 reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
936 for(manager = huser->managements; manager; manager = manager->next) {
937 if(manager->type == 1 && manager->object == tlfh)
941 reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
945 hs_del_manager(manager, 1);
946 reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
950 static MODCMD_FUNC(cmd_set) {
951 struct handle_info *hi;
952 struct hs_user *hs_user;
953 struct hs_assignment *assignment;
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 if(hs_get_assignment(slfh, hs_user)) {
1038 reply("HSMSG_FAKEHOST_ASSIGNED", slfh_name, tlfh_name);
1041 hs_add_assignment(slfh, hs_user);
1042 reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
1048 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1052 static MODCMD_FUNC(cmd_unassign) {
1053 struct handle_info *hi;
1055 if(!strchr(argv[1], '.')) {
1056 if (!(hi = modcmd_get_handle_info(user, argv[1])))
1060 if (!(hi = modcmd_get_handle_info(user, argv[2])))
1064 if (!user->handle_info) {
1065 reply("NSMSG_MUST_AUTH");
1068 char *slfh_name = fakehost;
1069 char *tlfh_name = strchr(fakehost, '.');
1073 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1077 if(strchr(tlfh_name, '.')) {
1078 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1081 struct hs_assignment *assignment;
1082 struct hs_user *hs_user = hs_get_user(hi, 0);
1084 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1087 for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1088 if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
1089 if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
1090 if(!check_management_access(user->handle_info, assignment->secondlevel->toplevel, assignment->secondlevel)) {
1091 reply("HSMSG_ACCESS_DENIED");
1094 hs_del_assignment(assignment, 1);
1095 reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
1100 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1104 static void hostserv_conf_read(void) {
1108 str = "modules/hostserv";
1109 if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1110 log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1114 str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1115 if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
1118 hostserv_conf.nick = str;
1120 str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1121 hostserv_conf.modes = (str ? str : NULL);
1123 str = database_get_data(conf_node, "toplevel_access", RECDB_QSTRING);
1124 unsigned int toplevel_access = atoi(str);
1125 hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
1127 str = database_get_data(conf_node, "fallback_other_assignment", RECDB_QSTRING);
1128 hostserv_conf.fallback_other_assignment = (atoi(str) ? 1 : 0);
1130 str = database_get_data(conf_node, "manager_can_del_toplevel", RECDB_QSTRING);
1131 hostserv_conf.manager_can_del_toplevel = (atoi(str) ? 1 : 0);
1133 str = database_get_data(conf_node, "manager_can_del_secondlevel", RECDB_QSTRING);
1134 hostserv_conf.manager_can_del_secondlevel = (atoi(str) ? 1 : 0);
1136 /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
1137 hostserv_conf.description = (str ? str : NULL);*/
1140 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));
1141 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra));
1143 static int hostserv_saxdb_read_toplevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1144 struct record_data *rd = data;
1145 struct hs_toplevel *tlfh;
1146 struct hs_manager *managerTL;
1147 struct hs_user *user;
1148 struct dict *object;
1150 if (rd->type == RECDB_OBJECT) {
1151 dict_t db = GET_RECORD_OBJECT(rd);
1154 tlfh = hs_add_toplevel(name);
1156 if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1157 for (it = dict_first(object); it; it = iter_next(it)) {
1158 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1159 //rd = iter_data(it);
1160 /* nothing in here, yet */
1161 managerTL = hs_add_manager_toplevel(tlfh, user);
1162 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1163 managerTL->active = 1;
1165 managerTL->active = 0;
1169 if ((object = database_get_data(db, KEY_SECONDLEVEL, RECDB_OBJECT)))
1170 dict_foreach(object, hostserv_saxdb_read_secondlevel, tlfh);
1175 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1176 struct record_data *rd = data;
1177 struct hs_toplevel *tlfh = extra;
1178 struct hs_secondlevel *slfh;
1179 struct hs_manager *managerSL;
1180 struct hs_user *user;
1181 struct dict *object;
1183 if (rd->type == RECDB_OBJECT) {
1184 dict_t db = GET_RECORD_OBJECT(rd);
1187 slfh = hs_add_secondlevel(tlfh, name);
1189 if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1190 for (it = dict_first(object); it; it = iter_next(it)) {
1191 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1192 //rd = iter_data(it);
1193 /* nothing in here, yet */
1194 managerSL = hs_add_manager_secondlevel(slfh, user);
1195 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1196 managerSL->active = 1;
1198 managerSL->active = 0;
1202 if ((object = database_get_data(db, KEY_ASSIGNMENTS, RECDB_OBJECT)))
1203 dict_foreach(object, hostserv_saxdb_read_assignments, slfh);
1208 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra)) {
1209 struct record_data *rd = data;
1210 struct hs_secondlevel *slfh = extra;
1211 struct hs_user *user;
1212 struct hs_assignment *assng;
1214 if (rd->type == RECDB_OBJECT) {
1215 dict_t db = GET_RECORD_OBJECT(rd);
1217 user = hs_get_user(get_handle_info(name), 1);
1218 assng = hs_add_assignment(slfh, user);
1220 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1230 hostserv_saxdb_read(struct dict *db)
1232 struct dict *object;
1234 if ((object = database_get_data(db, KEY_TOPLEVEL, RECDB_OBJECT)))
1235 dict_foreach(object, hostserv_saxdb_read_toplevel, NULL);
1241 hostserv_saxdb_write(struct saxdb_context *ctx)
1243 struct hs_toplevel *tlfh;
1244 struct hs_secondlevel *slfh;
1245 struct hs_assignment *assng;
1246 struct hs_manager *manager;
1248 saxdb_start_record(ctx, KEY_TOPLEVEL, 1);
1249 for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1250 saxdb_start_record(ctx, tlfh->fakehost, 1);
1252 saxdb_start_record(ctx, KEY_MANAGERS, 1);
1253 for(manager = tlfh->managers; manager; manager = manager->next) {
1254 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1255 //additional manager information?
1257 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1258 saxdb_end_record(ctx);
1260 saxdb_end_record(ctx);
1262 saxdb_start_record(ctx, KEY_SECONDLEVEL, 1);
1263 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1264 saxdb_start_record(ctx, slfh->fakehost, 1);
1266 saxdb_start_record(ctx, KEY_MANAGERS, 1);
1267 for(manager = slfh->managers; manager; manager = manager->next) {
1268 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1269 //additional manager information?
1271 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1272 saxdb_end_record(ctx);
1274 saxdb_end_record(ctx);
1276 saxdb_start_record(ctx, KEY_ASSIGNMENTS, 1);
1277 for(assng = slfh->assignments; assng; assng = assng->next) {
1278 saxdb_start_record(ctx, assng->user->hi->handle, 0);
1279 //additional assignment information?
1281 saxdb_write_int(ctx, KEY_ACTIVE, assng->active);
1282 saxdb_end_record(ctx);
1284 saxdb_end_record(ctx);
1286 saxdb_end_record(ctx);
1288 saxdb_end_record(ctx);
1290 saxdb_end_record(ctx);
1292 saxdb_end_record(ctx);
1298 static void hostserv_db_cleanup(void) {
1302 int hostserv_init() {
1303 HS_LOG = log_register_type("HostServ", "file:hostserv.log");
1305 const char *nick, *modes;
1306 if((nick = conf_get_data("modules/hostserv/nick", RECDB_QSTRING))) {
1307 modes = conf_get_data("modules/hostserv/modes", RECDB_QSTRING);
1308 hostserv = AddLocalUser(nick, nick, NULL, "Host Service", modes);
1309 hostserv_service = service_register(hostserv);
1310 hostserv_service->trigger = '*';
1313 conf_register_reload(hostserv_conf_read);
1314 reg_exit_func(hostserv_db_cleanup);
1315 saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
1316 hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
1317 modcmd_register(hostserv_module, "view", cmd_view, 0, MODCMD_REQUIRE_AUTHED, NULL);
1318 modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1319 modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1320 modcmd_register(hostserv_module, "set", cmd_set, 2, MODCMD_REQUIRE_AUTHED, NULL);
1321 modcmd_register(hostserv_module, "assign", cmd_assign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1322 modcmd_register(hostserv_module, "unassign", cmd_unassign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1323 modcmd_register(hostserv_module, "addhost", cmd_addhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1324 modcmd_register(hostserv_module, "delhost", cmd_delhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1325 message_register_table(msgtab);
1329 int hostserv_finalize(void) {
1333 str = "modules/hostserv";
1334 if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1335 log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1339 str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1340 if (str) hostserv_conf.nick = str;
1342 str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1343 if (str) hostserv_conf.modes = str;