Changeset - c318109520cc
[Not reviewed]
default
0 18 0
Nathan Brink (binki) - 15 years ago 2010-08-07 20:08:12
ohnobinki@ohnopublishing.net
User authentication and some access checking.
18 files changed with 610 insertions and 286 deletions:
0 comments (0 inline, 0 general)
doc/architecture.txt
Show inline comments
 
@@ -58,6 +58,10 @@ Concepts:
 
      of actions a client may perform.
 

	
 
- user: A user is an entity which is given access to a distren server.
 
  - user identifiction: As users are per-server, a user shall be identified by the name of the
 
      server he has an account on combined with his handle. A tilde prefixes the username to
 
      differentiate this URL from a job's URL.
 
      distren://<servername>/~<username> , like distren://ohnopub.net/~ohnobinki
 

	
 
- file: There are different uses of files above and distributed rendering requires file distribution.
 
  - file identification: Every file mentioned above was at least in the context of a job. Thus,
etc/distrencommon.conf
Show inline comments
 
@@ -28,6 +28,7 @@ server localhost
 
{
 
  hostname = "localhost"
 
  username = "test"
 
  password = "xyzzy123"
 
  method = "tcp"
 
  types = {"submit", "distribution", "master"}
 
}
src/client/libdistren.c
Show inline comments
 
@@ -47,6 +47,9 @@ int distren_init(distren_t *handle)
 
  struct distren_request *req;
 
  void *data;
 

	
 
  const char *username;
 
  const char *pass;
 

	
 
  if(!handle)
 
    return 1;
 

	
 
@@ -64,6 +67,20 @@ int distren_init(distren_t *handle)
 
      return 1;
 
    }
 

	
 
  tmp = remoteio_authinfo_get((*handle)->options->remoteio,
 
			      (*handle)->server,
 
			      &username,
 
			      &pass);
 
  if(tmp
 
     || !username
 
     || !pass)
 
    {
 
      fprintf(stderr, "error: unable to find information necessary to connect to the server named ``%s'', please check your configuration file.\n",
 
	      (*handle)->server);
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 

	
 
  tmp = remoteio_open_server(&(*handle)->rem,
 
			     (*handle)->options->remoteio,
 
			     (remoteio_read_handle_func_t)&libdistren_remoteio_read_handle,
 
@@ -90,8 +107,39 @@ int distren_init(distren_t *handle)
 
  distren_request_send((*handle)->rem, req, data);
 
  distren_request_free_with_data(req, data);
 

	
 
  tmp = distren_request_pass(&req, &data, username, pass);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error: unable to allocate request");
 

	
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 
  distren_request_send((*handle)->rem, req, data);
 
  distren_request_free_with_data(req, data);
 

	
 
  /*
 
   * There is no response to the DISTREN_REQUEST_PASS packet. However,
 
   * we want to ensure that the username/password we sent are valid
 
   * before returning to the claler. Thus, we here send a PING
 
   * packet. If we get the DISTREN_REQUEST_PONG, we know we're
 
   * authenticated. Otherwise, we'll receive a quit/discconect packet.
 
   */
 
  tmp = distren_request_poing(&req, &data, 1, "auth test", strlen("auth test"));
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error: Unable to allocate a DISTREN_REQUEST_PING\n");
 

	
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 
  distren_request_send((*handle)->rem, req, data);
 
  distren_request_free_with_data(req, data);
 

	
 
  /* flush out the above packets. */
 
  while((*handle)->rem
 
	&& (*handle)->state == DISTREN_STATE_VERSION)
 
	&& ((*handle)->state == DISTREN_STATE_VERSION
 
	    || (*handle)->state == DISTREN_STATE_AUTH))
 
      multiio_poll((*handle)->multiio, 500);
 

	
 
  if(!(*handle)->rem)
src/client/libdistren.h
Show inline comments
 
@@ -43,7 +43,6 @@ enum distren_state
 
     */
 
    DISTREN_STATE_AUTH,
 
    DISTREN_STATE_NORMAL,
 
    DISTREN_STATE_UPLOADING,
 
  };
 

	
 
struct distren
src/client/libdistren_request.c
Show inline comments
 
@@ -25,7 +25,10 @@
 
#include "common/remoteio.h"
 
#include "common/request.h"
 

	
 
#include <string.h>
 

	
 
static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data);
 
static void handle_pong(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data);
 
static void handle_version(distren_t distren, struct distren_request *req, void *req_data);
 
static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data);
 

	
 
@@ -72,6 +75,10 @@ size_t libdistren_remoteio_read_handle(s
 
	  handle_ping(rem, req, req_data);
 
	  break;
 

	
 
	case DISTREN_REQUEST_PONG:
 
	  handle_pong(distren, rem, req, req_data);
 
	  break;
 

	
 
	case DISTREN_REQUEST_VERSION:
 
	  handle_version(distren, req, req_data);
 
	  break;
 
@@ -118,6 +125,15 @@ static void handle_ping(struct remoteio 
 
  distren_request_free_with_data(pong_req, pong_req_data);
 
}
 

	
 
static void handle_pong(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data)
 
{
 
  const char *auth_test_str = "auth test";
 

	
 
  if(req->len == strlen(auth_test_str)
 
     && !strncmp(req_data, auth_test_str, req->len))
 
    distren->state = DISTREN_STATE_NORMAL;
 
}
 

	
 
static void handle_version(distren_t distren, struct distren_request *req, void *req_data)
 
{
 
  struct distren_request_version version;
src/common/libremoteio.h
Show inline comments
 
@@ -49,6 +49,7 @@ struct remoteio_server
 
  char *name; /*< The friendly named passed to remoteio_open() */
 
  char *hostname;
 
  char *username;
 
  char *password;
 
  enum remoteio_method method;
 
  unsigned int types; /*< See ``Server types'' in protocol.h */
 
};
src/common/options.c
Show inline comments
 
@@ -173,6 +173,7 @@ int options_init(int argc, char *argv[],
 
  cfg_opt_t server_opts[] =
 
    {
 
      CFG_STR("username", NULL, CFGF_NONE),
 
      CFG_STR("password", NULL, CFGF_NONE),
 
      CFG_STR("hostname", NULL, CFGF_NONE),
 
      CFG_STR("method", "ssh", CFGF_NONE),
 
      CFG_STR_LIST("types", NULL, CFGF_NONE),
src/common/protocol.h
Show inline comments
 
@@ -61,12 +61,28 @@ enum distren_request_type
 
    */
 
    DISTREN_REQUEST_VERSION = 1,
 
    /**
 
     * Test if the end has a live server.
 
     *
 
     * Only authenticated clients may use this request. Thus, if a
 
     * client wants to confirm that a DISTREN_REQUEST_PASS request was
 
     * successful, that client may send a DISTREN_REQUEST_PING
 
     * immediately after the DISTREN_REQUEST_PASS and then wait for
 
     * the PONG.
 
     *
 
     * DATA: up to 32 bytes of a PING cookie
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_PING = 2,
 
    /**
 
     * Response to DISTREN_REQUEST_PING.
 
     *
 
     * Unauthenticated clients may be penalized for responding to PING
 
     * requests. This is because a newly connecting client should
 
     * queue a DISTREN_REQUEST_VERSION and DISTREN_REQUEST_PASS
 
     * back-to-back before checking for and processing data from the
 
     * remote server.
 
     *
 
     * DATA: up to 32 bytes copied from a received PING cookie
 
     *
 
     * REQUIRED: ALL
 
@@ -84,12 +100,31 @@ enum distren_request_type
 
     */
 
    DISTREN_REQUEST_DISCONNECT = 4,
 

	
 

	
 
    /**
 
     * Allow a client to identify itself using simple password
 
     * authentication.
 
     *
 
     * As there is no distren request which affirms a
 
     * DISTREN_REQUEST_PASS went through, clients may send a
 
     * DISTREN_REQUEST_PING and wait for the DISTREN_REQUETS_PONG they
 
     * want to block until they're authenticated.
 
     *
 
     * DATA: struct distren_request_pass
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT (for now, since
 
     * server2server links are only protected using password
 
     * authentication, all server types have to support this except
 
     * for the client.)
 
     */
 
    DISTREN_REQUEST_PASS = 5,
 

	
 
    /**
 
     * DATA: struct distren_request_submit
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT
 
     */
 
    DISTREN_REQUEST_SUBMIT = 5,
 
    DISTREN_REQUEST_SUBMIT = 6,
 

	
 
    /**
 
     * Inform the other party about a job.
 
@@ -98,7 +133,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_JOBINFO = 6,
 
    DISTREN_REQUEST_JOBINFO = 7,
 

	
 
    /**
 
     * Request a DISTREN_REQUEST_JOBINFO
 
@@ -107,7 +142,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_JOBINFO_GET = 7,
 
    DISTREN_REQUEST_JOBINFO_GET = 8,
 

	
 
    /**
 
     * Command the other party to render a frame
 
@@ -116,7 +151,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER
 
     */
 
    DISTREN_REQUEST_FRAME_RENDER = 8,
 
    DISTREN_REQUEST_FRAME_RENDER = 9,
 
    /**
 
     * Inform the receiver of the sender's state, such as frames being
 
     * rendered or jobs that need to be completed.
 
@@ -125,7 +160,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER, DISTREN_SERVERTYPE_DISTRIBUTE, DISTREN_SERVERTYPE_CLIENT
 
     */
 
    DISTREN_REQUEST_STATUS = 9,
 
    DISTREN_REQUEST_STATUS = 10,
 

	
 
    /**
 
     * Request that the receiver send a DISTREN_REQUEST_FRAME_STATUS
 
@@ -136,7 +171,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER
 
     */
 
    DISTREN_REQUEST_STATUS_GET = 10,
 
    DISTREN_REQUEST_STATUS_GET = 11,
 

	
 
    /**
 
     * Declare that a client is preparing to post a file using a
 
@@ -157,7 +192,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_POST_START = 11,
 
    DISTREN_REQUEST_FILE_POST_START = 12,
 

	
 
    /**
 
     * Allow a client to upload a job tarball over a remoteio line.  A
 
@@ -182,7 +217,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_POST = 12,
 
    DISTREN_REQUEST_FILE_POST = 13,
 

	
 
    /**
 
     * Marks a post-id's file as having completely uploaded. Provides
 
@@ -193,7 +228,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_POST_FINISH = 13,
 
    DISTREN_REQUEST_FILE_POST_FINISH = 14,
 

	
 
    /**
 
     * Request information about obtaining a file (such as a
 
@@ -203,7 +238,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_FIND = 14,
 
    DISTREN_REQUEST_FILE_FIND = 15,
 

	
 
    /**
 
     * Provide information about obtaining a file (such as a URL).
 
@@ -212,7 +247,7 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE = 15,
 
    DISTREN_REQUEST_FILE = 16,
 
  };
 

	
 
struct distren_request
 
@@ -236,6 +271,14 @@ struct distren_request_version
 
  char package_string[DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN + 1];
 
};
 

	
 
#define DISTREN_REQUEST_PASS_USERNAME_LEN (16)
 
#define DISTREN_REQUEST_PASS_PASS_LEN (32)
 
struct distren_request_pass
 
{
 
  char username[DISTREN_REQUEST_PASS_USERNAME_LEN];
 
  char pass[DISTREN_REQUEST_PASS_PASS_LEN];
 
};
 

	
 
#define DISTREN_REQUEST_FILE_POST_NAME_LEN (64)
 
struct distren_request_file_post_start
 
{
src/common/remoteio.c
Show inline comments
 
@@ -142,9 +142,16 @@ int remoteio_config(cfg_t *cfg, struct r
 
      
 
      cfg_aserver = cfg_getnsec(cfg, "server", counter);
 
      
 
      aserver.name = NULL;
 
      aserver.hostname = NULL;
 
      aserver.username = NULL;
 
      aserver.password = NULL;
 
      
 
      aserver.name = strdup(cfg_title(cfg_aserver));
 
      aserver.hostname = strdup(cfg_getstr(cfg_aserver, "hostname"));
 
      aserver.username = strdup(cfg_getstr(cfg_aserver, "username"));
 
      if(cfg_getstr(cfg_aserver, "password"))
 
	aserver.password = strdup(cfg_getstr(cfg_aserver, "password"));
 

	
 
      aserver.method = REMOTEIO_METHOD_MAX;
 
      method = cfg_getstr(cfg_aserver, "method");
 
@@ -288,6 +295,26 @@ int remoteio_open_server(struct remoteio
 
  return 0;
 
}
 

	
 
int remoteio_authinfo_get(struct remoteio_opts *rem_opts, const char *servername, const char **username, const char **pass)
 
{
 
  struct remoteio_server *server;
 

	
 
  *username = NULL;
 
  *pass = NULL;
 

	
 
  server = remoteio_getserver(rem_opts, servername);
 
  if(!server)
 
    {
 
      fprintf(stderr, "%s:%d: Could not find server named ``%s''\n", __FILE__, __LINE__, servername);
 
      return 1;
 
    }
 

	
 
  *username = server->username;
 
  *pass = server->password;
 

	
 
  return 0;
 
}
 

	
 
/**
 
 * Implementation of multiio_event_handler_func_t
 
 */
src/common/remoteio.h
Show inline comments
 
@@ -120,6 +120,21 @@ int remoteio_open_socket(struct remoteio
 
int remoteio_write(struct remoteio *rem, const void *buf, size_t len);
 

	
 
/**
 
 * \brief Retrieves authentication information associated with a
 
 *   server's configuration entry.
 
 *
 
 * Possibly, the whole idea of remoteio handling server names with the
 
 * remoteio_open() function should be moved somewhere else and
 
 * remoteio should be more general-purpose I/O?
 
 *
 
 * \param rem_opts A remoteio options handle.
 
 * \param servername The name of the server whose information should be retrieved.
 
 * \param username Where to store a pointer to the username. Do not free this.
 
 * \param pass Where to store a pointer to the password. Do not free this.
 
 */
 
int remoteio_authinfo_get(struct remoteio_opts *rem_opts, const char *servername, const char **username, const char **pass);
 

	
 
/**
 
 * Closes a remoteio session.
 
 *
 
 * It is safe to call this function from within
src/common/request.c
Show inline comments
 
@@ -69,6 +69,35 @@ int distren_request_parse_version(struct
 
  return 0;
 
}
 

	
 
int distren_request_pass(struct distren_request **req, void **data, const char *username, const char *pass)
 
{
 
  struct distren_request_pass *request_pass;
 

	
 
  distren_request_new(req, sizeof(struct distren_request_pass), DISTREN_REQUEST_PASS);
 
  request_pass = malloc(sizeof(struct distren_request_pass));
 
  if(!request_pass || !*req)
 
    {
 
      if(*req)
 
	distren_request_free(*req);
 
      free(request_pass);
 

	
 
      return 1;
 
    }
 

	
 
  /*
 
   * The packet itself doesn't need the string's NULL terminator
 
   * _unless_ if the string is shorter than the maximum length of the
 
   * username or password. Thus, strncpy()'s behavior (not strlcpy()'s
 
   * behavior) is _exactly_ what we want for this case.
 
   */
 
  strncpy(request_pass->username, username, DISTREN_REQUEST_PASS_USERNAME_LEN);
 
  strncpy(request_pass->pass, pass, DISTREN_REQUEST_PASS_PASS_LEN);
 

	
 
  *data = request_pass;
 

	
 
  return 0;
 
}
 

	
 
int distren_request_poing(struct distren_request **req, void **data, short is_ping, const void *poing_cookie, size_t poing_data_len)
 
{
 
  enum distren_request_type type;
src/common/request.h
Show inline comments
 
@@ -56,6 +56,16 @@ int distren_request_version(struct distr
 
int distren_request_parse_version(struct distren_request *req, void *data, struct distren_request_version *version);
 

	
 
/**
 
 * Initialize a PASS request so as to identify to a server.
 
 *
 
 * \param req Where to store the newly allocated req.
 
 * \param data Where to store the newly allocated data.
 
 * \param user The username to send to the server.
 
 * \param pass The password to send to the server.
 
 */
 
int distren_request_pass(struct distren_request **req, void **data, const char *username, const char *pass);
 

	
 
/**
 
 * Initialize a PING or PONG request.
 
 *
 
 * @param data a place to allocate storage for the data associated with this request
src/server/distrend.c
Show inline comments
 
@@ -24,8 +24,9 @@
 

	
 
#include "distrenjob.h"
 
#include "listen.h"
 
#include "mysql.h"
 
#include "slavefuncs.h"
 
#include "mysql.h"
 
#include "user_mgr.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/execio.h"
 
@@ -62,6 +63,12 @@ struct general_info
 
  {
 
    /** general_info.xml */
 
    char *geninfo;
 

	
 
    /**
 
     * \brief Where to store the user listing.
 
     */
 
    char *userlist;
 

	
 
    /**
 
     * where to store in-progress uploads or things that should
 
     * otherwise be on the same filesystem as the rest of the datadir
 
@@ -81,6 +88,8 @@ struct general_info
 
  time_t timestamp;
 
  unsigned long total_render_power;
 
  unsigned long total_priority_pieces;
 

	
 
  user_mgr_t user_mgr;
 
};
 

	
 

	
 
@@ -98,6 +107,7 @@ int distrend_handle_request(struct distr
 
 * client request handlers
 
 */
 
int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
int distrend_handle_pass(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
int distrend_handle_file_post_start(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
int distrend_handle_file_post(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
int distrend_handle_file_post_finish(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
@@ -171,6 +181,18 @@ Ethan Zonca <e@ethanzonca.com>\n\
 
		    general_info.config->datadir);
 
  distren_mkdir_recurse(general_info.files.tmpdir);
 

	
 
  _distren_asprintf(&general_info.files.userlist, "%s/users.xml",
 
		    general_info.config->datadir);
 

	
 
  /** configuraton stuff that depends on the paths being calculated, such as loading data */
 
  general_info.user_mgr = user_mgr_init(general_info.files.userlist);
 
  if(!general_info.user_mgr)
 
    {
 
      fprintf(stderr, "Error initializing user_mgr\n");
 
      return 1;
 
    }
 

	
 

	
 
  /** MySQL Connection */
 
  fprintf(stderr,"Connecting to mysql...\n");
 
  if(mysqlConnect(&general_info.conn,
 
@@ -206,10 +228,12 @@ Ethan Zonca <e@ethanzonca.com>\n\
 
	}
 
    }
 

	
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_VERSION, &distrend_handle_version);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST_START, &distrend_handle_file_post_start);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST, &distrend_handle_file_post);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST_FINISH, &distrend_handle_file_post_finish);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_VERSION, &distrend_handle_version, (uint8_t)DISTREND_CLIENT_PREVERSION);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_PASS,
 
			      &distrend_handle_pass, (uint8_t)DISTREND_CLIENT_PREAUTH);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST_START, &distrend_handle_file_post_start, (uint8_t)DISTREND_CLIENT_GOOD);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST, &distrend_handle_file_post, (uint8_t)DISTREND_CLIENT_GOOD);
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_FILE_POST_FINISH, &distrend_handle_file_post_finish, (uint8_t)DISTREND_CLIENT_GOOD);
 

	
 
  /* Main Loop */
 
  general_info.config->die = 0;
 
@@ -230,6 +254,8 @@ Ethan Zonca <e@ethanzonca.com>\n\
 

	
 
  /** free() paths */
 
  free(general_info.files.geninfo);
 
  free(general_info.files.tmpdir);
 
  free(general_info.files.userlist);
 
  mysqlDisconnect(general_info.conn);
 

	
 
  return 0;
 
@@ -285,6 +311,45 @@ int distrend_handle_version(struct gener
 
}
 

	
 
/**
 
 * Handle a DISTREN_REQUEST_PASS request.
 
 */
 
int distrend_handle_pass(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data)
 
{
 
  struct distren_request_pass *pass_req;
 

	
 
  char username[DISTREN_REQUEST_PASS_USERNAME_LEN + 1];
 
  char pass[DISTREN_REQUEST_PASS_PASS_LEN + 1];
 

	
 
  struct user *user;
 

	
 
  if(req->len < sizeof(struct distren_request_pass))
 
    {
 
      distrend_send_disconnect(client, "You tried to send too short of a DISTREN_REQUEST_PASS.");
 
      return 1;
 
    }
 

	
 
  pass_req = req_data;
 
  memcpy(username, pass_req->username, DISTREN_REQUEST_PASS_USERNAME_LEN);
 
  username[DISTREN_REQUEST_PASS_USERNAME_LEN] = '\0';
 

	
 
  memcpy(pass, pass_req->pass, DISTREN_REQUEST_PASS_PASS_LEN);
 
  pass[DISTREN_REQUEST_PASS_PASS_LEN] = '\0';
 

	
 
  user = user_find(geninfo->user_mgr, username);
 
  if(!user
 
     || strcmp(user->username, username)
 
     || strcmp(user->pass, pass))
 
    {
 
      distrend_send_disconnect(client, "Invalid username or password.");
 
      return 1;
 
    }
 

	
 
  client->state = DISTREND_CLIENT_GOOD;
 

	
 
  return 0;
 
}
 

	
 
/**
 
 * Traversal helper for distrend_client_find_post().
 
 */
 
int distrend_client_find_post_traverse(uint32_t *post_id, struct distrend_client_file_post *client_file_post)
src/server/listen.c
Show inline comments
 
@@ -42,6 +42,11 @@ struct distrend_request_handler_info
 
{
 
  enum distren_request_type request_type;
 
  distrend_handle_request_func_t handler;
 
  /**
 
   * A bitmasking of different enum distren_client_states which are
 
   * allowed to use this particular command.
 
   */
 
  uint8_t client_states;
 
};
 

	
 
struct distrend_client *distrend_client_new(struct distrend_listens *listens,
 
@@ -277,7 +282,6 @@ int listen_handle_accept(multiio_context
 
			 short revent,
 
			 struct distrend_listens *listens,
 
			 int *port)
 
   //int distrend_accept(struct distrend_listens *listens)//, struct distrend_clientset *clients, distrend_handle_request_t handlereq, void *handlereqdata)
 
 {
 
   struct distrend_client *newclient;
 

	
 
@@ -361,6 +365,12 @@ size_t distrend_listen_read_handle(struc
 

	
 
   size_t used_len;
 

	
 
  /*
 
   * ignore packets from a client who's going to be disconnected.
 
   */
 
  if(client->state == DISTREND_CLIENT_BAD)
 
    return len;
 

	
 
   used_len = 0;
 
   /**
 
    * Manage input, etc.
 
@@ -555,7 +565,7 @@ int distrend_send_disconnect(struct dist
 
  return 0;
 
}
 

	
 
int distrend_listen_handler_add(struct distrend_listens *listens, enum distren_request_type type, distrend_handle_request_func_t handler)
 
int distrend_listen_handler_add(struct distrend_listens *listens, enum distren_request_type type, distrend_handle_request_func_t handler, uint8_t client_state_mask)
 
{
 
  struct distrend_request_handler_info *handler_info;
 

	
 
@@ -565,6 +575,7 @@ int distrend_listen_handler_add(struct d
 

	
 
  handler_info->request_type = type;
 
  handler_info->handler = handler;
 
  handler_info->client_states = client_state_mask;
 
  list_insert_after(listens->request_handlers, handler_info, 0);
 

	
 
  return 0;
 
@@ -584,8 +595,20 @@ struct distrend_dispatch_request_data
 
int _distrend_dispatch_request_trav(struct distrend_dispatch_request_data *data, struct distrend_request_handler_info *handler_info)
 
{
 
  if(handler_info->request_type == data->req->type)
 
    {
 
      /* check permissions first */
 
      if(!(data->client->state & handler_info->client_states))
 
	{
 
	  distrend_send_disconnect(data->client, "You attempted to use a command out of context.");
 
	  return FALSE;
 
	}
 

	
 
    (*handler_info->handler)(data->geninfo, data->client, data->req, data->req_data);
 

	
 
      /* shortcut one a hit ;-) */
 
      return FALSE;
 
    }
 

	
 
  return TRUE;
 
}
 

	
src/server/listen.h
Show inline comments
 
@@ -59,27 +59,31 @@ struct distrend_client;
 
 */
 
#define DISTREND_LISTEN_DISCONNECT_GRACE 8
 

	
 
/**
 
 * Numbers are explicitly given so that commands can be restricted to
 
 * clients in certain states.
 
 */
 
enum distrend_client_state
 
  {
 
    /**
 
       The client hasn't yet given us its version.
 
     */
 
    DISTREND_CLIENT_PREVERSION,
 
    DISTREND_CLIENT_PREVERSION = 1,
 
    /**
 
       We don't yet know the client. It may only use authentication
 
       commands.
 
     */
 
    DISTREND_CLIENT_PREAUTH,
 
    DISTREND_CLIENT_PREAUTH = 2,
 
    /**
 
       The client is authenticated, etc.
 
     */
 
    DISTREND_CLIENT_GOOD,
 
    DISTREND_CLIENT_GOOD = 4,
 
    /**
 
       The client is queued to be disconnected. (This state exists
 
       so that the client at least has a chance to recieve its
 
       disconnect message/error before being dumped).
 
     */
 
    DISTREND_CLIENT_BAD,
 
    DISTREND_CLIENT_BAD = 8,
 
  };
 

	
 
struct distrend_listens
 
@@ -188,11 +192,15 @@ int distrend_listen_add(struct distrend_
 
/**
 
 * Register a request handler with the listener.
 
 *
 
 * @param config distrend's configuration
 
 * @param type the request type for which this handler should be called
 
 * @param handler the handler to call when a request of type type is received.
 
 * \param config distrend's configuration.
 
 * \param type The request type for which this handler should be
 
 *   called
 
 * \param handler The handler to call when a request of type type is
 
 *   received.
 
 * \param client_state_mask A mask of enum distrend_client_state
 
 *   values that are allowed to use this command.
 
 */
 
int distrend_listen_handler_add(struct distrend_listens *listens, enum distren_request_type type, distrend_handle_request_func_t handler);
 
int distrend_listen_handler_add(struct distrend_listens *listens, enum distren_request_type type, distrend_handle_request_func_t handler, uint8_t client_state_mask);
 

	
 
/**
 
 * cleans listening sockets/frees main struct. Unnecessary for a working server, currently a stub.
src/server/tabletennis.c
Show inline comments
 
@@ -60,8 +60,8 @@ tabletennis_t tabletennis_new(struct dis
 
  tabletennis->clients_need_pong = q_init();
 
  clock_gettime(CLOCK_MONOTONIC, &tabletennis->time_last_check);
 

	
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PING, &tabletennis_ping_request_handle);
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PONG, &tabletennis_pong_request_handle);
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PING, &tabletennis_ping_request_handle, (uint8_t)DISTREND_CLIENT_GOOD);
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PONG, &tabletennis_pong_request_handle, (uint8_t)DISTREND_CLIENT_GOOD);
 

	
 
  return tabletennis;
 
}
src/server/user_mgr.c
Show inline comments
 
/*
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 

	
 
  This file is a part of DistRen.
 

	
 
  DistRen is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU Affero General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  DistRen is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU Affero General Public License for more details.
 

	
 
  You should have received a copy of the GNU Affero General Public License
 
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 *  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
 *
 
 * This file is a part of DistRen.
 
 *
 
 * DistRen is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "common/config.h"
 
@@ -23,6 +23,7 @@
 

	
 
#include "common/asprintf.h"
 

	
 
#include <list.h>
 

	
 
#include <libxml/xmlmemory.h>
 
#include <libxml/parser.h>
 
@@ -37,305 +38,288 @@
 
#include <unistd.h>
 
#include <sys/stat.h>
 

	
 
struct user_mgr_info
 
struct user_mgr
 
{
 
	struct user *user_array;
 
	int current_users;
 
	int user_array_size;
 
} user_mgr_info;
 

	
 
int resize_user_array()
 
{
 
	int counter;
 
	int counter2;
 

	
 
	// create array twice the size of the current amount of users
 
	user_mgr_info.user_array_size = user_mgr_info.current_users * 2;
 
	struct user *new_user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size);
 
  /* items are of type user_t */
 
  list_t user_list;
 
  /* where to load/save the userlist */
 
  char *userlist_filename;
 
};
 

	
 
	// this copies the original user_array over to the new one
 
	// using two counters allows the array to be resized at any time
 
	// leaving exactly 1 open space between each user when it is done;
 
	counter2 = 0;
 
	for(counter = 0; counter < user_mgr_info.current_users; counter++)
 
	{
 
		if(user_mgr_info.user_array[counter].username != 0)
 
static int user_find_traverse_forw(char *search_username, user_t user)
 
		{
 
			new_user_array[counter2*2] = user_mgr_info.user_array[counter];
 
			counter2++;
 
		}
 
	}
 

	
 
	// cleanup old array
 
	free(user_mgr_info.user_array);
 

	
 
	// change the pointer to point to the new user array
 
	user_mgr_info.user_array = new_user_array;
 

	
 
	return 1;
 
  if(strcmp(search_username, user->username) >= 0)
 
    return FALSE;
 
  return TRUE;
 
}
 

	
 
struct user *findUser(char *nameOfUser)
 
{
 
	int high;
 
	int low;
 
	int middle;
 
	int result;
 

	
 
	high = user_mgr_info.user_array_size - 1;
 
	low = 0;
 
	result = -1;
 

	
 
	for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
 
	{
 
		// in case middle lands on a part of the array with no user
 
		while(user_mgr_info.user_array[middle].username == 0)
 
static int user_find_traverse_back(char *search_username, user_t user)
 
		{
 
			if(result < 0)
 
				middle --;
 
			else
 
				middle ++;
 
		}
 

	
 
		// this is where the array is cut in half and the half that the nameOfUser is on is kept
 
		result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username);
 
		if(result == 0)
 
			return &user_mgr_info.user_array[middle];
 
		else if(result < 0)
 
			high = middle;
 
		else
 
			low = middle;
 

	
 
		// in case the user doesn't exist
 
		if(high-low <= 0)
 
			return 0;
 
	}
 
}
 

	
 
int deleteUser(struct user *user_ptr)
 
{
 
	free(user_ptr->username);
 
	memset(user_ptr, '\0', sizeof(struct user));
 

	
 
	user_mgr_info.current_users--;
 

	
 
	return 1;
 

	
 
	backup_list_XML();
 
}
 

	
 
int createUser(struct user *user_ptr, char *nameOfUser)
 
{
 
	// clear old memory
 
	memset(user_ptr, '\0', sizeof(struct user));
 

	
 
	user_ptr->username = nameOfUser;
 
	user_ptr->render_power = 0;
 
	user_ptr->last_job = 0;
 

	
 
	user_mgr_info.current_users++;
 

	
 
	return 1;
 
  if(strcmp(search_username, user->username) <= 0)
 
    return FALSE;
 
  return TRUE;
 
}
 

	
 
// places the new user at position index in the array, moves other users if it needs to
 
int placeUser(int index, char *nameOfUser)
 
user_t user_find(user_mgr_t user_mgr, const char *username)
 
{
 
	int higher;
 
	int lower;
 
	int total_moves;
 
  int list_direction;
 
  list_traverse_func_t traverse_func;
 

	
 
	total_moves = 0;
 
  user_t user;
 
  char *username_copy;
 

	
 
	// I shift data in the array to create an open the space where the user should be added
 
	// but first I figure out which way is the shortest
 
	if(user_mgr_info.user_array[index].username != 0)
 
	{
 
		higher = index + 1;
 
		while(user_mgr_info.user_array[higher].username != 0)
 
			higher++;
 
  if(list_empty(user_mgr->user_list))
 
    return NULL;
 

	
 
		lower = index - 1;
 
		while(user_mgr_info.user_array[lower].username != 0)
 
			lower--;
 
  /* grab the current user for tiny optimizations.. */
 
  user = list_curr(user_mgr->user_list);
 
  if(!user)
 
    return NULL;
 

	
 
		// here the data is shifted to open up a space
 
		if(index - lower < higher - index)
 
		  {
 
		    total_moves = index - lower;
 
		    for(; lower < index; lower++)
 
				memcpy(&user_mgr_info.user_array[lower], &user_mgr_info.user_array[lower + 1], sizeof(struct user));
 
		  }
 
		else
 
  list_direction = LIST_FORW;
 
  traverse_func = (list_traverse_func_t)&user_find_traverse_forw;
 
  if(strcmp(user->username, username) < 0)
 
		  {
 
		    total_moves = higher - index;
 
		    for(; higher > index; higher--)
 
				memcpy(&user_mgr_info.user_array[higher], &user_mgr_info.user_array[higher - 1], sizeof(struct user));
 
		  }
 
	}
 
      list_direction = LIST_BACK;
 
      traverse_func = (list_traverse_func_t)&user_find_traverse_back;
 
    };
 

	
 
	// add the user to the array
 
	createUser(&user_mgr_info.user_array[index], nameOfUser);
 
  username_copy = strdup(username);
 
  list_traverse(user_mgr->user_list, username_copy, traverse_func, list_direction|LIST_CURR|LIST_ALTR);
 
  free(username_copy);
 
  user = list_curr(user_mgr->user_list);
 
  if(!user)
 
    return NULL;
 

	
 
	if(total_moves > 50)
 
	  resize_user_array();
 
  if(!strcmp(username, user->username))
 
    return user;
 

	
 
	return 1;
 
  return NULL;
 
}
 

	
 
int addUser(char *nameOfUser)
 
int user_add(user_mgr_t user_mgr, const char *username, const char *pass)
 
{
 
	int high;
 
	int low;
 
	int middle;
 
	int result;
 
  user_t user;
 
  short insert_after;
 

	
 
  user = user_find(user_mgr, username);
 
  if(user)
 
    return 1;
 

	
 
	high = user_mgr_info.user_array_size - 1;
 
	low = 0;
 
	result = -1;
 

	
 
	for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
 
  /*
 
   * The list should be positioned within one element of where we want
 
   * to insert username.
 
   */
 
  insert_after = 1;
 
  user = list_curr(user_mgr->user_list);
 
  if(user)
 
	{
 
		// in case middle lands on a part of the array with no user
 
		while(user_mgr_info.user_array[middle].username == 0)
 
		{
 
			if(result < 0)
 
				middle--;
 
			else
 
				middle++;
 
      if(strcmp(username, user->username) < 0)
 
	insert_after = 0;
 
		}
 

	
 
		// this is where the array is cut in half and the half that the nameOfUser is on is kept
 
		result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username);
 
		if(result == 0)
 
			return 0;
 
		else if(result < 0)
 
			high = middle;
 
		else
 
			low = middle;
 

	
 
		// once there are less than 10 possible places for the user to be placed
 
		// break out of this loop and begin next loop
 
		if(high-low <= 10)
 
			break;
 
	}
 
  /*
 
   * construct the new user.
 
   */
 
  user = malloc(sizeof(struct user));
 
  if(!user)
 
    return 1;
 
  user->username = strdup(username);
 
  user->pass = strdup(pass);
 
  user->render_power = 0;
 
  user->last_job = 0;
 

	
 
	// this function starts at the low index number, and goes up until it finds a
 
	// username that is bigger than it alphabetically, and tells the userPlacer
 
	// that it needs to go 1 before that spot
 
	for(; low <= high; low++)
 
	{
 
		while(user_mgr_info.user_array[low].username == 0)
 
			low++;
 
  /* I admit it... I'm completely crazy --binki */
 
  if(insert_after)
 
    list_insert_after(user_mgr->user_list, user, 0);
 
  else
 
    list_insert_before(user_mgr->user_list, user, 0);
 

	
 
		result = strcmp(nameOfUser, user_mgr_info.user_array[low].username) < 0;
 
		if(result < 0)
 
		{
 
			placeUser(low - 1, nameOfUser);
 
			return 1;
 
		}
 
		if(result == 0)
 
		{
 
			fprintf(stderr, "user already exists");
 
			return 0;
 
		}
 
	}
 

	
 
	backup_list_XML();
 
	return 0;
 
}
 

	
 
int initialize_users()
 
{
 
  struct stat buffer;
 
  // cif user_list.xml exists
 
  if(stat("user_list.xml", &buffer) == 0)
 
  {
 
    restart_From_XML_backup();
 
  }
 
  else
 
/**
 
 * \brief For list_free() et al
 
 */
 
static void user_free(user_t user)
 
  {
 
    user_mgr_info.current_users = 0;
 

	
 
    user_mgr_info.user_array_size = 50;
 
    user_mgr_info.user_array = malloc(sizeof(struct user) * 50);
 
  }
 

	
 
  // if XML file is not found create new array of size 50
 

	
 

	
 
  return 1;
 
  free(user->username);
 
  free(user->pass);
 
  free(user);
 
}
 

	
 
/********************************** XMLness *****************************/
 

	
 
int backup_list_XML()
 
int user_delete(user_mgr_t user_mgr, user_t user)
 
{
 
	xmlTextWriterPtr writer;
 
        char *tmp;
 
	int counter;
 
  user_t user_found;
 
  int ret;
 

	
 

	
 
	writer = xmlNewTextWriterFilename("user_list.xml", 0);
 
	xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 
  ret = 0;
 

	
 
	// create root element user_list
 
	xmlTextWriterStartElement(writer, (xmlChar*)"user_list");
 
  user_found = user_find(user_mgr, user->username);
 
  if(user_found
 
     && user_found == user
 
     && user == list_curr(user_mgr->user_list))
 
    list_remove_curr(user_mgr->user_list);
 
  else
 
    {
 
      fprintf(stderr, __FILE__ ":%d:user_delete(): List is inconsistent :-/\n", __LINE__);
 
      ret = 1;
 
    }
 

	
 
	_distren_asprintf(&tmp, "%d", user_mgr_info.current_users);
 
	xmlTextWriterWriteAttribute(writer, (xmlChar*)"amount_of_users", (xmlChar*)tmp);
 
	free(tmp);
 
  user_free(user);
 

	
 
  return ret;
 
}
 

	
 
	for(counter = 0; counter < user_mgr_info.user_array_size; counter++)
 
static int user_mgr_save_traverse(xmlTextWriterPtr writer, user_t user)
 
	{
 
		if(user_mgr_info.user_array[counter].username != 0)
 
		{
 
  char *tmp;
 

	
 
			xmlTextWriterStartElement(writer, (xmlChar*)"user");
 

	
 
			xmlTextWriterWriteAttribute(writer, (xmlChar*)"name", (xmlChar*)user_mgr_info.user_array[counter].username);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar *)"name", (xmlChar*)user->username);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar *)"pass", (xmlChar*)user->pass);
 

	
 
			_distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].last_job);
 
  _distren_asprintf(&tmp, "%d", user->last_job);
 
			xmlTextWriterWriteAttribute(writer, (xmlChar*)"last_job", (xmlChar*)tmp);
 
			free(tmp);
 

	
 
			_distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].render_power);
 
  _distren_asprintf(&tmp, "%d", user->render_power);
 
			xmlTextWriterWriteAttribute(writer, (xmlChar*)"render_power", (xmlChar*)tmp);
 
			free(tmp);
 

	
 
			xmlTextWriterEndElement(writer);
 
		}
 
	}
 

	
 
	return 0;
 

	
 
  return TRUE;
 
}
 

	
 
int restart_From_XML_backup(){
 
int user_mgr_save(user_mgr_t user_mgr, const char *filename)
 
{
 
  xmlTextWriterPtr writer;
 

	
 
  if(!filename)
 
    filename = user_mgr->userlist_filename;
 

	
 
  writer = xmlNewTextWriterFilename(filename, 0);
 
  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

	
 
  /*
 
   * create root element user_list
 
   */
 
  xmlTextWriterStartElement(writer, (xmlChar*)"user_list");
 

	
 
  /**
 
   * \todo error checking/handling?
 
   */
 
  list_traverse(user_mgr->user_list, writer, (list_traverse_func_t)&user_mgr_save_traverse, LIST_FRNT|LIST_FORW|LIST_SAVE);
 

	
 
  xmlTextWriterEndElement(writer);
 
  xmlTextWriterEndDocument(writer);
 
  xmlTextWriterFlush(writer);
 

	
 
  return 0;
 
}
 

	
 
user_mgr_t user_mgr_init(const char *userfile)
 
{
 
  xmlDocPtr doc;
 
  xmlNodePtr cur;
 
  int counter;
 

	
 
  user_mgr_t user_mgr;
 

	
 
  user_t user;
 
  xmlChar *username;
 
  xmlChar *pass;
 
  xmlChar *tmp;
 
  int render_power;
 
  int last_job;
 

	
 
  doc = xmlParseFile("user_list.xml");
 
  user_mgr = malloc(sizeof(struct user_mgr));
 
  user_mgr->user_list = list_init();
 
  user_mgr->userlist_filename = strdup(userfile);
 

	
 
  doc = xmlParseFile(userfile);
 
  if (!doc)
 
    {
 
      fprintf(stderr, "user_mgr: Error opening userlist, assuming we should start with an empty userlist\n");
 
      return user_mgr;
 
    }
 

	
 
  cur = xmlDocGetRootElement(doc);
 
  if (xmlStrcmp(cur->name, (xmlChar*)"user_list"))
 
    {
 
      fprintf(stderr, "xml document is wrong type");
 
      fprintf(stderr, "user_mgr: xml document is wrong type. Using empty userlist, which will overwrite the old userlist soon probably...");
 
      xmlFreeDoc(doc);
 
      return 1;
 
      return user_mgr;
 
    }
 

	
 
  for(cur = cur->xmlChildrenNode; cur; cur = cur->next)
 
    {
 
      if (cur->type != XML_ELEMENT_NODE)
 
	/* skip the implicit XML_TEXT_NODEs */
 
	continue;
 

	
 
      if (xmlStrcmp(cur->name, (xmlChar *)"user"))
 
	{
 
	  fprintf(stderr, "user_mgr: Unrecognized XML element: <%s />\n",
 
		 cur->name);
 

	
 
	  continue;
 
	}
 

	
 
      username = xmlGetProp(cur, (xmlChar *)"name");
 
      pass = xmlGetProp(cur, (xmlChar *)"pass");
 

	
 
      if(!username)
 
	{
 
	  fprintf(stderr, "<user /> is missing a name attribute! (skipping)\n");
 
	  continue;
 
	}
 
      if(!pass)
 
	{
 
	  fprintf(stderr, "<user name=\"%s\"/> is missing a pass attribute! (skipping)\n",
 
		  username ? (char *)username : "");
 
	  continue;
 
    }
 

	
 
  user_mgr_info.current_users = atoi((char*)xmlGetProp(cur, (xmlChar*)"amount_of_users"));
 

	
 
  user_mgr_info.user_array_size = user_mgr_info.current_users * 2;
 
  user_mgr_info.user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size);
 
      last_job = 0;
 
      tmp = xmlGetProp(cur, (xmlChar *)"last_job");
 
      if(tmp)
 
	{
 
	  last_job = atoi((char *)tmp);
 
	  xmlFree(tmp);
 
	}
 

	
 
  cur = cur->xmlChildrenNode;
 
  for(counter = 0; cur->next; counter++){
 
    user_mgr_info.user_array[counter*2].username = (char*)xmlGetProp(cur, (xmlChar*)"amount_of_users");
 
    user_mgr_info.user_array[counter*2].last_job = atoi((char*)xmlGetProp(cur, (xmlChar*)"last_job"));
 
    user_mgr_info.user_array[counter*2].render_power = atoi((char*)xmlGetProp(cur, (xmlChar*)"render_power"));
 
    cur = cur->next;
 
      render_power = 0;
 
      if(tmp)
 
	{
 
	  tmp = xmlGetProp(cur, (xmlChar *)"render_power");
 
	  render_power = atoi((char *)tmp);
 
	  xmlFree(tmp);
 
  }
 

	
 
  return 0;
 
      user_add(user_mgr, (char *)username, (char *)pass);
 
      xmlFree(username);
 
      xmlFree(pass);
 

	
 
      /*
 
       * user_find should be a very inexpensive operation immediately
 
       * after the user_add() above. I just don't want to trust to
 
       * list_curr() right in this function ;-).
 
       *
 
       * Also, we set this information without passing the following
 
       * as arguments to user_add() because user_add() is an external
 
       * API used for when a user is initially added to the
 
       * userlist. Thus, everybody'd be calling it with
 
       * user_add("username", "pass", 0, 0);
 
       */
 
      user = user_find(user_mgr, (char *)username);
 
      if(user)
 
	{
 
	  user->render_power = render_power;
 
	  user->last_job = last_job;
 
}
 
    }
 

	
 
  return user_mgr;
 
}
src/server/user_mgr.h
Show inline comments
 
@@ -28,12 +28,62 @@
 
struct user
 
{
 
	char *username;
 
  char *pass;
 
	int render_power;
 
	int last_job;
 
};
 
typedef struct user *user_t;
 

	
 
struct user_mgr;
 
typedef struct user_mgr *user_mgr_t;
 

	
 
/**
 
 * \brief Allocate and initialize a user_mgr.
 
 *
 
 * \param userfile The path to where and XML file with user
 
 *   information may be found and where the users file should be save
 
 *   to when new users are added.
 
 * \return The new user_mgr or NULL on error.
 
 */
 
user_mgr_t user_mgr_init(const char *userfile);
 

	
 
/**
 
 * \brief Find a user by username.
 
 *
 
 * \param user_mgr The user_mgr...
 
 * \param username The username to search for.
 
 * \return The user if it is in user_mgr or NULL.
 
 */
 
user_t user_find(user_mgr_t user_mgr, const char *username);
 

	
 
/**
 
 * \brief Add a user to the user_mgr.
 
 *
 
 * \param username The user's username (which is local in scope to this server).
 
 * \param pass The user's plaintext password (insecurity is sooo much easier ;-) ).
 
 * \return 0 on success, 1 on failure (attempt to insert duplicate user, etc.).
 
 */
 
int user_add(user_mgr_t user_mgr, const char *username, const char *pass);
 

	
 
/**
 
 * \brief Delete a user.
 
 *
 
 * The user handle passed to this function is no longer valid after
 
 * this function is called.
 
 *
 
 * \param user The user's handle as retrieved via user_find().
 
 * \return 0 on success, 1 on failure (user does not exist, inconsistency, etc.)
 
 */
 
int user_delete(user_mgr_t user_mgr, user_t user);
 

	
 
/**
 
 * \brief Write out the XML file listing all of the users local to this server.
 
 *
 
 * \param filename The file to write the userlist to or NULL if you
 
 *   want to write to the same filename you loaded the usre_mgr from.
 
 */
 
int user_mgr_save(user_mgr_t user_mgr, const char *filename);
 

	
 

	
 
int restart_From_XML_backup();
 
int backup_list_XML();
 

	
 
#endif
0 comments (0 inline, 0 general)