void
reap_info_slave(void)
{
  struct response_dgram resp;
  ssize_t len;
  char hostname[BUFFER_LEN], *hp;
  int n, count;
  conn_source source;

  if (info_slave_state != INFO_SLAVE_PENDING) {
    if (info_slave_state == INFO_SLAVE_DOWN)
      make_info_slave();
    return;
  }

  len = recv(info_slave, &resp, sizeof resp, 0);
  if (len < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
    return;
  else if (len < 0 || len != (int) sizeof resp) {
    penn_perror("reading info_slave response");
    return;
  }

  /* okay, now we have some info! */
  if (!FD_ISSET(resp.fd, &info_pending)) {
    /* Duplicate or spoof. Ignore. */
    return;
  }

  FD_CLR(resp.fd, &info_pending);

  /* See if we have any other pending queries and change state if not. */
  for (n = 0, count = 0; n < pending_max; n++)
    if (FD_ISSET(n, &info_pending))
      count++;

  if (count == 0) {
    info_slave_state = INFO_SLAVE_READY;
    pending_max = 0;
  }

  hp = hostname;
  if (resp.hostname[0])
    safe_str(resp.hostname, hostname, &hp);
  else
    safe_str(resp.ipaddr, hostname, &hp);
  *hp = '\0';

  if (Forbidden_Site(resp.ipaddr) || Forbidden_Site(hostname)) {
    if (!Deny_Silent_Site(resp.ipaddr, AMBIGUOUS)
        || !Deny_Silent_Site(hostname, AMBIGUOUS)) {
      do_log(LT_CONN, 0, 0, "[%d/%s/%s] Refused connection.", resp.fd,
             hostname, resp.ipaddr);
    }
    shutdown(resp.fd, 2);
    closesocket(resp.fd);
    return;
  }

  if (resp.connected_to == TINYPORT)
    source = CS_IP_SOCKET;
  else if (resp.connected_to == SSLPORT)
    source = CS_OPENSSL_SOCKET;
  else
    source = CS_UNKNOWN;

  do_log(LT_CONN, 0, 0, "[%d/%s/%s] Connection opened from %s.", resp.fd,
         hostname, resp.ipaddr, source_to_s(source));
  set_keepalive(resp.fd, options.keepalive_timeout);


  initializesock(resp.fd, hostname, resp.ipaddr, source);
}
示例#2
0
/** Attempt to register a new player at the connect screen.
 * If registration is allowed, a new player object is created with
 * a random password which is emailed to the registering player.
 * \param name name of player to register.
 * \param email email address to send registration details.
 * \param host host from which registration is being attempted.
 * \param ip ip address from which registration is being attempted.
 * \return dbref of created player or NOTHING if creation failed.
 */
dbref
email_register_player(DESC *d, const char *name, const char *email,
                      const char *host, const char *ip)
{
  char *p;
  char passwd[20];
  static char elems[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  int i, len;
  bool resend = 0;
  dbref player = NOTHING;
  FILE *fp;
  size_t NELEMS = sizeof(elems) - 1;
  char sbuff[260];

  if (!check_fails(ip)) {
    return NOTHING;
  }

  if (strlen(options.sendmail_prog) == 0)
    return NOTHING;

  if (!ok_player_name(name, NOTHING, NOTHING)) {
    /* Check for re-registration request */
    player = lookup_player(name);
    if (GoodObject(player)) {
      ATTR *a;
      a = atr_get(player, "LASTLOGOUT");
      if (!a) {
        a = atr_get(player, "REGISTERED_EMAIL");
        if (a && !strcasecmp(atr_value(a), email))
          resend = 1;
      }
    }
    if (!resend) {
      do_log(LT_CONN, 0, 0, "Failed registration (bad name) from %s", host);
      queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s",
                  d->descriptor, ip, mark_failed(ip), "register: bad name",
                  name);
      return NOTHING;
    }
  }
  if (!resend) {
    /* Make sure that the email address is kind of valid. A valid
     * address must contain a @. Let the mailer sort it out beyond
     * that.  Also, to prevent someone from using the MUSH to mailbomb
     * another site, let's make sure that the site to which the user
     * wants the email sent is also allowed to use the register
     * command.  If there's an @, we check whatever's after the last @
     * (since @foo.bar:user@host is a valid email).
     */
    if ((p = strrchr(email, '@'))) {
      p++;
      if (!Site_Can_Register(p)) {
        if (!Deny_Silent_Site(p, AMBIGUOUS)) {
          do_log(LT_CONN, 0, 0,
                 "Failed registration (bad site in email: %s) from %s", email,
                 host);
          queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s",
                      d->descriptor, ip, mark_failed(ip),
                      "register: bad site in email", name);
        }
        return NOTHING;
      }
    } else {
      if (!Deny_Silent_Site(host, AMBIGUOUS)) {
        do_log(LT_CONN, 0, 0, "Failed registration (bad email: %s) from %s",
               email, host);
        queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s",
                    d->descriptor, ip, mark_failed(ip),
                    "register: sitelocked host", name);
      }
      return NOTHING;
    }

    if (DBTOP_MAX && (db_top >= DBTOP_MAX + 1) && (first_free == NOTHING)) {
      /* Oops, out of db space! */
      do_log(LT_CONN, 0, 0, "Failed registration (no db space) from %s", host);
      queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s",
                  d->descriptor, ip, count_failed(ip),
                  "register: no db space left to create!", name);
      return NOTHING;
    }
  }

  /* Come up with a random password of length 7-12 chars */
  len = get_random_u32(7, 12);
  for (i = 0; i < len; i++)
    passwd[i] = elems[get_random_u32(0, NELEMS - 1)];
  passwd[len] = '\0';

  /* If we've made it here, we can send the email and create the
   * character. Email first, since that's more likely to go bad.
   * Some security precautions we'll take:
   *  1) We'll use sendmail -t, so we don't pass user-given values to a shell.
   *  2) We'll cross our fingers and hope nobody uses this to spam.
   */

  release_fd();
  snprintf(sbuff, sizeof sbuff, "%s -t", options.sendmail_prog);
  if ((fp = popen(sbuff, "w")) == NULL) {
    do_log(LT_CONN, 0, 0,
           "Failed registration of %s by %s: unable to open sendmail", name,
           email);
    queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d",
                d->descriptor, ip, count_failed(ip),
                "register: Unable to open sendmail!", name, 1);
    reserve_fd();
    return NOTHING;
  }
  fprintf(fp, "Subject: ");
  fprintf(fp, T("[%s] Registration of %s\n"), MUDNAME, name);
  fprintf(fp, "To: %s\n", email);
  fprintf(fp, "Precedence: junk\n");
  fprintf(fp, "\n");
  fprintf(fp, T("This is an automated message.\n"));
  fprintf(fp, "\n");
  fprintf(fp, T("Your requested player, %s, has been created.\n"), name);
  fprintf(fp, T("The password is %s\n"), passwd);
  fprintf(fp, "\n");
  fprintf(fp, T("To access this character, connect to %s and type:\n"),
          MUDNAME);
  fprintf(fp, "\tconnect \"%s\" %s\n", name, passwd);
  fprintf(fp, "\n");
  i = pclose(fp);
  reserve_fd();

  if (i != 0) {
    /* Mailer exited with an error code. Log it. */
    do_rawlog(
      LT_CONN,
      "When attempting to email a password to a newly registered player,\n"
      "\tthe mailer exited with error code %d.\n"
      "\t(Check /usr/include/sysexits.h if present for the meaning.)",
      i);
    queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d",
                d->descriptor, ip, count_failed(ip),
                "register: Unable to send email", name, i);
    return NOTHING;
  } else if (resend) {
    /* Reset the password */
    (void) atr_add(player, pword_attr, password_hash(passwd, NULL), GOD, 0);
    return player;
  } else {
    /* Ok, all's well, make a player */
    player = make_player(name, passwd, host, ip);
    queue_event(SYSEVENT, "PLAYER`CREATE", "%s,%s,%s,%d,%s",
                unparse_objid(player), name, "register", d->descriptor, email);
    (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0);
    return player;
  }
}
void
query_info_slave(int fd)
{
  struct request_dgram req;
  struct hostname_info *hi;
  char buf[BUFFER_LEN], *bp;
  ssize_t slen;

  FD_SET(fd, &info_pending);
  if (fd > pending_max)
    pending_max = fd + 1;

  info_queue_time = time(NULL);

  if (info_slave_state == INFO_SLAVE_DOWN) {
    if (!make_info_slave()) {
      FD_CLR(fd, &info_pending);
      closesocket(fd);          /* Just drop the connection if the slave gets halted.
                                   A subsequent reconnect will work. */
    }
    return;
  }


  memset(&req, 0, sizeof req);

  req.rlen = MAXSOCKADDR;
  if (getpeername(fd, (struct sockaddr *) req.remote.data, &req.rlen) < 0) {
    penn_perror("socket peer vanished");
    shutdown(fd, 2);
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  /* Check for forbidden sites before bothering with ident */
  bp = buf;
  hi = ip_convert(&req.remote.addr, req.rlen);
  safe_str(hi ? hi->hostname : "Not found", buf, &bp);
  *bp = '\0';
  if (Forbidden_Site(buf)) {
    char port[NI_MAXSERV];
    if (getnameinfo(&req.remote.addr, req.rlen, NULL, 0, port, sizeof port,
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0)
      penn_perror("getting remote port number");
    else {
      if (!Deny_Silent_Site(buf, AMBIGUOUS)) {
        do_log(LT_CONN, 0, 0, "[%d/%s] Refused connection (remote port %s)",
               fd, buf, port);
      }
    }
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  req.llen = MAXSOCKADDR;
  if (getsockname(fd, (struct sockaddr *) req.local.data, &req.llen) < 0) {
    penn_perror("socket self vanished");
    closesocket(fd);
    FD_CLR(fd, &info_pending);
    return;
  }

  req.fd = fd;
  req.use_dns = USE_DNS;

  slen = send(info_slave, &req, sizeof req, 0);
  if (slen < 0) {
    penn_perror("info slave query: write error");
    make_info_slave();
    return;
  } else if (slen != (int) sizeof req) {
    /* Shouldn't happen! */
    penn_perror("info slave query: partial packet");
    make_info_slave();
    return;
  }
  info_slave_state = INFO_SLAVE_PENDING;
}
示例#4
0
/** Check to see if someone can connect to a player.
 * \param d DESC the connect attempt is being made for
 * \param name name of player to connect to.
 * \param password password of player to connect to.
 * \param host host from which connection is being attempted.
 * \param ip ip address from which connection is being attempted.
 * \param errbuf buffer to return connection errors.
 * \return dbref of connected player object or NOTHING for failure
 * (with reason for failure returned in errbuf).
 */
dbref
connect_player(DESC *d, const char *name, const char *password,
               const char *host, const char *ip, char *errbuf)
{
  dbref player;
  int count;

  /* Default error */
  strcpy(errbuf,
         T("Either that player does not exist, or has a different password."));

  if (!name || !*name)
    return NOTHING;

  /* validate name */
  if ((player = lookup_player(name)) == NOTHING) {
    /* Invalid player names are failures, too. */
    count = mark_failed(ip);
    strcpy(errbuf, T("There is no player with that name."));
    queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d,%s",
                d->descriptor, ip, count, "invalid player", -1, name);
    return NOTHING;
  }

  /* See if player is allowed to connect like this */
  if (Going(player) || Going_Twice(player)) {
    do_log(LT_CONN, 0, 0,
           "Connection to GOING player %s not allowed from %s (%s)",
           Name(player), host, ip);
    queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d", d->descriptor,
                ip, count_failed(ip), "player is going", player);
    strcpy(errbuf, T("You cannot connect to that player at this time."));
    return NOTHING;
  }
  /* Check sitelock patterns */
  if (Guest(player) &&
      (!Site_Can_Guest(host, player) || !Site_Can_Guest(ip, player))) {
    if (!Deny_Silent_Site(host, AMBIGUOUS) &&
        !Deny_Silent_Site(ip, AMBIGUOUS)) {
      do_log(LT_CONN, 0, 0, "Connection to %s (GUEST) not allowed from %s (%s)",
             name, host, ip);
      strcpy(errbuf, T("Guest connections not allowed."));
      count = mark_failed(ip);
      queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d",
                  d->descriptor, ip, count, "failed sitelock", player);
    }
    return NOTHING;
  } else if (!Guest(player) && (!Site_Can_Connect(host, player) ||
                                !Site_Can_Connect(ip, player))) {
    if (!Deny_Silent_Site(host, player) && !Deny_Silent_Site(ip, player)) {
      do_log(LT_CONN, 0, 0,
             "Connection to %s (Non-GUEST) not allowed from %s (%s)", name,
             host, ip);
      strcpy(errbuf, T("Player connections not allowed."));
      count = mark_failed(ip);
      queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d",
                  d->descriptor, ip, count, "failed sitelock", player);
    }
    return NOTHING;
  }
  /* validate password */
  if (!Guest(player))
    if (!password_check(player, password)) {
      /* Increment count of login failures */
      ModTime(player)++;
      check_lastfailed(player, host);
      count = mark_failed(ip);
      queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d",
                  d->descriptor, ip, count, "invalid password", player);
      strcpy(errbuf, T("That is not the correct password."));
      return NOTHING;
    }

  /* If it's a Guest player, and already connected, search the
   * db for another Guest player to connect them to. */
  if (Guest(player)) {
    /* Enforce guest limit */
    player = guest_to_connect(player);
    if (!GoodObject(player)) {
      do_log(LT_CONN, 0, 0, "Can't connect to a guest (too many connected)");
      strcpy(errbuf, T("Too many guests are connected now."));
      queue_event(SYSEVENT, "SOCKET`LOGINFAIL", "%d,%s,%d,%s,#%d",
                  d->descriptor, ip, count_failed(ip), "too many guests",
                  player);
      return NOTHING;
    }
  }
  if (Suspect_Site(host, player) || Suspect_Site(ip, player)) {
    do_log(LT_CONN, 0, 0,
           "Connection from Suspect site. Setting %s(#%d) suspect.",
           Name(player), player);
    set_flag_internal(player, "SUSPECT");
  }
  return player;
}