コード例 #1
0
ファイル: mod_memcache.c プロジェクト: laoflch/proftpd
static void mcache_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;
  config_rec *c;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&memcache_module, "core.exit", mcache_exit_ev);
  pr_event_unregister(&memcache_module, "core.session-reinit",
    mcache_sess_reinit_ev);

  (void) close(memcache_logfd);
  memcache_logfd = -1;

  c = find_config(session.prev_server->conf, CONF_PARAM, "MemcacheServers",
    FALSE);
  if (c != NULL) {
    memcached_server_st *memcache_servers;

    memcache_servers = c->argv[0];
    memcache_set_servers(memcache_servers);
  }

  /* XXX Restore other memcache settings? */
  /* reset MemcacheOptions */
  /* reset MemcacheReplicas */
  /* reset MemcacheTimeout */

  res = mcache_sess_init();
  if (res < 0) {
    pr_session_disconnect(&memcache_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}
コード例 #2
0
ファイル: mod_qos.c プロジェクト: Nakor78/proftpd
static void qos_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&qos_module, "core.data-connect", qos_data_connect_ev);
  pr_event_unregister(&qos_module, "core.data-listen", qos_data_listen_ev);
  pr_event_unregister(&qos_module, "core.session-reinit", qos_sess_reinit_ev);

  res = qos_sess_init();
  if (res < 0) {
    pr_session_disconnect(&qos_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}
コード例 #3
0
static void log_failure_mod_unload_ev(const void *event_data, void *user_data) {
  if (strcmp("mod_log_failure.c", (const char *) event_data) == 0) {
    pr_event_unregister(&log_failure_module, NULL);
    destroy_pool(log_failure_pool);
    log_failure_pool = NULL;
  }
}
コード例 #4
0
ファイル: mod_memcache.c プロジェクト: UIKit0/proftpd
MODRET memcache_post_host(cmd_rec *cmd) {

  /* If the HOST command changed the main_server pointer, reinitialize
   * ourselves.
   */
  if (session.prev_server != NULL) {
    int res;
    config_rec *c;

    pr_event_unregister(&memcache_module, "core.exit", mcache_exit_ev);
    (void) close(memcache_logfd);

    c = find_config(session.prev_server->conf, CONF_PARAM, "MemcacheServers",
      FALSE);
    if (c != NULL) {
      memcached_server_st *memcache_servers;

      memcache_servers = c->argv[0];
      memcache_set_servers(memcache_servers);
    }

    /* XXX Restore other memcache settings? */

    res = mcache_sess_init();
    if (res < 0) {
      pr_session_disconnect(&memcache_module,
        PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
    }
  }

  return PR_DECLINED(cmd);
}
コード例 #5
0
ファイル: event.c プロジェクト: Distrotech/proftpd
static void set_up(void) {
  if (p == NULL) {
    p = permanent_pool = make_sub_pool(NULL);
  }

  pr_event_unregister(NULL, NULL, NULL);
}
コード例 #6
0
static void counter_mod_unload_ev(const void *event_data, void *user_data) {
  if (strcmp("mod_counter.c", (const char *) event_data) == 0) {
    pr_event_unregister(&counter_module, NULL, NULL);

    if (counter_pool) {
      destroy_pool(counter_pool);
    }
  }
}
コード例 #7
0
ファイル: mod_dynmasq.c プロジェクト: predever/proftpd
static int dynmasq_sess_init(void) {

    /* Ensure that the timer only fires on the daemon process. */
    pr_timer_remove(dynmasq_timer_id, &dynmasq_module);
    dynmasq_timer_id = -1;

    pr_event_unregister(&dynmasq_module, "core.restart", NULL);

    return 0;
}
コード例 #8
0
ファイル: mod_sftp_pam.c プロジェクト: jmaggard10/proftpd
static void sftppam_mod_unload_ev(const void *event_data, void *user_data) {
  if (strcmp("mod_sftp_pam.c", (const char *) event_data) == 0) {
    if (sftppam_user) {
      free(sftppam_user);
      sftppam_user = NULL;
      sftppam_userlen = 0;
    }

    sftp_kbdint_unregister_driver("pam");
    pr_event_unregister(&sftp_pam_module, NULL, NULL);
  }
}
コード例 #9
0
ファイル: event.c プロジェクト: Distrotech/proftpd
END_TEST

START_TEST (event_unregister_test) {
  int res;
  const char *event = "foo";

  res = pr_event_unregister(NULL, NULL, NULL);
  fail_unless(res == 0, "Failed to handle empty event lists");

  res = pr_event_register(NULL, event, event_cb, NULL);
  fail_unless(res == 0, "Failed to register event: %s", strerror(errno));

  res = pr_event_unregister(NULL, "bar", NULL);
  fail_unless(res == -1, "Failed to handle unregistered event");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");

  res = pr_event_unregister(NULL, event, event_cb2);
  fail_unless(res == -1, "Failed to handle unregistered event");
  fail_unless(errno == ENOENT, "Failed to set errno to ENOENT");

  res = pr_event_unregister(NULL, event, event_cb);
  fail_unless(res == 0, "Failed to unregister event: %s", strerror(errno));

  res = pr_event_register(NULL, event, event_cb, NULL);
  fail_unless(res == 0, "Failed to register event: %s", strerror(errno));

  res = pr_event_unregister(NULL, event, NULL);
  fail_unless(res == 0, "Failed to unregister event: %s", strerror(errno));

  res = pr_event_register(NULL, event, event_cb, NULL);
  fail_unless(res == 0, "Failed to register event: %s", strerror(errno));

  res = pr_event_unregister(NULL, NULL, NULL);
  fail_unless(res == 0, "Failed to unregister event: %s", strerror(errno));
}
コード例 #10
0
ファイル: signals.c プロジェクト: Nakor78/proftpd
static void finish_terminate(void) {
  if (is_master &&
      mpid == getpid()) {
    PRIVS_ROOT

    /* Do not need the pidfile any longer. */
    if (ServerType == SERVER_STANDALONE &&
        !nodaemon) {
      pr_pidfile_remove();
    }

    /* Run any exit handlers registered in the master process here, so that
     * they may have the benefit of root privs.  More than likely these
     * exit handlers were registered by modules' module initialization
     * functions, which also occur under root priv conditions.
     *
     * If an exit handler is registered after the fork(), it won't be run here;
     * that registration occurs in a different process space.
     */
    pr_event_generate("core.exit", NULL);
    pr_event_generate("core.shutdown", NULL);

    /* Remove the registered exit handlers now, so that the ensuing
     * pr_session_end() call (outside the root privs condition) does not call
     * the exit handlers for the master process again.
     */
    pr_event_unregister(NULL, "core.exit", NULL);
    pr_event_unregister(NULL, "core.shutdown", NULL);

    PRIVS_RELINQUISH

    if (ServerType == SERVER_STANDALONE) {
      pr_log_pri(PR_LOG_NOTICE, "ProFTPD " PROFTPD_VERSION_TEXT
        " standalone mode SHUTDOWN");

      /* Clean up the scoreboard */
      PRIVS_ROOT
      pr_delete_scoreboard();
      PRIVS_RELINQUISH
    }
コード例 #11
0
ファイル: mod_sql_postgres.c プロジェクト: Distrotech/proftpd
static void sql_postgres_mod_unload_ev(const void *event_data,
    void *user_data) {

  if (strcmp("mod_sql_postgres.c", (const char *) event_data) == 0) {
    /* Unegister ourselves with mod_sql. */
    if (sql_unregister_backend("postgres") < 0) {
      pr_log_pri(PR_LOG_NOTICE, MOD_SQL_POSTGRES_VERSION
        ": notice: error unregistering backend: %s", strerror(errno));
      pr_session_end(0);
    }

    /* Unregister ourselves from all events. */
    pr_event_unregister(&sql_postgres_module, NULL, NULL);
  }
}
コード例 #12
0
ファイル: trace.c プロジェクト: dbarba74/proftpd
static void trace_restart_ev(const void *event_data, void *user_data) {
  trace_opts = PR_TRACE_OPT_DEFAULT;

  close(trace_logfd);
  trace_logfd = -1;

  if (trace_pool) {
    destroy_pool(trace_pool);
    trace_pool = NULL;
    trace_tab = NULL;

    pr_event_unregister(NULL, "core.restart", trace_restart_ev);
  }

  return;
}
コード例 #13
0
ファイル: mod_wrap.c プロジェクト: laoflch/proftpd
static void wrap_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer; reinitialize ourselves. */

  pr_event_unregister(&wrap_module, "core.session-reinit", wrap_sess_reinit_ev);

  /* Reset defaults */
  wrap_service_name = "proftpd";

  res = wrap_sess_init();
  if (res < 0) {
    pr_session_disconnect(&wrap_module, PR_SESS_DISCONNECT_SESSION_INIT_FAILED,
      NULL);
  }
}
コード例 #14
0
ファイル: mod_dynmasq.c プロジェクト: predever/proftpd
static void dynmasq_mod_unload_ev(const void *event_data, void *user_data) {
    if (strcmp("mod_dynmasq.c", (const char *) event_data) == 0) {
        pr_event_unregister(&dynmasq_module, NULL, NULL);

# ifdef PR_USE_CTRLS
        /* Unregister any control actions. */
        pr_ctrls_unregister(&dynmasq_module, "dynmasq");

        destroy_pool(dynmasq_act_pool);
        dynmasq_act_pool = NULL;
# endif /* PR_USE_CTRLS */

        pr_timer_remove(dynmasq_timer_id, &dynmasq_module);
        dynmasq_timer_id = -1;

    }
}
コード例 #15
0
ファイル: event.c プロジェクト: Distrotech/proftpd
END_TEST

START_TEST (event_generate_test) {
  int res;
  const char *event = "foo";

  pr_event_generate(NULL, NULL);
  fail_unless(event_triggered == 0, "Expected triggered count %u, got %u",
    0, event_triggered);
  
  pr_event_generate(event, NULL);
  fail_unless(event_triggered == 0, "Expected triggered count %u, got %u",
    0, event_triggered);

  res = pr_event_register(NULL, event, event_cb, NULL);
  fail_unless(res == 0, "Failed to register event: %s", strerror(errno));

  pr_event_generate("bar", NULL);
  fail_unless(event_triggered == 0, "Expected triggered count %u, got %u",
    0, event_triggered);

  pr_event_generate(event, NULL);
  fail_unless(event_triggered == 1, "Expected triggered count %u, got %u",
    1, event_triggered);

  pr_event_generate(event, NULL);
  fail_unless(event_triggered == 2, "Expected triggered count %u, got %u",
    2, event_triggered);

  res = pr_event_unregister(NULL, NULL, NULL);
  fail_unless(res == 0, "Failed to unregister events: %s", strerror(errno));

  pr_event_generate(event, NULL);
  fail_unless(event_triggered == 2, "Expected triggered count %u, got %u",
    2, event_triggered);
}
コード例 #16
0
ファイル: mod_quotatab_file.c プロジェクト: OPSF/uClinux
static void filetab_mod_unload_ev(const void *event_data, void *user_data) {
  if (strcmp("mod_quotatab_file.c", (const char *) event_data) == 0) {
    pr_event_unregister(&quotatab_file_module, NULL, NULL);
    quotatab_unregister_backend("file", QUOTATAB_LIMIT_SRC|QUOTATAB_TALLY_SRC);
  }
}
コード例 #17
0
ファイル: mod_dso.c プロジェクト: Distrotech/proftpd
static int dso_sess_init(void) {
  pr_event_unregister(&dso_module, "core.restart", dso_restart_ev);
  return 0;
}
コード例 #18
0
ファイル: modules.c プロジェクト: SangramSahuFIS/proftpd
int pr_module_unload(module *m) {
  char buf[256];

  if (m == NULL ||
      m->name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Make sure this module has been loaded.  We can't unload a module that
   * has not been loaded, now can we?
   */

  memset(buf, '\0', sizeof(buf));
  snprintf(buf, sizeof(buf), "mod_%s.c", m->name);
  buf[sizeof(buf)-1] = '\0';

  if (pr_module_get(buf) == NULL) {
    errno = ENOENT;
    return -1;
  } 

  /* Generate an event. */
  pr_event_generate("core.module-unload", buf);

  /* Remove the module from the loaded_modules list. */
  if (m->prev) {
    m->prev->next = m->next;

  } else {
    /* This module is the start of the loaded_modules list (prev is NULL),
     * so we need to update that pointer, too.
     */
    loaded_modules = m->next;
  }

  if (m->next)
    m->next->prev = m->prev;

  m->prev = m->next = NULL;

  /* Remove the module's config, cmd, and auth tables. */
  if (m->conftable) {
    conftable *conftab;

    for (conftab = m->conftable; conftab->directive; conftab++) {
      pr_stash_remove_symbol(PR_SYM_CONF, conftab->directive, conftab->m);
    }
  }

  if (m->cmdtable) {
    cmdtable *cmdtab;

    for (cmdtab = m->cmdtable; cmdtab->command; cmdtab++) {
      if (cmdtab->cmd_type == HOOK) {
        pr_stash_remove_symbol(PR_SYM_HOOK, cmdtab->command, cmdtab->m);

      } else {
        /* All other cmd_types are for CMDs: PRE_CMD, CMD, POST_CMD, etc. */
        pr_stash_remove_symbol(PR_SYM_CMD, cmdtab->command, cmdtab->m);
      }
    }
  }

  if (m->authtable) {
    authtable *authtab;

    for (authtab = m->authtable; authtab->name; authtab++) {
      pr_stash_remove_symbol(PR_SYM_AUTH, authtab->name, authtab->m);
    }
  }

  /* Remove any callbacks that the module may have registered, i.e.:
   *
   * ctrls
   * events
   * timers
   *
   * Ideally we would also automatically unregister other callbacks that
   * the module may have registered, such as FSIO, NetIO, variables, and
   * response handlers.  However, these APIs do not yet allow for
   * removal of all callbacks for a given module.
   */

#ifdef PR_USE_CTRLS
  pr_ctrls_unregister(m, NULL);
#endif /* PR_USE_CTRLS */
  pr_event_unregister(m, NULL, NULL);
  pr_timer_remove(-1, m);

  return 0;
}
コード例 #19
0
ファイル: mod_qos.c プロジェクト: Nakor78/proftpd
static void qos_mod_unload_ev(const void *event_data, void *user_data) {
  if (strcmp("mod_qos.c", (const char *) event_data) == 0) {
    pr_event_unregister(&qos_module, NULL, NULL);
  }
}
コード例 #20
0
ファイル: mod_auth_file.c プロジェクト: jmaggard10/proftpd
/* usage: AuthGroupFile path [id <min-max>] [name <regex>] */
MODRET set_authgroupfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;
  char *path;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 5) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  path = cmd->argv[1];
  if (*path != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", (char *) cmd->argv[0], " '",
      path, "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthGroupFiles, unlike AuthUserFiles, do not contain any sensitive
   * information, and can thus be world-readable.
   */
  flags = PR_AUTH_FILE_FL_ALLOW_WORLD_READABLE;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", path, ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, path);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        gid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.gid = min;
        file->af_max_id.gid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* usage: AuthUserFile path [home <regexp>] [id <min-max>] [name <regex>] */
MODRET set_authuserfile(cmd_rec *cmd) {
  config_rec *c = NULL;
  authfile_file_t *file = NULL;
  int flags = 0;
  char *path;

#ifdef PR_USE_REGEX
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 7) {
#else
  if (cmd->argc-1 < 1 ||
      cmd->argc-1 > 2) {
#endif /* regex support */
    CONF_ERROR(cmd, "wrong number of parameters");
  }

  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

  path = cmd->argv[1];
  if (*path != '/') {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use relative path for ", (char *) cmd->argv[0], " '",
      path, "'.", NULL));
  }

  /* Make sure the configured file has the correct permissions.  Note that
   * AuthUserFiles, unlike AuthGroupFiles, DO contain any sensitive
   * information, and thus CANNOT be world-readable.
   */
  flags = 0;
  if (af_check_file(cmd->tmp_pool, cmd->argv[0], cmd->argv[1], flags) < 0) {
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
      "unable to use ", path, ": ", strerror(errno), NULL));
  }

  c = add_config_param(cmd->argv[0], 1, NULL);

  file = pcalloc(c->pool, sizeof(authfile_file_t));
  file->af_path = pstrdup(c->pool, path);
  c->argv[0] = (void *) file;

  /* Check for restrictions */
  if (cmd->argc-1 != 1) {
    register unsigned int i = 0;

    for (i = 2; i < cmd->argc; i++) {
      if (strncmp(cmd->argv[i], "id", 3) == 0) {
        uid_t min, max;
        char *sep = NULL, *tmp = NULL;

        /* The range restriction parameter is of the form "min-max", where max
         * must be >= min.
         */

        sep = strchr(cmd->argv[++i], '-');
        if (sep == NULL) {
          CONF_ERROR(cmd, "badly formatted ID restriction parameter");
        }

        *sep = '\0';

        min = strtol(cmd->argv[i], &tmp, 10);
        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted minimum ID");
        }

        tmp = NULL;

        max = strtol(sep+1, &tmp, 10);

        if (tmp && *tmp) {
          CONF_ERROR(cmd, "badly formatted maximum ID");
        }

        if (min > max) {
          CONF_ERROR(cmd, "minimum cannot be larger than maximum");
        }

        file->af_min_id.uid = min;
        file->af_max_id.uid = max;
        file->af_restricted_ids = TRUE;

#ifdef PR_USE_REGEX
      } else if (strncmp(cmd->argv[i], "home", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_home_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_home_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_home_regex = pre;
        file->af_restricted_homes = TRUE;

      } else if (strncmp(cmd->argv[i], "name", 5) == 0) {
        char *filter = cmd->argv[++i];
        pr_regex_t *pre = NULL;
        int res = 0;

        pre = pr_regexp_alloc(&auth_file_module);

        /* Check for a ! negation/inversion filter prefix. */
        if (*filter == '!') {
          filter++;
          file->af_name_regex_inverted = TRUE;
        }

        res = pr_regexp_compile(pre, filter, REG_EXTENDED|REG_NOSUB);
        if (res != 0) {
          char errstr[200] = {'\0'};

          pr_regexp_error(res, pre, errstr, sizeof(errstr));
          pr_regexp_free(NULL, pre);

          CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "'", filter, "' failed "
            "regex compilation: ", errstr, NULL));
        }

        file->af_name_filter = pstrdup(c->pool, cmd->argv[i]);
        file->af_name_regex = pre;
        file->af_restricted_names = TRUE;
#endif /* regex support */

      } else {
        CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown restriction '",
          cmd->argv[i], "'", NULL));
      }
    }
  }

  return PR_HANDLED(cmd);
}

/* Event listeners
 */

static void authfile_sess_reinit_ev(const void *event_data, void *user_data) {
  int res;

  /* A HOST command changed the main_server pointer, reinitialize ourselves. */

  pr_event_unregister(&auth_file_module, "core.session-reinit",
    authfile_sess_reinit_ev);

  af_user_file = NULL;
  af_group_file = NULL;

  res = authfile_sess_init();
  if (res < 0) {
    pr_session_disconnect(&auth_file_module,
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
  }
}