From 75b30f3aa6ab8af80cfdc455e511beb3b0fb26e0 Mon Sep 17 00:00:00 2001 From: Igor Socec Date: Thu, 3 Apr 2014 02:04:13 +0200 Subject: [PATCH] connected client needs to provide a username which will be communicated to rejected clients --- client.c | 43 +++++++++++++++++++++++++++++++++++++++++++ feature_wishlist.txt | 12 ------------ moxerver.c | 4 +++- moxerver.h | 13 ++++++++++++- server.c | 8 +++++--- 5 files changed, 63 insertions(+), 17 deletions(-) delete mode 100644 feature_wishlist.txt diff --git a/client.c b/client.c index cca23df..75c26f9 100644 --- a/client.c +++ b/client.c @@ -82,3 +82,46 @@ int client_write(struct client_t *client, char *databuf, int datalen) { return len; } + +/* Waits for client to provide a username. Blocks until a username is entered. */ +int client_ask_username(struct client_t *client) { + + int i; + char databuf[DATABUF_LEN]; + fd_set read_fds; + + /* send username request to client */ + snprintf(databuf, DATABUF_LEN, + "\nPlease provide a username to identify yourself to other users (max %d characters):\n", USERNAME_LEN); + client_write(client, databuf, strlen(databuf)); + + /* wait for client input */ + client->username[0] = '\0'; + while (client->username[0] == '\0') { + /* send prompt character to client */ + snprintf(databuf, DATABUF_LEN, "> "); + client_write(client, databuf, strlen(databuf)); + /* setup select() parameters */ + FD_ZERO(&read_fds); + FD_SET(client->socket, &read_fds); + select((client->socket)+1, &read_fds, NULL, NULL, NULL); + if (FD_ISSET(client->socket, &read_fds)) { + client_read(client); + /* handle client input */ + for (i = 0; i < USERNAME_LEN; i++) { + if (client->data[i] == '\r') { + break; + } + client->username[i] = client->data[i]; + } + client->username[i+1] = '\0'; + } + } + + /* send welcome message to client */ + snprintf(databuf, DATABUF_LEN, + "\nWelcome %s!\n\n", client->username); + client_write(client, databuf, strlen(databuf)); + + return 0; +} diff --git a/feature_wishlist.txt b/feature_wishlist.txt deleted file mode 100644 index 3da2a33..0000000 --- a/feature_wishlist.txt +++ /dev/null @@ -1,12 +0,0 @@ -- support multiple client connections at the same time - - first client has control - - additional clients can see the traffic - - read-only: requests from controlling client and responses from tty device - - need to avoid unintentional lock up if controlling client stays connected but user goes away and forgets about it - - additional clients should be able to force disconnecting controlling client - - first additional client that forces this becomes controlling client - -- require username when connecting to the server - - allows tracking users - - makes the feature above (forcing disconnect) easier to use - - username can be connected to a person easier than an IP address diff --git a/moxerver.c b/moxerver.c index 77f68d4..b4ecc0a 100644 --- a/moxerver.c +++ b/moxerver.c @@ -210,12 +210,14 @@ int main(int argc, char *argv[]) { fprintf(stderr, "[%s] problem accepting client\n", NAME); continue; } + /* ask client to provide a username before going to "character" mode */ + client_ask_username(&client); /* put client in "character" mode */ telnet_set_character_mode(&client); } /* reject connection request if a client is already connected */ else { - server_reject(&server); + server_reject(&server, &client); } } /* check client status if connected */ diff --git a/moxerver.h b/moxerver.h index ccf5055..9b8d2d4 100644 --- a/moxerver.h +++ b/moxerver.h @@ -17,6 +17,7 @@ #define TIMESTAMP_FORMAT "%d.%m.%Y. %H:%M:%S" #define TIMESTAMP_LEN 20+1 /* calculated following timestamp format */ #define CONFILE "moxanix.cfg" +#define USERNAME_LEN 32 /* Structures used for communication parameters. */ struct server_t { @@ -30,6 +31,7 @@ struct client_t { struct sockaddr_in address; /* client address information */ char ip_string[INET_ADDRSTRLEN]; /* client IP address as a string */ time_t last_active; /* time of client's last activity in seconds from Epoch */ + char username[USERNAME_LEN]; /* username for human identification */ char data[DATABUF_LEN]; /* buffer for data received from client */ }; @@ -94,7 +96,7 @@ int server_accept(struct server_t *server, struct client_t *accepted_client); * Returns: * 0 always, errors with rejected client are ignored */ -int server_reject(struct server_t *server); +int server_reject(struct server_t *server, struct client_t *client); /* Functions handling communication with clients. */ @@ -127,6 +129,15 @@ int client_read(struct client_t *client); */ int client_write(struct client_t *client, char *databuf, int datalen); +/** + * Waits for client to provide a username. + * Blocks until a username is entered. + * + * Returns: + * 0 always + */ +int client_ask_username(struct client_t *client); + /* Functions handling details related to telnet protocol. */ diff --git a/server.c b/server.c index e6a96c6..17f6760 100644 --- a/server.c +++ b/server.c @@ -104,7 +104,7 @@ int server_accept(struct server_t *server, struct client_t *accepted_client) { } /* Rejects incoming client connection. Errors with rejected client are ignored. */ -int server_reject(struct server_t *server) { +int server_reject(struct server_t *server, struct client_t *client) { int namelen; struct client_t rclient; @@ -114,8 +114,10 @@ int server_reject(struct server_t *server) { /* accept connection request */ namelen = sizeof(rclient.address); rclient.socket = accept(server->socket, (struct sockaddr *) &rclient.address, (socklen_t *) &namelen); - /* send reject message */ - sprintf(reject_msg, "[%s] port %u is already being used\n", __func__, server->port); + /* send reject message to client */ + time2string(client->last_active, timestamp); + sprintf(reject_msg, "\nPort %u is already being used:\ncurrent user: %s\nlast activity: @ %s\n\n", + server->port, client->username, timestamp); send(rclient.socket, reject_msg, strlen(reject_msg), 0); /* close connection */ close(rclient.socket);