Example #1
0
/* Sentinel values:
 *
 *  cmd_type = 0
 *  cmd_group = NULL
 *  cmd_class = -1
 */
int pr_stash_remove_cmd(const char *cmd_name, module *m,
    unsigned char cmd_type, const char *cmd_group, int cmd_class) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t cmd_namelen = 0;
  unsigned int hash;
  cmdtable *tab = NULL;

  if (cmd_name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Don't forget to include one for the terminating NUL. */
  cmd_namelen = strlen(cmd_name) + 1;

  hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash);
  while (tab) {
    cmdtable *cmd_sym;

    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, cmd_curr_sym, to point to the struct stash just looked
     * up.  cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    cmd_sym = cmd_curr_sym->ptr.sym_cmd;
    if ((m == NULL || cmd_curr_sym->sym_module == m) &&
        (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) &&
        (cmd_group == NULL ||
         (cmd_group != NULL &&
          cmd_sym->group != NULL &&
          strcmp(cmd_sym->group, cmd_group) == 0)) &&
        (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) {
      xaset_remove(cmd_symbol_table[symtab_idx],
        (xasetmember_t *) cmd_curr_sym);
      destroy_pool(cmd_curr_sym->sym_pool);
      cmd_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash);
  }

  return count;
}
Example #2
0
static struct group *p_getgrnam(const char *name) {
  struct group *gr = NULL;

  p_setgrent();
  while ((gr = p_getgrent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, gr->gr_name) == 0)
      break;
  }

  return gr;
}
Example #3
0
unsigned char command_exists(char *name) {
  int idx = -1;
  unsigned int hash = 0;
  cmdtable *cmdtab;

  cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, NULL, &idx, &hash);
  while (cmdtab && cmdtab->cmd_type != CMD) {
    pr_signals_handle();
    cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, cmdtab, &idx, &hash);
  }

  return (cmdtab ? TRUE : FALSE);
}
Example #4
0
static struct passwd *p_getpwuid(uid_t uid) {
  struct passwd *pw = NULL;

  p_setpwent();
  while ((pw = p_getpwent()) != NULL) {
    pr_signals_handle();

    if (pw->pw_uid == uid)
      break;
  }

  return pw;
}
Example #5
0
static struct group *p_getgrgid(gid_t gid) {
  struct group *gr = NULL;

  p_setgrent();
  while ((gr = p_getgrent()) != NULL) {
    pr_signals_handle();

    if (gr->gr_gid == gid)
      break;
  }

  return gr;
}
Example #6
0
int pr_netio_lingering_abort(pr_netio_stream_t *nstrm, long linger) {
  int res;

  if (nstrm == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Send an appropriate response code down the stream asychronously. */
  pr_response_send_async(R_426, _("Transfer aborted. Data connection closed."));

  pr_netio_shutdown(nstrm, 1);

  if (nstrm->strm_fd >= 0) {
    fd_set rs;
    struct timeval tv;

    /* Wait for just a little while for the shutdown to take effect. */
    tv.tv_sec = 0L;
    tv.tv_usec = 300000L;

    while (TRUE) {
      run_schedule();

      FD_ZERO(&rs);
      FD_SET(nstrm->strm_fd, &rs);

      res = select(nstrm->strm_fd+1, &rs, NULL, NULL, &tv);
      if (res == -1) {
        if (errno == EINTR) {
          pr_signals_handle();

          /* Linger some more. */
          tv.tv_sec = 0L;
          tv.tv_usec = 300000L;
          continue;

        } else {
          nstrm->strm_errno = errno;
          return -1;
        }
      }

      break;
    }
  }

  /* Now continue with a normal lingering close. */
  return netio_lingering_close(nstrm, linger,
    NETIO_LINGERING_CLOSE_FL_NO_SHUTDOWN);  
}
Example #7
0
conn_t *pr_ipbind_accept_conn(fd_set *readfds, int *listenfd) {
  conn_t **listeners = listener_list->elts;
  register unsigned int i = 0;

  if (readfds == NULL ||
      listenfd == NULL) {
    errno = EINVAL;
    return NULL;
  }

  for (i = 0; i < listener_list->nelts; i++) {
    conn_t *listener = listeners[i];

    pr_signals_handle();
    if (FD_ISSET(listener->listen_fd, readfds) &&
        listener->mode == CM_LISTEN) {
      int fd = pr_inet_accept_nowait(listener->pool, listener);

      if (fd == -1) {
        int xerrno = errno;

        /* Handle errors gracefully.  If we're here, then
         * ipbind->ib_server->listen contains either error information, or
         * we just got caught in a blocking condition.
         */
        if (listener->mode == CM_ERROR) {

          /* Ignore ECONNABORTED, as they tend to be health checks/probes by
           * e.g. load balancers and other naive TCP clients.
           */
          if (listener->xerrno != ECONNABORTED) {
            pr_log_pri(PR_LOG_ERR, "error: unable to accept an incoming "
              "connection: %s", strerror(listener->xerrno));
          }

          listener->xerrno = 0;
          listener->mode = CM_LISTEN;

          errno = xerrno;
          return NULL;
        }
      }

      *listenfd = fd;
      return listener;
    }
  }

  errno = ENOENT;
  return NULL;
}
Example #8
0
/* Very similar to the {block,unblock}_signals() function, this masks most
 * of the same signals -- except for TERM.  This allows a throttling process
 * to be killed by the admin.
 */
static void xfer_rate_sigmask(int block) {
  static sigset_t sig_set;

  if (block) {
    sigemptyset(&sig_set);

    sigaddset(&sig_set, SIGCHLD);
    sigaddset(&sig_set, SIGUSR1);
    sigaddset(&sig_set, SIGINT);
    sigaddset(&sig_set, SIGQUIT);
#ifdef SIGIO
    sigaddset(&sig_set, SIGIO);
#endif /* SIGIO */
#ifdef SIGBUS
    sigaddset(&sig_set, SIGBUS);
#endif /* SIGBUS */
    sigaddset(&sig_set, SIGHUP);

    while (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) {
      if (errno == EINTR) {
        pr_signals_handle();
        continue;
      }

      break;
    }

  } else {
    while (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) {
      if (errno == EINTR) {
        pr_signals_handle();
        continue;
      }

      break;
    }
  }
}
Example #9
0
static int read_scoreboard_header(pr_scoreboard_header_t *sch) {
  int res = 0;

  /* No interruptions, please. */
  pr_signals_block();
 
  /* NOTE: reading a struct from a file using read(2) -- bad (in general). */
  while ((res = read(scoreboard_fd, sch, sizeof(pr_scoreboard_header_t))) !=
      sizeof(pr_scoreboard_header_t)) {
    int rd_errno = errno;

    if (res == 0) {
      pr_signals_unblock();
      errno = EIO;
      return -1;
    }

    if (errno == EINTR) {
      pr_signals_handle();
      continue;
    }

    pr_signals_unblock();
    errno = rd_errno;
    return -1;
  }

  pr_signals_unblock();

  /* Note: these errors will most likely occur only for inetd-run daemons.
   * Standalone daemons erase the scoreboard on startup.
   */
 
  if (sch->sch_magic != PR_SCOREBOARD_MAGIC) {
    pr_close_scoreboard();
    return PR_SCORE_ERR_BAD_MAGIC;
  }

  if (sch->sch_version < PR_SCOREBOARD_VERSION) {
    pr_close_scoreboard();
    return PR_SCORE_ERR_OLDER_VERSION;
  }

  if (sch->sch_version > PR_SCOREBOARD_VERSION) {
    pr_close_scoreboard();
    return PR_SCORE_ERR_NEWER_VERSION;
  }

  return 0;
}
Example #10
0
static struct passwd *p_getpwnam(const char *name) {
  struct passwd *pw = NULL;

  p_setpwent();
  while ((pw = p_getpwent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, pw->pw_name) == 0) {
      break;
    }
  }

  return pw;
}
Example #11
0
static int utf8_convert(iconv_t conv, const char *inbuf, size_t *inbuflen,
    char *outbuf, size_t *outbuflen) {
# ifdef HAVE_ICONV

  /* Reset the state machine before each conversion. */
  (void) iconv(conv, NULL, NULL, NULL, NULL);

  while (*inbuflen > 0) {
    size_t nconv;

    pr_signals_handle();

    /* Solaris/FreeBSD's iconv(3) takes a const char ** for the input buffer,
     * whereas Linux/Mac OSX iconv(3) use char ** for the input buffer.
     */
#if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \
    defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \
    defined(DARWIN11)
 
    nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen);
#else
    nconv = iconv(conv, &inbuf, inbuflen, &outbuf, outbuflen);
#endif

    if (nconv == (size_t) -1) {

      /* Note: an errno of EILSEQ here can indicate badly encoded strings OR
       * (more likely) that the source character set used in the iconv_open(3)
       * call for this iconv_t descriptor does not accurately describe the
       * character encoding of the given string.  E.g. a filename may use
       * the ISO8859-1 character set, but iconv_open(3) was called using
       * US-ASCII.
       */

      return -1;
    }

    /* XXX We should let the loop condition work, rather than breaking out
     * of the loop here.
     */
    break;
  }

  return 0;

# else
  errno = ENOSYS;
  return -1;
# endif /* HAVE_ICONV */
}
Example #12
0
int pr_ipbind_add_binds(server_rec *serv) {
  int res = 0;
  config_rec *c = NULL;
  conn_t *listen_conn = NULL;
  const pr_netaddr_t *addr = NULL;

  if (serv == NULL) {
    errno = EINVAL;
    return -1;
  }

  c = find_config(serv->conf, CONF_PARAM, "_bind_", FALSE);
  while (c != NULL) {
    listen_conn = NULL;

    pr_signals_handle();

    addr = pr_netaddr_get_addr(serv->pool, c->argv[0], NULL);
    if (addr == NULL) {
      pr_log_pri(PR_LOG_WARNING,
       "notice: unable to determine IP address of '%s'", (char *) c->argv[0]);
      c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE);
      continue;
    }

    /* If the SocketBindTight directive is in effect, create a separate
     * listen socket for this address, and add it to the binding list.
     */
    if (SocketBindTight &&
        serv->ServerPort) {
      listen_conn = pr_ipbind_get_listening_conn(serv, addr, serv->ServerPort);
      if (listen_conn == NULL) {
        return -1;
      }

      PR_CREATE_IPBIND(serv, addr, serv->ServerPort);
      PR_OPEN_IPBIND(addr, serv->ServerPort, listen_conn, FALSE, FALSE, TRUE);

    } else {

      PR_CREATE_IPBIND(serv, addr, serv->ServerPort);
      PR_OPEN_IPBIND(addr, serv->ServerPort, serv->listen, FALSE, FALSE, TRUE);
    }

    c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE);
  }

  return 0;
}
Example #13
0
int snmp_mib_get_idx(oid_t *mib_oid, unsigned int mib_oidlen,
    int *lacks_instance_id) {
  register unsigned int i;
  int mib_idx = -1;

  if (lacks_instance_id != NULL) {
    *lacks_instance_id = FALSE;
  }

  for (i = 1; snmp_mibs[i].mib_oidlen != 0; i++) {
    pr_signals_handle();

    /* Skip any disabled MIBs. */
    if (snmp_mibs[i].mib_enabled == FALSE) {
      continue;
    }

    if (snmp_mibs[i].mib_oidlen == mib_oidlen) {
      if (memcmp(snmp_mibs[i].mib_oid, mib_oid,
          mib_oidlen * sizeof(oid_t)) == 0) {
        mib_idx = i;
        break;
      }
    }

    /* Check for the case where the given OID might be missing the final
     * ".0" instance identifier.  This is done to support the slightly
     * more user-friendly NO_SUCH_INSTANCE exception for SNMPv2/SNMPv3
     * responses.
     */

    if (lacks_instance_id != NULL) {
      if (snmp_mibs[i].mib_oidlen == (mib_oidlen + 1)) {
        if (memcmp(snmp_mibs[i].mib_oid, mib_oid,
            mib_oidlen * sizeof(oid_t)) == 0) {
          *lacks_instance_id = TRUE;
          break;
        }
      }
    }
  }

  if (mib_idx < 0) {
    errno = ENOENT;
  }

  return mib_idx;
}
Example #14
0
int pr_auth_banned_by_ftpusers(xaset_t *ctx, const char *user) {
  int res = FALSE;
  unsigned char *use_ftp_users;

  use_ftp_users = get_param_ptr(ctx, "UseFtpUsers", FALSE);

  if (use_ftp_users == NULL ||
      *use_ftp_users == TRUE) {
    FILE *fh = NULL;
    char buf[256];

    PRIVS_ROOT
    fh = fopen(PR_FTPUSERS_PATH, "r");
    PRIVS_RELINQUISH

    if (fh == NULL)
      return res;

    memset(buf, '\0', sizeof(buf));

    while (fgets(buf, sizeof(buf)-1, fh)) {
      char *ptr;

      pr_signals_handle();

      buf[sizeof(buf)-1] = '\0';
      CHOP(buf);

      ptr = buf;
      while (isspace((int) *ptr) && *ptr) {
        ptr++;
      }

      if (!*ptr ||
          *ptr == '#') {
        continue;
      }

      if (strcmp(ptr, user) == 0 ) {
        res = TRUE;
        break;
      }

      memset(buf, '\0', sizeof(buf));
    }

    fclose(fh);
  }
Example #15
0
static int wlock_entry(void) {
  entry_lock.l_type = F_WRLCK;
  entry_lock.l_whence = SEEK_CUR;
  entry_lock.l_len = sizeof(pr_scoreboard_entry_t);

  while (fcntl(scoreboard_fd, F_SETLKW, &entry_lock) < 0) {
    if (errno == EINTR) {
      pr_signals_handle();
      continue;

    } else
      return -1;
  }

  return 0;
}
Example #16
0
int pr_stash_remove_conf(const char *directive_name, module *m) {
  int count = 0, prev_idx, symtab_idx = 0;
  size_t directive_namelen = 0;
  unsigned int hash;
  conftable *tab = NULL;

  if (directive_name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* Don't forget to include one for the terminating NUL. */
  directive_namelen = strlen(directive_name) + 1;

  hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen);
  symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE;
  prev_idx = -1;

  tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx,
    &hash);
  while (tab) {
    pr_signals_handle();

    /* Note: this works because of a hack: the symbol lookup functions set a
     * static pointer, conf_curr_sym, to point to the struct stash just looked
     * up.  conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns
     * non-NULL.
     */

    if (m == NULL ||
        conf_curr_sym->sym_module == m) {
      xaset_remove(conf_symbol_table[symtab_idx],
        (xasetmember_t *) conf_curr_sym);
      destroy_pool(conf_curr_sym->sym_pool);
      conf_curr_sym = NULL;
      tab = NULL;
      count++;
    }

    tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx,
      &hash);
  }

  return count;
}
Example #17
0
static struct passwd *af_getpwuid(uid_t uid) {
  struct passwd *pwd = NULL;

  if (af_setpwent() < 0) {
    return NULL;
  }

  while ((pwd = af_getpwent()) != NULL) {
    pr_signals_handle();

    if (pwd->pw_uid == uid) {
      /* Found the requested UID */
      break;
    }
  }

  return pwd;
}
Example #18
0
static struct passwd *af_getpwnam(const char *name) {
  struct passwd *pwd = NULL;

  if (af_setpwent() < 0) {
    return NULL;
  }

  while ((pwd = af_getpwent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, pwd->pw_name) == 0) {
      /* Found the requested user */
      break;
    }
  }

  return pwd;
}
Example #19
0
static struct group *af_getgrgid(gid_t gid) {
  struct group *grp = NULL;

  if (af_setgrent() < 0) {
    return NULL;
  }

  while ((grp = af_getgrent()) != NULL) {
    pr_signals_handle();

    if (grp->gr_gid == gid) {
      /* Found the requested GID */
      break;
    }
  }

  return grp;
}
Example #20
0
static struct group *af_getgrnam(const char *name) {
  struct group *grp = NULL;

  if (af_setgrent() < 0) {
    return NULL;
  }

  while ((grp = af_getgrent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, grp->gr_name) == 0) {
      /* Found the requested group */
      break;
    }
  }

  return grp;
}
static char *get_meta_arg(pool *p, unsigned char *m, size_t *arglen) {
  char buf[PR_TUNABLE_PATH_MAX+1], *ptr;
  size_t len;

  ptr = buf;
  len = 0;

  while (*m != LOGFMT_META_ARG_END) {
    pr_signals_handle();
    *ptr++ = (char) *m++;
    len++;
  }

  *ptr = '\0';
  *arglen = len;

  return pstrdup(p, buf);
}
Example #22
0
/* Use a hash function to hash the given lookup key to a slot in the
 * sd_entries list.  This hash, module the number of entries, is the initial
 * iteration start point.  This will hopefully avoid having to do many linear
 * scans for the add/get/delete operations.
 *
 * Use Perl's hashing algorithm.
 */
static unsigned int shmcache_hash(unsigned char *sess_id,
    unsigned int sess_id_len) {
  unsigned int i = 0;
  size_t sz = sess_id_len;

  while (sz--) {
    const unsigned char *k = sess_id;
    unsigned int c = *k;
    k++;

    /* Always handle signals in potentially long-running while loops. */
    pr_signals_handle();

    i = (i * 33) + c;
  }

  return i;
}
/* Use Perl's hashing algorithm by default.
 *
 * Here's a good article about this hashing algorithm, and about hashing
 * functions in general:
 *
 *  http://www.perl.com/pub/2002/10/01/hashes.html
 */
static unsigned int key_hash(const void *key, size_t keysz) {
  unsigned int i = 0;
  size_t sz = !keysz ? strlen((const char *) key) : keysz;

  while (sz--) {
    const char *k = key;
    unsigned int c;

    c = k[sz];

    /* Always handle signals in potentially long-running while loops. */
    pr_signals_handle();

    i = (i * 33) + c;
  }

  return i;
}
Example #24
0
static int core_netio_poll_cb(pr_netio_stream_t *nstrm) {
  int res;
  fd_set rfds, *rfdsp, wfds, *wfdsp;
  struct timeval tval;

  FD_ZERO(&rfds);
  rfdsp = NULL;
  FD_ZERO(&wfds);
  wfdsp = NULL;

  if (nstrm->strm_mode == PR_NETIO_IO_RD) {
    if (nstrm->strm_fd >= 0) {
      FD_SET(nstrm->strm_fd, &rfds);
      rfdsp = &rfds;
    }

  } else {
    if (nstrm->strm_fd >= 0) {
      FD_SET(nstrm->strm_fd, &wfds);
      wfdsp = &wfds;
    }
  }

  tval.tv_sec = ((nstrm->strm_flags & PR_NETIO_SESS_INTR) ?
    nstrm->strm_interval: 60);
  tval.tv_usec = 0;

  res = select(nstrm->strm_fd + 1, rfdsp, wfdsp, NULL, &tval);
  while (res < 0) {
    int xerrno = errno;

    /* Watch for EAGAIN, and handle it by delaying temporarily. */
    if (xerrno == EAGAIN) {
      errno = EINTR;
      pr_signals_handle();
      continue;
    }

    errno = nstrm->strm_errno = xerrno;
    break; 
  }

  return res;
}
Example #25
0
pr_scoreboard_entry_t *pr_scoreboard_read_entry(void) {
  static pr_scoreboard_entry_t scan_entry;
  int res = 0;

  if (scoreboard_fd < 0) {
    errno = EINVAL;
    return NULL;
  }

  /* Make sure the scoreboard file is read-locked. */
  if (!scoreboard_read_locked) {

    /* Do not proceed if we cannot lock the scoreboard. */
    if (rlock_scoreboard() < 0)
      return NULL; 
  }

  memset(&scan_entry, '\0', sizeof(scan_entry));

  /* NOTE: use readv(2)? */
  while (TRUE) {
    while ((res = read(scoreboard_fd, &scan_entry, sizeof(scan_entry))) <= 0) {
      if (res < 0 && errno == EINTR) {
        pr_signals_handle();
        continue;

      } else {
        unlock_scoreboard();
        return NULL;
      }
    }

    if (scan_entry.sce_pid) {
      unlock_scoreboard();
      return &scan_entry;

    } else
      continue;
  }

  unlock_scoreboard();
  return NULL;
}
Example #26
0
MODRET authfile_getgrnam(cmd_rec *cmd) {
  struct group *grp = NULL;
  const char *name = cmd->argv[0];

  if (af_setgrent() < 0) {
    return PR_DECLINED(cmd);
  }

  while ((grp = af_getgrent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, grp->gr_name) == 0) {
      /* Found the name requested */
      break;
    }
  }

  return grp ? mod_create_data(cmd, grp) : PR_DECLINED(cmd);
}
Example #27
0
void run_schedule(void) {
  sched_t *s, *snext;

  if (scheds == NULL ||
      scheds->xas_list == NULL) {
    return;
  }

  for (s = (sched_t *) scheds->xas_list; s; s = snext) {
    snext = s->next;

    pr_signals_handle();

    if (s->nloops-- <= 0) {
      s->cb(s->arg1, s->arg2, s->arg3, s->arg4);
      xaset_remove(scheds, (xasetmember_t *) s);
      destroy_pool(s->pool);
    }
  }
}
Example #28
0
char *pr_str_strip_end(char *s, char *ch) {
  size_t len;

  if (s == NULL ||
      ch == NULL) {
    errno = EINVAL;
    return NULL;
  }

  len = strlen(s);

  while (len && strchr(ch, *(s+len - 1))) {
    pr_signals_handle();

    *(s+len - 1) = '\0';
    len--;
  }

  return s;
}
Example #29
0
static int wlock_scoreboard(void) {
  struct flock lock;

  lock.l_type = F_WRLCK;
  lock.l_whence = 0;
  lock.l_start = 0;
  lock.l_len = 0;

  while (fcntl(scoreboard_fd, F_SETLKW, &lock) < 0) {
    if (errno == EINTR) {
      pr_signals_handle();
      continue;

    } else
      return -1;
  }

  scoreboard_write_locked = TRUE;
  return 0;
}
Example #30
0
MODRET authfile_getpwnam(cmd_rec *cmd) {
  struct passwd *pwd = NULL;
  const char *name = cmd->argv[0];

  if (af_setpwent() < 0) {
    return PR_DECLINED(cmd);
  }

  /* Ugly -- we iterate through the file.  Time-consuming. */
  while ((pwd = af_getpwent()) != NULL) {
    pr_signals_handle();

    if (strcmp(name, pwd->pw_name) == 0) {
      /* Found the requested name */
      break;
    }
  }

  return pwd ? mod_create_data(cmd, pwd) : PR_DECLINED(cmd);
}