Pass keyring entry pin to running daemon and unlock identities

This commit is contained in:
Jeremy Lakeman 2013-10-09 15:34:41 +10:30
parent 60e3f5a3fc
commit ae7e120ed5
6 changed files with 399 additions and 36 deletions

View File

@ -1967,6 +1967,67 @@ int app_keyring_set_did(const struct cli_parsed *parsed, struct cli_context *con
return 0;
}
int app_id_pin(const struct cli_parsed *parsed, struct cli_context *context)
{
const char *pin;
cli_arg(parsed, "entry-pin", &pin, NULL, "");
int ret=1;
struct mdp_header header={
.remote.port=MDP_IDENTITY,
};
int mdp_sock = mdp_socket();
set_nonblock(mdp_sock);
unsigned char payload[1200];
struct mdp_identity_request *request = (struct mdp_identity_request *)payload;
request->action=ACTION_UNLOCK;
request->type=TYPE_PIN;
int len = sizeof(struct mdp_identity_request);
int pin_len = strlen(pin)+1;
if (pin_len+len > sizeof(payload))
return WHY("Supplied pin is too long");
bcopy(pin, &payload[len], pin_len);
len+=pin_len;
if (!mdp_send(mdp_sock, &header, payload, len)){
WHY_perror("mdp_send");
goto end;
}
time_ms_t timeout=gettime_ms()+500;
while(1){
time_ms_t now = gettime_ms();
if (now>timeout)
break;
int p=mdp_poll(mdp_sock, timeout - now);
if (p<0){
WHY_perror("mdp_poll");
break;
}
if (p==0){
WHYF("Timeout while waiting for response");
break;
}
struct mdp_header rev_header;
unsigned char payload[1600];
ssize_t len = mdp_recv(mdp_sock, &rev_header, payload, sizeof(payload));
if (len<0){
WHY_perror("mdp_recv");
continue;
}
if (rev_header.flags & MDP_FLAG_OK)
ret=0;
if (rev_header.flags & MDP_FLAG_ERROR){
payload[len]=0;
WHYF("%s",payload);
}
break;
}
end:
mdp_close(mdp_sock);
return ret;
}
int app_id_self(const struct cli_parsed *parsed, struct cli_context *context)
{
int mdp_sockfd;
@ -2521,6 +2582,8 @@ struct cli_schema command_line_options[]={
"Set the DID for the specified SID (must supply PIN to unlock the SID record in the keyring)"},
{app_id_self,{"id","self|peers|allpeers",NULL}, 0,
"Return identity(s) as URIs of own node, or of known routable peers, or all known peers"},
{app_id_pin, {"id", "enter", "pin", "<entry-pin>", NULL}, 0,
"Unlock any pin protected identities and enable routing packets to them"},
{app_route_print, {"route","print",NULL}, 0,
"Print the routing table"},
{app_network_scan, {"scan","[<address>]",NULL}, 0,

View File

@ -28,6 +28,94 @@
#include "overlay_packet.h"
#include "mdp_client.h"
int mdp_socket(void)
{
// for now use the same process for creating sockets
return overlay_mdp_client_socket();
}
int mdp_close(int socket)
{
// use the same process for closing sockets, though this will need to change once bind is implemented
return overlay_mdp_client_close(socket);
}
int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len)
{
struct sockaddr_un addr;
socklen_t addrlen;
if (make_local_sockaddr(&addr, &addrlen, "mdp.2.socket") == -1)
return -1;
struct iovec iov[]={
{
.iov_base = (void *)header,
.iov_len = sizeof(struct mdp_header)
},
{
.iov_base = (void *)payload,
.iov_len = len
}
};
struct msghdr hdr={
.msg_name=&addr,
.msg_namelen=addrlen,
.msg_iov=iov,
.msg_iovlen=2,
};
return sendmsg(socket, &hdr, 0);
}
ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len)
{
/* Construct name of socket to receive from. */
struct sockaddr_un mdp_addr;
socklen_t mdp_addrlen;
if (make_local_sockaddr(&mdp_addr, &mdp_addrlen, "mdp.2.socket") == -1)
return -1;
struct sockaddr_un addr;
struct iovec iov[]={
{
.iov_base = (void *)header,
.iov_len = sizeof(struct mdp_header)
},
{
.iov_base = (void *)payload,
.iov_len = max_len
}
};
struct msghdr hdr={
.msg_name=&addr,
.msg_namelen=sizeof(struct sockaddr_un),
.msg_iov=iov,
.msg_iovlen=2,
};
ssize_t len = recvmsg(socket, &hdr, 0);
if (len<sizeof(struct mdp_header))
return -1;
// double check that the incoming address matches the servald daemon
if (cmp_sockaddr((struct sockaddr *)&addr, hdr.msg_namelen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
&& ( addr.sun_family != AF_UNIX
|| real_sockaddr(&addr, hdr.msg_namelen, &addr, &hdr.msg_namelen) <= 0
|| cmp_sockaddr((struct sockaddr *)&addr, hdr.msg_namelen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
)
)
return -1;
return len - sizeof(struct mdp_header);
}
int mdp_poll(int socket, time_ms_t timeout_ms)
{
return overlay_mdp_client_poll(socket, timeout_ms);
}
int overlay_mdp_send(int mdp_sockfd, overlay_mdp_frame *mdp, int flags, int timeout_ms)
{
if (mdp_sockfd == -1)
@ -128,21 +216,17 @@ int overlay_mdp_client_close(int mdp_sockfd)
int overlay_mdp_client_poll(int mdp_sockfd, time_ms_t timeout_ms)
{
fd_set r;
int ret;
FD_ZERO(&r);
FD_SET(mdp_sockfd, &r);
if (timeout_ms<0) timeout_ms=0;
struct timeval tv;
if (timeout_ms>=0) {
tv.tv_sec=timeout_ms/1000;
tv.tv_usec=(timeout_ms%1000)*1000;
ret=select(mdp_sockfd+1,&r,NULL,&r,&tv);
}
else
ret=select(mdp_sockfd+1,&r,NULL,&r,NULL);
return ret;
struct pollfd fds[]={
{
.fd = mdp_sockfd,
.events = POLLIN|POLLERR,
}
};
return poll(fds, 1, timeout_ms);
}
int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, int port, int *ttl)
@ -165,7 +249,7 @@ int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, int port, int *ttl)
return -1; // no packet received
// If the received address overflowed the buffer, then it cannot have come from the server, whose
// address always fits within a struct sockaddr_un.
// address must always fit within a struct sockaddr_un.
if (recvaddrlen > sizeof recvaddr)
return WHY("reply did not come from server: address overrun");

View File

@ -21,6 +21,43 @@
#include "serval.h"
// define 3rd party mdp API without any structure padding
#pragma pack(push, 1)
struct mdp_sockaddr {
sid_t sid;
uint32_t port;
};
#define MDP_FLAG_NO_CRYPT (1<<0)
#define MDP_FLAG_NO_SIGN (1<<1)
#define MDP_FLAG_BIND_ALL (1<<2)
#define MDP_FLAG_OK (1<<3)
#define MDP_FLAG_ERROR (1<<4)
struct mdp_header {
struct mdp_sockaddr local;
struct mdp_sockaddr remote;
uint8_t flags;
uint8_t qos;
uint8_t ttl;
};
#define TYPE_SID 1
#define TYPE_PIN 2
#define ACTION_LOCK 1
#define ACTION_UNLOCK 2
struct mdp_identity_request{
uint8_t action;
uint8_t type;
// followed by a list of SID's or NULL terminated entry pins for the remainder of the payload
};
#define MDP_IDENTITY 1
#pragma pack(pop)
struct overlay_route_record{
unsigned char sid[SID_SIZE];
char interface_name[256];
@ -32,6 +69,13 @@ struct overlay_mdp_scan{
struct in_addr addr;
};
/* V2 interface */
int mdp_socket(void);
int mdp_close(int socket);
int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len);
ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len);
int mdp_poll(int socket, time_ms_t timeout_ms);
/* Client-side MDP function */
int overlay_mdp_client_socket(void);
int overlay_mdp_client_close(int mdp_sockfd);

View File

@ -30,8 +30,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mdp_client.h"
#include "crypto.h"
static void overlay_mdp_poll(struct sched_ent *alarm);
static void mdp_poll2(struct sched_ent *alarm);
static struct profile_total mdp_stats = { .name="overlay_mdp_poll" };
static struct sched_ent mdp_sock = STRUCT_SCHED_ENT_UNUSED;
static struct sched_ent mdp_sock = {
.function = overlay_mdp_poll,
.stats = &mdp_stats,
.poll.fd = -1,
};
static struct profile_total mdp_stats2 = { .name="mdp_poll2" };
static struct sched_ent mdp_sock2 = {
.function = mdp_poll2,
.stats = &mdp_stats2,
.poll.fd = -1,
};
static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now);
@ -60,37 +74,43 @@ static void overlay_mdp_clean_socket_files()
closedir(dir);
}
int overlay_mdp_setup_sockets()
static int mdp_bind_socket(const char *name)
{
struct sockaddr_un addr;
socklen_t addrlen;
int sock;
if (make_local_sockaddr(&addr, &addrlen, "%s", name) == -1)
return -1;
if ((sock = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
return -1;
if (socket_set_reuseaddr(sock, 1) == -1)
WARN("Could not set socket to reuse addresses");
if (socket_bind(sock, (struct sockaddr *)&addr, addrlen) == -1) {
close(sock);
return -1;
}
socket_set_rcvbufsize(sock, 64 * 1024);
INFOF("Socket %s: fd=%d %s", name, sock, alloca_sockaddr(&addr, addrlen));
return sock;
}
int overlay_mdp_setup_sockets()
{
/* Delete stale socket files from instance directory. */
overlay_mdp_clean_socket_files();
if (mdp_sock.poll.fd == -1) {
if (make_local_sockaddr(&addr, &addrlen, "mdp.socket") == -1)
return -1;
if ((mdp_sock.poll.fd = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
return -1;
if (socket_set_reuseaddr(mdp_sock.poll.fd, 1) == -1)
WARN("Could not set socket to reuse addresses");
if (socket_bind(mdp_sock.poll.fd, (struct sockaddr *)&addr, addrlen) == -1) {
close(mdp_sock.poll.fd);
mdp_sock.poll.fd = -1;
return -1;
}
socket_set_rcvbufsize(mdp_sock.poll.fd, 64 * 1024);
#if 0
int buffer_size = 64 * 1024;
if (setsockopt(mdp_sock.poll.fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size)) == -1)
WARNF_perror("setsockopt(%d,SOL_SOCKET,SO_SNDBUF,&%d,%d)", mdp_sock.poll.fd, buffer_size, sizeof buffer_size);
#endif
mdp_sock.function = overlay_mdp_poll;
mdp_sock.stats = &mdp_stats;
mdp_sock.poll.fd = mdp_bind_socket("mdp.socket");
mdp_sock.poll.events = POLLIN;
watch(&mdp_sock);
INFOF("MDP socket: fd=%d %s", mdp_sock.poll.fd, alloca_sockaddr(&addr, addrlen));
}
if (mdp_sock2.poll.fd == -1) {
mdp_sock2.poll.fd = mdp_bind_socket("mdp.2.socket");
mdp_sock2.poll.events = POLLIN;
watch(&mdp_sock2);
}
return 0;
}
@ -914,7 +934,124 @@ static void overlay_mdp_scan(struct sched_ent *alarm)
}
}
void overlay_mdp_poll(struct sched_ent *alarm)
struct mdp_client{
struct sockaddr_un *addr;
socklen_t addrlen;
};
static int mdp_reply2(const struct mdp_client *client, const struct mdp_header *header,
int flags, const unsigned char *payload, int payload_len)
{
struct mdp_header response_header;
bcopy(header, &response_header, sizeof(response_header));
response_header.flags = flags;
struct iovec iov[]={
{
.iov_base = (void *)&response_header,
.iov_len = sizeof(struct mdp_header)
},
{
.iov_base = (void *)payload,
.iov_len = payload_len
}
};
struct msghdr hdr={
.msg_name=client->addr,
.msg_namelen=client->addrlen,
.msg_iov=iov,
.msg_iovlen=2,
};
if (config.debug.mdprequests)
DEBUGF("Replying to %s with code %d", alloca_sockaddr(client->addr, client->addrlen), flags);
return sendmsg(mdp_sock2.poll.fd, &hdr, 0);
}
#define mdp_reply_error(A,B,C) mdp_reply2(A,B,MDP_FLAG_ERROR,(const unsigned char *)C,strlen(C))
#define mdp_reply_ok(A,B) mdp_reply2(A,B,MDP_FLAG_OK,NULL,0)
static int mdp_process_identity_request(struct mdp_client *client, struct mdp_header *header,
const unsigned char *payload, int payload_len)
{
if (payload_len<sizeof(struct mdp_identity_request)){
mdp_reply_error(client, header, "Request too short");
return -1;
}
struct mdp_identity_request *request = (struct mdp_identity_request *)payload;
payload += sizeof(struct mdp_identity_request);
payload_len -= sizeof(struct mdp_identity_request);
switch(request->action){
case ACTION_UNLOCK:
{
if (request->type!=TYPE_PIN){
mdp_reply_error(client, header, "Unknown request type");
return -1;
}
int unlock_count=0;
const char *pin = (char *)payload;
int ofs=0;
while(ofs < payload_len){
if (!payload[ofs++]){
unlock_count += keyring_enter_pin(keyring, pin);
pin=(char *)&payload[ofs++];
}
}
}
break;
default:
mdp_reply_error(client, header, "Unknown request action");
return -1;
}
mdp_reply_ok(client, header);
return 0;
}
static void mdp_poll2(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN) {
unsigned char buffer[1600];
struct sockaddr_storage addr;
struct mdp_client client={
.addr = (struct sockaddr_un *)&addr,
.addrlen = sizeof(addr)
};
int ttl=-1;
ssize_t len = recvwithttl(alarm->poll.fd, buffer, sizeof(buffer), &ttl, (struct sockaddr *)&addr, &client.addrlen);
if (len<=sizeof(struct mdp_header)){
WHYF("Expected length %d, got %d from %s", (int)sizeof(struct mdp_header), (int)len, alloca_sockaddr(client.addr, client.addrlen));
return;
}
struct mdp_header *header = (struct mdp_header *)buffer;
unsigned char *payload = &buffer[sizeof(struct mdp_header)];
int payload_len = len - sizeof(struct mdp_header);
if (is_sid_any(header->remote.sid.binary)){
// process local commands
switch(header->remote.port){
case MDP_IDENTITY:
if (config.debug.mdprequests)
DEBUGF("Processing MDP_IDENTITY from %s", alloca_sockaddr(client.addr, client.addrlen));
mdp_process_identity_request(&client, header, payload, payload_len);
break;
default:
mdp_reply_error(&client, header, "Unknown port number");
break;
}
}else{
// TODO transmit packet
mdp_reply_error(&client, header, "Transmitting packets is not yet supported");
}
}
}
static void overlay_mdp_poll(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN) {
unsigned char buffer[16384];

View File

@ -831,7 +831,6 @@ int overlay_packetradio_tx_packet(struct overlay_frame *frame);
void overlay_dummy_poll(struct sched_ent *alarm);
void server_config_reload(struct sched_ent *alarm);
void server_shutdown_check(struct sched_ent *alarm);
void overlay_mdp_poll(struct sched_ent *alarm);
int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp);
int overlay_send_probe(struct subscriber *peer, struct network_destination *destination, int queue);
int overlay_send_stun_request(struct subscriber *server, struct subscriber *request);

View File

@ -206,6 +206,42 @@ teardown_KeyringKeyringPinServer() {
report_servald_server
}
doc_KeyringEntryPinServer="Start daemon and unlock identities"
setup_KeyringEntryPinServer() {
setup
executeOk_servald config set debug.mdprequests on
create_single_identity
executeOk_servald keyring add 'one'
extract_stdout_keyvalue ONE sid "$rexp_sid"
executeOk_servald keyring add 'two'
extract_stdout_keyvalue TWOA sid "$rexp_sid"
executeOk_servald keyring add 'two'
extract_stdout_keyvalue TWOB sid "$rexp_sid"
start_servald_server
}
test_KeyringEntryPinServer() {
executeOk_servald id self
assertStdoutLineCount == 1
assertStdoutGrep --fixed-strings "$SIDA"
executeOk_servald id enter pin 'one'
executeOk_servald id self
assertStdoutLineCount == 2
assertStdoutGrep --fixed-strings "$SIDA"
assertStdoutGrep --fixed-strings "$ONE"
executeOk_servald id enter pin 'two'
executeOk_servald id self
assertStdoutLineCount == 4
assertStdoutGrep --fixed-strings "$SIDA"
assertStdoutGrep --fixed-strings "$ONE"
assertStdoutGrep --fixed-strings "$TWOA"
assertStdoutGrep --fixed-strings "$TWOB"
}
teardown_KeyringEntryPinServer() {
kill_all_servald_processes
assert_no_servald_processes
report_servald_server
}
doc_Load="Load keyring entries from a keyring dump"
setup_Load() {
setup_servald