Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22948146
random-daemon.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
8 KB
Subscribers
None
random-daemon.c
View Options
/* random-daemon.c - Access to the external random daemon
* Copyright (C) 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
The functions here are used by random.c to divert calls to an
external random number daemon. The actual daemon we use is
gcryptrnd. Such a daemon is useful to keep a persistent pool in
memory over invocations of a single application and to allow
prioritizing access to the actual entropy sources. The drawback is
that we need to use IPC (i.e. unix domain socket) to convey
sensitive data.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<assert.h>
#include
<string.h>
#include
<sys/socket.h>
#include
<sys/un.h>
#include
<errno.h>
#include
<unistd.h>
#include
"g10lib.h"
#include
"random.h"
#include
"ath.h"
/* This is default socket name we use in case the provided socket name
is NULL. */
#define RANDOM_DAEMON_SOCKET "/var/run/libgcrypt/S.gcryptrnd"
/* The lock serializing access to the daemon. */
static
ath_mutex_t
daemon_lock
=
ATH_MUTEX_INITIALIZER
;
/* The socket connected to the daemon. */
static
int
daemon_socket
=
-1
;
/* Creates a socket connected to the daemon. On success, store the
socket fd in *SOCK. Returns error code. */
static
gcry_error_t
connect_to_socket
(
const
char
*
socketname
,
int
*
sock
)
{
struct
sockaddr_un
*
srvr_addr
;
socklen_t
addrlen
;
gcry_error_t
err
;
int
fd
;
int
rc
;
srvr_addr
=
NULL
;
/* Create a socket. */
fd
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
if
(
fd
==
-1
)
{
log_error
(
"can't create socket: %s
\n
"
,
strerror
(
errno
));
err
=
gcry_error_from_errno
(
errno
);
goto
out
;
}
/* Set up address. */
srvr_addr
=
gcry_malloc
(
sizeof
*
srvr_addr
);
if
(
!
srvr_addr
)
{
log_error
(
"malloc failed: %s
\n
"
,
strerror
(
errno
));
err
=
gcry_error_from_errno
(
errno
);
goto
out
;
}
memset
(
srvr_addr
,
0
,
sizeof
*
srvr_addr
);
srvr_addr
->
sun_family
=
AF_UNIX
;
if
(
strlen
(
socketname
)
+
1
>=
sizeof
(
srvr_addr
->
sun_path
))
{
log_error
(
"socket name `%s' too long
\n
"
,
socketname
);
err
=
gcry_error
(
GPG_ERR_INTERNAL
);
/* FIXME? */
goto
out
;
}
strcpy
(
srvr_addr
->
sun_path
,
socketname
);
addrlen
=
(
offsetof
(
struct
sockaddr_un
,
sun_path
)
+
strlen
(
srvr_addr
->
sun_path
)
+
1
);
/* Connect socket. */
rc
=
connect
(
fd
,
(
struct
sockaddr
*
)
srvr_addr
,
addrlen
);
if
(
rc
==
-1
)
{
log_error
(
"error connecting socket `%s': %s
\n
"
,
srvr_addr
->
sun_path
,
strerror
(
errno
));
err
=
gcry_error_from_errno
(
errno
);
goto
out
;
}
err
=
0
;
out
:
gcry_free
(
srvr_addr
);
if
(
err
)
{
close
(
fd
);
fd
=
-1
;
}
*
sock
=
fd
;
return
err
;
}
/* Initialize basics of this module. This should be viewed as a
constructor to prepare locking. */
void
_gcry_daemon_initialize_basics
(
void
)
{
static
int
initialized
;
int
err
;
if
(
!
initialized
)
{
initialized
=
1
;
err
=
ath_mutex_init
(
&
daemon_lock
);
if
(
err
)
log_fatal
(
"failed to create the daemon lock: %s
\n
"
,
strerror
(
err
)
);
}
}
/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on
success or another value on write error. */
static
int
writen
(
int
fd
,
const
void
*
buffer
,
size_t
length
)
{
ssize_t
n
;
while
(
length
)
{
do
n
=
ath_write
(
fd
,
buffer
,
length
);
while
(
n
<
0
&&
errno
==
EINTR
);
if
(
n
<
0
)
{
log_error
(
"write error: %s
\n
"
,
strerror
(
errno
));
return
-1
;
/* write error */
}
length
-=
n
;
buffer
=
(
const
char
*
)
buffer
+
n
;
}
return
0
;
/* Okay */
}
static
int
readn
(
int
fd
,
void
*
buf
,
size_t
buflen
,
size_t
*
ret_nread
)
{
size_t
nleft
=
buflen
;
int
nread
;
char
*
p
;
p
=
buf
;
while
(
nleft
>
0
)
{
nread
=
ath_read
(
fd
,
buf
,
nleft
);
if
(
nread
<
0
)
{
if
(
nread
==
EINTR
)
nread
=
0
;
else
return
-1
;
}
else
if
(
!
nread
)
break
;
/* EOF */
nleft
-=
nread
;
buf
=
(
char
*
)
buf
+
nread
;
}
if
(
ret_nread
)
*
ret_nread
=
buflen
-
nleft
;
return
0
;
}
/* This functions requests REQ_NBYTES from the daemon. If NONCE is
true, the data should be suited for a nonce. If NONCE is FALSE,
data of random level LEVEL will be generated. The retrieved random
data will be stored in BUFFER. Returns error code. */
static
gcry_error_t
call_daemon
(
const
char
*
socketname
,
void
*
buffer
,
size_t
req_nbytes
,
int
nonce
,
enum
gcry_random_level
level
)
{
static
int
initialized
;
unsigned
char
buf
[
255
];
gcry_error_t
err
=
0
;
size_t
nbytes
;
size_t
nread
;
int
rc
;
if
(
!
req_nbytes
)
return
0
;
ath_mutex_lock
(
&
daemon_lock
);
/* Open the socket if that has not been done. */
if
(
!
initialized
)
{
initialized
=
1
;
err
=
connect_to_socket
(
socketname
?
socketname
:
RANDOM_DAEMON_SOCKET
,
&
daemon_socket
);
if
(
err
)
{
daemon_socket
=
-1
;
log_info
(
"not using random daemon
\n
"
);
ath_mutex_unlock
(
&
daemon_lock
);
return
err
;
}
}
/* Check that we have a valid socket descriptor. */
if
(
daemon_socket
==
-1
)
{
ath_mutex_unlock
(
&
daemon_lock
);
return
gcry_error
(
GPG_ERR_INTERNAL
);
}
/* Do the real work. */
do
{
/* Process in chunks. */
nbytes
=
req_nbytes
>
sizeof
(
buf
)
?
sizeof
(
buf
)
:
req_nbytes
;
req_nbytes
-=
nbytes
;
/* Construct request. */
buf
[
0
]
=
3
;
if
(
nonce
)
buf
[
1
]
=
10
;
else
if
(
level
==
GCRY_VERY_STRONG_RANDOM
)
buf
[
1
]
=
12
;
else
if
(
level
==
GCRY_STRONG_RANDOM
)
buf
[
1
]
=
11
;
buf
[
2
]
=
nbytes
;
/* Send request. */
rc
=
writen
(
daemon_socket
,
buf
,
3
);
if
(
rc
==
-1
)
{
err
=
gcry_error_from_errno
(
errno
);
break
;
}
/* Retrieve response. */
rc
=
readn
(
daemon_socket
,
buf
,
2
,
&
nread
);
if
(
rc
==
-1
)
{
err
=
gcry_error_from_errno
(
errno
);
log_error
(
"read error: %s
\n
"
,
gcry_strerror
(
err
));
break
;
}
if
(
nread
&&
buf
[
0
])
{
log_error
(
"random daemon returned error code %d
\n
"
,
buf
[
0
]);
err
=
gcry_error
(
GPG_ERR_INTERNAL
);
/* ? */
break
;
}
if
(
nread
!=
2
)
{
log_error
(
"response too small
\n
"
);
err
=
gcry_error
(
GPG_ERR_PROTOCOL_VIOLATION
);
/* ? */
break
;
}
/* if (1)*/
/* FIXME, verbose */
/* log_info ("received response with %d bytes of data\n", buf[1]);*/
if
(
buf
[
1
]
<
nbytes
)
{
log_error
(
"error: server returned less bytes than requested
\n
"
);
err
=
gcry_error
(
GPG_ERR_PROTOCOL_VIOLATION
);
/* ? */
break
;
}
else
if
(
buf
[
1
]
>
nbytes
)
{
log_error
(
"warning: server returned more bytes than requested
\n
"
);
err
=
gcry_error
(
GPG_ERR_PROTOCOL_VIOLATION
);
/* ? */
break
;
}
assert
(
nbytes
<=
sizeof
(
buf
));
rc
=
readn
(
daemon_socket
,
buf
,
nbytes
,
&
nread
);
if
(
rc
==
-1
)
{
err
=
gcry_error_from_errno
(
errno
);
log_error
(
"read error: %s
\n
"
,
gcry_strerror
(
err
));
break
;
}
if
(
nread
!=
nbytes
)
{
log_error
(
"too little random data read
\n
"
);
err
=
gcry_error
(
GPG_ERR_INTERNAL
);
break
;
}
/* Successfuly read another chunk of data. */
memcpy
(
buffer
,
buf
,
nbytes
);
buffer
=
((
char
*
)
buffer
)
+
nbytes
;
}
while
(
req_nbytes
);
ath_mutex_unlock
(
&
daemon_lock
);
return
err
;
}
/* Internal function to fill BUFFER with LENGTH bytes of random. We
support GCRY_STRONG_RANDOM and GCRY_VERY_STRONG_RANDOM here.
Return 0 on success. */
int
_gcry_daemon_randomize
(
const
char
*
socketname
,
void
*
buffer
,
size_t
length
,
enum
gcry_random_level
level
)
{
gcry_error_t
err
;
err
=
call_daemon
(
socketname
,
buffer
,
length
,
0
,
level
);
return
err
?
-1
:
0
;
}
/* Internal function to fill BUFFER with NBYTES of data usable for a
nonce. Returns 0 on success. */
int
_gcry_daemon_create_nonce
(
const
char
*
socketname
,
void
*
buffer
,
size_t
length
)
{
gcry_error_t
err
;
err
=
call_daemon
(
socketname
,
buffer
,
length
,
1
,
0
);
return
err
?
-1
:
0
;
}
/* END */
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 10, 8:57 AM (1 d, 5 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
32/9f/1e0192eef2a3c214402ad108f479
Attached To
rC libgcrypt
Event Timeline
Log In to Comment