Merge pull request #2472 from matt335672/implement-uds-auth

Implement uds authentication
This commit is contained in:
matt335672 2023-01-05 10:43:13 +00:00 committed by GitHub
commit bef2e3b1e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 2277 additions and 1167 deletions

1
.gitignore vendored
View File

@ -36,6 +36,7 @@ NEWS
README
sesman/chansrv/xrdp-chansrv
sesman/sessvc/xrdp-sessvc
sesman/tools/xrdp-authtest
sesman/tools/xrdp-dis
sesman/tools/xrdp-sesadmin
sesman/tools/xrdp-sesrun

View File

@ -671,7 +671,7 @@ g_sck_get_peer_cred(int sck, int *pid, int *uid, int *gid)
unsigned int xucred_length;
xucred_length = sizeof(xucred);
if (getsockopt(sck, SOL_SOCKET, LOCAL_PEERCRED, &xucred, &xucred_length))
if (getsockopt(sck, SOL_LOCAL, LOCAL_PEERCRED, &xucred, &xucred_length))
{
return 1;
}
@ -2797,7 +2797,7 @@ g_initgroups(const char *username)
return 0;
#else
int gid;
int error = g_getuser_info(username, &gid, NULL, NULL, NULL, NULL);
int error = g_getuser_info_by_name(username, NULL, &gid, NULL, NULL, NULL);
if (error == 0)
{
error = initgroups(username, gid);
@ -3060,26 +3060,85 @@ g_sighup(int pid)
/* the caller is responsible to free the buffs */
/* does not work in win32 */
int
g_getuser_info(const char *username, int *gid, int *uid, char **shell,
char **dir, char **gecos)
g_getuser_info_by_name(const char *username, int *uid, int *gid,
char **shell, char **dir, char **gecos)
{
int rv = 1;
#if !defined(_WIN32)
if (username == NULL)
{
LOG(LOG_LEVEL_ERROR, "g_getuser_info_by_name() called for NULL user");
}
else
{
struct passwd *pwd_1 = getpwnam(username);
if (pwd_1 != 0)
{
rv = 0;
if (uid != 0)
{
*uid = pwd_1->pw_uid;
}
if (gid != 0)
{
*gid = pwd_1->pw_gid;
}
if (shell != 0)
{
*shell = g_strdup(pwd_1->pw_shell);
}
if (dir != 0)
{
*dir = g_strdup(pwd_1->pw_dir);
}
if (gecos != 0)
{
*gecos = g_strdup(pwd_1->pw_gecos);
}
}
}
#endif
return rv;
}
/*****************************************************************************/
/* returns 0 if ok */
/* the caller is responsible to free the buffs */
/* does not work in win32 */
int
g_getuser_info_by_uid(int uid, char **username, int *gid,
char **shell, char **dir, char **gecos)
{
#if defined(_WIN32)
return 1;
#else
struct passwd *pwd_1;
pwd_1 = getpwnam(username);
pwd_1 = getpwuid(uid);
if (pwd_1 != 0)
{
if (username != NULL)
{
*username = g_strdup(pwd_1->pw_name);
}
if (gid != 0)
{
*gid = pwd_1->pw_gid;
}
if (uid != 0)
if (shell != 0)
{
*uid = pwd_1->pw_uid;
*shell = g_strdup(pwd_1->pw_shell);
}
if (dir != 0)
@ -3087,11 +3146,6 @@ g_getuser_info(const char *username, int *gid, int *uid, char **shell,
*dir = g_strdup(pwd_1->pw_dir);
}
if (shell != 0)
{
*shell = g_strdup(pwd_1->pw_shell);
}
if (gecos != 0)
{
*gecos = g_strdup(pwd_1->pw_gecos);

View File

@ -193,8 +193,10 @@ int g_exit(int exit_code);
int g_getpid(void);
int g_sigterm(int pid);
int g_sighup(int pid);
int g_getuser_info(const char *username, int *gid, int *uid, char **shell,
char **dir, char **gecos);
int g_getuser_info_by_name(const char *username, int *uid, int *gid,
char **shell, char **dir, char **gecos);
int g_getuser_info_by_uid(int uid, char **username, int *gid,
char **shell, char **dir, char **gecos);
int g_getgroup_info(const char *groupname, int *gid);
int g_check_user_in_group(const char *username, int gid, int *ok);
int g_time1(void);

View File

@ -424,11 +424,6 @@ then
AC_DEFINE([XRDP_ENABLE_IPV6],1,[Enable IPv6])
fi
if test "x$enable_pam" = "xyes"
then
AC_DEFINE([USE_PAM],1,[Enable PAM])
fi
AS_IF( [test "x$enable_neutrinordp" = "xyes"] , [PKG_CHECK_MODULES(FREERDP, freerdp >= 1.0.0)] )
# checking for libjpeg

View File

@ -18,13 +18,11 @@ command.
A summary of options is included below.
.TP
.BI \-u= username
\fIUsername\fP for authentication on the server.
Defaults to \fBroot\fP.
Retained for compatibility, but ignored.
.TP
.BI \-p= password
The \fIpassword\fP to authenticate with.
The default is to ask for the password interactively.
Retained for compatibility, but ignored.
.TP
.BI \-i= port
@ -39,7 +37,7 @@ Valid commands are:
.RS 4
.TP
.B list
List currently active sessions.
List active sessions for the current user.
.TP
.BI kill: sid
Kills the session specified the given \fIsession id\fP.

View File

@ -4,18 +4,28 @@
.SH "SYNTAX"
.B xrdp\-sesrun
.I [ options ] username
.I --help
.br
.B xrdp\-sesrun
.I [ options ] [ username ]
.SH "DESCRIPTION"
\fBxrdp\-sesrun\fR starts a session using \fBxrdp\-sesman\fR(8).
.br
This is a tool useful for testing, it simply behaves like xrdp when some
This is a tool useful for testing. It simply behaves like xrdp when some
user logs in a new session and authenticates, thus starting a new session.
Default values for the options are set at compile-time. Run the utility without
a username to see what the defaults are for your installation.
Default values for the options are set at compile-time. Run the utility with
the '--help' option to see what the defaults are for your installation.
The utility prompts for a password if neither \fB-p\fR or \fB-F\fR is used.
If no username is used, the current username is used, and no password
needs to be provided. In this instance, it is important that any necessary
authentication tokens for a GUI session (e.g. a Kerberos ticket) have
already been acquired.
If a username is provided, a password must also be provided. In this instance
the utility prompts for a password if neither \fB-p\fR or \fB-F\fR is used.
.SH "OPTIONS"
.TP
@ -60,6 +70,10 @@ Override the default logging level. One of "error", "warn", "info",
.SH "EXAMPLES"
.TP
.B
xrdp-sesrun
Create a default session for the current user.
.TP
.B
xrdp-sesrun -F 0 user1 <passwd.txt
Create a default session for user \fBuser1\fR with a password from
a file

View File

@ -107,7 +107,9 @@ If not specified or set to \fB0\fP, unlimited.
.TP
\fBpamerrortxt\fP=\fIerror_text\fP
Specify text passed to PAM when authentication failed. The maximum length is \fB256\fP.
Specify additional text displayed to user if authentication fails. The maximum length is \fB256\fP.
The use of 'pam' in the name of this option is historic
.TP
\fBport\fP=\fIport\fP

View File

@ -15,7 +15,8 @@ libipm_la_SOURCES = \
libipm_private.h \
scp.h \
scp.c \
scp_application_types.h
scp_application_types.h \
scp_application_types.c
libipm_la_LIBADD = \
$(top_builddir)/common/libcommon.la

View File

@ -40,12 +40,21 @@ static const char *
msgno_to_str(unsigned short n)
{
return
(n == E_SCP_GATEWAY_REQUEST) ? "SCP_GATEWAY_REQUEST" :
(n == E_SCP_GATEWAY_RESPONSE) ? "SCP_GATEWAY_RESPONSE" :
(n == E_SCP_SET_PEERNAME_REQUEST) ? "SCP_SET_PEERNAME_REQUEST" :
(n == E_SCP_SYS_LOGIN_REQUEST) ? "SCP_SYS_LOGIN_REQUEST" :
(n == E_SCP_UDS_LOGIN_REQUEST) ? "SCP_UDS_LOGIN_REQUEST" :
(n == E_SCP_LOGIN_RESPONSE) ? "SCP_LOGIN_RESPONSE" :
(n == E_SCP_LOGOUT_REQUEST) ? "SCP_LOGOUT_REQUEST" :
(n == E_SCP_CREATE_SESSION_REQUEST) ? "SCP_CREATE_SESSION_REQUEST" :
(n == E_SCP_CREATE_SESSION_RESPONSE) ? "SCP_CREATE_SESSION_RESPONSE" :
(n == E_SCP_LIST_SESSIONS_REQUEST) ? "SCP_LIST_SESSIONS_REQUEST" :
(n == E_SCP_LIST_SESSIONS_RESPONSE) ? "SCP_LIST_SESSIONS_RESPONSE" :
(n == E_SCP_CLOSE_CONNECTION_REQUEST) ? "SCP_CLOSE_CONNECTION_REQUEST" :
NULL;
}
@ -147,6 +156,7 @@ scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen)
/*****************************************************************************/
struct trans *
scp_connect(const char *port,
const char *peername,
int (*term_func)(void))
{
char sock_path[256];
@ -162,8 +172,12 @@ scp_connect(const char *port,
trans_delete(t);
t = NULL;
}
else if (libipm_init_trans(t, LIBIPM_FAC_SCP, msgno_to_str) !=
E_LI_SUCCESS)
else if (scp_init_trans(t) != 0)
{
trans_delete(t);
t = NULL;
}
else if (scp_send_set_peername_request(t, peername) != 0)
{
trans_delete(t);
t = NULL;
@ -214,16 +228,48 @@ scp_msg_in_start(struct trans *trans)
/*****************************************************************************/
int
scp_send_gateway_request(struct trans *trans,
const char *username,
const char *password,
const char *ip_addr)
scp_send_set_peername_request(struct trans *trans,
const char *peername)
{
return libipm_msg_out_simple_send(
trans,
(int)E_SCP_SET_PEERNAME_REQUEST,
"s",
peername);
}
/*****************************************************************************/
int
scp_get_set_peername_request(struct trans *trans,
const char **peername)
{
return libipm_msg_in_parse( trans, "s", peername);
}
/*****************************************************************************/
int
scp_send_uds_login_request(struct trans *trans)
{
return libipm_msg_out_simple_send(trans,
(int)E_SCP_UDS_LOGIN_REQUEST,
NULL);
}
/*****************************************************************************/
int
scp_send_sys_login_request(struct trans *trans,
const char *username,
const char *password,
const char *ip_addr)
{
int rv;
rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_GATEWAY_REQUEST,
(int)E_SCP_SYS_LOGIN_REQUEST,
"sss",
username,
password,
@ -238,93 +284,99 @@ scp_send_gateway_request(struct trans *trans,
/*****************************************************************************/
int
scp_get_gateway_request(struct trans *trans,
const char **username,
const char **password,
const char **ip_addr)
scp_get_sys_login_request(struct trans *trans,
const char **username,
const char **password,
const char **ip_addr)
{
/* Make sure the buffer is cleared after processing this message */
libipm_set_flags(trans, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
return libipm_msg_in_parse(trans, "sss", username, password,
ip_addr);
return libipm_msg_in_parse( trans, "sss",
username, password, ip_addr);
}
/*****************************************************************************/
int
scp_send_gateway_response(struct trans *trans,
int auth_result)
scp_send_login_response(struct trans *trans,
enum scp_login_status login_result,
int server_closed)
{
return libipm_msg_out_simple_send(
trans,
(int)E_SCP_GATEWAY_RESPONSE,
"i",
auth_result);
(int)E_SCP_LOGIN_RESPONSE,
"ib",
login_result,
(server_closed != 0)); /* Convert to 0/1 */
}
/*****************************************************************************/
int
scp_get_gateway_response(struct trans *trans,
int *auth_result)
scp_get_login_response(struct trans *trans,
enum scp_login_status *login_result,
int *server_closed)
{
int32_t i_auth_result = 0;
int rv = libipm_msg_in_parse(trans, "i", &i_auth_result);
int32_t i_login_result = 0;
int dummy;
/* User can pass in NULL for server_closed if they're trying an
* login method like UDS for which all fails are fatal */
if (server_closed == NULL)
{
server_closed = &dummy;
}
int rv = libipm_msg_in_parse(trans, "ib", &i_login_result, server_closed);
if (rv == 0)
{
*auth_result = i_auth_result;
*login_result = (enum scp_login_status)i_login_result;
}
return rv;
}
/*****************************************************************************/
int
scp_send_logout_request(struct trans *trans)
{
return libipm_msg_out_simple_send( trans, (int)E_SCP_LOGOUT_REQUEST, NULL);
}
/*****************************************************************************/
int
scp_send_create_session_request(struct trans *trans,
const char *username,
const char *password,
enum scp_session_type type,
unsigned short width,
unsigned short height,
unsigned char bpp,
const char *shell,
const char *directory,
const char *ip_addr)
const char *directory)
{
int rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_CREATE_SESSION_REQUEST,
"ssyqqysss",
username,
password,
type,
width,
height,
bpp,
shell,
directory,
ip_addr);
/* Wipe the output buffer to remove the password */
libipm_msg_out_erase(trans);
return rv;
return libipm_msg_out_simple_send(
trans,
(int)E_SCP_CREATE_SESSION_REQUEST,
"yqqyss",
type,
width,
height,
bpp,
shell,
directory);
}
/*****************************************************************************/
int
scp_get_create_session_request(struct trans *trans,
const char **username,
const char **password,
enum scp_session_type *type,
unsigned short *width,
unsigned short *height,
unsigned char *bpp,
const char **shell,
const char **directory,
const char **ip_addr)
const char **directory)
{
/* Intermediate values */
uint8_t i_type;
@ -332,21 +384,15 @@ scp_get_create_session_request(struct trans *trans,
uint16_t i_height;
uint8_t i_bpp;
/* Make sure the buffer is cleared after processing this message */
libipm_set_flags(trans, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
int rv = libipm_msg_in_parse(
trans,
"ssyqqysss",
username,
password,
"yqqyss",
&i_type,
&i_width,
&i_height,
&i_bpp,
shell,
directory,
ip_addr);
directory);
if (rv == 0)
{
@ -364,7 +410,7 @@ scp_get_create_session_request(struct trans *trans,
int
scp_send_create_session_response(struct trans *trans,
int auth_result,
enum scp_screate_status status,
int display,
const struct guid *guid)
{
@ -374,7 +420,7 @@ scp_send_create_session_response(struct trans *trans,
trans,
(int)E_SCP_CREATE_SESSION_RESPONSE,
"iiB",
auth_result,
status,
display,
&guid_descriptor);
}
@ -383,12 +429,12 @@ scp_send_create_session_response(struct trans *trans,
int
scp_get_create_session_response(struct trans *trans,
int *auth_result,
enum scp_screate_status *status,
int *display,
struct guid *guid)
{
/* Intermediate values */
int32_t i_auth_result;
int32_t i_status;
int32_t i_display;
const struct libipm_fsb guid_descriptor = { (void *)guid, sizeof(*guid) };
@ -396,12 +442,12 @@ scp_get_create_session_response(struct trans *trans,
int rv = libipm_msg_in_parse(
trans,
"iiB",
&i_auth_result,
&i_status,
&i_display,
&guid_descriptor);
if (rv == 0)
{
*auth_result = i_auth_result;
*status = (enum scp_screate_status)i_status;
*display = i_display;
}
@ -411,36 +457,12 @@ scp_get_create_session_response(struct trans *trans,
/*****************************************************************************/
int
scp_send_list_sessions_request(struct trans *trans,
const char *username,
const char *password)
scp_send_list_sessions_request(struct trans *trans)
{
int rv;
rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_LIST_SESSIONS_REQUEST,
"ss",
username,
password);
/* Wipe the output buffer to remove the password */
libipm_msg_out_erase(trans);
return rv;
}
/*****************************************************************************/
int
scp_get_list_sessions_request(struct trans *trans,
const char **username,
const char **password)
{
/* Make sure the buffer is cleared after processing this message */
libipm_set_flags(trans, LIBIPM_E_MSG_IN_ERASE_AFTER_USE);
return libipm_msg_in_parse(trans, "ss", username, password);
return libipm_msg_out_simple_send(
trans,
(int)E_SCP_LIST_SESSIONS_REQUEST,
NULL);
}
/*****************************************************************************/
@ -465,7 +487,7 @@ scp_send_list_sessions_response(
rv = libipm_msg_out_simple_send(
trans,
(int)E_SCP_LIST_SESSIONS_RESPONSE,
"iiuyqqyxss",
"iiuyqqyxis",
status,
info->sid,
info->display,
@ -474,7 +496,7 @@ scp_send_list_sessions_response(
info->height,
info->bpp,
info->start_time,
info->username,
info->uid,
info->start_ip_addr);
}
@ -511,12 +533,12 @@ scp_get_list_sessions_response(
uint16_t i_height;
uint8_t i_bpp;
int64_t i_start_time;
char *i_username;
int32_t i_uid;
char *i_start_ip_addr;
rv = libipm_msg_in_parse(
trans,
"iuyqqyxss",
"iuyqqyxis",
&i_sid,
&i_display,
&i_type,
@ -524,7 +546,7 @@ scp_get_list_sessions_response(
&i_height,
&i_bpp,
&i_start_time,
&i_username,
&i_uid,
&i_start_ip_addr);
if (rv == 0)
@ -532,7 +554,6 @@ scp_get_list_sessions_response(
/* Allocate a block of memory large enough for the
* structure result, and the strings it contains */
unsigned int len = sizeof(struct scp_session_info) +
g_strlen(i_username) + 1 +
g_strlen(i_start_ip_addr) + 1;
if ((p = (struct scp_session_info *)g_malloc(len, 1)) == NULL)
{
@ -542,9 +563,8 @@ scp_get_list_sessions_response(
{
/* Set up the string pointers in the block to point
* into the memory allocated after the block */
p->username = (char *)p + sizeof(struct scp_session_info);
p->start_ip_addr =
p->username + g_strlen(i_username) + 1;
(char *)p + sizeof(struct scp_session_info);
/* Copy the data over */
p->sid = i_sid;
@ -554,7 +574,7 @@ scp_get_list_sessions_response(
p->height = i_height;
p->bpp = i_bpp;
p->start_time = i_start_time;
g_strcpy(p->username, i_username);
p->uid = i_uid;
g_strcpy(p->start_ip_addr, i_start_ip_addr);
}
}
@ -563,3 +583,14 @@ scp_get_list_sessions_response(
}
return rv;
}
/*****************************************************************************/
int
scp_send_close_connection_request(struct trans *trans)
{
return libipm_msg_out_simple_send(
trans,
(int)E_SCP_CLOSE_CONNECTION_REQUEST,
NULL);
}

View File

@ -43,12 +43,24 @@ struct trans;
/* Message codes */
enum scp_msg_code
{
E_SCP_GATEWAY_REQUEST = 1,
E_SCP_GATEWAY_RESPONSE,
E_SCP_SET_PEERNAME_REQUEST = 1,
// No E_SCP_SET_PEERNAME_RESPONSE
E_SCP_SYS_LOGIN_REQUEST,
E_SCP_UDS_LOGIN_REQUEST,
E_SCP_LOGIN_RESPONSE, /* Shared between login request types */
E_SCP_LOGOUT_REQUEST,
// No S_SCP_LOGOUT_RESPONSE
E_SCP_CREATE_SESSION_REQUEST,
E_SCP_CREATE_SESSION_RESPONSE,
E_SCP_LIST_SESSIONS_REQUEST,
E_SCP_LIST_SESSIONS_RESPONSE
E_SCP_LIST_SESSIONS_RESPONSE,
E_SCP_CLOSE_CONNECTION_REQUEST
// No E_SCP_CLOSE_CONNECTION_RESPONSE
};
/* Common facilities */
@ -97,6 +109,7 @@ scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen);
* Connect to an SCP server
*
* @param port Port definition (e.g. from sesman.ini)
* @param peername Name of this program or object (e.g. "xrdp-sesadmin")
* @param term_func Function to poll during connection for program
* termination, or NULL for none.
* @return Initialised SCP transport
@ -104,16 +117,19 @@ scp_port_to_display_string(const char *port, char *buff, unsigned int bufflen);
* The returned transport has the is_term member set to term_func.
*/
struct trans *
scp_connect(const char *port,
scp_connect(const char *port,
const char *peername,
int (*term_func)(void));
/**
* Converts a standard trans connected to an SCP endpoint to an SCP transport
*
* If you are running on a client, you may wish to use
* scp_send_set_peername_request() after the commnect to inform the
* server who you are.
*
* @param trans connected endpoint
* @return != 0 for error
*
* The returned transport has the is_term member set to term_func.
*/
int
scp_init_trans(struct trans *trans);
@ -170,9 +186,54 @@ scp_msg_in_start(struct trans *trans);
void
scp_msg_in_reset(struct trans *trans);
/* -------------------- Setup messages-------------------- */
/**
* Send an E_SCP_GATEWAY_REQUEST (SCP client)
* Send an E_SCP_SET_PEERNAME_REQUEST (SCP client)
*
* @param trans SCP transport
* @param peername Peername
* @return != 0 for error
*
* Server does not send a response
*
* This message is sent automatically by scp_connect(), but it can
* be sent at any time.
*/
int
scp_send_set_peername_request(struct trans *trans,
const char *peername);
/**
* Parse an incoming E_SCP_SET_PEERNAME_REQUEST message (SCP server)
*
* @param trans SCP transport
* @param[out] peername peername
* @return != 0 for error
*/
int
scp_get_set_peername_request(struct trans *trans,
const char **peername);
/* -------------------- Login messages-------------------- */
/**
* Send an E_SCP_UDS_LOGIN_REQUEST (SCP client)
*
* User is logged in using their socket details
*
* @param trans SCP transport
* @return != 0 for error
*
* Server replies with E_SCP_LOGIN_RESPONSE
*/
int
scp_send_uds_login_request(struct trans *trans);
/**
* Send an E_SCP_SYS_LOGIN_REQUEST (SCP client)
*
* User is logged in using explicit credentials
*
* @param trans SCP transport
* @param username Username
@ -180,16 +241,16 @@ scp_msg_in_reset(struct trans *trans);
* @param ip_addr IP address for the client (or "" if not known)
* @return != 0 for error
*
* Server replies with E_SCP_GATEWAY_RESPONSE
* Server replies with E_SCP_LOGIN_RESPONSE
*/
int
scp_send_gateway_request(struct trans *trans,
const char *username,
const char *password,
const char *ip_addr);
scp_send_sys_login_request(struct trans *trans,
const char *username,
const char *password,
const char *ip_addr);
/**
* Parse an incoming E_SCP_GATEWAY_REQUEST message (SCP server)
* Parse an incoming E_SCP_SYS_LOGIN_REQUEST message (SCP server)
*
* @param trans SCP transport
* @param[out] username Username
@ -198,78 +259,89 @@ scp_send_gateway_request(struct trans *trans,
* @return != 0 for error
*/
int
scp_get_gateway_request(struct trans *trans,
const char **username,
const char **password,
const char **ip_addr);
scp_get_sys_login_request(struct trans *trans,
const char **username,
const char **password,
const char **ip_addr);
/**
* Send an E_SCP_GATEWAY_RESPONSE (SCP server)
* Send an E_SCP_LOGIN_RESPONSE (SCP server)
*
* @param trans SCP transport
* @param auth_result 0 for success, PAM error code otherwise
* @param login_result What happened to the login
* @param server_closed. If login fails, whether server has closed connection.
* If not, a retry can be made.
* @return != 0 for error
*/
int
scp_send_gateway_response(struct trans *trans,
int auth_result);
scp_send_login_response(struct trans *trans,
enum scp_login_status login_result,
int server_closed);
/**
* Parses an incoming E_SCP_GATEWAY_RESPONSE (SCP client)
* Parses an incoming E_SCP_LOGIN_RESPONSE (SCP client)
*
* @param trans SCP transport
* @param[out] auth_result 0 for success, PAM error code otherwise
* @param[out] login_result 0 for success, PAM error code otherwise
* @param[out] server_closed. If login fails, whether server has closed
* connection. If not a retry can be made.
* @return != 0 for error
*/
int
scp_get_gateway_response(struct trans *trans,
int *auth_result);
scp_get_login_response(struct trans *trans,
enum scp_login_status *login_result,
int *server_closed);
/* Session messages */
/**
* Send an E_SCP_LOGOUT_REQUEST (SCP client)
*
* @param trans SCP transport
* @return != 0 for error
*
* Logs the user out (if they are logged in), so that another
* login request can be sent, maybe with a different user.
*
* A reply is not sent
*/
int
scp_send_logout_request(struct trans *trans);
/* -------------------- Session messages-------------------- */
/**
* Send an E_SCP_CREATE_SESSION_REQUEST (SCP client)
*
* @param trans SCP transport
* @param username Username of session to create or re-connect to
* @param password Password for user
* @param type Session type
* @param width Initial session width
* @param height Initial session height
* @param bpp Session bits-per-pixel (ignored for Xorg sessions)
* @param shell User program to run. May be ""
* @param directory Directory to run the program in. May be ""
* @param ip_addr IP address for the client (or "" if not known)
* @return != 0 for error
*
* Server replies with E_SCP_CREATE_SESSION_RESPONSE
*/
int
scp_send_create_session_request(struct trans *trans,
const char *username,
const char *password,
enum scp_session_type type,
unsigned short width,
unsigned short height,
unsigned char bpp,
const char *shell,
const char *directory,
const char *ip_addr);
const char *directory);
/**
* Parse an incoming E_SCP_CREATE_SESSION_REQUEST (SCP server)
*
* @param trans SCP transport
* @param[out] username Username of session to create or re-connect to
* @param[out] password Password for user
* @param[out] type Session type
* @param[out] width Initial session width
* @param[out] height Initial session height
* @param[out] bpp Session bits-per-pixel (ignored for Xorg sessions)
* @param[out] shell User program to run. May be ""
* @param[out] directory Directory to run the program in. May be ""
* @param[out] ip_addr IP address for the client. May be ""
* @return != 0 for error
*
* Returned string pointers are valid until scp_msg_in_reset() is
@ -277,29 +349,26 @@ scp_send_create_session_request(struct trans *trans,
*/
int
scp_get_create_session_request(struct trans *trans,
const char **username,
const char **password,
enum scp_session_type *type,
unsigned short *width,
unsigned short *height,
unsigned char *bpp,
const char **shell,
const char **directory,
const char **ip_addr);
const char **directory);
/**
* Send an E_SCP_CREATE_SESSION_RESPONSE (SCP server)
*
* @param trans SCP transport
* @param auth_result 0 for success, PAM error code otherwise
* @param display Should be zero if authentication failed.
* @param guid Guid for session. Should be all zeros if authentication failed
* @param status Status of creation request
* @param display Should be zero if create session failed.
* @param guid Guid for session. Should be all zeros if create session failed
*
* @return != 0 for error
*/
int
scp_send_create_session_response(struct trans *trans,
int auth_result,
enum scp_screate_status status,
int display,
const struct guid *guid);
@ -308,73 +377,29 @@ scp_send_create_session_response(struct trans *trans,
* Parse an incoming E_SCP_CREATE_SESSION_RESPONSE (SCP client)
*
* @param trans SCP transport
* @param[out] auth_result 0 for success, PAM error code otherwise
* @param[out] display Should be zero if authentication failed.
* @param[out] guid Guid for session. Should be all zeros if authentication
* @param[out] status Status of creation request
* @param[out] display Should be zero if create session failed.
* @param[out] guid Guid for session. Should be all zeros if create session
* failed
*
* @return != 0 for error
*/
int
scp_get_create_session_response(struct trans *trans,
int *auth_result,
enum scp_screate_status *status,
int *display,
struct guid *guid);
/**
* Status of an E_SCP_LIST_SESSIONS_RESPONSE message
*/
enum scp_list_sessions_status
{
/**
* This message contains a valid session, and other messages
* will be sent
*/
E_SCP_LS_SESSION_INFO = 0,
/**
* This message indicates the end of a list of sessions. No session
* is contained in the message */
E_SCP_LS_END_OF_LIST,
/**
* Authentication failed for the user
*/
E_SCP_LS_AUTHENTICATION_FAIL = 100,
/**
* A client-side error occurred allocating memory for the session
*/
E_SCP_LS_NO_MEMORY
};
/**
* Send an E_LIST_SESSIONS_REQUEST (SCP client)
*
* @param trans SCP transport
* @param username Username
* @param password Password
* @return != 0 for error
*
* Server replies with one or more E_SCP_LIST_SESSIONS_RESPONSE
*/
int
scp_send_list_sessions_request(struct trans *trans,
const char *username,
const char *password);
/**
* Parse an incoming E_LIST_SESSIONS_REQUEST (SCP server)
*
* @param trans SCP transport
* @param[out] username Username
* @param[out] password Password
* @return != 0 for error
*/
int
scp_get_list_sessions_request(struct trans *trans,
const char **username,
const char **password);
scp_send_list_sessions_request(struct trans *trans);
/**
* Send an E_LIST_SESSIONS_RESPONSE (SCP server)
@ -411,5 +436,16 @@ scp_get_list_sessions_response(
enum scp_list_sessions_status *status,
struct scp_session_info **info);
/**
* Send an E_CLOSE_CONNECTION_REQUEST (SCP client)
*
* @param trans SCP transport
* @return != 0 for error
*
* Server closes the connection quietly.
*/
int
scp_send_close_connection_request(struct trans *trans);
#endif /* SCP_H */

View File

@ -0,0 +1,84 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2022, all xrdp contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @file libipm/scp_application_types.c
* @brief Support routines for types in scp_application_types.h
* @author Matt Burt
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "scp_application_types.h"
#include "os_calls.h"
/*****************************************************************************/
const char *
scp_login_status_to_str(enum scp_login_status n,
char *buff, unsigned int buff_size)
{
const char *str =
(n == E_SCP_LOGIN_OK) ? "OK" :
(n == E_SCP_LOGIN_ALREADY_LOGGED_IN) ? "A user is already logged in" :
(n == E_SCP_LOGIN_NO_MEMORY) ? "No memory for login" :
(n == E_SCP_LOGIN_NOT_AUTHENTICATED) ? "User does not exist, or could not be authenticated" :
(n == E_SCP_LOGIN_NOT_AUTHORIZED) ? "User is not authorized" :
(n == E_SCP_LOGIN_GENERAL_ERROR) ? "General login error" :
/* Default */ NULL;
if (str == NULL)
{
g_snprintf(buff, buff_size, "[login error code #%d]", (int)n);
}
else
{
g_snprintf(buff, buff_size, "%s", str);
}
return buff;
}
/*****************************************************************************/
const char *
scp_screate_status_to_str(enum scp_screate_status n,
char *buff, unsigned int buff_size)
{
const char *str =
(n == E_SCP_SCREATE_OK) ? "OK" :
(n == E_SCP_SCREATE_NO_MEMORY) ? "No memory for session" :
(n == E_SCP_SCREATE_NOT_LOGGED_IN) ? "Connection is not logged in" :
(n == E_SCP_SCREATE_MAX_REACHED) ? "Max session limit reached" :
(n == E_SCP_SCREATE_NO_DISPLAY) ? "No X displays are avaiable" :
(n == E_SCP_SCREATE_GENERAL_ERROR) ? "General session creation error" :
/* Default */ NULL;
if (str == NULL)
{
g_snprintf(buff, buff_size, "[session creation error code #%d]",
(int)n);
}
else
{
g_snprintf(buff, buff_size, "%s", str);
}
return buff;
}

View File

@ -26,7 +26,7 @@
#ifndef SCP_APPLICATION_TYPES_H
#define SCP_APPLICATION_TYPES_H
#include <time.h>
#include <sys/types.h>
/**
* Select the desktop application session type
@ -57,9 +57,85 @@ struct scp_session_info
unsigned short height; ///< Initial session height
unsigned char bpp; ///< Session bits-per-pixel
time_t start_time; ///< When session was created
char *username; ///< Username for session
uid_t uid; ///< Username for session
char *start_ip_addr; ///< IP address of starting client
};
/**
* Status of a login request
*/
enum scp_login_status
{
E_SCP_LOGIN_OK = 0, ///< The connection is now loggned in
E_SCP_LOGIN_ALREADY_LOGGED_IN, //< A user is currently logged in
E_SCP_LOGIN_NO_MEMORY, ///< Memory allocation failure
/**
* User couldn't be authenticated, or user doesn't exist */
E_SCP_LOGIN_NOT_AUTHENTICATED,
E_SCP_LOGIN_NOT_AUTHORIZED, ///< User is authenticated, but not authorized
E_SCP_LOGIN_GENERAL_ERROR ///< An unspecific error has occurred
};
/**
* Convert an scp_login_status code to a readable string for output
* @param n Message code
* @param buff to contain string
* @param buff_size length of buff
* @return buff is returned for convenience.
*/
const char *
scp_login_status_to_str(enum scp_login_status n,
char *buff, unsigned int buff_size);
/**
* Status of a session creation request
*/
enum scp_screate_status
{
E_SCP_SCREATE_OK = 0, ///< Session created
E_SCP_SCREATE_NO_MEMORY, ///< Memory allocation failure
E_SCP_SCREATE_NOT_LOGGED_IN, ///< Connection is not logged in
E_SCP_SCREATE_MAX_REACHED, ///< Max number of sessions already reached
E_SCP_SCREATE_NO_DISPLAY, ///< No X server display number is available
E_SCP_SCREATE_GENERAL_ERROR ///< An unspecific error has occurred
};
/**
* Convert an scp_session creation code to a readable string for output
* @param n Message code
* @param buff to contain string
* @param buff_size length of buff
* @return buff is returned for convenience.
*/
const char *
scp_screate_status_to_str(enum scp_screate_status n,
char *buff, unsigned int buff_size);
/**
* Status of an list sessions message
*/
enum scp_list_sessions_status
{
/**
* This message contains a valid session, and other messages
* will be sent
*/
E_SCP_LS_SESSION_INFO = 0,
/**
* This message indicates the end of a list of sessions. No session
* is contained in the message */
E_SCP_LS_END_OF_LIST,
/**
* Client hasn't logged in yet
*/
E_SCP_LS_NOT_LOGGED_IN = 100,
/**
* A client-side error occurred allocating memory for the session
*/
E_SCP_LS_NO_MEMORY
};
#endif /* SCP_APPLICATION_TYPES_H */

View File

@ -28,7 +28,13 @@
#include <config_ac.h>
#endif
#include "arch.h"
#include "access.h"
#include "config.h"
#include "log.h"
#include "sesman.h"
#include "os_calls.h"
#include "string_calls.h"
/******************************************************************************/
@ -51,7 +57,7 @@ access_login_allowed(const char *user)
return 1;
}
if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0))
if (0 != g_getuser_info_by_name(user, 0, &gid, 0, 0, 0))
{
LOG(LOG_LEVEL_ERROR, "Cannot read user info! - login denied");
return 0;
@ -100,7 +106,7 @@ access_login_mng_allowed(const char *user)
return 1;
}
if (0 != g_getuser_info(user, &gid, 0, 0, 0, 0))
if (0 != g_getuser_info_by_name(user, 0, &gid, 0, 0, 0))
{
LOG(LOG_LEVEL_ERROR, "[MNG] Cannot read user info! - login denied");
return 0;

View File

@ -27,11 +27,11 @@
#ifndef AUTH_H
#define AUTH_H
/**
* Opaque type used to represent an authentication handle
*/
struct auth_info;
#include "scp_application_types.h"
/**
*
@ -39,13 +39,25 @@ struct auth_info;
* @param user user's login name
* @param pass user's password
* @param client_ip IP address of connecting client (or ""/NULL if not known)
* @param[out] errorcode from result
* @param[out] Error code for the operation. E_SCP_LOGIN_OK on success.
* @return auth handle on success, NULL on failure
*
*/
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode);
const char *client_ip, enum scp_login_status *errorcode);
/**
*
* @brief Gets an auth handle for a UDS login
*
* @param uid User ID
* @param[out] Error code for the operation. E_SCP_LOGIN_OK on success.
* @return auth handle on success, NULL on failure
*
*/
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode);
/**
*

View File

@ -29,9 +29,10 @@
#endif
#include "arch.h"
#include "config.h"
#include "list.h"
#include "file.h"
#include "sesman.h"
#include "log.h"
#include "string_calls.h"
#include "chansrv/chansrv_common.h"

View File

@ -30,11 +30,15 @@
#include <grp.h>
#include "xrdp_sockets.h"
#include "env.h"
#include "config.h"
#include "list.h"
#include "log.h"
#include "os_calls.h"
#include "sesman.h"
#include "ssl_calls.h"
#include "string_calls.h"
#include "xrdp_sockets.h"
/******************************************************************************/
int
@ -88,26 +92,27 @@ env_check_password_file(const char *filename, const char *passwd)
/******************************************************************************/
/* its the responsibility of the caller to free passwd_file */
int
env_set_user(const char *username, char **passwd_file, int display,
env_set_user(int uid, char **passwd_file, int display,
const struct list *env_names, const struct list *env_values)
{
int error;
int pw_uid;
int pw_gid;
int uid;
int index;
int len;
char *name;
char *value;
char *pw_username;
char *pw_shell;
char *pw_dir;
char text[256];
char hostname[256];
pw_username = 0;
pw_shell = 0;
pw_dir = 0;
error = g_getuser_info(username, &pw_gid, &pw_uid, &pw_shell, &pw_dir, 0);
error = g_getuser_info_by_uid(uid, &pw_username, &pw_gid, &pw_shell,
&pw_dir, 0);
if (error == 0)
{
@ -119,7 +124,6 @@ env_set_user(const char *username, char **passwd_file, int display,
if (error == 0)
{
uid = pw_uid;
error = g_setuid(uid);
}
@ -130,8 +134,8 @@ env_set_user(const char *username, char **passwd_file, int display,
g_clearenv();
g_setenv("SHELL", pw_shell, 1);
g_setenv("PATH", "/sbin:/bin:/usr/bin:/usr/local/bin", 1);
g_setenv("USER", username, 1);
g_setenv("LOGNAME", username, 1);
g_setenv("USER", pw_username, 1);
g_setenv("LOGNAME", pw_username, 1);
g_sprintf(text, "%d", uid);
g_setenv("UID", text, 1);
g_setenv("HOME", pw_dir, 1);
@ -177,14 +181,14 @@ env_set_user(const char *username, char **passwd_file, int display,
}
len = g_snprintf(NULL, 0, "%s/.vnc/sesman_passwd-%s@%s:%d",
pw_dir, username, hostname, display);
pw_dir, pw_username, hostname, display);
*passwd_file = (char *) g_malloc(len + 1, 1);
if (*passwd_file != NULL)
{
/* Try legacy names first, remove if found */
g_sprintf(*passwd_file, "%s/.vnc/sesman_%s_passwd:%d",
pw_dir, username, display);
pw_dir, pw_username, display);
if (g_file_exist(*passwd_file))
{
LOG(LOG_LEVEL_WARNING, "Removing old "
@ -192,7 +196,7 @@ env_set_user(const char *username, char **passwd_file, int display,
g_file_delete(*passwd_file);
}
g_sprintf(*passwd_file, "%s/.vnc/sesman_%s_passwd",
pw_dir, username);
pw_dir, pw_username);
if (g_file_exist(*passwd_file))
{
LOG(LOG_LEVEL_WARNING, "Removing insecure "
@ -200,18 +204,18 @@ env_set_user(const char *username, char **passwd_file, int display,
g_file_delete(*passwd_file);
}
g_sprintf(*passwd_file, "%s/.vnc/sesman_passwd-%s@%s:%d",
pw_dir, username, hostname, display);
pw_dir, pw_username, hostname, display);
}
}
else
{
/* we use auth_file_path as requested */
len = g_snprintf(NULL, 0, g_cfg->auth_file_path, username);
len = g_snprintf(NULL, 0, g_cfg->auth_file_path, pw_username);
*passwd_file = (char *) g_malloc(len + 1, 1);
if (*passwd_file != NULL)
{
g_sprintf(*passwd_file, g_cfg->auth_file_path, username);
g_sprintf(*passwd_file, g_cfg->auth_file_path, pw_username);
}
}
@ -221,6 +225,7 @@ env_set_user(const char *username, char **passwd_file, int display,
}
}
g_free(pw_username);
g_free(pw_dir);
g_free(pw_shell);
}
@ -228,8 +233,7 @@ env_set_user(const char *username, char **passwd_file, int display,
else
{
LOG(LOG_LEVEL_ERROR,
"error getting user info for user %s",
username);
"error getting user info for uid %d", uid);
}
return error;

View File

@ -43,14 +43,14 @@ env_check_password_file(const char *filename, const char *password);
/**
*
* @brief Sets user environment ($PATH, $HOME, $UID, and others)
* @param username Username
* @param uid user ID
* @param passwd_file VNC password file
* @param display The session display
* @return 0 on success, g_getuser_info() error codes on error
*
*/
int
env_set_user(const char *username, char **passwd_file, int display,
env_set_user(int uid, char **passwd_file, int display,
const struct list *env_names, const struct list *env_values);
#endif

View File

@ -35,7 +35,10 @@
#include "scp_process.h"
#include "access.h"
#include "auth.h"
#include "os_calls.h"
#include "session.h"
#include "sesman.h"
#include "string_calls.h"
/**************************************************************************//**
* Logs an authentication failure message
@ -58,142 +61,408 @@ log_authfail_message(const char *username, const char *ip_addr)
/******************************************************************************/
static int
process_gateway_request(struct trans *trans)
/**
* Mode parameter for authenticate_and_authorize_connection()
*/
enum login_mode
{
int rv;
const char *username;
const char *password;
const char *ip_addr;
AM_SYSTEM,
AM_UDS
};
rv = scp_get_gateway_request(trans, &username, &password, &ip_addr);
if (rv == 0)
/**
* Authenticate and authorize the connection
*
* @param sc Connection to sesman
* @param login_mode Describes the type of login in use
* @param uid UID for user
* @param username Name for user
* @param password Password (AM_SYSTEM) or NULL.
* @param ip_addr Remote IP address (AM_SYSTEM) or NULL.
* @return Status for the operation
*
* @pre sc->auth_info, sc->username and sc->ip_addr must be NULL
*
* @post If E_SCP_LOGIN_OK is returned, sc->auth_info is non-NULL
* @post If E_SCP_LOGIN_OK is returned, sc->username is non-NULL
* @post If E_SCP_LOGIN_OK is returned, sc->ip_addr is non-NULL
*
*/
static enum scp_login_status
authenticate_and_authorize_connection(struct sesman_con *sc,
enum login_mode login_mode,
int uid,
const char *username,
const char *password,
const char *ip_addr)
{
enum scp_login_status status = E_SCP_LOGIN_GENERAL_ERROR;
struct auth_info *auth_info = NULL;
/* Check preconditions */
if (sc->auth_info != NULL || sc->username != NULL || sc->ip_addr != NULL)
{
int errorcode = 0;
struct auth_info *auth_info;
LOG(LOG_LEVEL_ERROR,
"Internal error - connection already logged in");
}
else
{
switch (login_mode)
{
case AM_SYSTEM:
auth_info = auth_userpass(username, password, ip_addr, &status);
break;
case AM_UDS:
auth_info = auth_uds(username, &status);
break;
default:
LOG(LOG_LEVEL_ERROR, "%s called with invalid mode %d",
__func__, (int)login_mode);
}
LOG(LOG_LEVEL_INFO, "Received authentication request for user: %s",
username);
auth_info = auth_userpass(username, password, ip_addr, &errorcode);
if (auth_info != NULL)
{
if (1 == access_login_allowed(username))
if (status != E_SCP_LOGIN_OK)
{
/* the user is member of the correct groups. */
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
username);
/* This shouldn't happen */
LOG(LOG_LEVEL_ERROR,
"Unexpected status return %d from auth call",
(int)status);
}
else
else if (!access_login_allowed(username))
{
/* all first 32 are reserved for PAM errors */
errorcode = 32 + 3;
status = E_SCP_LOGIN_NOT_AUTHORIZED;
LOG(LOG_LEVEL_INFO, "Username okay but group problem for "
"user: %s", username);
}
/* If all is well, put the auth_info in the sesman connection
* for later use. If not, remove the auth_info */
if (status == E_SCP_LOGIN_OK)
{
char *dup_username = g_strdup(username);
char *dup_ip_addr =
(ip_addr == NULL) ? g_strdup("") : g_strdup(ip_addr);
if (dup_username == NULL || dup_ip_addr == NULL)
{
LOG(LOG_LEVEL_ERROR, "%s : Memory allocation failed",
__func__);
g_free(dup_username);
g_free(dup_ip_addr);
status = E_SCP_LOGIN_NO_MEMORY;
}
else
{
LOG(LOG_LEVEL_INFO, "Access permitted for user: %s",
username);
sc->auth_info = auth_info;
sc->uid = uid;
sc->username = dup_username;
sc->ip_addr = dup_ip_addr;
}
}
if (status != E_SCP_LOGIN_OK)
{
auth_end(auth_info);
}
}
else
{
log_authfail_message(username, ip_addr);
}
rv = scp_send_gateway_response(trans, errorcode);
auth_end(auth_info);
}
return status;
}
/******************************************************************************/
static int
process_set_peername_request(struct sesman_con *sc)
{
int rv;
const char *peername;
rv = scp_get_set_peername_request(sc->t, &peername);
if (rv == 0)
{
if (sesman_set_connection_peername(sc, peername) != 0)
{
LOG(LOG_LEVEL_WARNING,
"Failed to set connection peername from %s to %s",
sc->peername, peername);
}
}
return rv;
}
/******************************************************************************/
static int
process_create_session_request(struct trans *trans)
process_sys_login_request(struct sesman_con *sc)
{
int rv;
const char *supplied_username;
const char *password;
const char *ip_addr;
rv = scp_get_sys_login_request(sc->t, &supplied_username,
&password, &ip_addr);
if (rv == 0)
{
enum scp_login_status errorcode;
int server_closed = 1;
int uid;
char *username = NULL;
LOG(LOG_LEVEL_INFO,
"Received system login request from %s for user: %s IP: %s",
sc->peername, supplied_username, ip_addr);
if (sc->auth_info != NULL)
{
errorcode = E_SCP_LOGIN_ALREADY_LOGGED_IN;
LOG(LOG_LEVEL_ERROR, "Connection is already logged in for %s",
sc->username);
}
else if (g_getuser_info_by_name(supplied_username,
&uid, NULL, NULL, NULL, NULL) != 0)
{
/* we can't get a UID for the user */
errorcode = E_SCP_LOGIN_NOT_AUTHENTICATED;
LOG(LOG_LEVEL_ERROR, "Can't get UID for user %s",
supplied_username);
log_authfail_message(username, ip_addr);
}
else if (g_getuser_info_by_uid(uid,
&username, NULL, NULL, NULL, NULL) != 0)
{
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
LOG(LOG_LEVEL_ERROR, "Can't reverse lookup UID %d", uid);
}
else
{
if (g_strcmp(supplied_username, username) != 0)
{
/*
* If using a federated naming service (e.g. AD), the
* username supplied may not match that name mapped to by
* the UID. We will generate a warning in this instance so
* the user can see what is being used within sesman
*/
LOG(LOG_LEVEL_WARNING,
"Using username %s for the session (from UID %d)",
username, uid);
}
errorcode = authenticate_and_authorize_connection(
sc, AM_SYSTEM,
uid, username,
password, ip_addr);
if (errorcode == E_SCP_LOGIN_OK)
{
server_closed = 0;
}
else if (errorcode == E_SCP_LOGIN_NOT_AUTHENTICATED)
{
log_authfail_message(username, ip_addr);
if (sc->auth_retry_count > 0)
{
/* Password problem? Invite the user to retry */
server_closed = 0;
--sc->auth_retry_count;
}
}
g_free(username);
}
if (server_closed)
{
/* Expecting no more client messages. Close the connection
* after returning from this callback */
sc->close_requested = 1;
}
rv = scp_send_login_response(sc->t, errorcode, server_closed);
}
return rv;
}
/******************************************************************************/
static int
process_uds_login_request(struct sesman_con *sc)
{
enum scp_login_status errorcode;
int rv;
int uid;
int pid;
char *username = NULL;
int server_closed = 1;
rv = g_sck_get_peer_cred(sc->t->sck, &pid, &uid, NULL);
if (rv != 0)
{
LOG(LOG_LEVEL_INFO,
"Unable to get peer credentials for socket %d",
(int)sc->t->sck);
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
}
else
{
LOG(LOG_LEVEL_INFO,
"Received UDS login request from %s for UID: %d from PID: %d",
sc->peername, uid, pid);
if (sc->auth_info != NULL)
{
errorcode = E_SCP_LOGIN_ALREADY_LOGGED_IN;
LOG(LOG_LEVEL_ERROR, "Connection is already logged in for %s",
sc->username);
}
else if (g_getuser_info_by_uid(uid, &username,
NULL, NULL, NULL, NULL) != 0)
{
errorcode = E_SCP_LOGIN_GENERAL_ERROR;
LOG(LOG_LEVEL_ERROR, "Can't reverse lookup UID %d", uid);
}
else
{
errorcode = authenticate_and_authorize_connection(
sc, AM_UDS,
uid, username,
NULL, NULL);
g_free(username);
if (errorcode == E_SCP_LOGIN_OK)
{
server_closed = 0;
}
}
}
if (server_closed)
{
/* Close the connection after returning from this callback */
sc->close_requested = 1;
}
return scp_send_login_response(sc->t, errorcode, server_closed);
}
/******************************************************************************/
static int
process_logout_request(struct sesman_con *sc)
{
if (sc->auth_info != NULL)
{
LOG(LOG_LEVEL_INFO, "Logging out %s from sesman", sc->username);
auth_end(sc->auth_info);
sc->auth_info = NULL;
sc->uid = -1;
g_free(sc->username);
sc->username = NULL;
g_free(sc->ip_addr);
sc->ip_addr = NULL;
}
return 0;
}
/******************************************************************************/
static int
process_create_session_request(struct sesman_con *sc)
{
int rv;
struct session_parameters sp;
const char *password;
struct guid guid;
int display = 0;
enum scp_screate_status status = E_SCP_SCREATE_OK;
guid_clear(&guid);
int display = 0;
rv = scp_get_create_session_request(
trans,
&sp.username, &password,
&sp.type, &sp.width, &sp.height, &sp.bpp,
&sp.shell, &sp.directory, &sp.ip_addr);
rv = scp_get_create_session_request(sc->t,
&sp.type, &sp.width, &sp.height,
&sp.bpp, &sp.shell, &sp.directory);
if (rv == 0)
{
struct auth_info *auth_info;
struct session_item *s_item;
int errorcode = 0;
bool_t do_auth_end = 1;
LOG(LOG_LEVEL_INFO,
"Received request to create %s session for user: %s",
SCP_SESSION_TYPE_TO_STR(sp.type),
sp.username);
auth_info = auth_userpass(sp.username, password, sp.ip_addr, &errorcode);
if (auth_info != NULL)
if (sc->auth_info == NULL)
{
s_item = session_get_bydata(&sp);
status = E_SCP_SCREATE_NOT_LOGGED_IN;
}
else
{
LOG(LOG_LEVEL_INFO,
"Received request from %s to create a session for user %s",
sc->peername, sc->username);
// Copy over the items we got from the login request,
// but which we need to describe the session
sp.uid = sc->uid;
sp.ip_addr = sc->ip_addr; // Guaranteed to be non-NULL
struct session_item *s_item = session_get_bydata(&sp);
if (s_item != 0)
{
// Found an existing session
display = s_item->display;
guid = s_item->guid;
if (sp.ip_addr[0] != '\0')
{
LOG( LOG_LEVEL_INFO, "++ reconnected session: username %s, "
"display :%d.0, session_pid %d, ip %s",
sp.username, display, s_item->pid, sp.ip_addr);
sc->username, display, s_item->pid, sp.ip_addr);
}
else
{
LOG(LOG_LEVEL_INFO, "++ reconnected session: username %s, "
"display :%d.0, session_pid %d", sp.username, display,
s_item->pid);
"display :%d.0, session_pid %d",
sc->username, display, s_item->pid);
}
session_reconnect(display, sp.username, auth_info);
session_reconnect(display, sc->uid, sc->auth_info);
}
else
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "pre auth");
if (1 == access_login_allowed(sp.username))
// Need to create a new session
if (sp.ip_addr[0] != '\0')
{
if (sp.ip_addr[0] != '\0')
{
LOG(LOG_LEVEL_INFO,
"++ created session (access granted): "
"username %s, ip %s", sp.username, sp.ip_addr);
}
else
{
LOG(LOG_LEVEL_INFO,
"++ created session (access granted): "
"username %s", sp.username);
}
LOG(LOG_LEVEL_INFO,
"++ created session: username %s, ip %s",
sc->username, sp.ip_addr);
}
else
{
LOG(LOG_LEVEL_INFO,
"++ created session: username %s", sc->username);
}
display = session_start(auth_info, &sp, &guid);
/* if the session started up ok, auth_end will be called on
sig child */
do_auth_end = display == 0;
// The new session will have a lifetime longer than
// the sesman connection, and so needs to own
// the auth_info struct.
//
// Copy the auth_info struct out of the connection and pass
// it to the session
struct auth_info *auth_info = sc->auth_info;
sc->auth_info = NULL;
status = session_start(auth_info, &sp, &display, &guid);
if (status != E_SCP_SCREATE_OK)
{
// Close the auth session down as it can't be re-used.
auth_end(auth_info);
}
}
}
else
{
log_authfail_message(sp.username, sp.ip_addr);
}
if (do_auth_end)
{
auth_end(auth_info);
}
/* Currently a create session request is the last thing on a
* connection, and results in automatic closure */
sc->close_requested = 1;
rv = scp_send_create_session_response(trans, errorcode, display, &guid);
rv = scp_send_create_session_response(sc->t, status, display, &guid);
}
return rv;
@ -202,75 +471,99 @@ process_create_session_request(struct trans *trans)
/******************************************************************************/
static int
process_list_sessions_request(struct trans *trans)
process_list_sessions_request(struct sesman_con *sc)
{
int rv;
int rv = 0;
const char *username;
const char *password;
struct scp_session_info *info = NULL;
unsigned int cnt = 0;
unsigned int i;
rv = scp_get_list_sessions_request(trans, &username, &password);
if (rv == 0)
if (sc->auth_info == NULL)
{
rv = scp_send_list_sessions_response(sc->t,
E_SCP_LS_NOT_LOGGED_IN,
NULL);
}
else
{
enum scp_list_sessions_status status;
int errorcode = 0;
struct auth_info *auth_info;
LOG(LOG_LEVEL_INFO,
"Received request to list sessions for user %s", username);
"Received request from %s to list sessions for user %s",
sc->peername, sc->username);
auth_info = auth_userpass(username, password, NULL, &errorcode);
if (auth_info != NULL)
{
struct scp_session_info *info = NULL;
unsigned int cnt = 0;
unsigned int i;
info = session_get_byuser(username, &cnt,
SESMAN_SESSION_STATUS_ALL);
info = session_get_byuid(sc->uid, &cnt,
SESMAN_SESSION_STATUS_ALL);
for (i = 0; rv == 0 && i < cnt; ++i)
{
rv = scp_send_list_sessions_response(trans,
E_SCP_LS_SESSION_INFO,
&info[i]);
}
free_session_info_list(info, cnt);
status = E_SCP_LS_END_OF_LIST;
}
else
for (i = 0; rv == 0 && i < cnt; ++i)
{
status = E_SCP_LS_AUTHENTICATION_FAIL;
rv = scp_send_list_sessions_response(sc->t,
E_SCP_LS_SESSION_INFO,
&info[i]);
}
auth_end(auth_info);
free_session_info_list(info, cnt);
if (rv == 0)
{
rv = scp_send_list_sessions_response(trans, status, NULL);
rv = scp_send_list_sessions_response(sc->t,
E_SCP_LS_END_OF_LIST,
NULL);
}
}
return rv;
}
/******************************************************************************/
static int
process_close_connection_request(struct sesman_con *sc)
{
int rv = 0;
LOG(LOG_LEVEL_INFO, "Received request to close connection from %s",
sc->peername);
/* Expecting no more client messages. Close the connection
* after returning from this callback */
sc->close_requested = 1;
return rv;
}
/******************************************************************************/
int
scp_process(struct trans *t)
scp_process(struct sesman_con *sc)
{
enum scp_msg_code msgno;
int rv = 0;
switch ((msgno = scp_msg_in_start(t)))
switch ((msgno = scp_msg_in_start(sc->t)))
{
case E_SCP_GATEWAY_REQUEST:
rv = process_gateway_request(t);
case E_SCP_SET_PEERNAME_REQUEST:
rv = process_set_peername_request(sc);
break;
case E_SCP_SYS_LOGIN_REQUEST:
rv = process_sys_login_request(sc);
break;
case E_SCP_UDS_LOGIN_REQUEST:
rv = process_uds_login_request(sc);
break;
case E_SCP_LOGOUT_REQUEST:
rv = process_logout_request(sc);
break;
case E_SCP_CREATE_SESSION_REQUEST:
rv = process_create_session_request(t);
rv = process_create_session_request(sc);
break;
case E_SCP_LIST_SESSIONS_REQUEST:
rv = process_list_sessions_request(t);
rv = process_list_sessions_request(sc);
break;
case E_SCP_CLOSE_CONNECTION_REQUEST:
rv = process_close_connection_request(sc);
break;
default:

View File

@ -27,15 +27,15 @@
#ifndef SCP_PROCESS_H
#define SCP_PROCESS_H
struct trans;
struct sesman_con;
/**
*
* @brief Processes an SCP message
* @param t the connection trans
* @param sc the sesman connection
*
*/
int
scp_process(struct trans *t);
scp_process(struct sesman_con *sc);
#endif

View File

@ -30,13 +30,19 @@
#include <stdarg.h>
#include "arch.h"
#include "sesman.h"
#include "xrdp_configure_options.h"
#include "auth.h"
#include "config.h"
#include "lock_uds.h"
#include "os_calls.h"
#include "scp.h"
#include "scp_process.h"
#include "sig.h"
#include "string_calls.h"
#include "trans.h"
#include "scp_process.h"
#include "lock_uds.h"
#include "xrdp_configure_options.h"
/**
* Maximum number of short-lived connections to sesman
@ -72,14 +78,6 @@ tintptr g_term_event = 0;
tintptr g_sigchld_event = 0;
tintptr g_reload_event = 0;
/**
* Items stored on the g_con_list
*/
struct sesman_con
{
struct trans *t;
};
static struct trans *g_list_trans;
/* Variables used to lock g_list_trans */
@ -126,9 +124,11 @@ alloc_connection(struct trans *t)
{
struct sesman_con *result;
if ((result = g_new(struct sesman_con, 1)) != NULL)
if ((result = g_new0(struct sesman_con, 1)) != NULL)
{
g_snprintf(result->peername, sizeof(result->peername), "%s", "unknown");
result->t = t;
result->auth_retry_count = g_cfg->sec.login_retry;
}
return result;
@ -140,15 +140,40 @@ alloc_connection(struct trans *t)
* After this call, the passed-in pointer is invalid and must not be
* referenced.
*
* Any auth_info struct found in the sesman_con is also deallocated.
*
* @param sc struct to de-allocate
*/
static void
delete_connection(struct sesman_con *sc)
{
trans_delete(sc->t);
g_free(sc);
if (sc != NULL)
{
trans_delete(sc->t);
if (sc->auth_info != NULL)
{
auth_end(sc->auth_info);
}
g_free(sc->username);
g_free(sc->ip_addr);
g_free(sc);
}
}
/*****************************************************************************/
int
sesman_set_connection_peername(struct sesman_con *sc, const char *name)
{
int rv = 1;
if (sc != NULL && name != NULL)
{
g_snprintf(sc->peername, sizeof(sc->peername), "%s", name);
rv = 0;
}
return rv;
}
/*****************************************************************************/
/**
@ -275,16 +300,23 @@ static int sesman_listen_test(struct config_sesman *cfg)
/******************************************************************************/
int
sesman_close_all(void)
sesman_close_all(unsigned int flags)
{
int index;
struct sesman_con *sc;
LOG_DEVEL(LOG_LEVEL_TRACE, "sesman_close_all:");
sesman_delete_listening_transport();
for (index = 0; index < g_con_list->count; index++)
{
sc = (struct sesman_con *) list_get_item(g_con_list, index);
if (sc != NULL && (flags & SCA_CLOSE_AUTH_INFO) == 0)
{
// Prevent delete_connection() closing the auth_info down
sc->auth_info = NULL;
}
delete_connection(sc);
}
return 0;
@ -301,7 +333,8 @@ sesman_data_in(struct trans *self)
if (rv == 0 && available)
{
if ((rv = scp_process(self)) != 0)
struct sesman_con *sc = (struct sesman_con *)self->callback_data;
if ((rv = scp_process(sc)) != 0)
{
LOG(LOG_LEVEL_ERROR, "sesman_data_in: scp_process_msg failed");
}
@ -327,7 +360,7 @@ sesman_listen_conn_in(struct trans *self, struct trans *new_self)
{
LOG(LOG_LEVEL_ERROR, "sesman_data_in: No memory to allocate "
"new connection");
trans_delete(new_self);
delete_connection(sc);
}
else
{
@ -549,20 +582,30 @@ sesman_main_loop(void)
sig_sesman_reload_cfg();
}
for (index = 0; index < g_con_list->count; index++)
index = 0;
while (index < g_con_list->count)
{
int remove_con = 0;
scon = (struct sesman_con *)list_get_item(g_con_list, index);
if (scon != NULL)
if (trans_check_wait_objs(scon->t) != 0)
{
if (trans_check_wait_objs(scon->t) != 0)
{
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
"trans_check_wait_objs failed, removing trans");
delete_connection(scon);
list_remove_item(g_con_list, index);
index--;
continue;
}
LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
"trans_check_wait_objs failed, removing trans");
remove_con = 1;
}
else if (scon->close_requested)
{
remove_con = 1;
}
if (remove_con)
{
delete_connection(scon);
list_remove_item(g_con_list, index);
}
else
{
++index;
}
}
@ -577,13 +620,9 @@ sesman_main_loop(void)
}
}
}
for (index = 0; index < g_con_list->count; index++)
{
scon = (struct sesman_con *) list_get_item(g_con_list, index);
delete_connection(scon);
}
sesman_close_all(SCA_CLOSE_AUTH_INFO);
list_delete(g_con_list);
sesman_delete_listening_transport();
return 0;
}

View File

@ -27,17 +27,20 @@
#ifndef SESMAN_H
#define SESMAN_H
#include "arch.h"
#include "parse.h"
#include "os_calls.h"
#include "log.h"
#include "env.h"
#include "auth.h"
#include "config.h"
#include "sig.h"
#include "session.h"
#include "access.h"
#include "scp.h"
/**
* Type for managing sesman connections from xrdp (etc)
*/
struct sesman_con
{
struct trans *t;
char peername[15 + 1]; /* Name of peer, if known, for logging */
int close_requested; /* Set to close the connection normally */
unsigned int auth_retry_count;
struct auth_info *auth_info; /* non-NULL for an authenticated connection */
int uid; /* User */
char *username; /* Username from UID (at time of logon) */
char *ip_addr; /* Connecting IP address */
};
/* Globals */
extern struct config_sesman *g_cfg;
@ -46,6 +49,15 @@ extern tintptr g_term_event;
extern tintptr g_sigchld_event;
extern tintptr g_reload_event;
/**
* Set the peername of a connection
*
* @param name Name to set
* @result 0 for success
*/
int
sesman_set_connection_peername(struct sesman_con *sc, const char *name);
/*
* Close all file descriptors used by sesman.
*
@ -54,9 +66,14 @@ extern tintptr g_reload_event;
*
* This call will also release all trans and SCP_SESSION objects
* held by sesman
*
* @param flags Set SCA_CLOSE_AUTH_INFO to close any open auth_info
* objects. By default these are not cleared, and should
* only be done so when exiting sesman.
*/
#define SCA_CLOSE_AUTH_INFO (1<<0)
int
sesman_close_all(void);
sesman_close_all(unsigned int flags);
/*
* Remove the listening transport

View File

@ -37,10 +37,19 @@
#include <sys/prctl.h>
#endif
#include "arch.h"
#include "session.h"
#include "auth.h"
#include "config.h"
#include "env.h"
#include "list.h"
#include "log.h"
#include "os_calls.h"
#include "sesman.h"
#include "string_calls.h"
#include "xauth.h"
#include "xrdp_sockets.h"
#include "string_calls.h"
#ifndef PR_SET_NO_NEW_PRIVS
#define PR_SET_NO_NEW_PRIVS 38
@ -103,10 +112,10 @@ session_get_bydata(const struct session_parameters *sp)
config_output_policy_string(policy, policy_str, sizeof(policy_str));
LOG(LOG_LEVEL_DEBUG,
"%s: search policy=%s type=%s U=%s B=%d D=(%dx%d) I=%s",
"%s: search policy=%s type=%s U=%d B=%d D=(%dx%d) I=%s",
__func__,
policy_str, SCP_SESSION_TYPE_TO_STR(sp->type),
sp->username, sp->bpp, sp->width, sp->height,
sp->uid, sp->bpp, sp->width, sp->height,
sp->ip_addr);
/* 'Separate' policy never matches */
@ -121,11 +130,11 @@ session_get_bydata(const struct session_parameters *sp)
struct session_item *item = tmp->item;
LOG(LOG_LEVEL_DEBUG,
"%s: try %p type=%s U=%s B=%d D=(%dx%d) I=%s",
"%s: try %p type=%s U=%d B=%d D=(%dx%d) I=%s",
__func__,
item,
SCP_SESSION_TYPE_TO_STR(item->type),
item->name,
item->uid,
item->bpp,
item->width, item->height,
item->start_ip_addr);
@ -136,11 +145,10 @@ session_get_bydata(const struct session_parameters *sp)
continue;
}
if ((policy & SESMAN_CFG_SESS_POLICY_U) &&
g_strncmp(sp->username, item->name, sizeof(item->name) - 1) != 0)
if ((policy & SESMAN_CFG_SESS_POLICY_U) && sp->uid != item->uid)
{
LOG(LOG_LEVEL_DEBUG,
"%s: Username doesn't match for 'U' policy", __func__);
"%s: UID doesn't match for 'U' policy", __func__);
continue;
}
@ -399,7 +407,7 @@ wait_for_xserver(int display)
/******************************************************************************/
static int
session_start_chansrv(const char *username, int display)
session_start_chansrv(int uid, int display)
{
struct list *chansrv_params;
char exe_path[262];
@ -421,7 +429,7 @@ session_start_chansrv(const char *username, int display)
list_add_item(chansrv_params, (intptr_t) g_strdup(exe_path));
list_add_item(chansrv_params, 0); /* mandatory */
env_set_user(username, 0, display,
env_set_user(uid, 0, display,
g_cfg->env_names,
g_cfg->env_values);
@ -436,10 +444,38 @@ session_start_chansrv(const char *username, int display)
}
/******************************************************************************/
/**
* Convert a UID to a username
*
* @param uid UID
* @param uname pointer to output buffer
* @param uname_len Length of output buffer
* @return 0 for success.
*/
static int
username_from_uid(int uid, char *uname, int uname_len)
{
char *ustr;
int rv = g_getuser_info_by_uid(uid, &ustr, NULL, NULL, NULL, NULL);
int
if (rv == 0)
{
g_snprintf(uname, uname_len, "%s", ustr);
g_free(ustr);
}
else
{
g_snprintf(uname, uname_len, "<unknown>");
}
return rv;
}
/******************************************************************************/
enum scp_screate_status
session_start(struct auth_info *auth_info,
const struct session_parameters *s,
int *returned_display,
struct guid *guid)
{
int display = 0;
@ -448,6 +484,7 @@ session_start(struct auth_info *auth_info,
char depth[32];
char screen[32]; /* display number */
char text[256];
char username[256];
char execvpparams[2048];
char *xserver = NULL; /* absolute/relative path to Xorg/X11rdp/Xvnc */
char *passwd_file;
@ -467,12 +504,15 @@ session_start(struct auth_info *auth_info,
passwd_file = 0;
/* Get the username for display purposes */
username_from_uid(s->uid, username, sizeof(username));
/* check to limit concurrent sessions */
if (g_session_count >= g_cfg->sess.max_sessions)
{
LOG(LOG_LEVEL_ERROR, "max concurrent session limit "
"exceeded. login for user %s denied", s->username);
return 0;
"exceeded. login for user %s denied", username);
return E_SCP_SCREATE_MAX_REACHED;
}
temp = (struct session_chain *)g_malloc(sizeof(struct session_chain), 0);
@ -480,8 +520,8 @@ session_start(struct auth_info *auth_info,
if (temp == 0)
{
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
"chain element - user %s", s->username);
return 0;
"chain element - user %s", username);
return E_SCP_SCREATE_NO_MEMORY;
}
temp->item = (struct session_item *)g_malloc(sizeof(struct session_item), 0);
@ -490,8 +530,8 @@ session_start(struct auth_info *auth_info,
{
g_free(temp);
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
"item - user %s", s->username);
return 0;
"item - user %s", username);
return E_SCP_SCREATE_NO_MEMORY;
}
display = session_get_avail_display_from_chain();
@ -500,11 +540,12 @@ session_start(struct auth_info *auth_info,
{
g_free(temp->item);
g_free(temp);
return 0;
return E_SCP_SCREATE_NO_DISPLAY;
}
/* Create a GUID for the new session before we work */
/* Create a GUID for the new session before we fork */
*guid = guid_new();
*returned_display = display;
pid = g_fork(); /* parent is fork from tcp accept,
child forks X and wm, then becomes scp */
@ -515,8 +556,12 @@ session_start(struct auth_info *auth_info,
"[session start] (display %d): Failed to fork for scp with "
"errno: %d, description: %s",
display, g_get_errno(), g_get_strerror());
g_free(temp->item);
g_free(temp);
return E_SCP_SCREATE_GENERAL_ERROR;
}
else if (pid == 0)
if (pid == 0)
{
LOG(LOG_LEVEL_INFO,
"[session start] (display %d): calling auth_start_session from pid %d",
@ -538,16 +583,16 @@ session_start(struct auth_info *auth_info,
/* Set the secondary groups before starting the session to prevent
* problems on PAM-based systems (see pam_setcred(3)) */
if (g_initgroups(s->username) != 0)
if (g_initgroups(username) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Failed to initialise secondary groups for %s: %s",
s->username, g_get_strerror());
username, g_get_strerror());
g_exit(1);
}
sesman_close_all(0);
auth_start_session(auth_info, display);
sesman_close_all();
g_sprintf(geometry, "%dx%d", s->width, s->height);
g_sprintf(depth, "%d", s->bpp);
g_sprintf(screen, ":%d", display);
@ -579,11 +624,11 @@ session_start(struct auth_info *auth_info,
display, g_getpid());
}
if (g_setlogin(s->username) < 0)
if (g_setlogin(username) < 0)
{
LOG(LOG_LEVEL_WARNING,
"[session start] (display %d): setlogin failed for user %s - pid %d",
display, s->username, g_getpid());
display, username, g_getpid());
}
}
@ -608,7 +653,7 @@ session_start(struct auth_info *auth_info,
else if (window_manager_pid == 0)
{
wait_for_xserver(display);
env_set_user(s->username,
env_set_user(s->uid,
0,
display,
g_cfg->env_names,
@ -706,7 +751,7 @@ session_start(struct auth_info *auth_info,
{
if (s->type == SCP_SESSION_TYPE_XVNC)
{
env_set_user(s->username,
env_set_user(s->uid,
&passwd_file,
display,
g_cfg->env_names,
@ -714,7 +759,7 @@ session_start(struct auth_info *auth_info,
}
else
{
env_set_user(s->username,
env_set_user(s->uid,
0,
display,
g_cfg->env_names,
@ -892,11 +937,11 @@ session_start(struct auth_info *auth_info,
struct exit_status chansrv_exit_status;
wait_for_xserver(display);
chansrv_pid = session_start_chansrv(s->username, display);
chansrv_pid = session_start_chansrv(s->uid, display);
LOG(LOG_LEVEL_INFO,
"Session started successfully for user %s on display %d",
s->username, display);
username, display);
/* Monitor the amount of time we wait for the
* window manager. This is approximately how long the window
@ -930,10 +975,12 @@ session_start(struct auth_info *auth_info,
window_manager_pid, display, wm_wait_time);
}
LOG(LOG_LEVEL_INFO,
"Calling auth_stop_session and auth_end from pid %d",
"Calling auth_stop_session from pid %d",
g_getpid());
auth_stop_session(auth_info);
auth_end(auth_info);
// auth_end() is called from the main process currently,
// as this called auth_start()
//auth_end(auth_info);
LOG(LOG_LEVEL_INFO,
"Terminating X server (pid %d) on display %d",
@ -969,8 +1016,8 @@ session_start(struct auth_info *auth_info,
{
LOG(LOG_LEVEL_INFO, "Starting session: session_pid %d, "
"display :%d.0, width %d, height %d, bpp %d, client ip %s, "
"user name %s",
pid, display, s->width, s->height, s->bpp, s->ip_addr, s->username);
"UID %d",
pid, display, s->width, s->height, s->bpp, s->ip_addr, s->uid);
temp->item->pid = pid;
temp->item->display = display;
temp->item->width = s->width;
@ -979,7 +1026,7 @@ session_start(struct auth_info *auth_info,
temp->item->auth_info = auth_info;
g_strncpy(temp->item->start_ip_addr, s->ip_addr,
sizeof(temp->item->start_ip_addr) - 1);
g_strncpy(temp->item->name, s->username, 255);
temp->item->uid = s->uid;
temp->item->guid = *guid;
temp->item->start_time = g_time1();
@ -991,17 +1038,18 @@ session_start(struct auth_info *auth_info,
g_sessions = temp;
g_session_count++;
return display;
return E_SCP_SCREATE_OK;
}
/* Shouldn't get here */
g_free(temp->item);
g_free(temp);
return display;
return E_SCP_SCREATE_GENERAL_ERROR;
}
/******************************************************************************/
int
session_reconnect(int display, const char *username,
session_reconnect(int display, int uid,
struct auth_info *auth_info)
{
int pid;
@ -1014,7 +1062,7 @@ session_reconnect(int display, const char *username,
}
else if (pid == 0)
{
env_set_user(username,
env_set_user(uid,
0,
display,
g_cfg->env_names,
@ -1081,10 +1129,23 @@ session_kill(int pid)
if (tmp->item->pid == pid)
{
char username[256];
username_from_uid(tmp->item->uid, username, sizeof(username));
/* deleting the session */
if (tmp->item->auth_info != NULL)
{
LOG(LOG_LEVEL_INFO,
"Calling auth_end for pid %d from pid %d",
pid, g_getpid());
auth_end(tmp->item->auth_info);
tmp->item->auth_info = NULL;
}
LOG(LOG_LEVEL_INFO,
"++ terminated session: username %s, display :%d.0, session_pid %d, ip %s",
tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->start_ip_addr);
"++ terminated session: UID %d (%s), display :%d.0, "
"session_pid %d, ip %s",
tmp->item->uid, username, tmp->item->display,
tmp->item->pid, tmp->item->start_ip_addr);
g_free(tmp->item);
if (prev == 0)
@ -1177,7 +1238,7 @@ session_get_bypid(int pid)
/******************************************************************************/
struct scp_session_info *
session_get_byuser(const char *user, unsigned int *cnt, unsigned char flags)
session_get_byuid(int uid, unsigned int *cnt, unsigned char flags)
{
struct session_chain *tmp;
struct scp_session_info *sess;
@ -1188,10 +1249,10 @@ session_get_byuser(const char *user, unsigned int *cnt, unsigned char flags)
tmp = g_sessions;
LOG(LOG_LEVEL_DEBUG, "searching for session by user: %s", user);
LOG(LOG_LEVEL_DEBUG, "searching for session by UID: %d", uid);
while (tmp != 0)
{
if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256)))
if (uid == tmp->item->uid)
{
LOG(LOG_LEVEL_DEBUG, "session_get_byuser: status=%d, flags=%d, "
"result=%d", (tmp->item->status), flags,
@ -1227,8 +1288,7 @@ session_get_byuser(const char *user, unsigned int *cnt, unsigned char flags)
while (tmp != 0 && index < count)
{
/* #warning FIXME: we should get only disconnected sessions! */
if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256)))
if (uid == tmp->item->uid)
{
if ((tmp->item->status) & flags)
{
@ -1239,11 +1299,11 @@ session_get_byuser(const char *user, unsigned int *cnt, unsigned char flags)
(sess[index]).width = tmp->item->width;
(sess[index]).bpp = tmp->item->bpp;
(sess[index]).start_time = tmp->item->start_time;
(sess[index]).username = g_strdup(tmp->item->name);
(sess[index]).uid = tmp->item->uid;
(sess[index]).start_ip_addr = g_strdup(tmp->item->start_ip_addr);
if ((sess[index]).username == NULL ||
(sess[index]).start_ip_addr == NULL)
/* Check for string allocation failures */
if ((sess[index]).start_ip_addr == NULL)
{
free_session_info_list(sess, *cnt);
(*cnt) = 0;
@ -1270,7 +1330,6 @@ free_session_info_list(struct scp_session_info *sesslist, unsigned int cnt)
unsigned int i;
for (i = 0 ; i < cnt ; ++i)
{
g_free(sesslist[i].username);
g_free(sesslist[i].start_ip_addr);
}
}
@ -1383,7 +1442,6 @@ clone_session_params(const struct session_parameters *sp)
/* Allocate a single block of memory big enough for the structure and
* all the strings it points to */
unsigned int len = sizeof(*result);
len += g_strlen(sp->username) + 1;
len += g_strlen(sp->shell) + 1;
len += g_strlen(sp->directory) + 1;
len += g_strlen(sp->ip_addr) + 1;
@ -1403,7 +1461,6 @@ clone_session_params(const struct session_parameters *sp)
strptr += len;\
}
COPY_STRING_MEMBER(sp->username, result->username);
COPY_STRING_MEMBER(sp->shell, result->shell);
COPY_STRING_MEMBER(sp->directory, result->directory);
COPY_STRING_MEMBER(sp->ip_addr, result->ip_addr);

View File

@ -53,7 +53,7 @@ struct scp_session_info;
struct session_item
{
char name[256];
int uid; /* UID of session */
int pid; /* pid of sesman waiting for wm to end */
int display;
int width;
@ -85,11 +85,11 @@ struct session_chain
*/
struct session_parameters
{
int uid;
enum scp_session_type type;
unsigned short height;
unsigned short width;
unsigned char bpp;
const char *username;
const char *shell;
const char *directory;
const char *ip_addr;
@ -110,16 +110,17 @@ session_get_bydata(const struct session_parameters *params);
/**
*
* @brief starts a session
* @return 0 on error, display number if success
*
* @return Connection status.
*/
int
enum scp_screate_status
session_start(struct auth_info *auth_info,
const struct session_parameters *params,
int *display,
struct guid *guid);
int
session_reconnect(int display, const char *username,
session_reconnect(int display, int uid,
struct auth_info *auth_info);
/**
@ -154,14 +155,14 @@ session_get_bypid(int pid);
/**
*
* @brief retrieves session descriptions
* @param user the user for the sessions
* @param UID the UID for the descriptions
* @return A block of session descriptions
*
* Pass the return result to free_session_info_list() after use
*
*/
struct scp_session_info *
session_get_byuser(const char *user, unsigned int *cnt, unsigned char flags);
session_get_byuid(int uid, unsigned int *cnt, unsigned char flags);
/**
*

View File

@ -28,8 +28,15 @@
#include <config_ac.h>
#endif
#include "string_calls.h"
#include "arch.h"
#include "sig.h"
#include "config.h"
#include "log.h"
#include "os_calls.h"
#include "sesman.h"
#include "session.h"
#include "string_calls.h"
/******************************************************************************/
void

View File

@ -61,4 +61,5 @@ xrdp_xcon_LDADD = \
xrdp_authtest_LDADD = \
$(top_builddir)/common/libcommon.la \
$(top_builddir)/libipm/libipm.la \
$(AUTHMOD_LIB)

View File

@ -68,14 +68,17 @@ usage(void)
"etc.\n\n"
"This is a DEVELOPER-ONLY tool\n");
g_printf("\nusage:\n");
g_printf("authtest [options] username\n\n");
g_printf("authtest [options] [username]\n\n");
g_printf("options:\n");
g_printf(" -p <password>\n"
" -F <file-descriptor> Read password from this file descriptor\n"
" -c <command> Start a session and run the\n"
" specified non-interactive command\n"
" in it\n");
g_printf("Password is prompted if -p or -F are not specified\n");
g_printf("\nIf username is omitted, the current user is used, and.\n"
"a UDS login is attempted\n"
"If username is provided, password is needed.\n"
" Password is prompted for if -p or -F are not specified\n");
}
@ -186,10 +189,15 @@ parse_program_args(int argc, char *argv[], struct authmod_params *amp)
}
}
if (argc <= optind)
if (argc == optind)
{
LOG(LOG_LEVEL_ERROR, "No user name specified");
params_ok = 0;
// No username was specified
if (password_set)
{
LOG(LOG_LEVEL_WARNING, "No username - ignoring specified password");
amp->password[0] = '\0';
}
amp->username = NULL;
}
else if ((argc - optind) > 1)
{
@ -199,26 +207,58 @@ parse_program_args(int argc, char *argv[], struct authmod_params *amp)
else
{
amp->username = argv[optind];
}
if (params_ok && !password_set)
{
const char *p = getpass("Password: ");
if (p != NULL)
if (!password_set)
{
g_strcpy(amp->password, p);
const char *p = getpass("Password: ");
if (p == NULL)
{
params_ok = 0;
}
else
{
g_snprintf(amp->password, sizeof(amp->password), "%s", p);
}
}
}
return params_ok;
}
/******************************************************************************/
/**
* Gets the current username for a UDS login
*
* Result must be freed after use.
*/
static char *
get_username()
{
int uid = g_getuid();
char *this_user;
int status;
status = g_getuser_info_by_uid(uid, &this_user, NULL, NULL, NULL, NULL);
if (status != 0)
{
LOG(LOG_LEVEL_ERROR, "Can't map UID %d to a username", uid);
this_user = NULL;
}
else
{
LOG(LOG_LEVEL_INFO, "Mapped current UID %d to \"%s\"",
uid, this_user);
}
return this_user;
}
/******************************************************************************/
int
main(int argc, char **argv)
{
struct log_config *logging;
int rv = 1;
int rv = 0;
char *this_user = NULL;
struct authmod_params amp;
logging = log_config_init_for_console(LOG_LEVEL_DEBUG,
@ -229,16 +269,34 @@ main(int argc, char **argv)
if (!parse_program_args(argc, argv, &amp))
{
usage();
rv = 1;
}
else if (amp.username == NULL && (this_user = get_username()) == NULL)
{
rv = 1;
}
else
{
struct auth_info *auth_info;
auth_info = auth_userpass(amp.username, amp.password,
NULL, &rv);
enum scp_login_status errorcode;
char errstr[64];
LOG(LOG_LEVEL_INFO, "auth_userpass() returned %s, errorcode=%d",
if (amp.username == NULL)
{
auth_info = auth_uds(this_user, &errorcode);
}
else
{
auth_info = auth_userpass(amp.username, amp.password,
NULL, &errorcode);
}
scp_login_status_to_str(errorcode, errstr, sizeof(errstr));
LOG(LOG_LEVEL_INFO,
"auth_userpass() returned %s, errorcode=%d [%s]",
(auth_info == NULL) ? "NULL" : "non-NULL",
rv);
(int)errorcode, errstr);
rv = (int)errorcode;
if (auth_info && rv == 0 && amp.command != NULL)
{
int display = 10;
@ -261,6 +319,7 @@ main(int argc, char **argv)
}
}
g_free(this_user);
log_end();
return rv;

View File

@ -31,8 +31,6 @@
#include <stdio.h>
#include <unistd.h>
char user[257];
char pass[257];
char cmnd[257];
char port[257];
@ -47,12 +45,9 @@ int main(int argc, char **argv)
//int end;
int idx;
//int sel;
char *pwd;
struct log_config *logging;
int rv = 1;
user[0] = '\0';
pass[0] = '\0';
cmnd[0] = '\0';
port[0] = '\0';
@ -64,11 +59,11 @@ int main(int argc, char **argv)
{
if (0 == g_strncmp(argv[idx], "-u=", 3))
{
g_strncpy(user, (argv[idx]) + 3, 256);
g_printf("** Ignoring unused argument '-u'");
}
else if (0 == g_strncmp(argv[idx], "-p=", 3))
{
g_strncpy(pass, (argv[idx]) + 3, 256);
g_printf("** Ignoring unused argument '-p'");
}
else if (0 == g_strncmp(argv[idx], "-i=", 3))
{
@ -80,48 +75,57 @@ int main(int argc, char **argv)
}
}
if (0 == g_strncmp(port, "", 1))
{
g_strncpy(port, "3350", 256);
}
if (0 == g_strncmp(user, "", 1))
{
cmndHelp();
return 0;
}
if (0 == g_strncmp(cmnd, "", 1))
{
cmndHelp();
return 0;
}
if (0 == g_strncmp(pass, "", 1))
{
pwd = getpass("password:");
g_strncpy(pass, pwd, 256);
}
t = scp_connect(port, NULL);
t = scp_connect(port, "xrdp-sesadmin", NULL);
if (t == NULL)
{
LOG(LOG_LEVEL_ERROR, "scp_connect() error");
}
else if (0 == g_strncmp(cmnd, "list", 5))
else
{
rv = cmndList(t);
}
else if (0 == g_strncmp(cmnd, "kill:", 5))
{
rv = cmndKill(t);
enum scp_login_status login_result;
/* Log in as the current user */
if ((rv = scp_send_uds_login_request(t)) == 0 &&
(rv = wait_for_sesman_reply(t, E_SCP_LOGIN_RESPONSE)) == 0)
{
rv = scp_get_login_response(t, &login_result, NULL);
if (rv == 0)
{
if (login_result != E_SCP_LOGIN_OK)
{
char msg[256];
scp_login_status_to_str(login_result, msg, sizeof(msg));
g_printf("Login failed; %s\n", msg);
rv = 1;
}
}
scp_msg_in_reset(t); // Done with this message
}
}
g_memset(pass, '\0', sizeof(pass));
if (rv == 0)
{
if (0 == g_strncmp(cmnd, "list", 5))
{
rv = cmndList(t);
}
else if (0 == g_strncmp(cmnd, "kill:", 5))
{
rv = cmndKill(t);
}
}
if (rv == 0)
{
rv = scp_send_close_connection_request(t);
}
trans_delete(t);
log_end();
@ -133,10 +137,7 @@ cmndHelp(void)
{
fprintf(stderr, "sesadmin - a console sesman administration tool\n");
fprintf(stderr, "syntax: sesadmin [] COMMAND [OPTIONS]\n\n");
fprintf(stderr, "-u=<username>: username to connect to sesman [MANDATORY]\n");
fprintf(stderr, "-p=<password>: password to connect to sesman (asked if not given)\n");
fprintf(stderr, "-s=<hostname>: sesman host (default is localhost)\n");
fprintf(stderr, "-i=<port> : sesman port (default 3350)\n");
fprintf(stderr, "-i=<port> : sesman port (can be defaulted)\n");
fprintf(stderr, "-c=<command> : command to execute on the server [MANDATORY]\n");
fprintf(stderr, " it can be one of those:\n");
fprintf(stderr, " list\n");
@ -146,9 +147,14 @@ cmndHelp(void)
static void
print_session(const struct scp_session_info *s)
{
char *username;
const char *uptr;
g_getuser_info_by_uid(s->uid, &username, NULL, NULL, NULL, NULL);
uptr = (username == NULL) ? "<unknown>" : username;
printf("Session ID: %d\n", s->sid);
printf("\tDisplay: :%u\n", s->display);
printf("\tUser: %s\n", s->username);
printf("\tUser: %s\n", uptr);
printf("\tSession type: %s\n", SCP_SESSION_TYPE_TO_STR(s->type));
printf("\tScreen size: %dx%d, color depth %d\n",
s->width, s->height, s->bpp);
@ -157,6 +163,7 @@ print_session(const struct scp_session_info *s)
{
printf("\tStart IP address: %s\n", s->start_ip_addr);
}
g_free(username);
}
static int
@ -168,7 +175,7 @@ cmndList(struct trans *t)
enum scp_list_sessions_status status;
struct scp_session_info *p;
int rv = scp_send_list_sessions_request(t, user, pass);
int rv = scp_send_list_sessions_request(t);
sessions->auto_free = 1;
@ -188,11 +195,6 @@ cmndList(struct trans *t)
switch (status)
{
case E_SCP_LS_AUTHENTICATION_FAIL:
printf("Connection denied (authentication error)\n");
rv = 1;
break;
case E_SCP_LS_SESSION_INFO:
list_add_item(sessions, (tintptr)p);
break;

View File

@ -94,7 +94,7 @@ struct session_params
const char *directory;
const char *shell;
const char *connection_description;
const char *ip_addr;
const char *username;
char password[MAX_PASSWORD_LEN + 1];
@ -165,7 +165,9 @@ usage(void)
g_printf("xrdp session starter v" PACKAGE_VERSION "\n");
g_printf("\nusage:\n");
g_printf("sesrun [options] username\n\n");
g_printf("sesrun --help\n"
"\nor\n"
"sesrun [options] [username]\n\n");
g_printf("options:\n");
g_printf(" -g <geometry> Default:%dx%d\n",
DEFAULT_WIDTH, DEFAULT_HEIGHT);
@ -176,9 +178,11 @@ usage(void)
" -p <password> TESTING ONLY - DO NOT USE IN PRODUCTION\n"
" -F <file-descriptor> Read password from this file descriptor\n"
" -c <sesman_ini> Alternative sesman.ini file\n");
g_printf("Supported types are %s\n",
g_printf("\nSupported types are %s\n",
sesstype_list);
g_printf("Password is prompted if -p or -F are not specified\n");
g_printf("\nIf username is omitted, the current user is used.\n"
"If username is provided, password is needed.\n"
" Password is prompted for if -p or -F are not specified\n");
}
@ -286,7 +290,7 @@ parse_program_args(int argc, char *argv[], struct session_params *sp,
sp->directory = "";
sp->shell = "";
sp->connection_description = "";
sp->ip_addr = "";
sp->username = NULL;
sp->password[0] = '\0';
@ -367,33 +371,109 @@ parse_program_args(int argc, char *argv[], struct session_params *sp,
}
}
if (argc <= optind)
if (argc == optind)
{
LOG(LOG_LEVEL_ERROR, "No user name specified");
params_ok = 0;
// No username was specified
if (password_set)
{
LOG(LOG_LEVEL_WARNING, "No username - ignoring specified password");
sp->password[0] = '\0';
}
sp->username = NULL;
}
else if ((argc - optind) > 1)
{
LOG(LOG_LEVEL_ERROR, "Unexpected arguments after username");
params_ok = 0;
}
else
else if (params_ok)
{
// A username is specified
sp->username = argv[optind];
}
if (params_ok && !password_set)
{
const char *p = getpass("Password: ");
if (p != NULL)
if (!password_set)
{
g_strcpy(sp->password, p);
const char *p = getpass("Password: ");
if (p == NULL)
{
params_ok = 0;
}
else
{
g_snprintf(sp->password, sizeof(sp->password), "%s", p);
}
}
}
return params_ok;
}
/**************************************************************************//**
* Sends an SCP login request
*
* A sys login request (i.e. username / password) is used if a username
* is specified. Otherwise we use a uds login request for the current user.
*
* @param t SCP connection
* @param sp Data for request
*/
static int
send_login_request(struct trans *t, const struct session_params *sp)
{
int rv;
LOG(LOG_LEVEL_DEBUG, "ip_addr:\"%s\"", sp->ip_addr);
if (sp->username != NULL)
{
/* Only log the password in development builds */
LOG_DEVEL(LOG_LEVEL_DEBUG, "password:\"%s\"", sp->password);
rv = scp_send_sys_login_request(t, sp->username,
sp->password, sp->ip_addr);
}
else
{
rv = scp_send_uds_login_request(t);
}
return rv;
}
/**************************************************************************//**
* Receives an SCP login response
*
* @param t SCP transport to receive reply on
* @param[out] server_closed != 0 if server has gone away
* @return 0 for successful authentication
*/
static int
handle_login_response(struct trans *t, int *server_closed)
{
enum scp_login_status login_result;
int rv = wait_for_sesman_reply(t, E_SCP_LOGIN_RESPONSE);
if (rv != 0)
{
*server_closed = 1;
}
else
{
rv = scp_get_login_response(t, &login_result, server_closed);
if (rv == 0)
{
if (login_result != E_SCP_LOGIN_OK)
{
char msg[256];
scp_login_status_to_str(login_result, msg, sizeof(msg));
g_printf("Login failed; %s\n", msg);
rv = 1;
}
}
scp_msg_in_reset(t); // Done with this message
}
return rv;
}
/**************************************************************************//**
* Sends an SCP create session request
*
@ -405,18 +485,13 @@ send_create_session_request(struct trans *t, const struct session_params *sp)
{
LOG(LOG_LEVEL_DEBUG,
"width:%d height:%d bpp:%d code:%d\n"
"directory:\"%s\"\n"
"shell:\"%s\" connection_description:\"%s\"",
"directory:\"%s\" shell:\"%s\"",
sp->width, sp->height, sp->bpp, sp->session_type,
sp->directory,
sp->shell, sp->connection_description);
/* Only log the password in development builds */
LOG_DEVEL(LOG_LEVEL_DEBUG, "password:\"%s\"", sp->password);
sp->directory, sp->shell);
return scp_send_create_session_request(
t, sp->username, sp->password, sp->session_type,
sp->width, sp->height, sp->bpp, sp->shell, sp->directory,
sp->connection_description);
t, sp->session_type,
sp->width, sp->height, sp->bpp, sp->shell, sp->directory);
}
/**************************************************************************//**
@ -428,21 +503,24 @@ send_create_session_request(struct trans *t, const struct session_params *sp)
static int
handle_create_session_response(struct trans *t)
{
int auth_result;
enum scp_screate_status status;
int display;
struct guid guid;
int rv = wait_for_sesman_reply(t, E_SCP_CREATE_SESSION_RESPONSE);
if (rv == 0)
{
rv = scp_get_create_session_response(t, &auth_result,
rv = scp_get_create_session_response(t, &status,
&display, &guid);
if (rv == 0)
{
if (auth_result != 0)
if (status != E_SCP_SCREATE_OK)
{
g_printf("Connection denied (authentication error)\n");
char msg[256];
scp_screate_status_to_str(status, msg, sizeof(msg));
g_printf("Connection failed; %s\n", msg);
rv = 1;
}
else
{
@ -452,6 +530,7 @@ handle_create_session_response(struct trans *t)
guid_to_str(&guid, guid_str));
}
}
scp_msg_in_reset(t); // Done with this message
}
return rv;
@ -475,7 +554,12 @@ main(int argc, char **argv)
log_start_from_param(logging);
log_config_free(logging);
if (!parse_program_args(argc, argv, &sp, &sesman_ini))
if (argc == 2 && g_strcmp(argv[1], "--help") == 0)
{
usage();
rv = 0;
}
else if (!parse_program_args(argc, argv, &sp, &sesman_ini))
{
usage();
}
@ -484,20 +568,44 @@ main(int argc, char **argv)
LOG(LOG_LEVEL_ERROR, "error reading config file %s : %s",
sesman_ini, g_get_strerror());
}
else if (!(t = scp_connect(cfg->listen_port, NULL)))
else if (!(t = scp_connect(cfg->listen_port, "xrdp-sesrun", NULL)))
{
LOG(LOG_LEVEL_ERROR, "connect error - %s", g_get_strerror());
}
else
{
rv = send_create_session_request(t, &sp);
if (rv != 0)
int server_closed = 0;
while (!server_closed)
{
LOG(LOG_LEVEL_ERROR, "Error sending create session to sesman");
rv = send_login_request(t, &sp);
if (rv != 0)
{
LOG(LOG_LEVEL_ERROR, "Error sending login request to sesman");
break;
}
rv = handle_login_response(t, &server_closed);
if (rv == 0)
{
break; /* Successful authentication */
}
if (!server_closed)
{
const char *p = getpass("Password: ");
if (p == NULL)
{
break;
}
g_snprintf(sp.password, sizeof(sp.password), "%s", p);
}
}
else
if (rv == 0)
{
rv = handle_create_session_response(t);
if ((rv = send_create_session_request(t, &sp)) == 0)
{
rv = handle_create_session_response(t);
}
}
trans_delete(t);
}

View File

@ -63,53 +63,115 @@ struct auth_info
/* returns non-NULL for success */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode)
const char *client_ip, enum scp_login_status *errorcode)
{
const char *encr;
const char *epass;
const char *encr = NULL;
struct passwd *spw;
struct spwd *stp;
/* Need a non-NULL pointer to return to indicate success */
static struct auth_info success = {0};
spw = getpwnam(user);
/* Most likely codepath return from here is 'not authenticated' */
enum scp_login_status status = E_SCP_LOGIN_NOT_AUTHENTICATED;
if (spw == 0)
/* Find the encrypted password */
if ((spw = getpwnam(user)) != NULL)
{
return NULL;
}
if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
{
/* the system is using shadow */
stp = getspnam(user);
if (stp == 0)
if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
{
return NULL;
}
struct spwd *stp;
if (1 == auth_account_disabled(stp))
/* the system is using shadow */
if ((stp = getspnam(user)) == NULL)
{
LOG(LOG_LEVEL_ERROR, "Can't get shadow entry for account %s",
user);
status = E_SCP_LOGIN_GENERAL_ERROR;
}
else
{
if (1 == auth_account_disabled(stp))
{
LOG(LOG_LEVEL_INFO, "account %s is disabled", user);
status = E_SCP_LOGIN_NOT_AUTHORIZED;
}
else
{
encr = stp->sp_pwdp;
}
}
}
else
{
LOG(LOG_LEVEL_INFO, "account %s is disabled", user);
return NULL;
/* old system with only passwd */
encr = spw->pw_passwd;
}
}
encr = stp->sp_pwdp;
}
else
if (encr != NULL)
{
/* old system with only passwd */
encr = spw->pw_passwd;
const char *epass;
if ((epass = crypt(pass, encr)) != NULL &&
g_strcmp(encr, epass) == 0)
{
status = E_SCP_LOGIN_OK;
}
}
epass = crypt(pass, encr);
if (epass == 0)
if (errorcode != NULL)
{
return NULL;
*errorcode = status;
}
return (strcmp(encr, epass) == 0) ? &success : NULL;
return (status == E_SCP_LOGIN_OK) ? &success : NULL;
}
/******************************************************************************/
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode)
{
struct passwd *spw;
/* Need a non-NULL pointer to return to indicate success */
static struct auth_info success = {0};
enum scp_login_status status = E_SCP_LOGIN_OK;
/* Try to check for a disabled account */
if ((spw = getpwnam(user)) != NULL)
{
if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
{
struct spwd *stp;
/* the system is using shadow */
if ((stp = getspnam(user)) == NULL)
{
LOG(LOG_LEVEL_ERROR, "Can't get shadow entry for account %s",
user);
status = E_SCP_LOGIN_GENERAL_ERROR;
}
else
{
if (1 == auth_account_disabled(stp))
{
LOG(LOG_LEVEL_INFO, "account %s is disabled", user);
status = E_SCP_LOGIN_NOT_AUTHORIZED;
}
}
}
}
if (errorcode != NULL)
{
*errorcode = status;
}
return (status == E_SCP_LOGIN_OK) ? &success : NULL;
}
/******************************************************************************/
/* returns error */
int

View File

@ -37,13 +37,26 @@
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <limits.h>
#include <sys/param.h>
#if defined(OpenBSD)
#include <login_cap.h>
#include <bsd_auth.h>
#ifndef SECS_PER_DAY
#define SECS_PER_DAY (24L*3600L)
#else
/*
* If OpenBSD isn't defined, add static definitions of OpenBSD-specific
* functions. This won't work, but will let the compiler on other
* systems check that all is correctly defined */
static int
auth_userokay(char *name, char *style, char *type, char *password)
{
fprintf(stderr, "auth_userokay() not implmented on this platform!\n");
abort();
return 0;
}
#endif
/*
* Need a complete type for struct auth_info, even though we're
* not really using it if this module (BSD authentication) is selected */
@ -55,18 +68,53 @@ struct auth_info
/******************************************************************************/
/* returns non-NULL for success */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode)
auth_userpass(const char *const_user, const char *const_pass,
const char *client_ip, enum scp_login_status *errorcode)
{
/* Need a non-NULL pointer to return to indicate success */
static struct auth_info success = {0};
struct auth_info *ret = NULL;
enum scp_login_status status;
if (auth_userokay(user, NULL, "auth-xrdp", pass))
// auth_userokay is not const-correct. See usr.sbin/smtpd/smtpd.c in
// the OpenBSD source tree for this workaround
char user[LOGIN_NAME_MAX];
char pass[LINE_MAX];
char type[] = "auth-xrdp";
snprintf(user, sizeof(user), "%s", const_user);
snprintf(pass, sizeof(pass), "%s", const_pass);
if (auth_userokay(user, NULL, type, pass))
{
ret = &success;
status = E_SCP_LOGIN_OK;
}
return ret;
else
{
status = E_SCP_LOGIN_NOT_AUTHENTICATED;
}
if (errorcode != NULL)
{
*errorcode = status;
}
return (status == E_SCP_LOGIN_OK) ? &success : NULL;
}
/******************************************************************************/
/* returns non-NULL for success */
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode)
{
/* Need a non-NULL pointer to return to indicate success */
static struct auth_info success = {0};
if (errorcode != NULL)
{
*errorcode = E_SCP_LOGIN_OK;
}
return &success;
}
/******************************************************************************/

View File

@ -127,12 +127,12 @@ k5_begin(const char *username)
/******************************************************************************/
/* returns boolean */
static int
static enum scp_login_status
k5_kinit(struct auth_info *auth_info, const char *password)
{
enum scp_login_status status = E_SCP_LOGIN_GENERAL_ERROR;
krb5_creds my_creds;
krb5_error_code code = 0;
int rv = 0;
code = krb5_get_init_creds_password(auth_info->ctx,
&my_creds, auth_info->me,
@ -144,6 +144,7 @@ k5_kinit(struct auth_info *auth_info, const char *password)
{
log_kerberos_failure(auth_info->ctx, code,
"krb5_get_init_creds_password");
status = E_SCP_LOGIN_NOT_AUTHENTICATED;
}
else
{
@ -162,7 +163,7 @@ k5_kinit(struct auth_info *auth_info, const char *password)
}
else
{
rv = 1;
status = E_SCP_LOGIN_OK;
}
/* Prevent double-free of the client principal */
@ -174,20 +175,22 @@ k5_kinit(struct auth_info *auth_info, const char *password)
krb5_free_cred_contents(auth_info->ctx, &my_creds);
}
return rv;
return status;
}
/******************************************************************************/
/* returns non-NULL for success */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode)
const char *client_ip, enum scp_login_status *errorcode)
{
enum scp_login_status status = E_SCP_LOGIN_GENERAL_ERROR;
struct auth_info *auth_info = k5_begin(user);
if (auth_info)
{
if (!k5_kinit(auth_info, pass))
status = k5_kinit(auth_info, pass);
if (status != E_SCP_LOGIN_OK)
{
auth_end(auth_info);
auth_info = NULL;
@ -196,7 +199,23 @@ auth_userpass(const char *user, const char *pass,
if (errorcode != NULL)
{
*errorcode = (auth_info == NULL);
*errorcode = status;
}
return auth_info;
}
/******************************************************************************/
/* returns non-NULL for success */
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode)
{
struct auth_info *auth_info = k5_begin(user);
if (errorcode != NULL)
{
*errorcode =
(auth_info != NULL) ? E_SCP_LOGIN_OK : E_SCP_LOGIN_GENERAL_ERROR;
}
return auth_info;

View File

@ -37,10 +37,9 @@
#include <stdio.h>
#include <security/pam_appl.h>
/* Allows the conversation function to find the username and password */
struct t_user_pass
/* Allows the conversation function to find required items */
struct conv_func_data
{
const char *user;
const char *pass;
};
@ -100,7 +99,7 @@ msg_style_to_str(int msg_style, char *buff, unsigned int bufflen)
* @param[in] num_msg Count of messages in the msg array
* @param[in] msg Messages from the PAM stack to the application
* @param[out] resp Message replies from the application to the PAM stack
* @param[in] appdata_ptr Used to pass in a struct t_user_pass pointer
* @param[in] appdata_ptr Used to pass in a struct conv_func_data pointer
*
* @result PAM_SUCCESS if the messages were all processed successfully.
*
@ -120,7 +119,7 @@ verify_pam_conv(int num_msg, const struct pam_message **msg,
{
int i;
struct pam_response *reply = NULL;
struct t_user_pass *user_pass;
struct conv_func_data *conv_func_data;
char sb[64];
int rv = PAM_SUCCESS;
@ -144,10 +143,10 @@ verify_pam_conv(int num_msg, const struct pam_message **msg,
switch (msg[i]->msg_style)
{
case PAM_PROMPT_ECHO_OFF: /* password */
user_pass = (struct t_user_pass *) appdata_ptr;
conv_func_data = (struct conv_func_data *) appdata_ptr;
/* Check this function isn't being called
* later than we expected */
if (user_pass == NULL)
if (conv_func_data == NULL || conv_func_data->pass == NULL)
{
LOG(LOG_LEVEL_ERROR,
"verify_pam_conv: Password unavailable");
@ -155,7 +154,7 @@ verify_pam_conv(int num_msg, const struct pam_message **msg,
}
else
{
reply[i].resp = g_strdup(user_pass->pass);
reply[i].resp = g_strdup(conv_func_data->pass);
}
break;
@ -216,73 +215,79 @@ get_service_name(char *service_name)
}
/******************************************************************************/
/* returns non-NULL for success
* Detailed error code is in the errorcode variable */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode)
/** Performs PAM operations common to login methods
*
* @param auth_info Module auth_info structure
* @param user User name
* @param pass Password, if needed for authentication.
* @param client_ip Client IP if known, or NULL
* @param authentication_required True if user must be authenticated
*
* For a UDS connection, the user can be assumed to be authenticated,
* so in this instance authentication_required can be false.
*
* @return Code describing the success of the operation
*/
static enum scp_login_status
common_pam_login(struct auth_info *auth_info,
const char *user,
const char *pass,
const char *client_ip,
int authentication_required)
{
int error;
struct auth_info *auth_info;
int perror;
char service_name[256];
struct t_user_pass user_pass = {user, pass};
struct pam_conv pamc = {verify_pam_conv, (void *) &user_pass};
struct conv_func_data conv_func_data;
struct pam_conv pamc;
auth_info = g_new0(struct auth_info, 1);
if (auth_info == NULL)
{
LOG(LOG_LEVEL_ERROR, "auth_userpass: No memory");
error = PAM_BUF_ERR;
return NULL;
}
/*
* Set up the data required by the conversation function, and the
* structure which allows us to pass this to pam_start()
*/
conv_func_data.pass = (authentication_required) ? pass : NULL;
pamc.conv = verify_pam_conv;
pamc.appdata_ptr = (void *) &conv_func_data;
get_service_name(service_name);
error = pam_start(service_name, user, &pamc, &(auth_info->ph));
perror = pam_start(service_name, user, &pamc, &(auth_info->ph));
if (error != PAM_SUCCESS)
if (perror != PAM_SUCCESS)
{
if (errorcode != NULL)
{
*errorcode = error;
}
LOG(LOG_LEVEL_ERROR, "pam_start failed: %s",
pam_strerror(auth_info->ph, error));
pam_end(auth_info->ph, error);
g_free(auth_info);
return NULL;
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_GENERAL_ERROR;
}
if (client_ip != NULL && client_ip[0] != '\0')
{
error = pam_set_item(auth_info->ph, PAM_RHOST, client_ip);
if (error != PAM_SUCCESS)
perror = pam_set_item(auth_info->ph, PAM_RHOST, client_ip);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item(PAM_RHOST) failed: %s",
pam_strerror(auth_info->ph, error));
pam_strerror(auth_info->ph, perror));
}
}
error = pam_set_item(auth_info->ph, PAM_TTY, service_name);
if (error != PAM_SUCCESS)
perror = pam_set_item(auth_info->ph, PAM_TTY, service_name);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item(PAM_TTY) failed: %s",
pam_strerror(auth_info->ph, error));
pam_strerror(auth_info->ph, perror));
}
error = pam_authenticate(auth_info->ph, 0);
if (error != PAM_SUCCESS)
if (authentication_required)
{
if (errorcode != NULL)
perror = pam_authenticate(auth_info->ph, 0);
if (perror != PAM_SUCCESS)
{
*errorcode = error;
LOG(LOG_LEVEL_ERROR, "pam_authenticate failed: %s",
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_NOT_AUTHENTICATED;
}
LOG(LOG_LEVEL_ERROR, "pam_authenticate failed: %s",
pam_strerror(auth_info->ph, error));
pam_end(auth_info->ph, error);
g_free(auth_info);
return NULL;
}
/* From man page:
The pam_acct_mgmt function is used to determine if the users account is
@ -290,35 +295,99 @@ auth_userpass(const char *user, const char *pass,
verifies access restrictions. It is typically called after the user has
been authenticated.
*/
error = pam_acct_mgmt(auth_info->ph, 0);
perror = pam_acct_mgmt(auth_info->ph, 0);
if (error != PAM_SUCCESS)
if (perror != PAM_SUCCESS)
{
if (errorcode != NULL)
{
*errorcode = error;
}
LOG(LOG_LEVEL_ERROR, "pam_acct_mgmt failed: %s",
pam_strerror(auth_info->ph, error));
pam_end(auth_info->ph, error);
g_free(auth_info);
return NULL;
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_NOT_AUTHORIZED;
}
/* Set the appdata_ptr passed to the conversation function to
* NULL, as the existing value is going out of scope */
pamc.appdata_ptr = NULL;
error = pam_set_item(auth_info->ph, PAM_CONV, &pamc);
if (error != PAM_SUCCESS)
perror = pam_set_item(auth_info->ph, PAM_CONV, &pamc);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item(PAM_CONV) failed: %s",
pam_strerror(auth_info->ph, error));
pam_strerror(auth_info->ph, perror));
}
return E_SCP_LOGIN_OK;
}
/******************************************************************************/
/* returns non-NULL for success
* Detailed error code is in the errorcode variable */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, enum scp_login_status *errorcode)
{
struct auth_info *auth_info;
enum scp_login_status status;
auth_info = g_new0(struct auth_info, 1);
if (auth_info == NULL)
{
status = E_SCP_LOGIN_NO_MEMORY;
}
else
{
status = common_pam_login(auth_info, user, pass, client_ip, 1);
if (status != E_SCP_LOGIN_OK)
{
g_free(auth_info);
auth_info = NULL;
}
}
if (errorcode != NULL)
{
*errorcode = status;
}
return auth_info;
}
/******************************************************************************/
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode)
{
struct auth_info *auth_info;
enum scp_login_status status;
auth_info = g_new0(struct auth_info, 1);
if (auth_info == NULL)
{
status = E_SCP_LOGIN_NO_MEMORY;
}
else
{
status = common_pam_login(auth_info, user, NULL, NULL, 0);
if (status != E_SCP_LOGIN_OK)
{
g_free(auth_info);
auth_info = NULL;
}
}
if (errorcode != NULL)
{
*errorcode = status;
}
return auth_info;
}
/******************************************************************************/
/* returns error */
int
auth_start_session(struct auth_info *auth_info, int display_num)
@ -364,17 +433,31 @@ auth_start_session(struct auth_info *auth_info, int display_num)
int
auth_stop_session(struct auth_info *auth_info)
{
int rv = 0;
int error;
error = pam_close_session(auth_info->ph, 0);
if (error != PAM_SUCCESS)
if (auth_info->session_opened)
{
LOG(LOG_LEVEL_ERROR, "pam_close_session failed: %s",
pam_strerror(auth_info->ph, error));
return 1;
error = pam_close_session(auth_info->ph, 0);
if (error != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_close_session failed: %s",
pam_strerror(auth_info->ph, error));
rv = 1;
}
else
{
auth_info->session_opened = 0;
}
}
auth_info->session_opened = 0;
return 0;
if (auth_info->did_setcred)
{
pam_setcred(auth_info->ph, PAM_DELETE_CRED);
auth_info->did_setcred = 0;
}
return rv;
}
/******************************************************************************/
@ -387,15 +470,7 @@ auth_end(struct auth_info *auth_info)
{
if (auth_info->ph != 0)
{
if (auth_info->session_opened)
{
pam_close_session(auth_info->ph, 0);
}
if (auth_info->did_setcred)
{
pam_setcred(auth_info->ph, PAM_DELETE_CRED);
}
auth_stop_session(auth_info);
pam_end(auth_info->ph, PAM_SUCCESS);
auth_info->ph = 0;

View File

@ -18,8 +18,8 @@
/**
*
* @file verify_user_pam_userpass.c
* @brief Authenticate user using pam_userpass module
* @file verify_user_pam.c
* @brief Authenticate user using pam
* @author Jay Sorg
*
*/
@ -29,81 +29,220 @@
#endif
#include "arch.h"
#include "auth.h"
#include "os_calls.h"
#include "log.h"
#include "string_calls.h"
#include "auth.h"
#include <security/pam_userpass.h>
#include <stdio.h>
#include <security/pam_appl.h>
#define SERVICE "xrdp"
/*
* Need a complete type for struct auth_info, even though we're
* not really using it if this module (PAM userpass) is selected */
struct auth_info
{
char dummy;
pam_userpass_t userpass;
int session_opened;
int did_setcred;
struct pam_conv pamc;
pam_handle_t *ph;
};
/******************************************************************************/
/* returns non-NULL for success */
/** Performs PAM operations common to login methods
*
* @param auth_info Module auth_info structure
* @param client_ip Client IP if known, or NULL
* @param need_pam_authenticate True if user must be authenticated as
* well as authorized
* @return Code describing the success of the operation
*
* The username is assumed to be supplied by the caller in
* auth_info->userpass.user
*/
static enum scp_login_status
common_pam_login(struct auth_info *auth_info,
const char *client_ip,
int need_pam_authenticate)
{
int perror;
char service_name[256];
perror = pam_start(SERVICE, auth_info->userpass.user,
&(auth_info->pamc), &(auth_info->ph));
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_start failed: %s",
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_GENERAL_ERROR;
}
if (client_ip != NULL && client_ip[0] != '\0')
{
perror = pam_set_item(auth_info->ph, PAM_RHOST, client_ip);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item(PAM_RHOST) failed: %s",
pam_strerror(auth_info->ph, perror));
}
}
perror = pam_set_item(auth_info->ph, PAM_TTY, service_name);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item(PAM_TTY) failed: %s",
pam_strerror(auth_info->ph, perror));
}
if (need_pam_authenticate)
{
perror = pam_authenticate(auth_info->ph, 0);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_authenticate failed: %s",
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_NOT_AUTHENTICATED;
}
}
/* From man page:
The pam_acct_mgmt function is used to determine if the users account is
valid. It checks for authentication token and account expiration and
verifies access restrictions. It is typically called after the user has
been authenticated.
*/
perror = pam_acct_mgmt(auth_info->ph, 0);
if (perror != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_acct_mgmt failed: %s",
pam_strerror(auth_info->ph, perror));
pam_end(auth_info->ph, perror);
return E_SCP_LOGIN_NOT_AUTHORIZED;
}
return E_SCP_LOGIN_OK;
}
/******************************************************************************/
/* returns non-NULL for success
* Detailed error code is in the errorcode variable */
struct auth_info *
auth_userpass(const char *user, const char *pass,
const char *client_ip, int *errorcode)
const char *client_ip, enum scp_login_status *errorcode)
{
pam_handle_t *pamh;
pam_userpass_t userpass;
struct pam_conv conv = {pam_userpass_conv, &userpass};
const void *template1;
int status;
/* Need a non-NULL pointer to return to indicate success */
static struct auth_info success = {0};
struct auth_info *auth_info;
enum scp_login_status status;
userpass.user = user;
userpass.pass = pass;
if (pam_start(SERVICE, user, &conv, &pamh) != PAM_SUCCESS)
auth_info = g_new0(struct auth_info, 1);
if (auth_info == NULL)
{
return NULL;
status = E_SCP_LOGIN_NO_MEMORY;
}
else
{
auth_info->userpass.user = user;
auth_info->userpass.pass = pass;
auth_info->pamc.conv = &pam_userpass_conv;
auth_info->pamc.appdata_ptr = &(auth_info->userpass);
status = common_pam_login(auth_info, client_ip, 1);
if (status != E_SCP_LOGIN_OK)
{
g_free(auth_info);
auth_info = NULL;
}
}
status = pam_authenticate(pamh, 0);
if (status != PAM_SUCCESS)
if (errorcode != NULL)
{
pam_end(pamh, status);
return NULL;
*errorcode = status;
}
status = pam_acct_mgmt(pamh, 0);
if (status != PAM_SUCCESS)
{
pam_end(pamh, status);
return NULL;
}
status = pam_get_item(pamh, PAM_USER, &template1);
if (status != PAM_SUCCESS)
{
pam_end(pamh, status);
return NULL;
}
if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS)
{
return NULL;
}
return &success;
return auth_info;
}
/******************************************************************************/
struct auth_info *
auth_uds(const char *user, enum scp_login_status *errorcode)
{
struct auth_info *auth_info;
enum scp_login_status status;
auth_info = g_new0(struct auth_info, 1);
if (auth_info == NULL)
{
status = E_SCP_LOGIN_NO_MEMORY;
}
else
{
auth_info->userpass.user = user;
status = common_pam_login(auth_info, NULL, 0);
if (status != E_SCP_LOGIN_OK)
{
g_free(auth_info);
auth_info = NULL;
}
}
if (errorcode != NULL)
{
*errorcode = status;
}
return auth_info;
}
/******************************************************************************/
/* returns error */
int
auth_start_session(struct auth_info *auth_info, int display_num)
{
int error;
char display[256];
g_sprintf(display, ":%d", display_num);
error = pam_set_item(auth_info->ph, PAM_TTY, display);
if (error != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_set_item failed: %s",
pam_strerror(auth_info->ph, error));
return 1;
}
error = pam_setcred(auth_info->ph, PAM_ESTABLISH_CRED);
if (error != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_setcred failed: %s",
pam_strerror(auth_info->ph, error));
return 1;
}
auth_info->did_setcred = 1;
error = pam_open_session(auth_info->ph, 0);
if (error != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_open_session failed: %s",
pam_strerror(auth_info->ph, error));
return 1;
}
auth_info->session_opened = 1;
return 0;
}
@ -112,19 +251,90 @@ auth_start_session(struct auth_info *auth_info, int display_num)
int
auth_stop_session(struct auth_info *auth_info)
{
return 0;
int rv = 0;
int error;
if (auth_info->session_opened)
{
error = pam_close_session(auth_info->ph, 0);
if (error != PAM_SUCCESS)
{
LOG(LOG_LEVEL_ERROR, "pam_close_session failed: %s",
pam_strerror(auth_info->ph, error));
rv = 1;
}
else
{
auth_info->session_opened = 0;
}
}
if (auth_info->did_setcred)
{
pam_setcred(auth_info->ph, PAM_DELETE_CRED);
auth_info->did_setcred = 0;
}
return rv;
}
/******************************************************************************/
/* returns error */
/* cleanup */
int
auth_end(struct auth_info *auth_info)
{
if (auth_info != NULL)
{
if (auth_info->ph != 0)
{
auth_stop_session(auth_info);
pam_end(auth_info->ph, PAM_SUCCESS);
auth_info->ph = 0;
}
}
g_free(auth_info);
return 0;
}
/******************************************************************************/
/* returns error */
/* set any pam env vars */
int
auth_set_env(struct auth_info *auth_info)
{
char **pam_envlist;
char **pam_env;
char item[256];
char value[256];
int eq_pos;
if (auth_info != NULL)
{
/* export PAM environment */
pam_envlist = pam_getenvlist(auth_info->ph);
if (pam_envlist != NULL)
{
for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env)
{
eq_pos = g_pos(*pam_env, "=");
if (eq_pos >= 0 && eq_pos < 250)
{
g_strncpy(item, *pam_env, eq_pos);
g_strncpy(value, (*pam_env) + eq_pos + 1, 255);
g_setenv(item, value, 1);
}
g_free(*pam_env);
}
g_free(pam_envlist);
}
}
return 0;
}

View File

@ -30,15 +30,6 @@
#include "scp.h"
#ifdef USE_PAM
#if defined(HAVE__PAM_TYPES_H)
#define LINUXPAM 1
#include <security/_pam_types.h>
#elif defined(HAVE_PAM_CONSTANTS_H)
#define OPENPAM 1
#include <security/pam_constants.h>
#endif
#endif /* USE_PAM */
#include <ctype.h>
#include "xrdp_encoder.h"
@ -47,10 +38,6 @@
/* Forward declarations */
static const char *
getPAMError(const int pamError, char *text, int text_bytes);
static const char *
getPAMAdditionalErrorInfo(const int pamError, struct xrdp_mm *self);
static int
xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *port);
static void
@ -233,85 +220,63 @@ xrdp_mm_get_value_int(struct xrdp_mm *self, const char *aname, int def)
/*****************************************************************************/
/* Send gateway login information to sesman */
static int
xrdp_mm_send_gateway_login(struct xrdp_mm *self, const char *username,
const char *password)
xrdp_mm_send_sys_login_request(struct xrdp_mm *self, const char *username,
const char *password)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"sending login info to session manager, please wait...");
return scp_send_gateway_request(
return scp_send_sys_login_request(
self->sesman_trans, username, password,
self->wm->client_info->client_ip);
}
/*****************************************************************************/
/* Send login information to sesman */
/* Send a create session request to sesman */
static int
xrdp_mm_send_login(struct xrdp_mm *self)
xrdp_mm_create_session(struct xrdp_mm *self)
{
int rv = 0;
int xserverbpp;
const char *username;
const char *password;
enum scp_session_type type;
username = xrdp_mm_get_value(self, "username");
password = xrdp_mm_get_value(self, "password");
if (username == NULL || username[0] == '\0')
/* Map the session code to an SCP session type */
switch (self->code)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR, "No username is available");
rv = 1;
case XVNC_SESSION_CODE:
type = SCP_SESSION_TYPE_XVNC;
break;
case XRDP_SESSION_CODE:
type = SCP_SESSION_TYPE_XRDP;
break;
case XORG_SESSION_CODE:
type = SCP_SESSION_TYPE_XORG;
break;
default:
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Unrecognised session code %d", self->code);
rv = 1;
}
else if (password == NULL)
if (rv == 0)
{
/* Can't find a password definition at all - even an empty one */
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"No password field is available");
rv = 1;
}
else
{
enum scp_session_type type;
/* Map the session code to an SCP session type */
switch (self->code)
{
case XVNC_SESSION_CODE:
type = SCP_SESSION_TYPE_XVNC;
break;
xserverbpp = xrdp_mm_get_value_int(self, "xserverbpp",
self->wm->screen->bpp);
case XRDP_SESSION_CODE:
type = SCP_SESSION_TYPE_XRDP;
break;
case XORG_SESSION_CODE:
type = SCP_SESSION_TYPE_XORG;
break;
default:
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Unrecognised session code %d", self->code);
rv = 1;
}
if (rv == 0)
{
xserverbpp = xrdp_mm_get_value_int(self, "xserverbpp",
self->wm->screen->bpp);
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"sending login info to session manager. "
"Please wait...");
rv = scp_send_create_session_request(
self->sesman_trans,
username,
password,
type,
self->wm->screen->width,
self->wm->screen->height,
xserverbpp,
self->wm->client_info->program,
self->wm->client_info->directory,
self->wm->client_info->client_ip);
}
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"sending create session request to session"
" manager. Please wait...");
rv = scp_send_create_session_request(
self->sesman_trans,
type,
self->wm->screen->width,
self->wm->screen->height,
xserverbpp,
self->wm->client_info->program,
self->wm->client_info->directory);
}
return rv;
@ -1920,21 +1885,6 @@ xrdp_mm_chan_data_in(struct trans *trans)
return error;
}
/*****************************************************************************/
static void cleanup_sesman_connection(struct xrdp_mm *self)
{
/* Don't delete any transports here - we may be in
* an auth callback from one of them */
self->delete_sesman_trans = 1;
if (self->wm->login_state != WMLS_CLEANUP)
{
xrdp_wm_set_login_state(self->wm, WMLS_INACTIVE);
xrdp_mm_module_cleanup(self);
}
}
/*****************************************************************************/
/* does the section in xrdp.ini has any channel.*=true | false */
static int
@ -2088,38 +2038,49 @@ xrdp_mm_process_channel_data(struct xrdp_mm *self, tbus param1, tbus param2,
/*****************************************************************************/
static int
xrdp_mm_process_gateway_response(struct xrdp_mm *self)
xrdp_mm_process_login_response(struct xrdp_mm *self)
{
int auth_result;
enum scp_login_status login_result;
int rv;
int server_closed;
rv = scp_get_gateway_response(self->sesman_trans, &auth_result);
rv = scp_get_login_response(self->sesman_trans, &login_result, &server_closed);
if (rv == 0)
{
const char *additionalError;
char pam_error[128];
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Reply from access control: %s",
getPAMError(auth_result,
pam_error, sizeof(pam_error)));
if (auth_result != 0)
if (login_result != E_SCP_LOGIN_OK)
{
additionalError = getPAMAdditionalErrorInfo(auth_result, self);
if (additionalError && additionalError[0])
char buff[128];
scp_login_status_to_str(login_result, buff, sizeof(buff));
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s", buff);
if (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED &&
self->wm->pamerrortxt[0] != '\0')
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s",
additionalError);
self->wm->pamerrortxt);
}
/* TODO : Check this is displayed */
cleanup_sesman_connection(self);
if (server_closed)
{
if (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s",
"Login retry limit reached");
}
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO, "%s",
"Close the log window to exit.");
self->wm->fatal_error_in_log_window = 1;
/* Transport can be deleted now */
self->delete_sesman_trans = 1;
}
/* If the server hasn't closed, inform the window manager
* of the fail, but leave the sesman connection open for
* further login attempts */
xrdp_wm_mod_connect_done(self->wm, 1);
}
else
{
/* Authentication successful */
/* login successful */
xrdp_mm_connect_sm(self);
}
}
@ -2131,18 +2092,17 @@ xrdp_mm_process_gateway_response(struct xrdp_mm *self)
static int
xrdp_mm_process_create_session_response(struct xrdp_mm *self)
{
int auth_result;
enum scp_screate_status status;
int display;
struct guid guid;
int rv;
rv = scp_get_create_session_response(self->sesman_trans, &auth_result,
rv = scp_get_create_session_response(self->sesman_trans, &status,
&display, &guid);
if (rv == 0)
{
const char *username;
char displayinfo[64];
/* Sort out some logging information */
if ((username = xrdp_mm_get_value(self, "username")) == NULL)
@ -2150,38 +2110,27 @@ xrdp_mm_process_create_session_response(struct xrdp_mm *self)
username = "???";
}
if (display == 0)
if (status == E_SCP_SCREATE_OK)
{
/* A returned display of zero doesn't mean anything useful, and
* can confuse the user. It's most likely authentication has
* failed and no display was allocated */
displayinfo[0] = '\0';
}
else
{
g_snprintf(displayinfo, sizeof(displayinfo),
" on display %d", display);
}
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"session is available on display %d for user %s",
display, username);
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"login %s for user %s%s",
((auth_result == 0) ? "successful" : "failed"),
username, displayinfo);
if (auth_result != 0)
{
/* Authentication failure */
cleanup_sesman_connection(self);
xrdp_wm_mod_connect_done(self->wm, 1);
}
else
{
/* Authentication successful - carry on with the connect
* state machine */
/* Carry on with the connect state machine */
self->display = display;
self->guid = guid;
xrdp_mm_connect_sm(self);
}
else
{
char buff[128];
scp_screate_status_to_str(status, buff, sizeof(buff));
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Can't create session for user %s - %s",
username, buff);
/* Leave the sesman connection open for further login attenpts */
xrdp_wm_mod_connect_done(self->wm, 1);
}
}
return rv;
@ -2203,8 +2152,8 @@ xrdp_mm_scp_data_in(struct trans *trans)
switch ((msgno = scp_msg_in_start(trans)))
{
case E_SCP_GATEWAY_RESPONSE:
rv = xrdp_mm_process_gateway_response(self);
case E_SCP_LOGIN_RESPONSE:
rv = xrdp_mm_process_login_response(self);
break;
case E_SCP_CREATE_SESSION_RESPONSE:
@ -2229,7 +2178,10 @@ xrdp_mm_scp_data_in(struct trans *trans)
/*****************************************************************************/
/* 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.*/
* connect again we must make sure that no previous information is stored.
*
* This routine does not clear a sesman_trans if it is allocated, as this
* would break the password retry limit mechanism */
static void
cleanup_states(struct xrdp_mm *self)
{
@ -2238,8 +2190,8 @@ cleanup_states(struct xrdp_mm *self)
self->connect_state = MMCS_CONNECT_TO_SESMAN;
self->use_sesman = 0; /* true if this is a sesman session */
self->use_chansrv = 0; /* true if chansrvport is set in xrdp.ini or using sesman */
self->use_pam_auth = 0; /* true if we're to use the PAM authentication facility */
self->sesman_trans = NULL; /* connection to sesman */
self->use_gw_login = 0; /* true if we're to use the gateway login facility */
//self->sesman_trans = NULL; /* connection to sesman */
self->chan_trans = NULL; /* connection to chansrv */
self->delete_sesman_trans = 0;
self->display = 0; /* 10 for :10.0, 11 for :11.0, etc */
@ -2248,235 +2200,6 @@ cleanup_states(struct xrdp_mm *self)
}
}
static const char *
getPAMError(const int pamError, char *text, int text_bytes)
{
switch (pamError)
{
#if defined(LINUXPAM)
case PAM_SUCCESS:
return "Success";
case PAM_OPEN_ERR:
return "dlopen() failure";
case PAM_SYMBOL_ERR:
return "Symbol not found";
case PAM_SERVICE_ERR:
return "Error in service module";
case PAM_SYSTEM_ERR:
return "System error";
case PAM_BUF_ERR:
return "Memory buffer error";
case PAM_PERM_DENIED:
return "Permission denied";
case PAM_AUTH_ERR:
return "Authentication failure";
case PAM_CRED_INSUFFICIENT:
return "Insufficient credentials to access authentication data";
case PAM_AUTHINFO_UNAVAIL:
return "Authentication service cannot retrieve authentication info.";
case PAM_USER_UNKNOWN:
return "User not known to the underlying authentication module";
case PAM_MAXTRIES:
return "Have exhausted maximum number of retries for service.";
case PAM_NEW_AUTHTOK_REQD:
return "Authentication token is no longer valid; new one required.";
case PAM_ACCT_EXPIRED:
return "User account has expired";
case PAM_CRED_UNAVAIL:
return "Authentication service cannot retrieve user credentials";
case PAM_CRED_EXPIRED:
return "User credentials expired";
case PAM_CRED_ERR:
return "Failure setting user credentials";
case PAM_NO_MODULE_DATA:
return "No module specific data is present";
case PAM_BAD_ITEM:
return "Bad item passed to pam_*_item()";
case PAM_CONV_ERR:
return "Conversation error";
case PAM_AUTHTOK_ERR:
return "Authentication token manipulation error";
case PAM_AUTHTOK_LOCK_BUSY:
return "Authentication token lock busy";
case PAM_AUTHTOK_DISABLE_AGING:
return "Authentication token aging disabled";
case PAM_TRY_AGAIN:
return "Failed preliminary check by password service";
case PAM_IGNORE:
return "Please ignore underlying account module";
case PAM_MODULE_UNKNOWN:
return "Module is unknown";
case PAM_AUTHTOK_EXPIRED:
return "Authentication token expired";
case PAM_CONV_AGAIN:
return "Conversation is waiting for event";
case PAM_INCOMPLETE:
return "Application needs to call libpam again";
case 32 + 1:
return "Error connecting to PAM";
case 32 + 3:
return "Username okey but group problem";
#elif defined(OPENPAM)
case PAM_SUCCESS: /* 0 */
return "Success";
case PAM_OPEN_ERR:
return "dlopen() failure";
case PAM_SYMBOL_ERR:
return "Symbol not found";
case PAM_SERVICE_ERR:
return "Error in service module";
case PAM_SYSTEM_ERR:
return "System error";
case PAM_BUF_ERR:
return "Memory buffer error";
case PAM_CONV_ERR:
return "Conversation error";
case PAM_PERM_DENIED:
return "Permission denied";
case PAM_MAXTRIES:
return "Have exhausted maximum number of retries for service.";
case PAM_AUTH_ERR:
return "Authentication failure";
case PAM_NEW_AUTHTOK_REQD: /* 10 */
return "Authentication token is no longer valid; new one required.";
case PAM_CRED_INSUFFICIENT:
return "Insufficient credentials to access authentication data";
case PAM_AUTHINFO_UNAVAIL:
return "Authentication service cannot retrieve authentication info.";
case PAM_USER_UNKNOWN:
return "User not known to the underlying authentication module";
case PAM_CRED_UNAVAIL:
return "Authentication service cannot retrieve user credentials";
case PAM_CRED_EXPIRED:
return "User credentials expired";
case PAM_CRED_ERR:
return "Failure setting user credentials";
case PAM_ACCT_EXPIRED:
return "User account has expired";
case PAM_AUTHTOK_EXPIRED:
return "Authentication token expired";
case PAM_SESSION_ERR:
return "Session failure";
case PAM_AUTHTOK_ERR: /* 20 */
return "Authentication token manipulation error";
case PAM_AUTHTOK_RECOVERY_ERR:
return "Failed to recover old authentication token";
case PAM_AUTHTOK_LOCK_BUSY:
return "Authentication token lock busy";
case PAM_AUTHTOK_DISABLE_AGING:
return "Authentication token aging disabled";
case PAM_NO_MODULE_DATA:
return "No module specific data is present";
case PAM_IGNORE:
return "Please ignore underlying account module";
case PAM_ABORT:
return "General failure";
case PAM_TRY_AGAIN:
return "Failed preliminary check by password service";
case PAM_MODULE_UNKNOWN:
return "Module is unknown";
case PAM_DOMAIN_UNKNOWN: /* 29 */
return "Unknown authentication domain";
#endif
default:
g_snprintf(text, text_bytes, "Not defined PAM error:%d", pamError);
return text;
}
}
static const char *
getPAMAdditionalErrorInfo(const int pamError, struct xrdp_mm *self)
{
switch (pamError)
{
#if defined(LINUXPAM)
case PAM_SUCCESS:
return NULL;
case PAM_OPEN_ERR:
case PAM_SYMBOL_ERR:
case PAM_SERVICE_ERR:
case PAM_SYSTEM_ERR:
case PAM_BUF_ERR:
case PAM_PERM_DENIED:
case PAM_AUTH_ERR:
case PAM_CRED_INSUFFICIENT:
case PAM_AUTHINFO_UNAVAIL:
case PAM_USER_UNKNOWN:
case PAM_CRED_UNAVAIL:
case PAM_CRED_ERR:
case PAM_NO_MODULE_DATA:
case PAM_BAD_ITEM:
case PAM_CONV_ERR:
case PAM_AUTHTOK_ERR:
case PAM_AUTHTOK_LOCK_BUSY:
case PAM_AUTHTOK_DISABLE_AGING:
case PAM_TRY_AGAIN:
case PAM_IGNORE:
case PAM_MODULE_UNKNOWN:
case PAM_CONV_AGAIN:
case PAM_INCOMPLETE:
case _PAM_RETURN_VALUES + 1:
case _PAM_RETURN_VALUES + 3:
return NULL;
case PAM_MAXTRIES:
case PAM_NEW_AUTHTOK_REQD:
case PAM_ACCT_EXPIRED:
case PAM_CRED_EXPIRED:
case PAM_AUTHTOK_EXPIRED:
if (self->wm->pamerrortxt[0])
{
return self->wm->pamerrortxt;
}
else
{
return "Authentication error - Verify that user/password is valid";
}
#elif defined(OPENPAM)
case PAM_SUCCESS: /* 0 */
return NULL;
case PAM_OPEN_ERR:
case PAM_SYMBOL_ERR:
case PAM_SERVICE_ERR:
case PAM_SYSTEM_ERR:
case PAM_BUF_ERR:
case PAM_CONV_ERR:
case PAM_PERM_DENIED:
case PAM_MAXTRIES:
case PAM_AUTH_ERR:
case PAM_NEW_AUTHTOK_REQD: /* 10 */
case PAM_CRED_INSUFFICIENT:
case PAM_AUTHINFO_UNAVAIL:
case PAM_USER_UNKNOWN:
case PAM_CRED_UNAVAIL:
case PAM_CRED_EXPIRED:
case PAM_CRED_ERR:
case PAM_ACCT_EXPIRED:
case PAM_AUTHTOK_EXPIRED:
case PAM_SESSION_ERR:
case PAM_AUTHTOK_ERR: /* 20 */
case PAM_AUTHTOK_RECOVERY_ERR:
case PAM_AUTHTOK_LOCK_BUSY:
case PAM_AUTHTOK_DISABLE_AGING:
case PAM_NO_MODULE_DATA:
case PAM_IGNORE:
case PAM_ABORT:
case PAM_TRY_AGAIN:
case PAM_MODULE_UNKNOWN:
case PAM_DOMAIN_UNKNOWN: /* 29 */
if (self->wm->pamerrortxt[0])
{
return self->wm->pamerrortxt;
}
else
{
return "Authentication error - Verify that user/password is valid";
}
#endif
default:
return "No expected error";
}
}
/*************************************************************************//**
* Parses a chansrvport string
*
@ -2539,7 +2262,7 @@ xrdp_mm_scp_connect(struct xrdp_mm *self)
xrdp_wm_log_msg(self->wm, LOG_LEVEL_DEBUG,
"connecting to sesman on %s", port_description);
t = scp_connect(port, g_is_term);
t = scp_connect(port, "xrdp", g_is_term);
if (t != NULL)
{
/* fully connected */
@ -2650,7 +2373,7 @@ void
xrdp_mm_connect(struct xrdp_mm *self)
{
const char *port = xrdp_mm_get_value(self, "port");
const char *gateway_username = xrdp_mm_get_value(self, "pamusername");
const char *gw_username = xrdp_mm_get_value(self, "pamusername");
/* make sure we start in correct state */
cleanup_states(self);
@ -2680,7 +2403,7 @@ xrdp_mm_connect(struct xrdp_mm *self)
}
}
if (gateway_username != NULL)
if (gw_username != NULL)
{
/* Connecting to a remote sesman is no longer supported */
if (xrdp_mm_get_value(self, "pamsessionmng") != NULL)
@ -2690,13 +2413,7 @@ xrdp_mm_connect(struct xrdp_mm *self)
"Parameter 'pamsessionmng' is obsolete."
" Please remove from config");
}
#ifdef USE_PAM
self->use_pam_auth = 1;
#else
xrdp_wm_log_msg(self->wm, LOG_LEVEL_WARNING,
"pamusername parameter ignored - "
"xrdp is compiled without PAM support");
#endif
self->use_gw_login = 1;
}
/* Will we need chansrv ? We use it unconditionally for a
@ -2731,7 +2448,8 @@ xrdp_mm_connect_sm(struct xrdp_mm *self)
{
case MMCS_CONNECT_TO_SESMAN:
{
if (self->use_sesman || self->use_pam_auth)
if (self->sesman_trans == NULL &&
(self->use_sesman || self->use_gw_login))
{
/* Synchronous call */
status = xrdp_mm_sesman_connect(self);
@ -2739,45 +2457,46 @@ xrdp_mm_connect_sm(struct xrdp_mm *self)
}
break;
case MMCS_PAM_AUTH:
case MMCS_GATEWAY_LOGIN:
{
if (self->use_pam_auth)
if (self->use_gw_login)
{
const char *gateway_username;
const char *gateway_password;
const char *gw_username;
const char *gw_password;
gateway_username = xrdp_mm_get_value(self, "pamusername");
gateway_password = xrdp_mm_get_value(self, "pampassword");
if (!g_strcmp(gateway_username, "same"))
gw_username = xrdp_mm_get_value(self, "pamusername");
gw_password = xrdp_mm_get_value(self, "pampassword");
if (!g_strcmp(gw_username, "same"))
{
gateway_username = xrdp_mm_get_value(self, "username");
gw_username = xrdp_mm_get_value(self, "username");
}
if (gateway_password == NULL ||
!g_strcmp(gateway_password, "same"))
if (gw_password == NULL ||
!g_strcmp(gw_password, "same"))
{
gateway_password = xrdp_mm_get_value(self, "password");
gw_password = xrdp_mm_get_value(self, "password");
}
if (gateway_username == NULL || gateway_password == NULL)
if (gw_username == NULL || gw_password == NULL)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"Can't determine username and/or "
"password for gateway authorization");
"password for gateway login");
status = 1;
}
else
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Performing access control for %s",
gateway_username);
gw_username);
status = xrdp_mm_send_gateway_login(self,
gateway_username,
gateway_password);
status = xrdp_mm_send_sys_login_request(self,
gw_username,
gw_password);
if (status == 0)
{
/* Now waiting for a reply from sesman */
/* Now waiting for a reply from sesman - see
xrdp_mm_process_login_response() */
waiting_for_msg = 1;
}
}
@ -2785,21 +2504,77 @@ xrdp_mm_connect_sm(struct xrdp_mm *self)
}
break;
case MMCS_SESSION_AUTH:
case MMCS_SESSION_LOGIN:
{
if (self->use_sesman)
// Finished with the gateway login
if (self->use_gw_login)
{
if ((status = xrdp_mm_send_login(self)) == 0)
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"access control check was successful");
// No reply needed for this one
status = scp_send_logout_request(self->sesman_trans);
}
if (status == 0 && self->use_sesman)
{
const char *username;
const char *password;
username = xrdp_mm_get_value(self, "username");
password = xrdp_mm_get_value(self, "password");
if (username == NULL || username[0] == '\0')
{
/* Now waiting for a reply from sesman */
waiting_for_msg = 1;
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"No username is available");
status = 1;
}
else if (password == NULL)
{
/* Can't find a password definition at all - even
* an empty one */
xrdp_wm_log_msg(self->wm, LOG_LEVEL_ERROR,
"No password field is available");
status = 1;
}
else
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Performing login request for %s",
username);
status = xrdp_mm_send_sys_login_request(self,
username,
password);
if (status == 0)
{
/* Now waiting for a reply from sesman - see
xrdp_mm_process_create_session_response() */
waiting_for_msg = 1;
}
}
}
}
break;
case MMCS_CREATE_SESSION:
if (self->use_sesman)
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"login was successful - creating session");
if ((status = xrdp_mm_create_session(self)) == 0)
{
/* Now waiting for a reply from sesman. Note that
* at this point sesman is expecting us to
* close the connection - we can do nothing else
* with it */
waiting_for_msg = 1;
}
}
break;
case MMCS_CONNECT_TO_SESSION:
{
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Connecting to session");
/* This is synchronous - no reply message expected */
status = xrdp_mm_user_session_connect(self);
}
@ -2811,6 +2586,8 @@ xrdp_mm_connect_sm(struct xrdp_mm *self)
{
char portbuff[256];
xrdp_wm_log_msg(self->wm, LOG_LEVEL_INFO,
"Connecting to chansrv");
if (self->use_sesman)
{
g_snprintf(portbuff, sizeof(portbuff),
@ -2848,8 +2625,17 @@ xrdp_mm_connect_sm(struct xrdp_mm *self)
if (!waiting_for_msg)
{
/* We don't need the sesman transport anymore */
if (self->sesman_trans != NULL)
{
self->delete_sesman_trans = 1;
}
xrdp_wm_mod_connect_done(self->wm, status);
cleanup_sesman_connection(self);
/* Make sure the module is cleaned up if we weren't successful */
if (status != 0)
{
xrdp_mm_module_cleanup(self);
}
}
}

View File

@ -312,8 +312,9 @@ struct xrdp_enc_data;
enum mm_connect_state
{
MMCS_CONNECT_TO_SESMAN,
MMCS_PAM_AUTH,
MMCS_SESSION_AUTH,
MMCS_GATEWAY_LOGIN,
MMCS_SESSION_LOGIN,
MMCS_CREATE_SESSION,
MMCS_CONNECT_TO_SESSION,
MMCS_CONNECT_TO_CHANSRV,
MMCS_DONE
@ -348,10 +349,8 @@ struct xrdp_mm
struct xrdp_wm *wm; /* owner */
enum mm_connect_state connect_state; /* State of connection */
/* Other processes we connect to */
/* NB : When we move to UDS, the sesman and pam_auth
* connection be merged */
int use_sesman; /* true if this is a sesman session */
int use_pam_auth; /* True if we're to authenticate using PAM */
int use_gw_login; /* True if we're to login using a gateway */
int use_chansrv; /* true if chansrvport is set in xrdp.ini or using sesman */
struct trans *sesman_trans; /* connection to sesman */
struct trans *chan_trans; /* connection to chansrv */
@ -495,6 +494,7 @@ struct xrdp_wm
struct xrdp_font *default_font;
struct xrdp_keymap keymap;
int hide_log_window;
int fatal_error_in_log_window;
struct xrdp_bitmap *target_surface; /* either screen or os surface */
int current_surface_index;
int hints;

View File

@ -2034,12 +2034,22 @@ xrdp_wm_login_state_changed(struct xrdp_wm *self)
LOG(LOG_LEVEL_DEBUG, "xrdp_wm_login_mode_changed: login_mode is %d", self->login_state);
if (self->login_state == WMLS_RESET)
{
/* this is the initial state of the login window */
xrdp_wm_set_login_state(self, WMLS_USER_PROMPT);
list_clear(self->log);
xrdp_wm_delete_all_children(self);
self->dragging = 0;
xrdp_wm_init(self);
if (self->fatal_error_in_log_window)
{
/* We've got here after OK is pressed in the log
* window, so the user has read the message(s) in it */
g_set_wait_obj(self->pro_layer->self_term_event);
}
else
{
/* this is the initial state of the login window */
xrdp_wm_set_login_state(self, WMLS_USER_PROMPT);
xrdp_wm_init(self);
}
}
else if (self->login_state == WMLS_START_CONNECT)
{
@ -2160,7 +2170,6 @@ add_string_to_logwindow(const char *msg, struct list *log)
do
{
new_part_message = g_strndup(current_pointer, LOG_WINDOW_CHAR_PER_LINE);
LOG(LOG_LEVEL_INFO, "%s", new_part_message);
list_add_item(log, (tintptr) new_part_message);
len_done += g_strlen(new_part_message);
current_pointer += g_strlen(new_part_message);