Merge branch 'HostServ' of ssh://git.pk910.de:16110/srvx into HostServ
authorpk910 <philipp@zoelle1.de>
Fri, 4 Jan 2013 20:05:47 +0000 (21:05 +0100)
committerpk910 <philipp@zoelle1.de>
Fri, 4 Jan 2013 20:05:47 +0000 (21:05 +0100)
1  2 
src/mod-hostserv.c

diff --combined src/mod-hostserv.c
index 152eed0fb7333f055eec973140bdf3be2e3b7537,9084ac1d3158a6ff423255b525b59238dac8d55b..fbba68cb27893f073f10ab5f17c20b3a4cebfe61
  #include "modcmd.h"
  #include "saxdb.h"
  #include "timeq.h"
- #include "gline.h"
  
  #define KEY_TOPLEVEL "TopLevel"
  #define KEY_SECONDLEVEL "SecondLevel"
  #define KEY_MANAGERS "Manager"
  #define KEY_ASSIGNMENTS "Assignments"
  #define KEY_ACTIVE "active"
 -#define KEY_TITLEHOST_SUFFIX "title_suffix"
  
  static const struct message_entry msgtab[] = {
 +    { "HSMSG_ACCESS_DENIED", "Access denied." },
      { "HSMSG_ASSIGNED_FAKEHOSTS", "Assigned Fakehosts for User $b%s$b:" },
      { "HSMSG_ASSIGNED_FAKEHOST", "  $b%s.%s$b" },
      { "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE", "  $b%s.%s$b (active)" },
@@@ -91,9 -90,6 +90,9 @@@ static struct 
      const char *nick;
      const char *modes;
      int toplevel_access;
 +    int fallback_other_assignment : 1;
 +    int manager_can_del_toplevel : 1;
 +    int manager_can_del_secondlevel : 1;
  } hostserv_conf;
  
  const char *hostserv_module_deps[] = { NULL };
@@@ -104,6 -100,7 +103,6 @@@ static struct service *hostserv_service
  static struct log_type *HS_LOG;
  static struct hs_toplevel *toplevels = NULL;
  static struct hs_user *hostserv_users = NULL;
 -const char *title_suffix = NULL;
  
  /* FAKEHOST STRUCTS */
  struct hs_toplevel {
@@@ -151,6 -148,67 +150,6 @@@ static void hs_del_manager(struct hs_ma
  static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
  static void hs_del_user(struct hs_user *user);
  
 -static void apply_fakehost(struct handle_info *handle, struct userNode *user);
 -
 -static char *
 -generate_fakehost(struct handle_info *handle)
 -{
 -    extern const char *hidden_host_suffix;
 -    static char buffer[HOSTLEN+1];
 -
 -    if (!handle->fakehost) {
 -        snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
 -        return buffer;
 -    } else if (handle->fakehost[0] == '.') {
 -        /* A leading dot indicates the stored value is actually a title. */
 -        snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, title_suffix);
 -        return buffer;
 -    } else if (handle->fakehost[0] == '$') {
 -        /* A leading $ indicates the stored value begins with the user handle. */
 -        snprintf(buffer, sizeof(buffer), "%s%s", handle->handle, handle->fakehost+1);
 -        return buffer;
 -    }
 -    return handle->fakehost;
 -}
 -
 -static char *
 -generate_fakeident(struct handle_info *handle, struct userNode *user)
 -{
 -    static char buffer[USERLEN+1];
 -
 -    if (!handle->fakeident) {
 -        if (!user)
 -            return NULL;
 -        safestrncpy(buffer, user->ident, sizeof(buffer));
 -        return buffer;
 -    }
 -    return handle->fakeident;
 -}
 -
 -static void
 -apply_fakehost(struct handle_info *handle, struct userNode *user)
 -{
 -    struct userNode *target;
 -    char *fakehost, *fakeident;
 -
 -    if (!handle->users)
 -        return;
 -
 -    fakehost = generate_fakehost(handle);
 -
 -    if (user) {
 -        fakeident = generate_fakeident(handle, user);
 -        assign_fakehost(user, fakehost, fakeident, 0, 1);
 -        return;
 -    }
 -
 -    for (target = handle->users; target; target = target->next_authed) {
 -        fakeident = generate_fakeident(handle, target);
 -        assign_fakehost(target, fakehost, fakeident, 0, 1);
 -    }
 -    return;
 -}
 -
  static void hs_free_all() {
      struct hs_toplevel *tlfh, *next_tlfh;
      struct hs_secondlevel *slfh, *next_slfh;
@@@ -330,33 -388,26 +329,33 @@@ static void hs_del_manager(struct hs_ma
      free(manager);
  }
  
 -static void activateAssignment(struct hs_assignment *assignment) {
 +static void hs_activate_assignment(struct hs_user *user, struct hs_assignment *assignment) {
      struct hs_toplevel *tlfh;
      struct hs_secondlevel *slfh;
 -    struct hs_user *hs_user;
      struct hs_assignment *assgn;
 -    char fakehost[140];
 -    char *prefix = "$";
 +    char fakehost[HOSTLEN];
 +    
 +    assert((!assignment || (assignment->user == user)));
      
 -    hs_user = assignment->user;
 -    if(hs_user->assignments) {
 -        for(assgn = hs_user->assignments; assgn; assgn = assgn->unext) {
 +    if(user->assignments) {
 +        for(assgn = assignment->user->assignments; assgn; assgn = assgn->unext)
              assgn->active = 0;
 -        }
      }
 -    slfh = assignment->secondlevel;
 -    tlfh = slfh->toplevel;
 -    sprintf(fakehost, "%s.%s.%s", prefix, slfh->fakehost, tlfh->fakehost);
 -    hs_user->hi->fakehost = strdup(fakehost);
 -    apply_fakehost(hs_user->hi, NULL);
 -    assignment->active = 1;
 +    
 +    if(user->hi->fakehost) {
 +        free(user->hi->fakehost);
 +        user->hi->fakehost = NULL;
 +    }
 +    
 +    if(assignment) {
 +        slfh = assignment->secondlevel;
 +        tlfh = slfh->toplevel;
 +        snprintf(fakehost, sizeof(fakehost), "$.%s.%s", slfh->fakehost, tlfh->fakehost);
 +        user->hi->fakehost = strdup(fakehost);
 +        assignment->active = 1;
 +    }
 +    
 +    apply_fakehost(assignment->user->hi, NULL);
  }
  
  static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
      assignment->unext = user->assignments;
      user->assignments = assignment;
      if(assignment->active) {
 -        activateAssignment(assignment);
 +        hs_activate_assignment(user, assignment);
      }
      return assignment;
  }
@@@ -404,19 -455,11 +403,19 @@@ static void hs_del_assignment(struct hs
          }
          
          if(assignment->active) {
 -            struct handle_info *hi;
 -            
 -            hi = assignment->user->hi;
 -            hi->fakehost = NULL;
 -            apply_fakehost(hi, NULL);
 +            /* use another assignment - or fall back to default user host? */
 +            cassignment = NULL;
 +            if(hostserv_conf.fallback_other_assignment && assignment->user->assignments) {
 +                /* try to find another assignment from same slfh first */
 +                for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
 +                    if(cassignment != assignment && cassignment->user == assignment->user)
 +                        break;
 +                }
 +                /* use another tlfh assignment */
 +                if(!cassignment)
 +                    cassignment = assignment->user->assignments;
 +            }
 +            hs_activate_assignment(assignment->user, cassignment);
          }
          
          if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
      free(assignment);
  }
  
 +static struct hs_assignment *hs_get_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
 +    struct hs_assignment *cassignment;
 +    for(cassignment = slfh->assignments; cassignment; cassignment = cassignment->next) {
 +        if(cassignment->user == user)
 +            return cassignment;
 +    }
 +    return NULL;
 +}
 +
  static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
      struct hs_user *cuser;
      for(cuser = hostserv_users; cuser; cuser = cuser->next) {
@@@ -565,6 -599,112 +564,6 @@@ static void cmd_view_secondlevel_inform
      }
  }
  
 -static MODCMD_FUNC(cmd_addhost) {
 -    struct handle_info *hi;
 -    if (!(hi = user->handle_info)) {
 -        reply("NSMSG_MUST_AUTH");
 -        return 0;
 -    }
 -    char *slfh_name = argv[1];
 -    char *tlfh_name = strchr(argv[1], '.');
 -    if(!tlfh_name) {
 -        reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
 -        return 0;
 -    }
 -    *tlfh_name = '\0';
 -    tlfh_name++;
 -    if(strchr(tlfh_name, '.')) {
 -        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -        return 0;
 -    }
 -    if(!irccasecmp(slfh_name, "*")) {
 -        if(hi->opserv_level >= hostserv_conf.toplevel_access) {
 -            struct hs_toplevel *tlfh;
 -            for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 -                if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 -            }
 -            if(tlfh) {
 -                reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
 -                return 0;
 -            }
 -            hs_add_toplevel(tlfh_name);
 -            reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
 -            return 1;
 -        }
 -        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -        return 0;
 -    } else {
 -        struct hs_secondlevel *slfh;
 -        struct hs_toplevel *tlfh;
 -        for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 -            if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 -        }
 -        if(!tlfh) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -            return 0;
 -        }
 -        for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
 -            if(!irccasecmp(slfh->fakehost, slfh_name)) break;
 -        }
 -        if(slfh) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -            return 0;
 -        }
 -        if(!check_management_access(hi, tlfh, NULL)) {
 -            reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
 -            return 0;
 -        }
 -        hs_add_secondlevel(tlfh, slfh_name);
 -        reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
 -    }
 -    return 0;
 -}
 -
 -static MODCMD_FUNC(cmd_delhost) {
 -    struct handle_info *hi;
 -    if (!(hi = user->handle_info)) {
 -        reply("NSMSG_MUST_AUTH");
 -        return 0;
 -    }
 -    char *slfh_name = argv[1];
 -    char *tlfh_name = strchr(argv[1], '.');
 -    *tlfh_name = '\0';
 -    tlfh_name++;
 -    if(strchr(tlfh_name, '.')) {
 -        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -        return 0;
 -    }
 -    struct hs_toplevel *tlfh;
 -    for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 -        if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 -    }
 -    if(!tlfh) {
 -        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -        return 0;
 -    }
 -    if(!irccasecmp(slfh_name, "*")) {
 -        if(hi->opserv_level < hostserv_conf.toplevel_access) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -            return 0;
 -        }
 -        hs_del_toplevel(tlfh);
 -        reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
 -        return 1;
 -    } else {
 -        struct hs_secondlevel *slfh;
 -        for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
 -            if(!irccasecmp(slfh->fakehost, slfh_name)) break;
 -        }
 -        if(!slfh || !check_management_access(hi, tlfh, NULL)) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -            return 0;
 -        }
 -        hs_del_secondlevel(slfh, 1);
 -        reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
 -    }
 -    return 0;
 -}
 -
  static MODCMD_FUNC(cmd_view) {
      struct handle_info *hi;
      if(argc >= 2 && !strchr(argv[1], '.')) {
      return 1;
  }
  
 +static MODCMD_FUNC(cmd_addhost) {
 +    struct handle_info *hi;
 +    struct hs_toplevel *tlfh;
 +    struct hs_secondlevel *slfh;
 +    if (!(hi = user->handle_info)) {
 +        reply("NSMSG_MUST_AUTH");
 +        return 0;
 +    }
 +    char *slfh_name = argv[1];
 +    char *tlfh_name = strchr(argv[1], '.');
 +    if(!tlfh_name) {
 +        reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
 +        return 0;
 +    }
 +    *tlfh_name = '\0';
 +    tlfh_name++;
 +    if(strchr(tlfh_name, '.')) {
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +        return 0;
 +    }
 +    if(!irccasecmp(slfh_name, "*")) {
 +        if(!check_management_access(hi, NULL, NULL)) {
 +            reply("HSMSG_ACCESS_DENIED");
 +            return NULL;
 +        }
 +        for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 +            if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 +        }
 +        if(tlfh) {
 +            reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
 +            return 0;
 +        }
 +        hs_add_toplevel(tlfh_name);
 +        reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
 +    } else {
 +        for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 +            if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 +        }
 +        if(!tlfh) {
 +            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +            return 0;
 +        }
 +        if(!check_management_access(hi, tlfh, NULL)) {
 +            reply("HSMSG_ACCESS_DENIED");
 +            return 0;
 +        }
 +        for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
 +            if(!irccasecmp(slfh->fakehost, slfh_name)) break;
 +        }
 +        if(slfh) {
 +            reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
 +            return 0;
 +        }
 +        hs_add_secondlevel(tlfh, slfh_name);
 +        reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
 +    }
 +    return 1;
 +}
 +
 +static MODCMD_FUNC(cmd_delhost) {
 +    struct handle_info *hi;
 +    if (!(hi = user->handle_info)) {
 +        reply("NSMSG_MUST_AUTH");
 +        return 0;
 +    }
 +    char *slfh_name = argv[1];
 +    char *tlfh_name = strchr(argv[1], '.');
 +    *tlfh_name = '\0';
 +    tlfh_name++;
 +    if(strchr(tlfh_name, '.')) {
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +        return 0;
 +    }
 +    struct hs_toplevel *tlfh;
 +    for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
 +        if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
 +    }
 +    if(!tlfh) {
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +        return 0;
 +    }
 +    if(!irccasecmp(slfh_name, "*")) {
 +        if(!check_management_access(hi, (hostserv_conf.manager_can_del_toplevel ? tlfh : NULL), NULL)) { /* manager access is enough to delete whole toplevel? */
 +            reply("HSMSG_ACCESS_DENIED");
 +            return 0;
 +        }
 +        hs_del_toplevel(tlfh);
 +        reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
 +    } else {
 +        struct hs_secondlevel *slfh;
 +        for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
 +            if(!irccasecmp(slfh->fakehost, slfh_name)) break;
 +        }
 +        if(!slfh) {
 +            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +            return 0;
 +        }
 +        if(!check_management_access(hi, tlfh, (hostserv_conf.manager_can_del_secondlevel ? slfh : NULL))) {
 +            reply("HSMSG_ACCESS_DENIED");
 +            return 0;
 +        }
 +        hs_del_secondlevel(slfh, 1);
 +        reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
 +    }
 +    return 1;
 +}
 +
  static MODCMD_FUNC(cmd_addmanager) {
      struct handle_info *hi;
      char *fakehost;
          }
          if(!irccasecmp(slfh_name, "*")) {
              if(!check_management_access(user->handle_info, tlfh, NULL)) {
 -                reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +                reply("HSMSG_ACCESS_DENIED");
                  return 0;
              }
          } else {
              for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
                  if(!irccasecmp(slfh->fakehost, slfh_name)) break;
              }
 -            if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
 +            if(!slfh) {
                  reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
                  return 0;
              }
 +            if(!check_management_access(user->handle_info, tlfh, slfh)) {
 +                reply("HSMSG_ACCESS_DENIED");
 +                return 0;
 +            }
          }
          struct hs_user *huser = hs_get_user(hi, 1);
          struct hs_manager *manager;
@@@ -877,12 -906,16 +876,12 @@@ static MODCMD_FUNC(cmd_delmanager) 
              return 0;
          fakehost = argv[1];
      }
 -    if(!fakehost) {
 -        reply("HSMSG_ASSIGNED_NONE");
 -        return 0;
 -    }
      char *slfh_name = fakehost;
      char *tlfh_name = strchr(fakehost, '.');
      if(tlfh_name) {
          *tlfh_name = '\0';
      } else {
 -        reply("HSMSG_ASSIGNED_NONE");
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
          return 0;
      }
      tlfh_name++;
      }
      if(!irccasecmp(slfh_name, "*")) {
          if(!check_management_access(user->handle_info, tlfh, NULL)) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +            reply("HSMSG_ACCESS_DENIED");
              return 0;
          }
      } else {
          for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
              if(!irccasecmp(slfh->fakehost, slfh_name)) break;
          }
 -        if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
 +        if(!slfh) {
              reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
              return 0;
          }
 +        if(!check_management_access(user->handle_info, tlfh, slfh)) {
 +            reply("HSMSG_ACCESS_DENIED");
 +            return 0;
 +        }
      }
      struct hs_user *huser = hs_get_user(hi, 0);
      struct hs_manager *manager;
@@@ -961,33 -990,37 +960,33 @@@ static MODCMD_FUNC(cmd_set) 
          return 0;
      }
      hs_user = hs_get_user(hi, 0);
 +    if(!hs_user)
 +        return 0; //nothing to do here
      if(!strcmp(argv[1], "*")) {
 -        hi->fakehost = NULL;
 -        apply_fakehost(hi, NULL);
 -        if(hs_user->assignments) {
 -            for(assgn = hs_user->assignments; assgn; assgn = assgn->unext) {
 -                assgn->active = 0;
 -            }
 -        }
 +        hs_activate_assignment(hs_user, NULL);
          return 1;
      } else {
          if(!strchr(argv[1], '.')) {
 -            return 0;
 +            
          }
          fakehost = argv[1];
          char *slfh_name = fakehost;
          char *tlfh_name = strchr(fakehost, '.');
 -        *tlfh_name = '\0';
 -        tlfh_name++;
 -        if(strchr(tlfh_name, '.')) {
 -            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +        if(tlfh_name) {
 +            *tlfh_name = '\0';
 +            tlfh_name++;
 +        }
 +        if(!tlfh_name || strchr(tlfh_name, '.')) {
 +            reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, (tlfh_name ? tlfh_name : ""));
              return 0;
          }
          for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
              slfh = assignment->secondlevel;
              tlfh = slfh->toplevel;
 -            if(!irccasecmp(slfh_name, slfh->fakehost)) {
 -                if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
 -                    activateAssignment(assignment);
 -                    reply("HSMSG_FAKEHOST_SET_SUCCESS", slfh->fakehost, tlfh->fakehost);
 -                    return 1;
 -                }
 +            if(!irccasecmp(tlfh_name, tlfh->fakehost) && !irccasecmp(slfh_name, slfh->fakehost)) {
 +                hs_activate_assignment(hs_user, assignment);
 +                reply("HSMSG_FAKEHOST_SET_SUCCESS", slfh->fakehost, tlfh->fakehost);
 +                return 1;
              }
          }
          reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
  
  static MODCMD_FUNC(cmd_assign) {
      struct handle_info *hi;
 -    struct handle_info *hiuser;
      char *fakehost;
      if(!strchr(argv[1], '.')) {
          if (!(hi = modcmd_get_handle_info(user, argv[1])))
              return 0;
          fakehost = argv[1];
      }
 -    if (!(hiuser = user->handle_info)) {
 +    if (!user->handle_info) {
          reply("NSMSG_MUST_AUTH");
          return 0;
      }
 -    if(!fakehost) {
 -        reply("HSMSG_ASSIGNED_NONE");
 -        return 0;
 -    }
      char *slfh_name = fakehost;
      char *tlfh_name = strchr(fakehost, '.');
      if(tlfh_name) {
          *tlfh_name = '\0';
      } else {
 -        reply("HSMSG_ASSIGNED_NONE");
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
          return 0;
      }
      tlfh_name++;
          reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
          return 0;
      }
 -    struct hs_toplevel *tlfh;;
 +    struct hs_toplevel *tlfh;
      struct hs_secondlevel *slfh;
      struct hs_user *hs_user = hs_get_user(hi, 1);
      for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
          if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
              for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
                  if(!irccasecmp(slfh_name, slfh->fakehost)) {
 -                    if(check_management_access(hiuser, tlfh, slfh)) {
 -                        hs_add_assignment(slfh, hs_user);
 -                        reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
 -                        return 1;
 +                    if(!check_management_access(user->handle_info, tlfh, slfh)) {
 +                        reply("HSMSG_ACCESS_DENIED");
 +                        return 0;
                      }
 -                    reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -                    return 0;
 +                    hs_add_assignment(slfh, hs_user);
 +                    reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
 +                    return 1;
                  }
              }
          }
  
  static MODCMD_FUNC(cmd_unassign) {
      struct handle_info *hi;
 -    struct handle_info *hiuser;
      char *fakehost;
      if(!strchr(argv[1], '.')) {
          if (!(hi = modcmd_get_handle_info(user, argv[1])))
              return 0;
          fakehost = argv[1];
      }
 -    if (!(hiuser = user->handle_info)) {
 +    if (!user->handle_info) {
          reply("NSMSG_MUST_AUTH");
          return 0;
      }
 -    if(!fakehost) {
 -        reply("HSMSG_ASSIGNED_NONE");
 -        return 0;
 -    }
      char *slfh_name = fakehost;
      char *tlfh_name = strchr(fakehost, '.');
      if(tlfh_name) {
          *tlfh_name = '\0';
      } else {
 -        reply("HSMSG_ASSIGNED_NONE");
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
          return 0;
      }
      tlfh_name++;
      }
      struct hs_assignment *assignment;
      struct hs_user *hs_user = hs_get_user(hi, 0);
 +    if(!hs_user) {
 +        reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 +        return 0;
 +    }
      for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
          if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
              if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
 -                if(check_management_access(hiuser, assignment->secondlevel->toplevel, assignment->secondlevel)) {
 -                    hs_del_assignment(assignment, 1);
 -                    reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
 -                    return 1;
 +                if(!check_management_access(user->handle_info, assignment->secondlevel->toplevel, assignment->secondlevel)) {
 +                    reply("HSMSG_ACCESS_DENIED");
 +                    return 0;
                  }
 -                reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
 -                return 0;
 +                hs_del_assignment(assignment, 1);
 +                reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
 +                return 1;
              }
          }
      }
      return 0;
  }
  
 -static void hostserv_conf_read(void)
 -{
 +static void hostserv_conf_read(void) {
      dict_t conf_node;
      const char *str;
  
      unsigned int toplevel_access = atoi(str);
      hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
      
 +    str = database_get_data(conf_node, "fallback_other_assignment", RECDB_QSTRING);
 +    hostserv_conf.fallback_other_assignment = (atoi(str) ? 1 : 0);
 +    
 +    str = database_get_data(conf_node, "manager_can_del_toplevel", RECDB_QSTRING);
 +    hostserv_conf.manager_can_del_toplevel = (atoi(str) ? 1 : 0);
 +    
 +    str = database_get_data(conf_node, "manager_can_del_secondlevel", RECDB_QSTRING);
 +    hostserv_conf.manager_can_del_secondlevel = (atoi(str) ? 1 : 0);
 +    
      /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
      hostserv_conf.description = (str ? str : NULL);*/
 -    str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
 -    title_suffix = str ? str : "example.net";
  }
  
  static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));