From 078b4d3f4127042b020e78bb9d9762196ff070c3 Mon Sep 17 00:00:00 2001 From: ilsimo Date: Fri, 24 Nov 2006 20:46:45 +0000 Subject: [PATCH] adding scp v1 first code, fixed passwd auth for disabled password --- sesman/Makefile | 7 +- sesman/libscp.h | 2 +- sesman/libscp_v1c.c | 249 +++++++++++++++++++++++++++++++++++++++++ sesman/libscp_v1c.h | 23 ++-- sesman/libscp_v1s.c | 179 ++++++++++++++++++++++++++--- sesman/libscp_v1s.h | 30 +++-- sesman/scp.c | 5 +- sesman/scp.h | 3 +- sesman/scp_v1.c | 192 +++++++++++++++++++++++++++++++ sesman/scp_v1.h | 42 +++++++ sesman/tools/Makefile | 40 +++++++ sesman/tools/sestest.c | 155 +++++++++++++++++++++++++ sesman/verify_user.c | 101 ++++++++++++++++- 13 files changed, 982 insertions(+), 46 deletions(-) create mode 100644 sesman/libscp_v1c.c create mode 100644 sesman/scp_v1.c create mode 100644 sesman/scp_v1.h create mode 100644 sesman/tools/Makefile create mode 100644 sesman/tools/sestest.c diff --git a/sesman/Makefile b/sesman/Makefile index 9dd94c45d9..293f5372c2 100644 --- a/sesman/Makefile +++ b/sesman/Makefile @@ -3,7 +3,7 @@ LIBSCPOBJ = libscp_vX.o libscp_v0.o libscp_v1s.o SESMANOBJ = sesman.o config.o tcp.o sig.o session.o env.o \ os_calls.o d3des.o list.o file.o log.o access.o \ - scp.o scp_v0.o thread.o lock.o \ + scp.o scp_v0.o scp_v1.o thread.o lock.o \ $(LIBSCPOBJ) SESRUNOBJ = sesrun.o config.o tcp.o lock.o \ @@ -16,7 +16,7 @@ MANDIR = /usr/local/man DOCDIR = /usr/doc/xrdp DEFINES = -DSESMAN_CFG_FILE=\"$(CFGDIR)/sesman.ini\" \ - -DSESMAN_PID_FILE=\"$(PIDDIR)/sesman.pid\" + -DSESMAN_PID_FILE=\"$(PIDDIR)/sesman.pid\" -DDEBUG CFLAGS = -Wall -O2 -I../common -I/usr/include/nptl $(DEFINES) LDFLAGS = -L /usr/gnu/lib -I/usr/include/nptl -L/usr/lib/nptl -lpthread $(DEFINES) @@ -44,15 +44,18 @@ kerberos-base: $(SESMANOBJ) verify_user_kerberos.o tools: $(SESRUNOBJ) $(CC) $(LDFLAGS) -o sesrun $(SESRUNOBJ) -ldl + make -C tools clean: rm -f $(SESMANOBJ) verify_user.o verify_user_pam.o verify_user_pam_userpass.o sesman sesrun.o sesrun + make -C tools clean install: install sesman $(DESTDIR)/sesman install sesrun $(DESTDIR)/sesrun install startwm.sh $(DESTDIR)/startwm.sh install sesman.ini $(CFGDIR)/sesman.ini + make -C tools install installdeb: install sesman $(DESTDIRDEB)/usr/lib/xrdp/sesman diff --git a/sesman/libscp.h b/sesman/libscp.h index d4b412baee..a445e98ee5 100644 --- a/sesman/libscp.h +++ b/sesman/libscp.h @@ -32,6 +32,6 @@ #include "libscp_vX.h" #include "libscp_v0.h" #include "libscp_v1s.h" -//#include "libscp_v1c.h" +#include "libscp_v1c.h" #endif diff --git a/sesman/libscp_v1c.c b/sesman/libscp_v1c.c new file mode 100644 index 0000000000..f2f6ffeec7 --- /dev/null +++ b/sesman/libscp_v1c.c @@ -0,0 +1,249 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +/** + * + * @file libscp_v1c.c + * @brief libscp version 1 client api code + * @author Simone Fedele + * + */ + +#include "libscp_v1c.h" + +static enum SCP_CLIENT_STATES_E _scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s); + +/* client API */ +/* 001 */ +enum SCP_CLIENT_STATES_E scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +{ + unsigned char sz; + uint32_t size; + //uint32_t version; + //uint16_t cmd; + //uint16_t dim; + + init_stream(c->out_s, c->out_s->size); + init_stream(c->in_s, c->in_s->size); + + size=19+17+4+ g_strlen(s->hostname) + g_strlen(s->username) + g_strlen(s->password); + if (s->addr_type==SCP_ADDRESS_TYPE_IPV4) + { + size=size+4; + } + else + { + size=size+16; + } + + /* sending request */ + + /* header */ + out_uint32_be(c->out_s, 1); /* version */ + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, 1); + + /* body */ + out_uint8(c->out_s, s->type); + out_uint16_be(c->out_s, s->height); + out_uint16_be(c->out_s, s->width); + out_uint8(c->out_s, s->bpp); + out_uint8(c->out_s, s->rsr); + out_uint8p(c->out_s, s->locale, 17); + out_uint8(c->out_s, s->addr_type); + + if (s->addr_type==SCP_ADDRESS_TYPE_IPV4) + { + out_uint32_be(c->out_s, s->ipv4addr); + } + else + { + #warning ipv6 address needed + } + + sz=g_strlen(s->hostname); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->hostname, sz); + sz=g_strlen(s->username); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->username, sz); + sz=g_strlen(s->password); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->password, sz); + + if (0!=tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + /* wait for response */ + return _scp_v1c_check_response(c, s); +} + +/* 004 */ +enum SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +{ + unsigned char sz; + uint32_t size; + //uint32_t version; + //uint16_t cmd; + //uint16_t dim; + + init_stream(c->out_s, c->out_s->size); + init_stream(c->in_s, c->in_s->size); + + size=12+2+g_strlen(s->username)+g_strlen(s->password); + + /* sending request */ + /* header */ + out_uint32_be(c->out_s, 1); /* version */ + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, 4); + + /* body */ + sz=g_strlen(s->username); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->username, sz); + sz=g_strlen(s->password); + out_uint8(c->out_s, sz); + out_uint8p(c->out_s, s->password, sz); + + if (0!=tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + /* wait for response */ + return _scp_v1c_check_response(c, s); +} + +/* 021 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); +/* 022 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); + +/* ... */ enum SCP_CLIENT_STATES_E scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s); +/* 041 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, SCP_SID sid); +/* 042 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c); + +/* 03x */ enum SCP_CLIENT_STATES_E scp_v1c_retrieve_session(struct SCP_CONNECTION* c, struct SCP_SESSION* s, struct SCP_DISCONNECTED_SESSION* ds); + +static enum SCP_CLIENT_STATES_E _scp_v1c_check_response(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +{ + uint32_t version; + uint32_t size; + uint16_t cmd; + uint16_t dim; + + init_stream(c->in_s, c->in_s->size); + if (0!=tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + if (version!=1) + { + return SCP_CLIENT_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + + init_stream(c->in_s, c->in_s->size); + /* read the rest of the packet */ + if (0!=tcp_force_recv(c->in_sck, c->in_s->data, size-8)) + { + return SCP_CLIENT_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + if (cmd!=SCP_COMMAND_SET_DEFAULT) + { + return SCP_CLIENT_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd) + if (cmd==2) /* connection denied */ + { + in_uint16_be(c->in_s, dim); + if (s->errstr!=0) + { + g_free(s->errstr); + } + s->errstr=g_malloc(dim+1,0); + if (s->errstr==0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim]='\0'; + + return SCP_CLIENT_STATE_CONNECTION_DENIED; + } + else if (cmd==3) /* resend usr/pwd */ + { + in_uint16_be(c->in_s, dim); + if (s->errstr!=0) + { + g_free(s->errstr); + } + s->errstr=g_malloc(dim+1,0); + if (s->errstr==0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim]='\0'; + + return SCP_CLIENT_STATE_RESEND_CREDENTIALS; + } + else if (cmd==20) /* password change */ + { + in_uint16_be(c->in_s, dim); + if (s->errstr!=0) + { + g_free(s->errstr); + } + s->errstr=g_malloc(dim+1,0); + if (s->errstr==0) + { + return SCP_CLIENT_STATE_INTERNAL_ERR; + } + in_uint8a(c->in_s, s->errstr, dim); + (s->errstr)[dim]='\0'; + + return SCP_CLIENT_STATE_PWD_CHANGE_REQ; + } + else if (cmd==30) /* display */ + { + in_uint16_be(c->in_s, s->display); + + return SCP_CLIENT_STATE_OK; + } + else if (cmd==32) /* display of a disconnected session */ + { + return SCP_CLIENT_STATE_RECONNECT; + } + else if (cmd==40) /* session list */ + { + return SCP_CLIENT_STATE_SESSION_LIST; + } + + return SCP_CLIENT_STATE_SEQUENCE_ERR; +} diff --git a/sesman/libscp_v1c.h b/sesman/libscp_v1c.h index b85b75081f..1707fb688a 100644 --- a/sesman/libscp_v1c.h +++ b/sesman/libscp_v1c.h @@ -30,24 +30,15 @@ #include "libscp_types.h" -enum SCP_CLIENt_STATES_E -{ - SCP_CLIENT_STATE_NO, - SCP_CLIENT_STATE_WRONGPWD, - SCP_CLIENT_STATE_PWDCHG_REQ, - SCP_CLIENT_STATE_PWDCHG_CANCEL, - SCP_CLIENT_STATE_ -}; - /* client API */ -/* 001 */ SCP_CLIENT_STATES_E scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); -/* 004 */ SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +/* 001 */ enum SCP_CLIENT_STATES_E scp_v1c_connect(struct SCP_CONNECTION* c, struct SCP_SESSION* s); +/* 004 */ enum SCP_CLIENT_STATES_E scp_v1c_resend_credentials(struct SCP_CONNECTION* c, struct SCP_SESSION* s); -/* 021 */ SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); -/* 022 */ SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); +/* 021 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change(struct SCP_CONNECTION* c, char* newpass); +/* 022 */ enum SCP_CLIENT_STATES_E scp_v1c_pwd_change_cancel(struct SCP_CONNECTION* c); -/* ... */ SCP_CLIENT_STATES_E scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s); -/* 041 */ SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, SCP_SID sid); -/* 042 */ SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c); +/* ... */ enum SCP_CLIENT_STATES_E scp_v1c_get_session_list(struct SCP_CONNECTION* c, int* scount, struct SCP_DISCONNECTED_SESSION** s); +/* 041 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session(struct SCP_CONNECTION* c, SCP_SID sid); +/* 042 */ enum SCP_CLIENT_STATES_E scp_v1c_select_session_cancel(struct SCP_CONNECTION* c); #endif diff --git a/sesman/libscp_v1s.c b/sesman/libscp_v1s.c index 47f6b376f5..e0b3058ee5 100644 --- a/sesman/libscp_v1s.c +++ b/sesman/libscp_v1s.c @@ -56,8 +56,13 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES return SCP_SERVER_STATE_NETWORK_ERR; } } + else + { + version=1; + } in_uint32_be(c->in_s, size); + LOG_DBG("size: %d",size); if (size<12) { return SCP_SERVER_STATE_SIZE_ERR; @@ -71,6 +76,7 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES /* reading command set */ in_uint16_be(c->in_s, cmdset); + LOG_DBG("command set: %d",cmdset); /* if we are starting a management session */ if (cmdset==SCP_COMMAND_SET_MANAGE) @@ -86,13 +92,18 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES /* reading command */ in_uint16_be(c->in_s, cmd); - if (cmd != 0) + LOG_DBG("command: %d",cmd); + if (cmd != 1) { return SCP_SERVER_STATE_SEQUENCE_ERR; } session = g_malloc(sizeof(struct SCP_SESSION),1); - if (0 == session) return SCP_SERVER_STATE_INTERNAL_ERR; + if (0 == session) + { + return SCP_SERVER_STATE_INTERNAL_ERR; + } + session->version=1; in_uint8(c->in_s, session->type); if ((session->type != SCP_SESSION_TYPE_XVNC) && (session->type != SCP_SESSION_TYPE_XRDP)) @@ -107,6 +118,8 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES in_uint8(c->in_s, session->rsr); in_uint8a(c->in_s, session->locale, 17); session->locale[17]='\0'; + + LOG_DBG("locale: %s\n", session->locale); in_uint8(c->in_s, session->addr_type); if (session->addr_type==SCP_ADDRESS_TYPE_IPV4) @@ -117,9 +130,12 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES { #warning how to handle ipv6 addresses? } - + + LOG_DBG("rest: %d\n",(unsigned char)*((c->in_s->p)+2)); + /* reading hostname */ in_uint8(c->in_s, sz); + LOG_DBG("size read: %d", sz); session->hostname=g_malloc(sz+1,1); if (0==session->hostname) { @@ -143,6 +159,7 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES /* reading password */ in_uint8(c->in_s, sz); + LOG_DBG("size read: %d", sz); session->password=g_malloc(sz+1,1); if (0==session->password) { @@ -154,15 +171,20 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES session->password[sz]='\0'; in_uint8a(c->in_s, session->password, sz); + LOG_DBG("password: %s - size: %d - pointer: %x", session->password, sz, session->password); + /* returning the struct */ - *s=session; + (*s)=session; return SCP_SERVER_STATE_OK; } -enum SCP_SERVER_STATES_E scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason) +enum SCP_SERVER_STATES_E +scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason) { int rlen; + + init_stream(c->out_s,c->out_s->size); /* forcing message not to exceed 64k */ rlen = g_strlen(reason); @@ -188,7 +210,8 @@ enum SCP_SERVER_STATES_E scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* return SCP_SERVER_STATE_END; } -enum SCP_SERVER_STATES_E scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason) +enum SCP_SERVER_STATES_E +scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason) { unsigned char sz; char *ubuf; @@ -233,11 +256,18 @@ enum SCP_SERVER_STATES_E scp_v1s_request_password(struct SCP_CONNECTION* c, stru { return SCP_SERVER_STATE_NETWORK_ERR; } -#warning check version + + in_uint32_be(c->in_s, version); + if (version!=1) + { + LOG_DBG("version: %d",version); + return SCP_SERVER_STATE_VERSION_ERR; + } in_uint32_be(c->in_s, size); if (size<12) { + LOG_DBG("size: %d",size); return SCP_SERVER_STATE_SIZE_ERR; } @@ -282,32 +312,151 @@ enum SCP_SERVER_STATES_E scp_v1s_request_password(struct SCP_CONNECTION* c, stru } /* 020 */ -enum SCP_SERVER_STATES_E scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw) +enum SCP_SERVER_STATES_E +scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw) { return SCP_SERVER_STATE_INTERNAL_ERR; } + /* 023 */ -enum SCP_SERVER_STATES_E scp_v1s_pwd_change_error(struct SCP_CONNECTION* s, char* error, int retry, char* npw) +enum SCP_SERVER_STATES_E +scp_v1s_pwd_change_error(struct SCP_CONNECTION* c, char* error, int retry, char* npw) { return SCP_SERVER_STATE_INTERNAL_ERR; } + /* 030 */ -enum SCP_SERVER_STATES_E scp_v1s_connect_new_session(struct SCP_CONNECTION* s, SCP_DISPLAY d) +enum SCP_SERVER_STATES_E +scp_v1s_connect_new_session(struct SCP_CONNECTION* c, SCP_DISPLAY d) { - return SCP_SERVER_STATE_INTERNAL_ERR; + /* send password request */ + uint32_t version=1; + uint32_t size=14; + uint16_t cmd=30; + + init_stream(c->out_s, c->out_s->size); + + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ + + out_uint16_be(c->out_s, d); /* display */ + + if (0!=tcp_force_send(c->in_sck, c->out_s->data, 14)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + return SCP_SERVER_STATE_OK; } + /* 031 */ -enum SCP_SERVER_STATES_E scp_v1s_reconnect_session(struct SCP_CONNECTION* s, SCP_DISPLAY d) +enum SCP_SERVER_STATES_E +scp_v1s_reconnect_session(struct SCP_CONNECTION* c, struct SCP_DISCONNECTED_SESSION* ds, + SCP_DISPLAY d) { - return SCP_SERVER_STATE_INTERNAL_ERR; + uint32_t version=1; + uint32_t size=12; + uint16_t cmd=32; +#warning FIXME check this command code + + /* first we send a notice that we're reconnecting to an existing session */ + init_stream(c->out_s, c->out_s->size); + + out_uint32_be(c->out_s, version); /* version */ + out_uint32_be(c->out_s, size); /* size */ + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); /* cmdset */ + out_uint16_be(c->out_s, cmd); /* cmd */ + + if (0!=tcp_force_send(c->in_sck, c->out_s->data, 14)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + /* then we wait for client ack */ +#warning maybe this message could say if the session should be resized on +#warning server side or client side + if (0!=tcp_force_recv(c->in_sck, c->in_s->data, 8)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint32_be(c->in_s, version); + if (version!=1) + { + return SCP_SERVER_STATE_VERSION_ERR; + } + + in_uint32_be(c->in_s, size); + if (size<12) + { + return SCP_SERVER_STATE_SIZE_ERR; + } + + init_stream(c->in_s, c->in_s->size); + if (0!=tcp_force_recv(c->in_sck, c->in_s->data, (size-8))) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + in_uint16_be(c->in_s, cmd); + if (cmd != SCP_COMMAND_SET_DEFAULT) + { + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + in_uint16_be(c->in_s, cmd); +#warning FIXME check this command code + if (cmd != 33) + { + return SCP_SERVER_STATE_SEQUENCE_ERR; + } + + /* ok, we send session data and display */ + init_stream(c->out_s, c->out_s->size); + + /* size */ + size=4+4+2+2+ \ + 2+1+2+2+1+1+1+1; + + /* header */ + cmd=31; + out_uint32_be(c->out_s, version); + out_uint32_be(c->out_s, size); + out_uint16_be(c->out_s, SCP_COMMAND_SET_DEFAULT); + out_uint16_be(c->out_s, cmd); + + /* session data */ + out_uint16_be(c->out_s, d); /* session display */ + out_uint8(c->out_s, ds->type); + out_uint16_be(c->out_s, ds->height); + out_uint16_be(c->out_s, ds->width); + out_uint8(c->out_s, ds->bpp); + out_uint8(c->out_s, ds->idle_days); + out_uint8(c->out_s, ds->idle_hours); + out_uint8(c->out_s, ds->idle_minutes); + /* these last three are not really needed... */ + + if (0!=tcp_force_send(c->in_sck, c->out_s->data, size)) + { + return SCP_SERVER_STATE_NETWORK_ERR; + } + + return SCP_SERVER_STATE_OK; } + /* 032 */ -enum SCP_SERVER_STATES_E scp_v1s_connection_error(struct SCP_CONNECTION* s, char* error) +enum SCP_SERVER_STATES_E +scp_v1s_connection_error(struct SCP_CONNECTION* c, char* error) { return SCP_SERVER_STATE_INTERNAL_ERR; + return SCP_SERVER_STATE_END; } + /* 040 */ -enum SCP_SERVER_STATES_E scp_v1s_list_sessions(struct SCP_CONNECTION* s, int sescnt, struct SCP_DISCONNECTED_SESSION** ds, SCP_SID* sid) +enum SCP_SERVER_STATES_E +scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNECTED_SESSION* ds, SCP_SID* sid) { return SCP_SERVER_STATE_INTERNAL_ERR; } diff --git a/sesman/libscp_v1s.h b/sesman/libscp_v1s.h index d61392d10f..5dc85960d0 100644 --- a/sesman/libscp_v1s.h +++ b/sesman/libscp_v1s.h @@ -42,7 +42,8 @@ * this function places in *s the address of a newely allocated SCP_SESSION structure * that should be free()d */ -enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); +enum SCP_SERVER_STATES_E +scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk); /** * @@ -51,25 +52,36 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION* c, struct SCP_SES * @param reason pointer to a string containinge the reason for denying connection */ /* 002 */ -enum SCP_SERVER_STATES_E scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason); +enum SCP_SERVER_STATES_E +scp_v1s_deny_connection(struct SCP_CONNECTION* c, char* reason); +enum SCP_SERVER_STATES_E +scp_v1s_request_password(struct SCP_CONNECTION* c, struct SCP_SESSION* s, char* reason); + /* 020 */ -enum SCP_SERVER_STATES_E scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw); +enum SCP_SERVER_STATES_E +scp_v1s_request_pwd_change(struct SCP_CONNECTION* c, char* reason, char* npw); /* 023 */ -enum SCP_SERVER_STATES_E scp_v1s_pwd_change_error(struct SCP_CONNECTION* s, char* error, int retry, char* npw); +enum SCP_SERVER_STATES_E +scp_v1s_pwd_change_error(struct SCP_CONNECTION* c, char* error, int retry, char* npw); /* 030 */ -enum SCP_SERVER_STATES_E scp_v1s_connect_new_session(struct SCP_CONNECTION* s, SCP_DISPLAY d); +enum SCP_SERVER_STATES_E +scp_v1s_connect_new_session(struct SCP_CONNECTION* c, SCP_DISPLAY d); /* 031 */ -enum SCP_SERVER_STATES_E scp_v1s_reconnect_session(struct SCP_CONNECTION* s, SCP_DISPLAY d); +enum SCP_SERVER_STATES_E +scp_v1s_reconnect_session(struct SCP_CONNECTION* c, struct SCP_DISCONNECTED_SESSION* ds, + SCP_DISPLAY d); /* 032 */ -enum SCP_SERVER_STATES_E scp_v1s_connection_error(struct SCP_CONNECTION* s, char* error); +enum SCP_SERVER_STATES_E +scp_v1s_connection_error(struct SCP_CONNECTION* c, char* error); /* 040 */ -enum SCP_SERVER_STATES_E scp_v1s_list_sessions(struct SCP_CONNECTION* s, int sescnt, struct - SCP_DISCONNECTED_SESSION** ds, SCP_SID* sid); +enum SCP_SERVER_STATES_E +scp_v1s_list_sessions(struct SCP_CONNECTION* c, int sescnt, struct SCP_DISCONNECTED_SESSION* ds, + SCP_SID* sid); #endif diff --git a/sesman/scp.c b/sesman/scp.c index 6631154ce9..476c3e3ae3 100644 --- a/sesman/scp.c +++ b/sesman/scp.c @@ -58,11 +58,14 @@ scp_process_start(void* sck) if (sdata->version == 0) { /* starts processing an scp v0 connection */ + LOG_DBG("accept ok, go on with scp v0\n",0); scp_v0_process(&scon, sdata); } else { - //scp_v1_process(); + LOG_DBG("accept ok, go on with scp v1\n",0); + LOG_DBG("user: %s\npass: %s",sdata->username, sdata->password); + scp_v1_process(&scon, sdata); } break; diff --git a/sesman/scp.h b/sesman/scp.h index 8da78b8660..145ea5e6eb 100644 --- a/sesman/scp.h +++ b/sesman/scp.h @@ -28,8 +28,9 @@ #ifndef SCP_H #define SCP_H +//#include "libscp.h" #include "scp_v0.h" -#include "libscp.h" +#include "scp_v1.h" /** * diff --git a/sesman/scp_v1.c b/sesman/scp_v1.c new file mode 100644 index 0000000000..03461b72cf --- /dev/null +++ b/sesman/scp_v1.c @@ -0,0 +1,192 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +/** + * + * @file scp_v1.c + * @brief scp version 1 implementation + * @author Jay Sorg, Simone Fedele + * + */ + +#include "sesman.h" + +//#include "libscp_types.h" +#include "libscp.h" + +extern struct config_sesman g_cfg; + +/******************************************************************************/ +void DEFAULT_CC +scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s) +{ + long data; + int display; + int retries; + int current_try; + enum SCP_SERVER_STATES_E e; + struct SCP_DISCONNECTED_SESSION* slist; + struct session_item* sitem; + int scount; + SCP_SID sid; + + retries=g_cfg.sec.login_retry; + current_try=retries; + + data=auth_userpass(s->username, s->password); + LOG_DBG("user: %s\npass: %s", s->username, s->password); + + while ((!data) && ((retries==0) || (current_try>0))) + { + LOG_DBG("data %d - retry %d - currenttry %d - expr %d", data, retries, current_try, ((!data) && ((retries==0) || (current_try>0)))); + + e=scp_v1s_request_password(c,s,"Wrong username and/or password"); + + switch (e) + { + case SCP_SERVER_STATE_OK: + /* all ok, we got new username and password */ + data=auth_userpass(s->username, s->password); + /* one try less */ + if (current_try>0) + { + current_try--; + } + break; + case SCP_SERVER_STATE_VERSION_ERR: + LOG_DBG("version error",0) + case SCP_SERVER_STATE_SIZE_ERR: + /* an unknown scp version was requested, so we shut down the */ + /* connection (and log the fact) */ + log_message(LOG_LEVEL_WARNING,"protocol violation. connection closed."); + return; + case SCP_SERVER_STATE_NETWORK_ERR: + log_message(LOG_LEVEL_WARNING,"libscp network error."); + return; + case SCP_SERVER_STATE_SEQUENCE_ERR: + log_message(LOG_LEVEL_WARNING,"libscp sequence error."); + return; + case SCP_SERVER_STATE_INTERNAL_ERR: + /* internal error occurred (eg. malloc() error, ecc.) */ + log_message(LOG_LEVEL_ERROR, "libscp internal error occurred."); + return; + default: + /* dummy: scp_v1s_request_password won't generate any other */ + /* error other than the ones before */ + log_message(LOG_LEVEL_ALWAYS, "unknown return from scp_v1s_request_password()"); + return; + } + } + + if (!data) + { + scp_v1s_deny_connection(c,"Login failed"); + log_message(LOG_LEVEL_INFO,"Login failed for user %s. Connection terminated", s->username); + free_session(s); + return; + } + + /* testing if login is allowed*/ + if (0==access_login_allowed(s->username)) + { + scp_v1s_deny_connection(c,"Access to Terminal Server not allowed."); + log_message(LOG_LEVEL_INFO,"User %s not allowed on TS. Connection terminated", s->username); + free_session(s); + return; + } + + //check if we need password change + + /* list disconnected sessions */ + slist=session_get_byuser(s->username, &scount); + + if (scount==0) + { +#warning FIXME we should check for MaxSessions + /* no disconnected sessions - start a new one */ + log_message(LOG_LEVEL_INFO, "granted TS access to user %s", s->username); + if (SCP_SESSION_TYPE_XVNC == s->type) + { + log_message(LOG_LEVEL_INFO, "starting Xvnc session..."); + display = session_start(s->width, s->height, s->bpp, s->username, s->password, + data, SESMAN_SESSION_TYPE_XVNC); + } + else + { + log_message(LOG_LEVEL_INFO, "starting Xrdp session..."); + display = session_start(s->width, s->height, s->bpp, s->username, s->password, + data, SESMAN_SESSION_TYPE_XRDP); + } + + e=scp_v1s_connect_new_session(c, display); + switch (e) + { + case SCP_SERVER_STATE_OK: + /* all ok, we got new username and password */ + break; + case SCP_SERVER_STATE_NETWORK_ERR: + log_message(LOG_LEVEL_WARNING,"libscp network error."); + return; + default: + return; + } + } + else if (scount==1) + { + /* there's only one session - returning that */ + sitem=session_get_bypid(slist->SID); +#warning FIXME session_get_by*() should return a malloc()ated struct +#warning FIXME or at least lock the chain + if (0==sitem) + { + e=scp_v1s_connection_error(c, "Internal error"); + log_message(LOG_LEVEL_INFO, "Cannot find session item on the chain"); + } + else + { + display=sitem->display; + e=scp_v1s_reconnect_session(c, slist, display); + log_message(LOG_LEVEL_INFO, "User %s reconnected to session %d on port %d", \ + s->username, sitem->pid, display); + } + g_free(slist); + } + else + { + /* 2 or more disconnected sessions - listing */ + + //max session x packet = 100 => pkt size = 1300 (13x100) + e=scp_v1s_list_sessions(c, scount, slist, &sid); + + //CHECK RETURN + + g_free(slist); + } + + /* resource management */ + if ((e==SCP_SERVER_STATE_OK) && (s->rsr)) + { + /* here goes scp resource sharing code */ + } + + /* cleanup */ + free_session(s); + auth_end(data); +} + diff --git a/sesman/scp_v1.h b/sesman/scp_v1.h new file mode 100644 index 0000000000..5f0b41aee6 --- /dev/null +++ b/sesman/scp_v1.h @@ -0,0 +1,42 @@ +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + xrdp: A Remote Desktop Protocol server. + Copyright (C) Jay Sorg 2005-2006 +*/ + +/** + * + * @file scp_v1.h + * @brief scp version 1 declarations + * @author Simone Fedele + * + */ + +#ifndef SCP_V1_H +#define SCP_V1_H + +/** + * + * @brief processes the stream using scp version 1 + * @param in_sck connection socket + * @param in_s input stream + * @param out_s output stream + * + */ +void DEFAULT_CC +scp_v1_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s); + +#endif diff --git a/sesman/tools/Makefile b/sesman/tools/Makefile new file mode 100644 index 0000000000..b4902ad5f8 --- /dev/null +++ b/sesman/tools/Makefile @@ -0,0 +1,40 @@ +# sesman makefile +SESTESTOBJ = sestest.o tcp.o \ + os_calls.o d3des.o list.o file.o \ + libscp_v1c.o + +DEFINES = -DLIBSCP_CLIENT + +CFLAGS = -Wall -O2 -I../../common -I../ -I/usr/include/nptl $(DEFINES) +LDFLAGS = -L /usr/gnu/lib -I/usr/include/nptl -L/usr/lib/nptl -lpthread -ldl $(DEFINES) +C_OS_FLAGS = $(CFLAGS) -c +CC = gcc + +all: sestest + +sestest: $(SESTESTOBJ) + $(CC) $(LDFLAGS) -o sestest $(SESTESTOBJ) + +os_calls.o: ../../common/os_calls.c + $(CC) $(C_OS_FLAGS) ../../common/os_calls.c + +d3des.o: ../../common/d3des.c + $(CC) $(C_OS_FLAGS) ../../common/d3des.c + +list.o: ../../common/list.c + $(CC) $(C_OS_FLAGS) ../../common/list.c + +file.o: ../../common/file.c + $(CC) $(C_OS_FLAGS) ../../common/file.c + +tcp.o: ../tcp.c + $(CC) $(C_OS_FLAGS) ../tcp.c + +libscp_v1c.o: ../libscp_v1c.c + $(CC) $(C_OS_FLAGS) ../libscp_v1c.c + +clean: + rm $(SESTESTOBJ) sestest + +install: + #install:wq diff --git a/sesman/tools/sestest.c b/sesman/tools/sestest.c new file mode 100644 index 0000000000..62629f3a91 --- /dev/null +++ b/sesman/tools/sestest.c @@ -0,0 +1,155 @@ + + +#include "arch.h" +#include "tcp.h" +#include "libscp.h" +#include "parse.h" + +#include + +int inputSession(struct SCP_SESSION* s); +unsigned int menuSelect(unsigned int choices); + +int main(int argc, char** argv) +{ + struct SCP_SESSION s; + struct SCP_CONNECTION c; + enum SCP_CLIENT_STATES_E e; + int end; + + make_stream(c.in_s); + init_stream(c.in_s, 8192); + make_stream(c.out_s); + init_stream(c.out_s, 8192); + c.in_sck = g_tcp_socket(); + + if (0!=g_tcp_connect(c.in_sck, "localhost", "3350")) + { + g_printf("error connecting"); + return 1; + } + + g_printf("001 - send connect request\n"); + +/*struct SCP_SESSION +{ + uint16_t display; + char* errstr; +};*/ + + s.type=SCP_SESSION_TYPE_XVNC; + s.version=1; + s.height=600; + s.width=800; + s.bpp=8; + s.rsr=0; + g_strncpy(s.locale,"it_IT 0123456789",18); + + s.username=g_malloc(256, 1); + g_strncpy(s.username,"prog",255); + + s.password=g_malloc(256,1); + g_strncpy(s.password, "prog", 255); + g_printf("%s - %s\n", s.username, s.password); + + + s.hostname=g_malloc(256,1); + g_strncpy(s.hostname, "odin", 255); + + s.addr_type=SCP_ADDRESS_TYPE_IPV4; + s.ipv4addr=0; + s.errstr=0; + + end=0; + e=scp_v1c_connect(&c,&s); + + while (!end) + { + switch (e) + { + case SCP_CLIENT_STATE_OK: + g_printf("OK : display is %d\n", (int)s.display); + end=1; + break; + case SCP_CLIENT_STATE_SESSION_LIST: + g_printf("OK : session list needed\n"); + break; + case SCP_CLIENT_STATE_RESEND_CREDENTIALS: + g_printf("ERR: resend credentials - %s\n", s.errstr); + g_printf(" username:"); + scanf("%255s", s.username); + g_printf(" password:"); + scanf("%255s", s.password); + e=scp_v1c_resend_credentials(&c,&s); + break; + case SCP_CLIENT_STATE_CONNECTION_DENIED: + g_printf("ERR: connection denied: %s\n", s.errstr); + end=1; + break; + case SCP_CLIENT_STATE_PWD_CHANGE_REQ: + g_printf("OK : password change required\n"); + break; + default: + g_printf("protocol error: %d\n", e); + end=1; + } + } + + g_tcp_close(c.in_sck); + free_stream(c.in_s); + free_stream(c.out_s); + + return 0; +} + +int inputSession(struct SCP_SESSION* s) +{ + unsigned int integer; + + g_printf("username: "); + scanf("%255s", s->username); + g_printf("password:"); + scanf("%255s", s->password); + g_printf("hostname:"); + scanf("%255s", s->hostname); + + g_printf("session type:\n"); + g_printf("0: Xvnc\n", SCP_SESSION_TYPE_XVNC); + g_printf("1: x11rdp\n", SCP_SESSION_TYPE_XRDP); + integer=menuSelect(1); + if (integer==1) + { + s->type=SCP_SESSION_TYPE_XRDP; + } + else + { + s->type=SCP_SESSION_TYPE_XVNC; + } + + s->version=1; + s->height=600; + s->width=800; + s->bpp=8; + + /* fixed for now */ + s->rsr=0; + g_strncpy(s->locale,"it_IT 0123456789",18); + + return 0; +} + +unsigned int menuSelect(unsigned int choices) +{ + unsigned int sel; + int ret; + + ret=scanf("%u", &sel); + + while ((ret==0) || (sel > choices)) + { + g_printf("invalid choice."); + scanf("%u", &sel); + } + + return sel; +} diff --git a/sesman/verify_user.c b/sesman/verify_user.c index 11c6473cab..03ecfadbee 100644 --- a/sesman/verify_user.c +++ b/sesman/verify_user.c @@ -21,7 +21,7 @@ * * @file verify_user.c * @brief Authenticate user using standard unix passwd/shadow system - * @author Jay Sorg + * @author Jay Sorg, Simone Fedele * */ @@ -34,8 +34,15 @@ #include #include +#ifndef SECS_PER_DAY +#define SECS_PER_DAY (24L*3600L) +#endif + extern struct config_sesman g_cfg; +static int DEFAULT_CC +auth_account_disabled(struct spwd* stp); + /******************************************************************************/ /* returns boolean */ long DEFAULT_CC @@ -61,6 +68,11 @@ auth_userpass(char* user, char* pass) { return 0; } + if (1==auth_account_disabled(stp)) + { + log_message(LOG_LEVEL_INFO, "account %s is disabled", user); + return 0; + } g_strncpy(hash, stp->sp_pwdp, 34); } else @@ -118,3 +130,90 @@ auth_set_env(long in_val) return 0; } +#define AUTH_NO_PWD_CHANGE 0 +#define AUTH_PWD_CHANGE 1 + +/******************************************************************************/ +int DEFAULT_CC +auth_check_pwd_chg(char* user) +{ + struct passwd* spw; + struct spwd* stp; + int now; + long today; + + spw = getpwnam(user); + if (spw == 0) + { + return AUTH_NO_PWD_CHANGE; + } + if (g_strncmp(spw->pw_passwd, "x", 3) != 0) + { + /* old system with only passwd */ + return AUTH_NO_PWD_CHANGE; + } + + /* the system is using shadow */ + stp = getspnam(user); + if (stp == 0) + { + return AUTH_NO_PWD_CHANGE; + } + + /* check if we need a pwd change */ + now=g_time1(); + today=now/SECS_PER_DAY; + + if (today >= (stp->sp_lstchg + stp->sp_max - stp->sp_warn)) + { + return AUTH_PWD_CHANGE; + } + + if (today < ((stp->sp_lstchg)+(stp->sp_min))) + { + /* cannot change pwd for now */ + return AUTH_NO_PWD_CHANGE; + } + + return AUTH_NO_PWD_CHANGE; +} + +/** + * + * @return 1 if the account is disabled, 0 otherwise + * + */ +static int DEFAULT_CC +auth_account_disabled(struct spwd* stp) +{ + int today; + + if (0==stp) + { + /* if an invalid struct was passed we assume a disabled account */ + return 1; + } + + today=g_time1()/SECS_PER_DAY; + + LOG_DBG("last %d",stp->sp_lstchg); + LOG_DBG("min %d",stp->sp_min); + LOG_DBG("max %d",stp->sp_max); + LOG_DBG("inact %d",stp->sp_inact); + LOG_DBG("warn %d",stp->sp_warn); + LOG_DBG("expire %d",stp->sp_expire); + LOG_DBG("today %d",today); + + if ((stp->sp_expire != -1) && (today >= stp->sp_expire)) + { + return 1; + } + + if (today >= (stp->sp_lstchg+stp->sp_max+stp->sp_inact)) + { + return 1; + } + + return 0; +} +