summaryrefslogtreecommitdiff
path: root/random/random.c
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-06-15 18:52:49 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-06-15 18:52:49 +0200
commitbd02b7ae376ece2d3b09e01886ec6ed73194024f (patch)
tree6f7cff799a3659672d70dbeef740a53ce039ae73 /random/random.c
parentaa80cbd0cf4a55e1cd47ae78d43c74ebb5828468 (diff)
random and procfs have been merged, drop the local version, amend external.patch
Diffstat (limited to 'random/random.c')
-rw-r--r--random/random.c621
1 files changed, 0 insertions, 621 deletions
diff --git a/random/random.c b/random/random.c
deleted file mode 100644
index ca963580..00000000
--- a/random/random.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/* random.c - A single-file translator providing random data
- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
-
- 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 the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- This program 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
- General Public License for more details.
-
- You should have received a copy of the GNU 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 */
-
-#define _GNU_SOURCE 1
-
-#include <hurd/trivfs.h>
-#include <hurd/startup.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <argp.h>
-#include <argz.h>
-#include <error.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <assert.h>
-
-#include <version.h>
-
-#include "random.h"
-#include "gnupg-random.h"
-
-/* Our control port. */
-struct trivfs_control *fsys;
-
-int read_blocked; /* For read and select. */
-pthread_cond_t wait; /* For read and select. */
-pthread_cond_t select_alert; /* For read and select. */
-
-
-/* The quality of randomness we provide.
- 0: Very weak randomness based on time() and getrusage().
- No external random data is used.
- 1: Pseudo random numbers based on all available real random
- numbers.
- 2: Strong random numbers with a somewhat guaranteed entropy.
-*/
-#define DEFAULT_LEVEL 2
-static int level = DEFAULT_LEVEL;
-
-/* Name of file to use as seed. */
-static char *seed_file;
-
-/* The random bytes we collected. */
-char gatherbuf[GATHERBUFSIZE];
-
-/* The current positions in gatherbuf[]. */
-int gatherrpos;
-int gatherwpos;
-
-/* XXX Yuk Yuk. */
-#define POOLSIZE 600
-
-/* Take up to length bytes from gather_random if available. If
- nothing is available, sleep until something becomes available.
- Must be called with global_lock held. */
-int
-gather_random( void (*add)(const void*, size_t, int), int requester,
- size_t length, int level )
-{
- int avail = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
- int first = GATHERBUFSIZE - gatherrpos;
- int second = length - first;
-
- /* If level is zero, we should not block and not add anything
- to the pool. */
- if( !level )
- return 0;
-
- /* io_read() should guarantee that there is always data available. */
- if (level == 2)
- assert (avail);
-
- if (length > avail)
- length = avail;
-
- if (first > length)
- first = length;
- (*add) (&gatherbuf[gatherrpos], first, requester);
- gatherrpos = (gatherrpos + first) % GATHERBUFSIZE;
- if (second > 0)
- {
- (*add) (&gatherbuf[gatherrpos], second, requester);
- gatherrpos += second;
- }
- return length;
-}
-
-
-const char *argp_program_version = STANDARD_HURD_VERSION (random);
-
-/* This lock protects the GnuPG code. */
-static pthread_mutex_t global_lock;
-
-/* Trivfs hooks. */
-int trivfs_fstype = FSTYPE_MISC;
-int trivfs_fsid = 0;
-
-int trivfs_allow_open = O_READ | O_WRITE;
-
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 0;
-
-void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-{
- /* Mark the node as a read-only plain file. */
- st->st_mode &= ~S_IFMT;
- st->st_mode |= (S_IFCHR);
- st->st_size = 0;
-}
-
-error_t
-trivfs_goaway (struct trivfs_control *cntl, int flags)
-{
- update_random_seed_file ();
- exit (0);
-}
-
-/* Read data from an IO object. If offset is -1, read from the object
- maintained file pointer. If the object is not seekable, offset is
- ignored. The amount desired to be read is in AMOUNT. */
-error_t
-trivfs_S_io_read (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- data_t *data, mach_msg_type_number_t *data_len,
- loff_t offs, mach_msg_type_number_t amount)
-{
- /* Deny access if they have bad credentials. */
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_READ))
- return EBADF;
-
- pthread_mutex_lock (&global_lock);
-
- if (amount > 0)
- {
- while (readable_pool (amount, level) == 0)
- {
- if (cred->po->openmodes & O_NONBLOCK)
- {
- pthread_mutex_unlock (&global_lock);
- return EWOULDBLOCK;
- }
- read_blocked = 1;
- if (pthread_hurd_cond_wait_np (&wait, &global_lock))
- {
- pthread_mutex_unlock (&global_lock);
- return EINTR;
- }
- /* See term/users.c for possible race? */
- }
-
- /* Possibly allocate a new buffer. */
- if (*data_len < amount)
- *data = mmap (0, amount, PROT_READ|PROT_WRITE,
- MAP_ANON, 0, 0);
-
- amount = read_pool ((byte *) *data, amount, level);
- }
- *data_len = amount;
-
- /* Set atime, see term/users.c */
-
- pthread_mutex_unlock (&global_lock);
-
- return 0;
-}
-
-/* Write data to an IO object. If offset is -1, write at the object
- maintained file pointer. If the object is not seekable, offset is
- ignored. The amount successfully written is returned in amount. A
- given user should not have more than one outstanding io_write on an
- object at a time; servers implement congestion control by delaying
- responses to io_write. Servers may drop data (returning ENOBUFS)
- if they receive more than one write when not prepared for it. */
-error_t
-trivfs_S_io_write (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t replytype,
- data_t data,
- mach_msg_type_number_t datalen,
- loff_t offset,
- mach_msg_type_number_t *amount)
-{
- int i = 0;
- /* Deny access if they have bad credentials. */
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_WRITE))
- return EBADF;
-
- pthread_mutex_lock (&global_lock);
-
- while (i < datalen)
- {
- gatherbuf[gatherwpos] = data[i++];
- gatherwpos = (gatherwpos + 1) % GATHERBUFSIZE;
- if (gatherrpos == gatherwpos)
- /* Overrun. */
- gatherrpos = (gatherrpos + 1) % GATHERBUFSIZE;
- }
- *amount = datalen;
-
- if (datalen > 0 && read_blocked)
- {
- read_blocked = 0;
- pthread_cond_broadcast (&wait);
- pthread_cond_broadcast (&select_alert);
- }
-
- pthread_mutex_unlock (&global_lock);
- return 0;
-}
-
-/* Tell how much data can be read from the object without blocking for
- a "long time" (this should be the same meaning of "long time" used
- by the nonblocking flag. */
-kern_return_t
-trivfs_S_io_readable (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
- mach_msg_type_number_t *amount)
-{
- /* Deny access if they have bad credentials. */
- if (! cred)
- return EOPNOTSUPP;
- else if (! (cred->po->openmodes & O_READ))
- return EBADF;
-
- pthread_mutex_lock (&global_lock);
-
- /* XXX: Before initialization, the amount depends on the amount we
- want to read. Assume some medium value. */
- *amount = readable_pool (POOLSIZE/2, level);
-
- pthread_mutex_unlock (&global_lock);
-
- return 0;
-}
-
-/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
- Block until one of the indicated types of i/o can be done "quickly", and
- return the types that are then available. ID_TAG is returned as passed; it
- is just for the convenience of the user in matching up reply messages with
- specific requests sent. */
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int *type)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- /* We only deal with SELECT_READ and SELECT_WRITE here. */
- if (*type & ~(SELECT_READ | SELECT_WRITE))
- return EINVAL;
-
- if (*type == 0)
- return 0;
-
- pthread_mutex_lock (&global_lock);
-
- while (1)
- {
- /* XXX Before initialization, readable_pool depends on length. */
- int avail = readable_pool (POOLSIZE/2, level);
-
- if (avail != 0 || *type & SELECT_WRITE)
- {
- *type = (avail ? SELECT_READ : 0) | (*type & SELECT_WRITE);
- pthread_mutex_unlock (&global_lock);
- return 0;
- }
-
- ports_interrupt_self_on_port_death (cred, reply);
- read_blocked = 1;
-
- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
- {
- *type = 0;
- pthread_mutex_unlock (&global_lock);
- return EINTR;
- }
- }
-}
-
-
-/* Change current read/write offset */
-error_t
-trivfs_S_io_seek (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- loff_t offs, int whence, loff_t *new_offs)
-{
- if (! cred)
- return EOPNOTSUPP;
-
- /* Not seekable. */
- return ESPIPE;
-}
-
-/* Change the size of the file. If the size increases, new blocks are
- zero-filled. After successful return, it is safe to reference mapped
- areas of the file up to NEW_SIZE. */
-error_t
-trivfs_S_file_set_size (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- loff_t size)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- return size == 0 ? 0 : EINVAL;
-}
-
-/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
- O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
- will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
- I/O is done through io_async which is orthogonal to these calls. */
-error_t
-trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int mode)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- return 0;
-}
-
-error_t
-trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int bits)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- return 0;
-}
-
-error_t
-trivfs_S_io_get_owner (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- pid_t *owner)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- *owner = 0;
- return 0;
-}
-
-error_t
-trivfs_S_io_mod_owner (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- pid_t owner)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- return EINVAL;
-}
-
-/* Return objects mapping the data underlying this memory object. If
- the object can be read then memobjrd will be provided; if the
- object can be written then memobjwr will be provided. For objects
- where read data and write data are the same, these objects will be
- equal, otherwise they will be disjoint. Servers are permitted to
- implement io_map but not io_map_cntl. Some objects do not provide
- mapping; they will set none of the ports and return an error. Such
- objects can still be accessed by io_read and io_write. */
-error_t
-trivfs_S_io_map(struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- mach_port_t *rdobj,
- mach_msg_type_name_t *rdtype,
- mach_port_t *wrobj,
- mach_msg_type_name_t *wrtype)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- return EINVAL;
-}
-
-
-int
-random_demuxer (mach_msg_header_t *inp,
- mach_msg_header_t *outp)
-{
- extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
-
- return (trivfs_demuxer (inp, outp)
- || startup_notify_server (inp, outp));
-}
-
-
-/* Options processing. We accept the same options on the command line
- and from fsys_set_options. */
-
-static const struct argp_option options[] =
-{
- {"weak", 'w', 0, 0, "Output weak pseudo random data"},
- {"fast", 'f', 0, 0, "Output cheap random data fast"},
- {"secure", 's', 0, 0, "Output cryptographically secure random"},
- {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
- {0}
-};
-
-static error_t
-parse_opt (int opt, char *arg, struct argp_state *state)
-{
- switch (opt)
- {
- default:
- return ARGP_ERR_UNKNOWN;
- case ARGP_KEY_INIT:
- case ARGP_KEY_SUCCESS:
- case ARGP_KEY_ERROR:
- break;
-
- case 'w':
- {
- level = 0;
- break;
- }
- case 'f':
- {
- level = 1;
- break;
- }
- case 's':
- {
- level = 2;
- break;
- }
- case 'S':
- {
- seed_file = strdup (arg);
- set_random_seed_file (arg);
- }
- }
- return 0;
-}
-
-/* This will be called from libtrivfs to help construct the answer
- to an fsys_get_options RPC. */
-error_t
-trivfs_append_args (struct trivfs_control *fsys,
- char **argz, size_t *argz_len)
-{
- error_t err = 0;
- char *opt;
-
- pthread_mutex_lock (&global_lock);
- switch (level)
- {
- case 0:
- {
- opt = "--weak";
- break;
- }
- case 1:
- {
- opt = "--fast";
- break;
- }
- default:
- {
- opt = "--secure";
- break;
- }
- }
- if (level != DEFAULT_LEVEL)
- err = argz_add (argz, argz_len, opt);
-
- if (!err && seed_file)
- {
- if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
- err = ENOMEM;
- else
- {
- err = argz_add (argz, argz_len, opt);
- free (opt);
- }
- }
- pthread_mutex_unlock (&global_lock);
-
- return err;
-}
-
-static struct argp random_argp =
-{ options, parse_opt, 0,
- "A translator providing random output." };
-
-/* Setting this variable makes libtrivfs use our argp to
- parse options passed in an fsys_set_options RPC. */
-struct argp *trivfs_runtime_argp = &random_argp;
-
-struct port_class *shutdown_notify_class;
-
-/* The system is going down; destroy all the extant port rights. That
- will cause net channels and such to close promptly. */
-error_t
-S_startup_dosync (struct port_info *inpi)
-{
- if (!inpi)
- return EOPNOTSUPP;
-
- update_random_seed_file ();
- return 0;
-}
-
-void
-sigterm_handler (int signo)
-{
- update_random_seed_file ();
- signal (SIGTERM, SIG_DFL);
- raise (SIGTERM);
-}
-
-void
-arrange_shutdown_notification ()
-{
- error_t err;
- mach_port_t initport, notify;
- process_t procserver;
- struct port_info *pi;
-
- shutdown_notify_class = ports_create_class (0, 0);
-
- signal (SIGTERM, sigterm_handler);
-
- /* Arrange to get notified when the system goes down,
- but if we fail for some reason, just silently give up. No big deal. */
-
- err = ports_create_port (shutdown_notify_class, fsys->pi.bucket,
- sizeof (struct port_info), &pi);
- if (err)
- return;
-
- procserver = getproc ();
- if (!procserver)
- return;
-
- err = proc_getmsgport (procserver, 1, &initport);
- mach_port_deallocate (mach_task_self (), procserver);
- if (err)
- return;
-
- notify = ports_get_send_right (pi);
- ports_port_deref (pi);
- startup_request_notification (initport, notify,
- MACH_MSG_TYPE_MAKE_SEND,
- program_invocation_short_name);
- mach_port_deallocate (mach_task_self (), notify);
- mach_port_deallocate (mach_task_self (), initport);
-}
-
-
-int
-main (int argc, char **argv)
-{
- error_t err;
- mach_port_t bootstrap;
-
- /* Initialize the lock that will protect everything.
- We must do this before argp_parse, because parse_opt (above) will
- use the lock. */
- pthread_mutex_init (&global_lock, NULL);
-
- /* The conditions are used to implement proper read/select
- behaviour. */
- pthread_cond_init (&wait, NULL);
- pthread_cond_init (&select_alert, NULL);
-
- /* We use the same argp for options available at startup
- as for options we'll accept in an fsys_set_options RPC. */
- argp_parse (&random_argp, argc, argv, 0, 0, 0);
-
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (1, 0, "Must be started as a translator");
-
- /* Reply to our parent */
- err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
- mach_port_deallocate (mach_task_self (), bootstrap);
- if (err)
- error (3, err, "trivfs_startup");
-
- arrange_shutdown_notification ();
-
- /* Launch. */
- ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,
- 10 * 1000, /* idle thread */
- 10 * 60 * 1000, /* idle server */
- 0);
- return 0;
-}