Initial support for CredSSP smartcard authentication.
- Add implementation of TSSmartCardCreds and TSCSPDataDetail for CredSSP protocol. - Add handling of long opts for getopt() - Added 4 new long opts for providing information to CredSSP which is required for smartcard credentials. - Updated manual with information about the new arguments. If smartcard authentication is request by commandline "-i" option, and no CredSSP smartcard options is provided, rdesktop will negotiate to use SSL and warn. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/rdesktop/trunk@1705 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
d0bf92a9c3
commit
d1e8fdc90a
201
cssp.c
201
cssp.c
@ -1,7 +1,7 @@
|
||||
/* -*- c-basic-offset: 8 -*-
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
CredSSP layer and kerberos support.
|
||||
Copyright 2012 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
||||
Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -20,6 +20,13 @@
|
||||
#include <gssapi/gssapi.h>
|
||||
#include "rdesktop.h"
|
||||
|
||||
extern RD_BOOL g_use_password_as_pin;
|
||||
|
||||
extern char *g_sc_csp_name;
|
||||
extern char *g_sc_reader_name;
|
||||
extern char *g_sc_card_name;
|
||||
extern char *g_sc_container_name;
|
||||
|
||||
static gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
|
||||
{ 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
|
||||
|
||||
@ -285,6 +292,178 @@ cssp_encode_tspasswordcreds(char *username, char *password, char *domain)
|
||||
return out;
|
||||
}
|
||||
|
||||
/* KeySpecs from wincrypt.h */
|
||||
#define AT_KEYEXCHANGE 1
|
||||
#define AT_SIGNATURE 2
|
||||
|
||||
static STREAM
|
||||
cssp_encode_tscspdatadetail(unsigned char keyspec, char *card, char *reader, char *container, char *csp)
|
||||
{
|
||||
int i;
|
||||
STREAM out;
|
||||
STREAM h1, h2;
|
||||
struct stream tmp = { 0 };
|
||||
struct stream message = { 0 };
|
||||
|
||||
// allocate local streams
|
||||
tmp.size = 4096;
|
||||
tmp.data = xmalloc(tmp.size);
|
||||
s_reset(&tmp);
|
||||
|
||||
message.size = 4096;
|
||||
message.data = xmalloc(message.size);
|
||||
s_reset(&message);
|
||||
|
||||
// keySpec [0]
|
||||
s_reset(&tmp);
|
||||
out_uint8(&tmp, keyspec);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
|
||||
// cardName [1]
|
||||
if (card)
|
||||
{
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(card); i++)
|
||||
out_uint16_le(&tmp, card[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
// readerName [2]
|
||||
if (reader)
|
||||
{
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(reader); i++)
|
||||
out_uint16_le(&tmp, reader[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
// containerName [3]
|
||||
if (container)
|
||||
{
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(container); i++)
|
||||
out_uint16_le(&tmp, container[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
// cspName [4]
|
||||
if (csp) {
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(csp); i++)
|
||||
out_uint16_le(&tmp, csp[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 4, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
s_mark_end(&message);
|
||||
|
||||
// build message
|
||||
out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
|
||||
|
||||
// cleanup
|
||||
free(tmp.data);
|
||||
free(message.data);
|
||||
return out;
|
||||
}
|
||||
|
||||
static STREAM
|
||||
cssp_encode_tssmartcardcreds(char *username, char *password,char *domain)
|
||||
{
|
||||
int i;
|
||||
STREAM out, h1, h2;
|
||||
struct stream tmp = { 0 };
|
||||
struct stream message = { 0 };
|
||||
|
||||
// allocate local streams
|
||||
tmp.size = 4096;
|
||||
tmp.data = xmalloc(tmp.size);
|
||||
s_reset(&tmp);
|
||||
|
||||
message.size = 4096;
|
||||
message.data = xmalloc(message.size);
|
||||
s_reset(&message);
|
||||
|
||||
// pin [0]
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(password); i++)
|
||||
out_uint16_le(&tmp, password[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
|
||||
// cspData[1]
|
||||
h2 = cssp_encode_tscspdatadetail(AT_KEYEXCHANGE, g_sc_card_name, g_sc_reader_name, g_sc_container_name, g_sc_csp_name);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
|
||||
// userHint [2]
|
||||
if (username && strlen(username))
|
||||
{
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(username); i++)
|
||||
out_uint16_le(&tmp, username[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 2, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
// domainHint [3]
|
||||
if (domain && strlen(domain))
|
||||
{
|
||||
s_reset(&tmp);
|
||||
for (i = 0; i < strlen(domain); i++)
|
||||
out_uint16_le(&tmp, domain[i]);
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 3, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
s_free(h2);
|
||||
s_free(h1);
|
||||
}
|
||||
|
||||
s_mark_end(&message);
|
||||
|
||||
// build message
|
||||
out = ber_wrap_hdr_data(BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED, &message);
|
||||
|
||||
// cleanup
|
||||
free(tmp.data);
|
||||
free(message.data);
|
||||
return out;
|
||||
}
|
||||
|
||||
STREAM
|
||||
cssp_encode_tscredentials(char *username, char *password, char *domain)
|
||||
{
|
||||
@ -304,7 +483,15 @@ cssp_encode_tscredentials(char *username, char *password, char *domain)
|
||||
|
||||
// credType [0]
|
||||
s_reset(&tmp);
|
||||
out_uint8(&tmp, 1); // TSPasswordCreds
|
||||
if (g_use_password_as_pin == False)
|
||||
{
|
||||
out_uint8(&tmp, 1); // TSPasswordCreds
|
||||
}
|
||||
else
|
||||
{
|
||||
out_uint8(&tmp, 2); // TSSmartCardCreds
|
||||
}
|
||||
|
||||
s_mark_end(&tmp);
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_INTEGER, &tmp);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 0, h2);
|
||||
@ -313,7 +500,15 @@ cssp_encode_tscredentials(char *username, char *password, char *domain)
|
||||
s_free(h1);
|
||||
|
||||
// credentials [1]
|
||||
h3 = cssp_encode_tspasswordcreds(username, password, domain);
|
||||
if (g_use_password_as_pin == False)
|
||||
{
|
||||
h3 = cssp_encode_tspasswordcreds(username, password, domain);
|
||||
}
|
||||
else
|
||||
{
|
||||
h3 = cssp_encode_tssmartcardcreds(username, password, domain);
|
||||
}
|
||||
|
||||
h2 = ber_wrap_hdr_data(BER_TAG_OCTET_STRING, h3);
|
||||
h1 = ber_wrap_hdr_data(BER_TAG_CTXT_SPECIFIC | BER_TAG_CONSTRUCTED | 1, h2);
|
||||
out_uint8p(&message, h1->data, s_length(h1));
|
||||
|
@ -74,9 +74,9 @@ screen size. This requires that rdesktop has been compiled with RandR
|
||||
support.
|
||||
.TP
|
||||
.BR "-i"
|
||||
Use password as smartcard pin, if a valid user certificate is matched in smart card
|
||||
reader the password passed with \f-p\fR argument is used as pin for the smart card. This
|
||||
feature also requires that smart card redirection is used using \f-r scard\fR argument.
|
||||
Use password as smartcard pin. If a valid user certificate is matched in smart card
|
||||
reader the password passed with \f-p\fR argument is used as pin for the smart card.
|
||||
This feature also requires that smart card redirection is used using \f-r scard\fR argument.
|
||||
.TP
|
||||
.BR "-f"
|
||||
Enable fullscreen mode. This overrides the window manager and causes the
|
||||
@ -241,6 +241,27 @@ Use RDP version 4.
|
||||
.BR "-5"
|
||||
Use RDP version 5 (default).
|
||||
.PP
|
||||
|
||||
.SH "CredSSP Smartcard options"
|
||||
.TP
|
||||
.BR "--sc-csp-name <name>"
|
||||
Specify the CSP (Crypto Service Provider) to use on the windows side for the smartcard
|
||||
authentication. CSP is the driver for your smartcard and it seems like this is required
|
||||
to be specified for CredSSP authentication. For swedish NetID the following CSP name is
|
||||
used; "Net iD - CSP".
|
||||
.TP
|
||||
.BR "--sc-container-name <name>"
|
||||
Specify the container name, usally this is the username for default container and it seems
|
||||
like this is required to be specified for CredSSP authentication.
|
||||
.TP
|
||||
.BR "--sc-reader-name <name>"
|
||||
Specify the reader name to be used to prevent the pin code being sent to wrong card if there
|
||||
are several readers.
|
||||
.TP
|
||||
.BR "--sc-card-name <name>"
|
||||
Specify the card name for example; "Telia EID IP5a".
|
||||
.PP
|
||||
|
||||
.SH "EXIT VALUES"
|
||||
.PP
|
||||
.IP "\fB0\fP"
|
||||
|
10
iso.c
10
iso.c
@ -27,6 +27,12 @@ extern RD_BOOL g_use_password_as_pin;
|
||||
|
||||
static RD_BOOL g_negotiate_rdp_protocol = True;
|
||||
|
||||
extern char *g_sc_csp_name;
|
||||
extern char *g_sc_reader_name;
|
||||
extern char *g_sc_card_name;
|
||||
extern char *g_sc_container_name;
|
||||
|
||||
|
||||
/* Send a self-contained ISO PDU */
|
||||
static void
|
||||
iso_send_msg(uint8 code)
|
||||
@ -207,8 +213,10 @@ iso_connect(char *server, char *username, char *domain, char *password,
|
||||
#ifdef WITH_CREDSSP
|
||||
if (!g_use_password_as_pin)
|
||||
neg_proto |= PROTOCOL_HYBRID;
|
||||
else if (g_sc_csp_name || g_sc_reader_name || g_sc_card_name || g_sc_container_name)
|
||||
neg_proto |= PROTOCOL_HYBRID;
|
||||
else
|
||||
warning("CredSSP will be disabled if smartcard SSO is used.\n");
|
||||
warning("Disables CredSSP due to missing smartcard information for SSO.\n");
|
||||
#endif
|
||||
|
||||
retry:
|
||||
|
57
rdesktop.c
57
rdesktop.c
@ -21,6 +21,7 @@
|
||||
|
||||
#include <stdarg.h> /* va_list va_start va_end */
|
||||
#include <unistd.h> /* read close getuid getgid getpid getppid gethostname */
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h> /* open */
|
||||
#include <pwd.h> /* getpwuid */
|
||||
#include <termios.h> /* tcgetattr tcsetattr */
|
||||
@ -131,6 +132,27 @@ RD_BOOL g_rdpsnd = False;
|
||||
char g_codepage[16] = "";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
char *g_sc_csp_name = NULL; /* Smartcard CSP name */
|
||||
char *g_sc_reader_name = NULL;
|
||||
char *g_sc_card_name = NULL;
|
||||
char *g_sc_container_name = NULL;
|
||||
#define OPT_BASE 256
|
||||
#define OPT_SC_CSP_NAME (OPT_BASE+1)
|
||||
#define OPT_SC_READER_NAME (OPT_BASE+2)
|
||||
#define OPT_SC_CARD_NAME (OPT_BASE+3)
|
||||
#define OPT_SC_CONTAINER_NAME (OPT_BASE+4)
|
||||
|
||||
struct option longopts[] = {
|
||||
{"sc-csp-name", 1, 0, OPT_SC_CSP_NAME},
|
||||
{"sc-reader-name", 1, 0, OPT_SC_READER_NAME},
|
||||
{"sc-card-name", 1, 0, OPT_SC_CARD_NAME},
|
||||
{"sc-container-name", 1, 0, OPT_SC_CONTAINER_NAME},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||
extern uint32 g_num_devices;
|
||||
extern char *g_rdpdr_clientname;
|
||||
@ -165,7 +187,7 @@ usage(char *program)
|
||||
fprintf(stderr, " -k: keyboard layout on server (en-us, de, sv, etc.)\n");
|
||||
fprintf(stderr, " -g: desktop geometry (WxH)\n");
|
||||
#ifdef WITH_SCARD
|
||||
fprintf(stderr, " -i: password is smartcard pin\n");
|
||||
fprintf(stderr, " -i: enables smartcard authentication, password is used as pin\n");
|
||||
#endif
|
||||
fprintf(stderr, " -f: full-screen mode\n");
|
||||
fprintf(stderr, " -b: force bitmap updates\n");
|
||||
@ -236,6 +258,17 @@ usage(char *program)
|
||||
fprintf(stderr, " -0: attach to console\n");
|
||||
fprintf(stderr, " -4: use RDP version 4\n");
|
||||
fprintf(stderr, " -5: use RDP version 5 (default)\n");
|
||||
#ifdef WITH_SCARD
|
||||
fprintf(stderr, "\nCredSSP Smartcard hinting\n");
|
||||
fprintf(stderr, " --sc-csp-name Specifies the Crypto Service Provider name which\n");
|
||||
fprintf(stderr, " is used to authenticate the user by smartcard\n");
|
||||
fprintf(stderr, " --sc-container-name Specifies the container name, this is usally the username\n");
|
||||
fprintf(stderr, " --sc-reader-name Smartcard reader name to use\n");
|
||||
fprintf(stderr, " --sc-card-name Specifies the card name of the smartcard to use\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
@ -484,6 +517,7 @@ main(int argc, char *argv[])
|
||||
#ifdef WITH_RDPSND
|
||||
char *rdpsnd_optarg = NULL;
|
||||
#endif
|
||||
int longidx;
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* Set locale according to environment */
|
||||
@ -515,9 +549,8 @@ main(int argc, char *argv[])
|
||||
#else
|
||||
#define VNCOPT
|
||||
#endif
|
||||
|
||||
while ((c = getopt(argc, argv,
|
||||
VNCOPT "A:u:L:d:s:c:p:n:k:g:fbBeEitmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
|
||||
while ((c = getopt_long(argc, argv,
|
||||
VNCOPT "A:u:L:d:s:c:p:n:k:g:fbBeEitmzCDKS:T:NX:a:x:Pr:045h?", longopts, &longidx)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -862,7 +895,23 @@ main(int argc, char *argv[])
|
||||
case '5':
|
||||
g_rdp_version = RDP_V5;
|
||||
break;
|
||||
#if WITH_SCARD
|
||||
case OPT_SC_CSP_NAME:
|
||||
g_sc_csp_name = strdup(optarg);
|
||||
break;
|
||||
|
||||
case OPT_SC_READER_NAME:
|
||||
g_sc_reader_name = strdup(optarg);
|
||||
break;
|
||||
|
||||
case OPT_SC_CARD_NAME:
|
||||
g_sc_card_name = strdup(optarg);
|
||||
break;
|
||||
|
||||
case OPT_SC_CONTAINER_NAME:
|
||||
g_sc_container_name = strdup(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user