From 7a8d4d0934cb51c8ad7f7af84669bb0197c7b89e Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Fri, 19 Jun 2020 18:03:08 +0200 Subject: Zero incoming passwords in memory using libsodium --- Makefile | 6 ++- command.c | 167 ++++++++++++++++++++++++++++++++++---------------------------- main.c | 5 ++ 3 files changed, 101 insertions(+), 77 deletions(-) diff --git a/Makefile b/Makefile index 03ad55b..0ed32b2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ CC = gcc -CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -D_DEFAULT_SOURCE -LDFLAGS = -lsqlite3 -ldl +CFLAGS = -Wall -Wextra -std=c11 -g -O2 -fwrapv -D_DEFAULT_SOURCE +LDFLAGS = -ldl +CFLAGS += $(shell pkg-config --cflags sqlite3 libsodium) +LDFLAGS += $(shell pkg-config --libs sqlite3 libsodium) TARGETS = tomsg_server diff --git a/command.c b/command.c index e4d75d3..04e9fe0 100644 --- a/command.c +++ b/command.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "broadcast.h" #include "command.h" #include "db.h" @@ -15,17 +16,31 @@ #include "util.h" -static bool cmd_register(struct conn_data *data,const char *tag,const char **args){ +struct cmd_retval{ + bool socket_close; + bool memzero; +}; +#define RET_OK ((struct cmd_retval){.socket_close=false,.memzero=false}) +#define RET_CLOSE(close_) ((struct cmd_retval){.socket_close=(close_),.memzero=false}) +#define RET_MEMZERO ((struct cmd_retval){.socket_close=false,.memzero=true}) +#define RET_MEMZERO_CLOSE(close_) ((struct cmd_retval){.socket_close=(close_),.memzero=true}) + +static struct cmd_retval cmd_register(struct conn_data *data,const char *tag,const char **args){ i64 userid=db_find_user(args[0]); if(userid!=-1){ net_send_error(data->fd,tag,"Username already exists"); - return false; + return RET_OK; } db_create_user(args[0],args[1]); - return net_send_ok(data->fd,tag); + return RET_MEMZERO_CLOSE(net_send_ok(data->fd,tag)); } -static bool cmd_login(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_login(struct conn_data *data,const char *tag,const char **args){ + // TODO: use sodium_mlock correctly for the password + + // Note: this function has exactly ONE return point, so that it is easier + // to see that we indeed return MEMZERO. + i64 userid=db_find_user(args[0]); if(userid==-1){ net_send_error(data->fd,tag,"User not found"); @@ -34,28 +49,28 @@ static bool cmd_login(struct conn_data *data,const char *tag,const char **args){ broadcast_online_change(data->userid); data->userid=-1; } - return false; - } - char *pass=db_get_pass(userid); - bool success=strcmp(args[1],pass)==0; - free(pass); - if(data->userid!=-1){ - userdata_unregister(data->userid,data->fd); - broadcast_online_change(data->userid); - } - if(success){ - data->userid=userid; - userdata_register(userid,data->fd); - net_send_ok(data->fd,tag); - broadcast_online_change(userid); } else { - data->userid=-1; - net_send_error(data->fd,tag,"Incorrect password"); + char *pass=db_get_pass(userid); + bool success=strcmp(args[1],pass)==0; + free(pass); + if(data->userid!=-1){ + userdata_unregister(data->userid,data->fd); + broadcast_online_change(data->userid); + } + if(success){ + data->userid=userid; + userdata_register(userid,data->fd); + net_send_ok(data->fd,tag); + broadcast_online_change(userid); + } else { + data->userid=-1; + net_send_error(data->fd,tag,"Incorrect password"); + } } - return false; + return RET_MEMZERO; } -static bool cmd_logout(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_logout(struct conn_data *data,const char *tag,const char **args){ (void)args; if(data->userid!=-1){ userdata_unregister(data->userid,data->fd); @@ -63,19 +78,19 @@ static bool cmd_logout(struct conn_data *data,const char *tag,const char **args) data->userid=-1; } net_send_ok(data->fd,tag); - return false; + return RET_OK; } -static bool cmd_list_rooms(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_list_rooms(struct conn_data *data,const char *tag,const char **args){ (void)args; if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } struct db_room_list rl=db_list_rooms(data->userid); if(rl.count<=0){ db_nullify_room_list(rl); - return net_send_list(data->fd,tag,0,NULL); + return RET_CLOSE(net_send_list(data->fd,tag,0,NULL)); } const char *names[rl.count]; for(i64 i=0;ifd,tag,rl.count,names); db_nullify_room_list(rl); - return closed; + return RET_CLOSE(closed); } -static bool cmd_list_members(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_list_members(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } i64 roomid=db_find_room(args[0]); if(roomid==-1){ net_send_error(data->fd,tag,"Room not found"); - return false; + return RET_OK; } if(!db_is_member(roomid,data->userid)){ net_send_error(data->fd,tag,"Not in that room"); - return false; + return RET_OK; } struct db_user_list ul=db_list_members(roomid); if(ul.count<=0){ db_nullify_user_list(ul); - return net_send_list(data->fd,tag,0,NULL); + return RET_CLOSE(net_send_list(data->fd,tag,0,NULL)); } const char *names[ul.count]; for(i64 i=0;ifd,tag,ul.count,names); db_nullify_user_list(ul); - return closed; + return RET_CLOSE(closed); } -static bool cmd_create_room(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_create_room(struct conn_data *data,const char *tag,const char **args){ (void)args; if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } userdata_mark_active(data->userid,data->fd,true); struct db_name_id room=db_create_room(); db_add_member(room.id,data->userid); bool closed=net_send_name(data->fd,tag,room.name); db_nullify_name_id(room); - return closed; + return RET_CLOSE(closed); } -static bool cmd_invite(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_invite(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } userdata_mark_active(data->userid,data->fd,true); const char *roomname=args[0]; i64 roomid=db_find_room(roomname); if(roomid==-1){ net_send_error(data->fd,tag,"Room not found"); - return false; + return RET_OK; } i64 user2=db_find_user(args[1]); if(user2==-1){ net_send_error(data->fd,tag,"User not found"); - return false; + return RET_OK; } if(!db_is_member(roomid,data->userid)){ net_send_error(data->fd,tag,"Not in that room"); - return false; + return RET_OK; } if(db_is_member(roomid,user2)){ net_send_error(data->fd,tag,"User already in that room"); - return false; + return RET_OK; } db_add_member(roomid,user2); @@ -187,13 +202,13 @@ static bool cmd_invite(struct conn_data *data,const char *tag,const char **args) free(joinbuf); free(invitebuf); - return net_send_ok(data->fd,tag); + return RET_CLOSE(net_send_ok(data->fd,tag)); } -static bool cmd_send(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_send(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } userdata_mark_active(data->userid,data->fd,true); const char *roomname=args[0]; @@ -201,11 +216,11 @@ static bool cmd_send(struct conn_data *data,const char *tag,const char **args){ i64 roomid=db_find_room(roomname); if(roomid==-1){ net_send_error(data->fd,tag,"Room not found"); - return false; + return RET_OK; } if(!db_is_member(roomid,data->userid)){ net_send_error(data->fd,tag,"Not in that room"); - return false; + return RET_OK; } i64 timestamp=make_timestamp(); @@ -236,10 +251,10 @@ static bool cmd_send(struct conn_data *data,const char *tag,const char **args){ db_nullify_user_list(members); free(pushbuf); - return closed; + return RET_CLOSE(closed); } -static bool history_cmd_helper( +static struct cmd_retval history_cmd_helper( struct conn_data *data,const char *tag,const char **args, const char *cmdname,i64 beforeid){ char *endp; @@ -247,22 +262,22 @@ static bool history_cmd_helper( if(args[1][0]=='\0'||*endp!='\0'||nrequested<0){ debug("Connection fd=%d sent an invalid number for '%s': '%s'", data->fd,cmdname,args[1]); - return true; + return RET_CLOSE(true); } if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } const char *roomname=args[0]; i64 roomid=db_find_room(roomname); if(roomid==-1){ net_send_error(data->fd,tag,"Room not found"); - return false; + return RET_OK; } if(!db_is_member(roomid,data->userid)){ net_send_error(data->fd,tag,"Not in that room"); - return false; + return RET_OK; } struct db_message_list ml=db_get_messages_before(roomid,nrequested,beforeid); @@ -273,7 +288,7 @@ static bool history_cmd_helper( if(closed){ db_nullify_message_list(ml); - return true; + return RET_CLOSE(true); } for(i64 i=ml.count-1;i>=0;i--){ @@ -287,73 +302,73 @@ static bool history_cmd_helper( } db_nullify_message_list(ml); - return closed; + return RET_CLOSE(closed); } -static bool cmd_history(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_history(struct conn_data *data,const char *tag,const char **args){ return history_cmd_helper(data,tag,args,"history",-1); } -static bool cmd_history_before(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_history_before(struct conn_data *data,const char *tag,const char **args){ char *endp; i64 beforeid=strtoll(args[2],&endp,10); if(args[2][0]=='\0'||*endp!='\0'){ debug("Connection fd=%d sent an invalid id for 'history_before': '%s'", data->fd,args[2]); - return true; + return RET_CLOSE(true); } if(beforeid<0)beforeid=INT64_MAX; return history_cmd_helper(data,tag,args,"history_before",beforeid); } -static bool cmd_ping(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_ping(struct conn_data *data,const char *tag,const char **args){ (void)args; - return net_send_pong(data->fd,tag); + return RET_CLOSE(net_send_pong(data->fd,tag)); } -static bool cmd_is_online(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_is_online(struct conn_data *data,const char *tag,const char **args){ i64 userid=db_find_user(args[0]); if(userid==-1){ net_send_error(data->fd,tag,"User not found"); - return false; + return RET_OK; } i64 nfds; (void)userdata_online(userid,&nfds); - return net_send_number(data->fd,tag,nfds); + return RET_CLOSE(net_send_number(data->fd,tag,nfds)); } -static bool cmd_firebase_token(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_firebase_token(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } db_add_token(data->userid,args[0]); - return net_send_ok(data->fd,tag); + return RET_CLOSE(net_send_ok(data->fd,tag)); } -static bool cmd_delete_firebase_token(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_delete_firebase_token(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } db_delete_token(data->userid,args[0]); - return net_send_ok(data->fd,tag); + return RET_CLOSE(net_send_ok(data->fd,tag)); } -static bool cmd_user_active(struct conn_data *data,const char *tag,const char **args){ +static struct cmd_retval cmd_user_active(struct conn_data *data,const char *tag,const char **args){ if(data->userid==-1){ net_send_error(data->fd,tag,"Not logged in"); - return false; + return RET_OK; } char *endp; i64 active=strtoll(args[0],&endp,10); if(args[0][0]=='\0'||*endp!='\0'||active<0){ debug("Connection fd=%d sent an invalid number for 'user_active': '%s'",data->fd,args[0]); - return true; + return RET_CLOSE(true); } userdata_mark_active(data->userid,data->fd,active>0); - return net_send_ok(data->fd,tag); + return RET_CLOSE(net_send_ok(data->fd,tag)); } @@ -361,7 +376,7 @@ struct cmd_info{ const char *cmdname; int nargs; bool longlast; // whether the last argument should span the rest of the input line - bool (*handler)(struct conn_data *data,const char *tag,const char **args); + struct cmd_retval (*handler)(struct conn_data *data,const char *tag,const char **args); }; static const struct cmd_info commands[]={ @@ -437,5 +452,7 @@ bool handle_input_line(struct conn_data *data,char *line,size_t linelen){ return true; } - return commands[cmdi].handler(data,tag,(const char**)args); + struct cmd_retval retval=commands[cmdi].handler(data,tag,(const char**)args); + if(retval.memzero)sodium_memzero(line,linelen); + return retval.socket_close; } diff --git a/main.c b/main.c index 6388fe2..497f66e 100644 --- a/main.c +++ b/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "broadcast.h" #include "command.h" #include "conn_data.h" @@ -157,6 +158,10 @@ void signal_handler(int sig){ int main(int argc,char **argv){ srandomdev(); + if(sodium_init()<0){ + fprintf(stderr,"Could not initialise libsodium!\n"); + return 1; + } signal(SIGPIPE,signal_handler); -- cgit v1.2.3-54-g00ecf