Merge pull request #29 from ArvidNorr/authenticate

Authenticate
This commit is contained in:
ArvidNorr 2012-06-18 01:25:03 -07:00
commit 02124492c2
8 changed files with 355 additions and 30 deletions

View File

@ -60,6 +60,9 @@ scp_session_set_type(struct SCP_SESSION* s, tui8 type)
case SCP_SESSION_TYPE_XRDP:
s->type = SCP_SESSION_TYPE_XRDP;
break;
case SCP_GW_AUTHENTICATION:
s->type = SCP_GW_AUTHENTICATION;
break;
case SCP_SESSION_TYPE_MANAGE:
s->type = SCP_SESSION_TYPE_MANAGE;
s->mng = (struct SCP_MNG_DATA*)g_malloc(sizeof(struct SCP_MNG_DATA), 1);

View File

@ -42,6 +42,10 @@
#define SCP_SESSION_TYPE_XVNC 0x00
#define SCP_SESSION_TYPE_XRDP 0x01
#define SCP_SESSION_TYPE_MANAGE 0x02
/* SCP_GW_AUTHENTICATION can be used when XRDP + sesman act as a gateway
* XRDP sends this command to let sesman verify if the user is allowed
* to use the gateway */
#define SCP_GW_AUTHENTICATION 0x04
#define SCP_ADDRESS_TYPE_IPV4 0x00
#define SCP_ADDRESS_TYPE_IPV6 0x01

View File

@ -277,6 +277,42 @@ scp_v0s_accept(struct SCP_CONNECTION* c, struct SCP_SESSION** s, int skipVchk)
}
}
}
if (code == SCP_GW_AUTHENTICATION)
{
/* g_writeln("Command is SCP_GW_AUTHENTICATION"); */
session = scp_session_create();
if (0 == session)
{
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);*/
return SCP_SERVER_STATE_INTERNAL_ERR;
}
scp_session_set_version(session, version);
scp_session_set_type(session, SCP_GW_AUTHENTICATION);
/* reading username */
in_uint16_be(c->in_s, sz);
buf[sz]='\0';
in_uint8a(c->in_s, buf, sz);
/* g_writeln("Received user name: %s",buf); */
if (0 != scp_session_set_username(session, buf))
{
scp_session_destroy(session);
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);*/
return SCP_SERVER_STATE_INTERNAL_ERR;
}
/* reading password */
in_uint16_be(c->in_s, sz);
buf[sz]='\0';
in_uint8a(c->in_s, buf, sz);
/* g_writeln("Received password: %s",buf); */
if (0 != scp_session_set_password(session, buf))
{
scp_session_destroy(session);
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */
return SCP_SERVER_STATE_INTERNAL_ERR;
}
}
else
{
log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: sequence error", __LINE__);
@ -315,8 +351,8 @@ scp_v0s_deny_connection(struct SCP_CONNECTION* c)
out_uint32_be(c->out_s, 0); /* version */
out_uint32_be(c->out_s, 14); /* size */
out_uint16_be(c->out_s, 3); /* cmd */
out_uint16_be(c->out_s, 0); /* data */
out_uint16_be(c->out_s, 0); /* data */
out_uint16_be(c->out_s, 0); /* data = 0 - means NOT ok*/
out_uint16_be(c->out_s, 0); /* reserved for display number*/
s_mark_end(c->out_s);
if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
@ -328,3 +364,26 @@ scp_v0s_deny_connection(struct SCP_CONNECTION* c)
LOG_DBG("[v0:%d] connection terminated (denied)", __LINE__);
return SCP_SERVER_STATE_OK;
}
/******************************************************************************/
enum SCP_SERVER_STATES_E
scp_v0s_replyauthentication(struct SCP_CONNECTION* c, unsigned short int value)
{
out_uint32_be(c->out_s, 0); /* version */
out_uint32_be(c->out_s, 14); /* size */
/* cmd SCP_GW_AUTHENTICATION means authentication reply */
out_uint16_be(c->out_s, SCP_GW_AUTHENTICATION);
out_uint16_be(c->out_s, value); /* reply code */
out_uint16_be(c->out_s, 0); /* dummy data */
s_mark_end(c->out_s);
/* g_writeln("Total number of bytes that will be sent %d",c->out_s->end - c->out_s->data);*/
if (0 != scp_tcp_force_send(c->in_sck, c->out_s->data, c->out_s->end - c->out_s->data))
{
/* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__); */
return SCP_SERVER_STATE_NETWORK_ERR;
}
/* until syslog merge LOG_DBG(s_log, "[v0:%d] connection terminated (scp_v0s_deny_authentication)", __LINE__);*/
return SCP_SERVER_STATE_OK;
}

View File

@ -73,5 +73,14 @@ scp_v0s_allow_connection(struct SCP_CONNECTION* c, SCP_DISPLAY d);
enum SCP_SERVER_STATES_E
scp_v0s_deny_connection(struct SCP_CONNECTION* c);
/**
* @brief send reply to an authentication request
* @param c connection descriptor
* @param value the reply code 0 means ok
* @return
*/
enum SCP_SERVER_STATES_E
scp_v0s_replyauthentication(struct SCP_CONNECTION* c, unsigned short int value);
#endif

View File

@ -38,20 +38,52 @@ scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
struct session_item* s_item;
data = auth_userpass(s->username, s->password);
if (data)
if(s->type==SCP_GW_AUTHENTICATION)
{
/* this is just authentication in a gateway situation */
/* g_writeln("SCP_GW_AUTHENTICATION message received"); */
if(data)
{
if (1 == access_login_allowed(s->username))
{
/* the user is member of the correct groups. */
scp_v0s_replyauthentication(c,0);
log_message( LOG_LEVEL_INFO,"Access permitted for user: %s",
s->username);
/* g_writeln("Connection allowed"); */
}
else
{
scp_v0s_replyauthentication(c,3);
log_message( LOG_LEVEL_INFO,"Username okey but group problem for user: %s",
s->username);
/* g_writeln("user password ok, but group problem"); */
}
}
else
{
/* g_writeln("username or password error"); */
log_message( LOG_LEVEL_INFO,"Username or password error for user: %s",
s->username);
scp_v0s_replyauthentication(c,2);
}
auth_end(data);
}
else if (data)
{
s_item = session_get_bydata(s->username, s->width, s->height, s->bpp, s->type);
if (s_item != 0)
{
display = s_item->display;
if (0 != s->client_ip)
{
log_message( LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d, ip %s", s->username, display, s_item->pid, s->client_ip);
log_message( LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, "
"session_pid %d, ip %s", s->username, display, s_item->pid, s->client_ip);
}
else
{
log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, session_pid %d", s->username, display, s_item->pid);
log_message(LOG_LEVEL_INFO, "++ reconnected session: username %s, display :%d.0, "
"session_pid %d", s->username, display, s_item->pid);
}
auth_end(data);
/* don't set data to null here */
@ -63,11 +95,13 @@ scp_v0_process(struct SCP_CONNECTION* c, struct SCP_SESSION* s)
{
if (0 != s->client_ip)
{
log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s, ip %s", s->username, s->client_ip);
log_message(LOG_LEVEL_INFO, "++ created session (access granted): "
"username %s, ip %s", s->username, s->client_ip);
}
else
{
log_message(LOG_LEVEL_INFO, "++ created session (access granted): username %s", s->username);
log_message(LOG_LEVEL_INFO, "++ created session (access granted): "
"username %s", s->username);
}
if (SCP_SESSION_TYPE_XVNC == s->type)

View File

@ -65,6 +65,9 @@ ip=ask
port=ask5900
username=na
password=ask
#pamusername=asksame
#pampassword=asksame
#pamsessionmng=127.0.0.1
[xrdp4]
name=sesman-any

View File

@ -21,6 +21,7 @@
*/
#include "xrdp.h"
#define ACCESS
#include "log.h"
/*****************************************************************************/
@ -223,6 +224,10 @@ xrdp_wm_ok_clicked(struct xrdp_bitmap* wnd)
xrdp_wm_set_login_mode(wm, 2);
}
}
else
{
log_message(LOG_LEVEL_ERROR,"Combo is 0 - potential programming error");
}
return 0;
}
@ -262,7 +267,7 @@ xrdp_wm_show_edits(struct xrdp_wm* self, struct xrdp_bitmap* combo)
if (g_strncmp("ask", value, 3) == 0)
{
/* label */
b = xrdp_bitmap_create(70, DEFAULT_EDIT_H, self->screen->bpp,
b = xrdp_bitmap_create(95, DEFAULT_EDIT_H, self->screen->bpp,
WND_TYPE_LABEL, self);
list_insert_item(self->login_window->child_list, insert_index,
(long)b);
@ -303,7 +308,11 @@ xrdp_wm_show_edits(struct xrdp_wm* self, struct xrdp_bitmap* combo)
username_set = 1;
}
}
#ifdef ACCESS
if ((g_strncmp(name, "password", 255) == 0) || (g_strncmp(name, "pampassword", 255) == 0))
#else
if (g_strncmp(name, "password", 255) == 0)
#endif
{
b->password_char = '*';
if (username_set)

View File

@ -21,6 +21,8 @@
*/
#include "xrdp.h"
#include "log.h"
#define ACCESS
/*****************************************************************************/
struct xrdp_mm* APP_CC
@ -104,6 +106,7 @@ xrdp_mm_delete(struct xrdp_mm* self)
}
/*****************************************************************************/
/* Send login information to sesman */
static int APP_CC
xrdp_mm_send_login(struct xrdp_mm* self)
{
@ -201,6 +204,7 @@ xrdp_mm_send_login(struct xrdp_mm* self)
s_mark_end(s);
s_pop_layer(s, channel_hdr);
/* Version 0 of the protocol to sesman is currently used by XRDP */
out_uint32_be(s, 0); /* version */
index = (int)(s->end - s->data);
out_uint32_be(s, index); /* size */
@ -748,6 +752,17 @@ xrdp_mm_connect_chansrv(struct xrdp_mm* self, char* ip, char* port)
return 0;
}
static void cleanup_sesman_connection(struct xrdp_mm* self)
{
self->delete_sesman_trans = 1;
self->connected_state = 0;
if (self->wm->login_mode != 10)
{
xrdp_wm_set_login_mode(self->wm, 11);
xrdp_mm_module_cleanup(self);
}
}
/*****************************************************************************/
static int APP_CC
xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s)
@ -793,14 +808,7 @@ xrdp_mm_process_login_response(struct xrdp_mm* self, struct stream* s)
xrdp_wm_log_msg(self->wm, "xrdp_mm_process_login_response: "
"login failed");
}
self->delete_sesman_trans = 1;
self->connected_state = 0;
if (self->wm->login_mode != 10)
{
xrdp_wm_set_login_mode(self->wm, 11);
xrdp_mm_module_cleanup(self);
}
cleanup_sesman_connection(self);
return rv;
}
@ -905,6 +913,7 @@ xrdp_mm_process_channel_data(struct xrdp_mm* self, tbus param1, tbus param2,
}
/*****************************************************************************/
/* This is the callback registered for sesman communication replies. */
static int APP_CC
xrdp_mm_sesman_data_in(struct trans* trans)
{
@ -933,11 +942,14 @@ xrdp_mm_sesman_data_in(struct trans* trans)
in_uint16_be(s, code);
switch (code)
{
/* even when the request is denied the reply will hold 3 as the command. */
case 3:
error = xrdp_mm_process_login_response(self, s);
break;
default:
g_writeln("xrdp_mm_sesman_data_in: unknown code %d", code);
xrdp_wm_log_msg(self->wm, "An undefined reply code was received from sesman");
g_writeln("Fatal xrdp_mm_sesman_data_in: unknown cmd code %d", code);
cleanup_sesman_connection(self);
break;
}
}
@ -945,6 +957,130 @@ xrdp_mm_sesman_data_in(struct trans* trans)
return error;
}
#ifdef ACCESS
/*********************************************************************/
/* return 0 on success */
int access_control(char *username, char *password, char *srv){
int reply ;
int rec = 1 ; // failure
struct stream* in_s;
struct stream* out_s;
unsigned long version ;
unsigned short int dummy;
unsigned short int ok;
unsigned short int code;
unsigned long size ;
int index ;
int socket = g_tcp_socket();
if (socket > 0) {
/* we use a blocking socket here */
reply = g_tcp_connect(socket, srv, "3350");
if (reply == 0)
{
make_stream(in_s);
init_stream(in_s, 500);
make_stream(out_s);
init_stream(out_s, 500);
s_push_layer(out_s, channel_hdr, 8);
out_uint16_be(out_s, 4); /*0x04 means SCP_GW_AUTHENTICATION*/
index = g_strlen(username);
out_uint16_be(out_s, index);
out_uint8a(out_s, username, index);
index = g_strlen(password);
out_uint16_be(out_s, index);
out_uint8a(out_s, password, index);
s_mark_end(out_s);
s_pop_layer(out_s, channel_hdr);
out_uint32_be(out_s, 0); /* version */
index = (int)(out_s->end - out_s->data);
out_uint32_be(out_s, index); /* size */
/* g_writeln("Number of data to send : %d",index); */
reply = g_tcp_send(socket, out_s->data, index, 0);
free_stream(out_s);
if (reply > 0)
{
/* We wait in 5 sec for a reply from sesman*/
if(g_tcp_can_recv(socket,5000)){
reply = g_tcp_recv(socket, in_s->end, 500, 0);
if (reply > 0)
{
in_s->end = in_s->end + reply ;
in_uint32_be(in_s, version);
/*g_writeln("Version number in reply from sesman: %d",version) ; */
in_uint32_be(in_s, size);
if((size==14) && (version==0))
{
in_uint16_be(in_s, code);
in_uint16_be(in_s, ok);
in_uint16_be(in_s, dummy);
if(code!=4)
{
log_message(LOG_LEVEL_ERROR,"Returned cmd code from "
"sesman is corrupt");
}
else
{
rec = ok; /* here we read the reply from the access control */
}
}
else
{
log_message(LOG_LEVEL_ERROR,"Corrupt reply size or "
"version from sesman: %d",size);
}
}
else
{
log_message(LOG_LEVEL_ERROR,"No data received from sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR,"Timeout when waiting for sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR,"No success sending to sesman");
}
free_stream(in_s);
g_tcp_close(socket);
}
else
{
log_message(LOG_LEVEL_ERROR,"Failure connecting to socket sesman");
}
}
else
{
log_message(LOG_LEVEL_ERROR,"Failure creating socket - for access control");
}
return rec;
}
#endif
/*****************************************************************************/
/* This routine clears all states to make sure that our next login will be
* as expected. If the user does not press ok on the log window and try to
* connect again we must make sure that no previous information is stored.*/
void cleanup_states(struct xrdp_mm* self)
{
if(self != NULL)
{
self-> connected_state = 0; /* true if connected to sesman else false */
self-> sesman_trans = NULL; /* connection to sesman */
self-> sesman_trans_up = 0 ; /* true once connected to sesman */
self-> delete_sesman_trans = 0; /* boolean set when done with sesman connection */
self-> display = 0; /* 10 for :10.0, 11 for :11.0, etc */
self-> code = 0; /* 0 Xvnc session 10 X11rdp session */
self-> sesman_controlled = 0; /* true if this is a sesman session */
self-> chan_trans = NULL; /* connection to chansrv */
self-> chan_trans_up = 0; /* true once connected to chansrv */
self-> delete_chan_trans = 0; /* boolean set when done with channel connection */
self-> usechansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */
}
}
/*****************************************************************************/
int APP_CC
xrdp_mm_connect(struct xrdp_mm* self)
@ -953,7 +1089,6 @@ xrdp_mm_connect(struct xrdp_mm* self)
struct list* values;
int index;
int count;
int use_sesman;
int ok;
int rv;
char* name;
@ -963,14 +1098,24 @@ xrdp_mm_connect(struct xrdp_mm* self)
char text[256];
char port[8];
char chansrvport[256];
#ifdef ACCESS
int use_pam_auth = 0 ;
char pam_auth_sessionIP[256] ;
char pam_auth_password[256];
char pam_auth_username[256];
char username[256];
char password[256];
username[0] = 0;
password[0] = 0;
#endif
/* make sure we start in correct state */
cleanup_states(self);
g_memset(ip, 0, sizeof(ip));
g_memset(errstr, 0, sizeof(errstr));
g_memset(text, 0, sizeof(text));
g_memset(port, 0, sizeof(port));
g_memset(chansrvport, 0, sizeof(chansrvport));
rv = 0; /* success */
use_sesman = 0;
names = self->login_names;
values = self->login_values;
count = names->count;
@ -986,25 +1131,83 @@ xrdp_mm_connect(struct xrdp_mm* self)
{
if (g_strcasecmp(value, "-1") == 0)
{
use_sesman = 1;
self->sesman_controlled = 1;
}
}
#ifdef ACCESS
else if (g_strcasecmp(name, "pamusername") == 0)
{
use_pam_auth = 1;
g_strncpy(pam_auth_username, value, 255);
}
else if (g_strcasecmp(name, "pamsessionmng") == 0)
{
g_strncpy(pam_auth_sessionIP, value, 255);
}
else if (g_strcasecmp(name, "pampassword") == 0)
{
g_strncpy(pam_auth_password, value, 255);
}
else if (g_strcasecmp(name, "password") == 0)
{
g_strncpy(password, value, 255);
}
else if (g_strcasecmp(name, "username") == 0)
{
g_strncpy(username, value, 255);
}
#endif
else if (g_strcasecmp(name, "chansrvport") == 0)
{
g_strncpy(chansrvport, value, 255);
self->usechansrv = 1;
}
}
if (use_sesman)
#ifdef ACCESS
if(use_pam_auth){
int reply;
char replytxt[80];
char replymessage[4][80] = {"Ok","Sesman connect failure","User or password error","Privilege group error"};
xrdp_wm_log_msg(self->wm, "Please wait, we now perform access control...");
/* g_writeln("we use pam modules to check if we can approve this user"); */
if(!g_strncmp(pam_auth_username,"same",255))
{
log_message(LOG_LEVEL_DEBUG,"pamusername copied from username - same: %s",username);
g_strncpy(pam_auth_username,username,255);
}
if(!g_strncmp(pam_auth_password,"same",255))
{
log_message(LOG_LEVEL_DEBUG,"pam_auth_password copied from username - same: %s",password);
g_strncpy(pam_auth_password,password,255);
}
/* access_control return 0 on success */
reply = access_control(pam_auth_username, pam_auth_password, pam_auth_sessionIP);
if(reply>=0 && reply<4)
{
g_sprintf(replytxt,"Reply from access control: %s",replymessage[reply]);
}
else
{
g_sprintf(replytxt,"Reply from access control undefined");
}
xrdp_wm_log_msg(self->wm,replytxt);
log_message(LOG_LEVEL_INFO,replytxt);
if(reply!=0)
{
rv = 1 ;
return rv ;
}
}
#endif
if (self->sesman_controlled)
{
ok = 0;
errstr[0] = 0;
trans_delete(self->sesman_trans);
self->sesman_trans = trans_create(TRANS_MODE_TCP, 8192, 8192);
xrdp_mm_get_sesman_port(port, sizeof(port));
g_snprintf(text, 255, "connecting to sesman ip %s port %s", ip, port);
xrdp_wm_log_msg(self->wm, text);
/* xrdp_mm_sesman_data_in is the callback that is called when data arrives */
self->sesman_trans->trans_data_in = xrdp_mm_sesman_data_in;
self->sesman_trans->header_size = 8;
self->sesman_trans->callback_data = self;
@ -1030,6 +1233,8 @@ xrdp_mm_connect(struct xrdp_mm* self)
}
else
{
g_snprintf(errstr, 255, "Failure to connect to sesman: %s port: %s",
ip, port);
xrdp_wm_log_msg(self->wm, errstr);
trans_delete(self->sesman_trans);
self->sesman_trans = 0;
@ -1049,13 +1254,13 @@ xrdp_mm_connect(struct xrdp_mm* self)
else
{
/* connect error */
g_snprintf(errstr, 255, "Failure to connect to: %s port: %s",
ip, port);
g_writeln(errstr);
g_snprintf(errstr, 255, "Failure to connect to: %s",ip);
xrdp_wm_log_msg(self->wm, errstr);
rv = 1; /* failure */
}
}else{
}
else
{
g_writeln("Failure setting up module");
}
if (self->wm->login_mode != 10)
@ -1065,7 +1270,6 @@ xrdp_mm_connect(struct xrdp_mm* self)
rv = 1 ; /* failure */
}
}
self->sesman_controlled = use_sesman;
if ((self->wm->login_mode == 10) && (self->sesman_controlled == 0) &&
(self->usechansrv != 0))