For download links and other information go to the readsecret home page.

For version 1.0, August 2012

Preliminaries

The core code consists of one header file "readsecret.h" and one source file "readsecret.c". You can mix them directly in with your own code, or compile it as a separate library. No special compiler options are needed.

To use the function simply include the readsecret.h header file in your own code,

#include "readsecret.h"

Under Linux and perhaps some other operating systems you may need to link your executable with the librealtime system library, using the -lrt linker flag.

Functions

rsecret_get_secret_from_tty()

The rsecret_get_secret_from_tty() function is used to prompt the user for a secret and to read that secret from the process's terminal device. Note that the terminal device is not necessarily the same as stdin or stdout.

rsecret_error_ty rsecret_get_secret_from_tty(
    char* buf,
    size_t bufsize,
    const char* prompt );

buf and bufsize refer to a caller-supplied buffer into which the user's password or other entered secret will be copied.

prompt is a string you provide that will be displayed on the terminal device prior to accepting input. Generally it should not end with a newline character so that the cursor remains on the same line. If prompt is NULL or an empty string, then no prompt will be displayed.

Please note that if you write your own prompt prior to calling this function you should insure that it gets displayed first such as:

printf( "Enter secret:" );
fflush( stdout );
tcdrain( fileno( stdout ) );

However it is recommended that you leave the prompt display to this function.

rsecret_get_secret_from_tty_timed()

The rsecret_get_secret_from_tty_timed() function is like rsecret_get_secret_from_tty() but can time-out if the user takes too long to enter a response.

rsecret_error_ty rsecret_get_secret_from_tty(
    char* buf,
    size_t bufsize,
    const char* prompt,
    struct timespec* timeout
 );

The timeout argument points to a POSIX timespec structure, not a timeval. The sub-second field is in nanoseconds.

rsecret_strerror()

The rsecret_strerror() function can be used to convert an error code raised by the rsecret_get_secret_from_tty() into a more friendly human readable error string.

const char* rsecret_strerror( rsecret_error_ty error_code );

The returned string is in English. For multilingual support you'll need to provide your own error code translation.

rsecret_overwrite_buffer()

The rsecret_overwrite_buffer() function can be used to securely overwrite a memory buffer that had previously contained sensitive information.

void rsecret_overwrite_buffer( char* buf, size_t bufsize );

Traditionally one would simply use the standard memset(3) function for this purpose, however, it has been discovered that several C compilers, including gcc, will cleverly optimize away the memory overwrite. For more background and information see,

rsecret_inhibit_corefiles()

The rsecret_inhibit_corefiles() function will prevent the process from leaving a core file should it be terminated. Calling this prior to text entry will help prevent disclosure of secrets.

void* rsecret_inhibit_corefiles();

This function returns an opaque pointer which can later be passed to rsecret_restore_corefiles to return the process back to its original state.

rsecret_restore_corefiles()

The rsecret_restore_corefiles() function will return the process's core file behavior back to its original state when a prior call to rsecret_inhibit_corefiles() was called. You must pass in the opaque pointer that was returned by rsecret_inhibit_corefiles().

void rsecret_inhibit_corefiles( void* );

Signal handling

These signals may be used: SIGINT, SIGTERM, SIGALRM

The functions that get secrets or passwords, rsecret_get_secret_from_tty() and rsecret_get_secret_from_tty_timed(), will attempt to catch signals typically used to interrupt or terminate the process, namely SIGINT and SIGTERM. These are often raised by the user aborting the process, for example by entering Control-C.

If these signals occur, the functions will insure that no partially-entered secret or password still resides in memory or in the terminal I/O buffers, and then return with a RSECRET_ERROR_INTERRUPTED error code. However if either SIGINT or SIGTERM have been ignored with SIG_IGN prior to calling these functions, then those signals will continue to ignored and will not abort the text entry.

If you have established your own signal handlers, understand that while one of these function is operating your handlers will not be called. However your handlers will be re-established as you had left them when these functions do return.

When using timed text entry, the SIGALRM signal is also diverted and used internally. Again, upon exit the original handler for that signal will be restored.

Terminal device

The functions that get secrets or passwords from the user will open the process's controling terminal device, typically /dev/tty but may be different under some operating systems. It will not read from stdin.

While the function is active it will disable the echoing of characters to the terminal, and will restore the terminal line disipline upon completion. The terminal is kept in cooked icannon line mode rather than raw character mode, so terminal controls such as backspace work as configured (see stty(1) man page). Also note these functions will attempt to flush the terminal I/O buffers at appropriate points to help prevent accidental keystroke leakage.

Nothing special is done regarding character sets. Under Linux usually the IUTF8 input mode flag is set so that the returned byte string will be encoded in UTF-8, but this is outside of the responsibility of this library.

List of errors

The following are the possible error codes of type rsecret_error_ty that may be returned.

RSECRET_SUCCESS
The operation was successful.
RSECRET_ERROR_BAD_ARG
The arguments provided to the function are invalid, such as NULL pointers or zero-length buffers.
RSECRET_ERROR_TTY_OPEN
There was a failure trying to open the process's terminal (tty) device. Perhaps the process has no terminal.
RSECRET_ERROR_SIGACTION
There was a failure trying to establish signal handlers.
RSECRET_ERROR_NOECHO
The terminal device does not support supressing character echo.
RSECRET_ERROR_PROMPT
There was a failure trying to display the prompt.
RSECRET_ERROR_READ
There was a failure trying to read the user's input from the terminal.
RSECRET_ERROR_LENGTH
The user attempted to type in more data than the supplied buffer could hold.
RSECRET_ERROR_INTERRUPTED
The process was interrupted, such as the user pressing Control-C.

In all cases other than RSECRET_SUCCESS, any data the user entered will have been securely erased and the supplied buffer will be empty.