예제 #1
0
/**************************************************************************
  Close the dialogs for all cities.
**************************************************************************/
void popdown_all_city_dialogs(void)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
}
예제 #2
0
/**************************************************************************
 Saves pconn fields to the database. If the username already exists, 
 replace the data.
**************************************************************************/
static bool auth_db_save(struct connection *pconn)
{
#ifdef HAVE_AUTH
  char buffer[1024] = "";
  const int bufsize = sizeof(buffer);
  char *name_buffer = NULL;
  char *pw_buffer = NULL;
  MYSQL *sock, mysql;
  int str_result;

  mysql_init(&mysql);

  /* attempt to connect to the server */
  if (!(sock = mysql_real_connect(&mysql, auth_config.host.value,
                                  auth_config.user.value, auth_config.password.value,
                                  auth_config.database.value,
                                  atoi(auth_config.port.value),
                                  NULL, 0))) {
    freelog(LOG_ERROR, "Can't connect to server! (%s)", mysql_error(&mysql));
    return FALSE;
  }

  name_buffer = alloc_escaped_string(&mysql, pconn->username);
  pw_buffer = alloc_escaped_string(&mysql, pconn->server.password);
  if (name_buffer == NULL || pw_buffer == NULL) {
    free_escaped_string(name_buffer);
    mysql_close(sock);
    return FALSE;
  }

  /* insert new user into table. we insert the following things: name
   * md5sum of the password, the creation time in seconds, the accesstime
   * also in seconds from 1970, the users address (twice) and the logincount */
  str_result = my_snprintf(buffer, bufsize,
                           "insert into %s values "
                           "(NULL, '%s', '%s', NULL, "
                           "unix_timestamp(), unix_timestamp(),"
                           "'%s', '%s', 0)",
                           auth_config.table.value, name_buffer, pw_buffer,
                           pconn->server.ipaddr, pconn->server.ipaddr);

  /* Password is not needed for further queries. */
  free_escaped_string(pw_buffer);
  pw_buffer = NULL;

  if (str_result < 0 || str_result >= bufsize || mysql_query(sock, buffer)) {
    freelog(LOG_ERROR, "db_save insert failed for new user: %s (%s)",
                       pconn->username, mysql_error(sock));
    mysql_close(sock);
    return FALSE;
  }

  /* insert an entry into our log */
  memset(buffer, 0, bufsize);
  str_result = my_snprintf(buffer, bufsize,
                           "insert into %s (name, logintime, address, succeed) "
                           "values ('%s',unix_timestamp(),'%s', 'S')",
                           auth_config.login_table.value,
                           name_buffer, pconn->server.ipaddr);

  free_escaped_string(name_buffer);
  name_buffer = 0;

  if (str_result < 0 || str_result >= bufsize || mysql_query(sock, buffer)) {
    freelog(LOG_ERROR, "db_load insert loginlog failed for user: %s (%s)",
                       pconn->username, mysql_error(sock));
  }

  mysql_close(sock);
#endif
  return TRUE;
}
예제 #3
0
/**************************************************************************
  Close the dialog for the given city.
**************************************************************************/
void popdown_city_dialog(struct city *pcity)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
}
예제 #4
0
/**************************************************************************
  handle authentication of a user; called by handle_login_request()
  if authentication is enabled.

  if the connection is rejected right away, return FALSE, otherwise return TRUE
**************************************************************************/
bool authenticate_user(struct connection *pconn, char *username)
{
  char tmpname[MAX_LEN_NAME] = "\0";

  /* assign the client a unique guest name/reject if guests aren't allowed */
  if (is_guest_name(username)) {
    if (srvarg.auth_allow_guests) {

      sz_strlcpy(tmpname, username);
      get_unique_guest_name(username);

      if (strncmp(tmpname, username, MAX_LEN_NAME) != 0) {
        notify_conn(pconn->self, NULL, E_CONNECTION, ftc_warning,
                    _("Warning: the guest name '%s' has been "
                      "taken, renaming to user '%s'."), tmpname, username);
      }
      sz_strlcpy(pconn->username, username);
      establish_new_connection(pconn);
    } else {
      reject_new_connection(_("Guests are not allowed on this server. "
                              "Sorry."), pconn);
      freelog(LOG_NORMAL, _("%s was rejected: Guests not allowed."), username);
      return FALSE;
    }
  } else {
    /* we are not a guest, we need an extra check as to whether a 
     * connection can be established: the client must authenticate itself */
    char buffer[MAX_LEN_MSG];

    sz_strlcpy(pconn->username, username);

    switch(auth_db_load(pconn)) {
    case AUTH_DB_ERROR:
      if (srvarg.auth_allow_guests) {
        sz_strlcpy(tmpname, pconn->username);
        get_unique_guest_name(tmpname); /* don't pass pconn->username here */
        sz_strlcpy(pconn->username, tmpname);

        freelog(LOG_ERROR, "Error reading database; connection -> guest");
        notify_conn(pconn->self, NULL, E_CONNECTION, ftc_warning,
                    _("There was an error reading the user "
                      "database, logging in as guest connection '%s'."), 
                    pconn->username);
        establish_new_connection(pconn);
      } else {
        reject_new_connection(_("There was an error reading the user database "
                                "and guest logins are not allowed. Sorry"), 
                              pconn);
        freelog(LOG_NORMAL, 
                _("%s was rejected: Database error and guests not allowed."),
                pconn->username);
        return FALSE;
      }
      break;
    case AUTH_DB_SUCCESS:
      /* we found a user */
      my_snprintf(buffer, sizeof(buffer), _("Enter password for %s:"),
                  pconn->username);
      dsend_packet_authentication_req(pconn, AUTH_LOGIN_FIRST, buffer);
      pconn->server.auth_settime = time(NULL);
      pconn->server.status = AS_REQUESTING_OLD_PASS;
      break;
    case AUTH_DB_NOT_FOUND:
      /* we couldn't find the user, he is new */
      if (srvarg.auth_allow_newusers) {
        sz_strlcpy(buffer, _("Enter a new password (and remember it)."));
        dsend_packet_authentication_req(pconn, AUTH_NEWUSER_FIRST, buffer);
        pconn->server.auth_settime = time(NULL);
        pconn->server.status = AS_REQUESTING_NEW_PASS;
      } else {
        reject_new_connection(_("This server allows only preregistered "
                                "users. Sorry."), pconn);
        freelog(LOG_NORMAL,
                _("%s was rejected: Only preregistered users allowed."),
                pconn->username);

        return FALSE;
      }
      break;
    default:
      assert(0);
      break;
    }
    return TRUE;
  }

  return TRUE;
}
예제 #5
0
/**************************************************************************
 Loads a user from the database.
**************************************************************************/
static enum authdb_status auth_db_load(struct connection *pconn)
{
#ifdef HAVE_AUTH
  char buffer[512] = "";
  const int bufsize = sizeof(buffer);
  int num_rows = 0;
  MYSQL *sock, mysql;
  MYSQL_RES *res;
  MYSQL_ROW row;
  char *name_buffer;
  int str_result;

  mysql_init(&mysql);

  /* attempt to connect to the server */
  if (!(sock = mysql_real_connect(&mysql, auth_config.host.value,
                                  auth_config.user.value,
                                  auth_config.password.value,
                                  auth_config.database.value,
                                  atoi(auth_config.port.value),
                                  NULL, 0))) {
    freelog(LOG_ERROR, "Can't connect to server! (%s)", mysql_error(&mysql));
    return AUTH_DB_ERROR;
  }

  name_buffer = alloc_escaped_string(&mysql, pconn->username);

  if (name_buffer != NULL) {
    /* select the password from the entry */
    str_result = my_snprintf(buffer, bufsize,
                             "select password from %s where name = '%s'",
                             auth_config.table.value, name_buffer);

    if (str_result < 0 || str_result >= bufsize || mysql_query(sock, buffer)) {
      freelog(LOG_ERROR, "db_load query failed for user: %s (%s)",
              pconn->username, mysql_error(sock));
      free_escaped_string(name_buffer);
      mysql_close(sock);
      return AUTH_DB_ERROR;
    }

    res = mysql_store_result(sock);
    num_rows = mysql_num_rows(res);
  
    /* if num_rows = 0, then we could find no such user */
    if (num_rows < 1) {
      mysql_free_result(res);
      free_escaped_string(name_buffer);
      mysql_close(sock);

      return AUTH_DB_NOT_FOUND;
    }
  
    /* if there are more than one row that matches this name, it's an error 
     * continue anyway though */
    if (num_rows > 1) {
      freelog(LOG_ERROR, "db_load query found multiple entries (%d) for user: %s",
              num_rows, pconn->username);
    }

    /* if there are rows, then fetch them and use the first one */
    row = mysql_fetch_row(res);
    mystrlcpy(pconn->server.password, row[0], sizeof(pconn->server.password));
    mysql_free_result(res);

    /* update the access time for this user */
    memset(buffer, 0, bufsize);
    str_result = my_snprintf(buffer, bufsize,
                             "update %s set accesstime=unix_timestamp(), "
                             "address='%s', logincount=logincount+1 "
                             "where strcmp(name, '%s') = 0",
                             auth_config.table.value, pconn->server.ipaddr,
                             name_buffer);

    free_escaped_string(name_buffer);
    name_buffer = NULL;

    if (str_result < 0 || str_result >= bufsize || mysql_query(sock, buffer)) {
      freelog(LOG_ERROR, "db_load update accesstime failed for user: %s (%s)",
              pconn->username, mysql_error(sock));
    }
  }

  mysql_close(sock);
#endif
  return AUTH_DB_SUCCESS;
}
예제 #6
0
/**************************************************************************
  Returns current client page
**************************************************************************/
enum client_pages get_client_page(void)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */
  return PAGE_MAIN;
}
예제 #7
0
/**************************************************************************
  update the start page.
**************************************************************************/
void update_start_page(void)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */    
}
예제 #8
0
/**************************************************************************
  Sets the "page" that the client should show.  See also pages_g.h.
**************************************************************************/
void set_client_page(enum client_pages page)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */
}
예제 #9
0
/****************************************************************************
  Set the list of available rulesets.  The default ruleset should be
  "default", and if the user changes this then set_ruleset() should be
  called.
****************************************************************************/
void gui_set_rulesets(int num_rulesets, char **rulesets)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */
}
예제 #10
0
/**************************************************************************
A wrapper around read_socket_data() which also handles the case the
socket becomes writeable and there is still data which should be sent
to the server.

Returns:
    -1  :  an error occurred - you should close the socket
    >0  :  number of bytes read
    =0  :  no data read, would block
**************************************************************************/
static int read_from_connection(struct connection *pc, bool block)
{
  for (;;) {
    fd_set readfs, writefs, exceptfs;
    int socket_fd = pc->sock;
    bool have_data_for_server = (pc->used && pc->send_buffer
				&& pc->send_buffer->ndata > 0);
    int n;
    struct timeval tv;

    tv.tv_sec = 0;
    tv.tv_usec = 0;

    MY_FD_ZERO(&readfs);
    FD_SET(socket_fd, &readfs);

    MY_FD_ZERO(&exceptfs);
    FD_SET(socket_fd, &exceptfs);

    if (have_data_for_server) {
      MY_FD_ZERO(&writefs);
      FD_SET(socket_fd, &writefs);
      n =
	  fc_select(socket_fd + 1, &readfs, &writefs, &exceptfs,
		    block ? NULL : &tv);
    } else {
      n =
	  fc_select(socket_fd + 1, &readfs, NULL, &exceptfs,
		    block ? NULL : &tv);
    }

    /* the socket is neither readable, writeable nor got an
       exception */
    if (n == 0) {
      return 0;
    }

    if (n == -1) {
      if (errno == EINTR) {
	/* EINTR can happen sometimes, especially when compiling with -pg.
	 * Generally we just want to run select again. */
	freelog(LOG_DEBUG, "select() returned EINTR");
	continue;
      }

      freelog(LOG_ERROR, "select() return=%d errno=%d (%s)",
	      n, errno, fc_strerror(fc_get_errno()));
      return -1;
    }

    if (FD_ISSET(socket_fd, &exceptfs)) {
      return -1;
    }

    if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) {
      flush_connection_send_buffer_all(pc);
    }

    if (FD_ISSET(socket_fd, &readfs)) {
      return read_socket_data(socket_fd, pc->buffer);
    }
  }
}
예제 #11
0
/***************************************************************************
  Look up the service at hostname:port and fill in *sa.
***************************************************************************/
bool net_lookup_service(const char *name, int port, union fc_sockaddr *addr,
                        bool force_ipv4)
{
    struct hostent *hp;
    struct sockaddr_in *sock4;
#ifdef IPV6_SUPPORT
    struct sockaddr_in6 *sock6;
#endif /* IPv6 support */

    sock4 = &addr->saddr_in4;

#ifdef IPV6_SUPPORT
    sock6 = &addr->saddr_in6;

    if (!force_ipv4) {
        addr->saddr.sa_family = AF_INET6;
        sock6->sin6_port = htons(port);

        if (!name) {
            sock6->sin6_addr = in6addr_any;
            return TRUE;
        }

        if (inet_pton(AF_INET6, name, &sock6->sin6_addr)) {
            return TRUE;
        }
        /* TODO: Replace gethostbyname2() with getaddrinfo() */
        hp = gethostbyname2(name, AF_INET6);
    } else
#endif /* IPv6 support */
    {
        addr->saddr.sa_family = AF_INET;
        sock4->sin_port = htons(port);

        if (!name) {
            sock4->sin_addr.s_addr = htonl(INADDR_ANY);
            return TRUE;
        }
    }

#ifdef IPV6_SUPPORT
    if (force_ipv4 || !hp || hp->h_addrtype != AF_INET6) {
        /* Try to fallback to IPv4 resolution */
        if (!force_ipv4) {
            freelog(LOG_DEBUG, "Falling back to IPv4");
        }
        hp = gethostbyname2(name, AF_INET);
        if (!hp || hp->h_addrtype != AF_INET) {
            return FALSE;
        }
        addr->saddr.sa_family = AF_INET;
        sock4->sin_port = htons(port);
    }
#else  /* IPV6 support */
#if defined(HAVE_INET_ATON)
    if (inet_aton(name, &sock4->sin_addr) != 0) {
        return TRUE;
    }
#else  /* HAVE_INET_ATON */
    if ((sock4->sin_addr.s_addr = inet_addr(name)) != INADDR_NONE) {
        return TRUE;
    }
#endif /* HAVE_INET_ATON */
    hp = gethostbyname(name);
    if (!hp || hp->h_addrtype != AF_INET) {
        return FALSE;
    }
#endif /* IPv6 support */

#ifdef IPV6_SUPPORT
    if (addr->saddr.sa_family == AF_INET6) {
        memcpy(&sock6->sin6_addr, hp->h_addr, hp->h_length);
    } else
#endif /* IPv6 support */
    {
        memcpy(&sock4->sin_addr, hp->h_addr, hp->h_length);
    }

    return TRUE;
}
예제 #12
0
/**************************************************************************
  Update all information in the player list dialog.
**************************************************************************/
void update_players_dialog(void)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */
}
예제 #13
0
/**************************************************************************
  Display the player list dialog.  Optionally raise it.
**************************************************************************/
void popup_players_dialog(bool raise)
{
	freelog(LOG_VERBOSE, "Port Me %s [@%s:%d]", __func__, __FILE__, __LINE__);
  /* PORTME */
}
예제 #14
0
/********************************************************************** 
  Read a new line into cur_line; also copy to copy_line.
  Increments line_num and cur_line_pos.
  Returns 0 if didn't read or other problem: treat as EOF.
  Strips newline from input.
***********************************************************************/
static bool read_a_line(struct inputfile *inf)
{
  struct astring *line;
  char *ret;
  int pos;
  
  assert_sanity(inf);

  if (inf->at_eof)
    return FALSE;
  
  /* abbreviation: */
  line = &inf->cur_line;
  
  /* minimum initial line length: */
  astr_minsize(line, 80);
  pos = 0;

  /* don't print "orig line" in warnings until we have it: */
  inf->copy_line.n = 0;
  
  /* Read until we get a full line:
   * At start of this loop, pos is index to trailing null
   * (or first position) in line.
   */
  for(;;) {
    ret = fz_fgets(line->str + pos, line->n_alloc - pos, inf->fp);
    
    if (!ret) {
      /* fgets failed */
      inf->at_eof = TRUE;
      if (inf->in_string) {
        /* Note: Don't allow multi-line strings to cross "include"
         * boundaries */
        inf_log(inf, LOG_ERROR, "Multi-line string went to end-of-file");
        return FALSE;
      }
      break;
    }
    
    pos += strlen(line->str + pos);
    line->n = pos + 1;
    
    if (line->str[pos-1] == '\n') {
      line->str[pos-1] = '\0';
      line->n--;
      break;
    }
    if (line->n != line->n_alloc) {
      freelog(LOG_VERBOSE, "inputfile: expect missing newline at EOF");
    }
    astr_minsize(line, line->n*2);
  }
  inf->line_num++;
  inf->cur_line_pos = 0;

  astr_minsize(&inf->copy_line, inf->cur_line.n + ((inf->cur_line.n == 0) ? 1 : 0));
  strcpy(inf->copy_line.str, inf->cur_line.str);

  if (check_include(inf)) {
    return read_a_line(inf);
  }

  if (inf->at_eof) {
    line->str[0] = '\0';
    line->n = 0;
    if (inf->included_from) {
      /* Pop the include, and get next line from file above instead. */
      struct inputfile *inc = inf->included_from;
      inf_close_partial(inf);
      *inf = *inc;    /* so the user pointer in still valid
                       * (and inf pointers in calling functions) */
      free(inc);
      return read_a_line(inf);
    }
    return FALSE;
  } else {
    return TRUE;
  }
}
예제 #15
0
/********************************************************************** 
  Check for an include command, which is an isolated line with:
     *include "filename"
  If a file is included via this mechanism, returns 1, and sets up
  data appropriately: (*inf) will now correspond to the new file,
  which is opened but no data read, and inf->included_from is set
  to newly malloced memory which corresponds to the old file.
***********************************************************************/
static bool check_include(struct inputfile *inf)
{
  const char *include_prefix = "*include";
  static size_t len = 0;
  char *bare_name, *full_name, *c;
  struct inputfile *new_inf, temp;

  if (len==0) {
    len = strlen(include_prefix);
  }
  assert_sanity(inf);
  if (inf->in_string || inf->cur_line.n <= len || inf->cur_line_pos > 0) {
    return FALSE;
  }
  if (strncmp(inf->cur_line.str, include_prefix, len)!=0) {
    return FALSE;
  }
  /* from here, the include-line must be well formed or we die */
  /* keep inf->cur_line_pos accurate just so error messages are useful */

  /* skip any whitespace: */
  inf->cur_line_pos = len;
  c = inf->cur_line.str + len;
  while (*c != '\0' && my_isspace(*c)) c++;

  if (*c != '\"') {
    inf_log(inf, LOG_ERROR, 
            "Did not find opening doublequote for '*include' line");
    return FALSE;
  }
  c++;
  inf->cur_line_pos = c - inf->cur_line.str;

  bare_name = c;
  while (*c != '\0' && *c != '\"') c++;
  if (*c != '\"') {
    inf_log(inf, LOG_ERROR, 
            "Did not find closing doublequote for '*include' line");
    return FALSE;
  }
  *c++ = '\0';
  inf->cur_line_pos = c - inf->cur_line.str;

  /* check rest of line is well-formed: */
  while (*c != '\0' && my_isspace(*c) && !is_comment(*c)) c++;
  if (!(*c=='\0' || is_comment(*c))) {
    inf_log(inf, LOG_ERROR, "Junk after filename for '*include' line");
    return FALSE;
  }
  inf->cur_line_pos = inf->cur_line.n-1;

  full_name = inf->datafn(bare_name);
  if (!full_name) {
    freelog(LOG_ERROR, "Could not find included file \"%s\"", bare_name);
    return FALSE;
  }

  /* avoid recursion: (first filename may not have the same path,
     but will at least stop infinite recursion) */
  {
    struct inputfile *inc = inf;
    do {
      if (inc->filename && strcmp(full_name, inc->filename)==0) {
        freelog(LOG_ERROR, 
                "Recursion trap on '*include' for \"%s\"", full_name);
        return FALSE;
      }
    } while((inc=inc->included_from));
  }
  
  new_inf = inf_from_file(full_name, inf->datafn);

  /* Swap things around so that memory pointed to by inf (user pointer,
     and pointer in calling functions) contains the new inputfile,
     and newly allocated memory for new_inf contains the old inputfile.
     This is pretty scary, lets hope it works...
  */
  temp = *new_inf;
  *new_inf = *inf;
  *inf = temp;
  inf->included_from = new_inf;
  return TRUE;
}
예제 #16
0
/**************************************************************************
  Convert string from display encoding (16 bit unicode) to
  local encoding (8 bit char) and resut put in 'pToString'.
  if 'pToString' == NULL then resulting string will be allocate automaticaly.
  'length' give real sizeof 'pToString' array.

  Function return (char *) pointer to (new) pToString.
**************************************************************************/
char *convertcopy_to_chars(char *pToString, size_t length,
			    const Uint16 * pFromUniString)
{
  /* Start Parametrs */
  const char *pFromcode = get_display_encoding();
  const char *pTocode = get_internal_encoding();
  const char *pStart = (char *) pFromUniString;
  size_t ulength = (unistrlen(pFromUniString) + 1) * 2;

  /* ===== */

  char *pResult;
  iconv_t cd;
  
  /* ===== */

  if (!pStart) {
    return pToString;
  }

  cd = iconv_open(pTocode, pFromcode);
  if (cd == (iconv_t) (-1)) {
    if (errno != EINVAL) {
      return pToString;
    }
  }

  if(pToString) {
    pResult = pToString;
  } else {
    length = ulength * 2; /* UTF-8: up to 4 bytes per char */
    pResult = fc_calloc(1, length);
  }
  
  iconv(cd, NULL, NULL, NULL, NULL);	/* return to the initial state */

  /* Do the conversion for real. */
  {
    const char *pInptr = pStart;
    size_t Insize = ulength;
    char *pOutptr = pResult;
    size_t Outsize = length;

    while (Insize > 0 && Outsize > 0) {
      size_t Res =
	  iconv(cd, (ICONV_CONST char **) &pInptr, &Insize, &pOutptr, &Outsize);
      if (Res == (size_t) (-1)) {
        freelog(LOG_ERROR, "iconv() error: %s", fc_strerror(fc_get_errno()));        
	if (errno == EINVAL) {
	  break;
	} else {
	  int saved_errno = errno;
	  iconv_close(cd);
	  errno = saved_errno;
	  if(!pToString) {
	    FC_FREE(pResult);
	  }
	  return pToString;
	}
      }
    }

    {
      size_t Res = iconv(cd, NULL, NULL, &pOutptr, &Outsize);
      if (Res == (size_t) (-1)) {
	int saved_errno = errno;
	iconv_close(cd);
	errno = saved_errno;
	if(!pToString) {
	  FC_FREE(pResult);
	}
	return pToString;
      }
    }

  }

  iconv_close(cd);

  return pResult;
}