zsh-workers
 help / color / mirror / code / Atom feed
From: Clinton Bunch <cdb_zsh@zentaur.org>
To: "zsh-workers@zsh.org" <zsh-workers@zsh.org>
Subject: preliminary patch for zsh/random module
Date: Sat, 22 Oct 2022 22:43:11 -0500	[thread overview]
Message-ID: <c5817309-e7db-686b-d9f2-29de96d503b9@zentaur.org> (raw)

It still needs testing on more platforms and additional error-checking 
as well as documentation, but I was hoping for some feedback on the 
general ideas.

diff --git a/Src/Modules/random.c b/Src/Modules/random.c
new file mode 100644
index 000000000..038a56c1f
--- /dev/null
+++ b/Src/Modules/random.c
@@ -0,0 +1,350 @@
+/*
+ * random.c - module to access kernel randome sources.
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2022 Clinton Bunch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Zoltán Hidvégi or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Zoltán Hidvégi and the Zsh Development Group have been 
advised of
+ * the possibility of such damage.
+ *
+ * Clinton Bunch and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Zoltán Hidvégi and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "random.mdh"
+#include "random.pro"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
+/* Simplify select URANDOM specific code */
+#if !defined(HAVE_ARC4RANDOM) && !defined(HAVE_GETRANDOM)
+#define USE_URANDOM
+#endif
+
+/* Define a buffer type for 32 bit integers */
+#ifdef UINT32_MAX
+typedef uint32_t zuint32;
+#else
+#define UINT32_MAX  UINT_MAX
+typedef unsigned int zuint32;
+#endif
+
+/* buffer to pre-load integers for SRANDOM to lessen the context 
switches */
+zuint32 rand_buff[8];
+static int buf_cnt = -1;
+
+#ifdef USE_URANDOM
+/* File descriptor for /dev/urandom */
+int randfd = -1;
+#endif /* USE_URANDOM */
+
+/*
+ *  Function takes an input buffer and converts the characters to hex and
+ *  places them in an outbut buffer twice the size. Returns -1 if it can't.
+ *  Returns the size of the output otherwise.
+ */
+
+/**/
+static int
+ztr_to_hex(char *out, size_t outlen, unsigned char *input, size_t inlen)
+{
+    int i = 0, j = 0;
+
+    if (outlen < (inlen * 2 + 1))
+    return -1;
+
+    for(i = 0, j = 0; i < inlen; i++, j+=2) {
+    if (j < outlen) {
+        sprintf((char *)(out + j),"%02X",input[i]);
+    } else {
+        return -1;
+    }
+    }
+    out[j]='\0';
+    return j;
+}
+
+/**/
+static int
+getrandom_buffer(void *buf, size_t len)
+{
+    int ret;
+
+#ifdef HAVE_ARC4RANDOM
+    arc4random_buf(buf,len);
+    ret = len;
+#elif defined(HAVE_GETRANDOM)
+    ret=getrandom(buf,len,0);
+#else
+    ret=read(randfd,buf,len);
+#endif
+    return ret;
+}
+
+/*
+ * Implements the getrandom builtin to return a string of random bytes of
+ * user-specified length.  It either prints them to stdout or returns them
+ * in a parameter passed on the command line.
+ *
+ */
+
+/**/
+static int
+bin_getrandom(char *name, char **argv, Options ops, int func)
+{
+
+    size_t len=8;
+    size_t byte_len=0, outlen;
+    int integer_out=0, i;
+    char int2str[11];  /*maximum string length of a 32-bit integer + 
null */
+
+    unsigned char *buf;
+    zuint32  *int_buf;
+    char *scalar = NULL, *arrname= NULL, *endptr, *len_arg, *outbuff;
+    char **array;
+
+    if (OPT_ISSET(ops, 's')) {
+    scalar = OPT_ARG(ops, 's');
+    if (!isident(scalar)) {
+        zwarnnam(name, "argument to -s not an identifier: %s", scalar);
+        return 1;
+    }
+    }
+
+    if (OPT_ISSET(ops,'a')) {
+    arrname = OPT_ARG(ops, 'a');
+    if (!isident(arrname)) {
+        zwarnnam(name,"argument to -a not an identifier: %s", arrname);
+        return 1;
+    }
+    }
+
+    if (OPT_ISSET(ops, 'i')) {
+    if (!OPT_ISSET(ops,'a')) {
+        zwarnnam(name,"-i requires -a");
+        return 1;
+    }
+    integer_out=1;
+    }
+
+    if (OPT_ISSET(ops, 'l')) {
+    errno = 0;
+
+    len_arg=OPT_ARG(ops, 'l');
+    len = strtoul(len_arg, &endptr, 10);
+    if (errno != 0) {
+        zwarnnam(name, "%s: %e", len_arg, errno);
+        return 1;
+    } else if (*len_arg == '\0' || *endptr != '\0') {
+        zwarnnam(name, "%s: invalid decimal number", len_arg);
+        return 1;
+    } else if (len > 64 || (integer_out && len > 16) || len <= 0) {
+        zwarnnam(name,"length must be between 1 and %d you specified: %d",
+            (integer_out?16:64), len);
+        return 1;
+    }
+
+    }
+
+    if (!byte_len)
+    byte_len = len;
+    if (integer_out)
+    byte_len = len*sizeof(zuint32);
+
+    buf = zalloc(byte_len);
+
+    if (getrandom_buffer(buf, byte_len) < 0) {
+    zwarnnam(name,"Couldn't get random data");
+    return 1;
+    }
+
+    if (OPT_ISSET(ops, 'r')) {
+    outbuff = (char *) buf;
+    outlen  = byte_len;
+    } else {
+    outlen=byte_len*2+1;
+    outbuff = (char*) zalloc(outlen);
+    ztr_to_hex(outbuff, outlen, buf, byte_len);
+    }
+
+    if (scalar) {
+    setsparam(scalar, metafy(outbuff, outlen, META_DUP));
+    }
+
+    if(arrname) {
+    array = (char **) zalloc((len+1)*sizeof(char *));
+    array[len] = NULL;
+
+    if(integer_out)
+        int_buf=(zuint32 *)buf;
+
+    for(i=0;i < len;i++) {
+        if(integer_out) {
+        sprintf(int2str,"%u",int_buf[i]);
+        } else {
+        sprintf(int2str,"%d",buf[i]);
+        }
+        array[i]=ztrdup(int2str);
+    }
+    setaparam(arrname,array);
+    }
+
+    if (!scalar && !arrname) {
+        fwrite(outbuff,1,outlen,stdout);
+        if (outbuff !=  (void *) buf) {
+        zfree(outbuff,outlen);
+    }
+    }
+
+
+    zfree(buf, len);
+    return 0;
+}
+
+
+
+/**/
+static zlong
+get_srandom(UNUSED(Param pm)) {
+
+    if(buf_cnt < 0) {
+    getrandom_buffer((void*) rand_buff,sizeof(rand_buff));
+    buf_cnt=7;
+    }
+    return rand_buff[buf_cnt--];
+}
+
+/**/
+static mnumber
+math_zrandom(UNUSED(char *name), UNUSED(int argc), UNUSED(mnumber *argv),
+         UNUSED(int id))
+{
+    mnumber ret;
+    uint32_t r;
+
+    r=get_srandom(NULL);
+    ret.type = MN_FLOAT;
+    ret.u.d = r/(UINT32_MAX+0.0);
+
+    return ret;
+}
+
+static struct builtin bintab[] = {
+    BUILTIN("getrandom", 0, bin_getrandom, 0, 5, 0, "ria:s:l:%", NULL),
+};
+
+static const struct gsu_integer srandom_gsu =
+{ get_srandom, nullintsetfn, stdunsetfn };
+
+static struct paramdef patab[] = {
+    SPECIALPMDEF("SRANDOM", PM_INTEGER|PM_READONLY, 
&srandom_gsu,NULL,NULL),
+};
+
+static struct mathfunc mftab[] = {
+    NUMMATHFUNC("zrandom", math_zrandom, 0, 0, 0),
+};
+
+static struct features module_features = {
+    bintab, sizeof(bintab)/sizeof(*bintab),
+    NULL, 0,
+    mftab, sizeof(mftab)/sizeof(*mftab),
+    patab, sizeof(patab)/sizeof(*patab),
+    0
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+#ifdef USE_URANDOM
+    struct stat st;
+
+    if (lstat("/dev/urandom",&st) < 0) {
+    zwarn("No kernel random pool found.");
+    return 1;
+    }
+
+    if (!(S_ISCHR(st.st_mode)) ) {
+    zwarn("No kernel random pool found.");
+    return 1;
+    }
+#endif /* USE_URANDOM */
+    return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+    *features = featuresarray(m, &module_features);
+    return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+    return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(Module m)
+{
+#ifdef USE_URANDOM
+    int tmpfd=-1;
+
+    if ((tmpfd = open("/dev/urandom", O_RDONLY)) < 0) {
+    zwarnnam("Could not access kernel random pool");
+    return 1;
+    }
+    randfd = movefd(tmpfd);
+    if (randfd < 0)
+    zwarnnam("Could not access kernel random pool");
+    return 1;
+    }
+#endif
+    return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+#ifdef USE_URANDOM
+    if (randfd >= 0)
+    zclose(randfd);
+#endif /* USE_URANDOM */
+    return 0;
+}
diff --git a/Src/Modules/random.mdd b/Src/Modules/random.mdd
new file mode 100644
index 000000000..3803a4533
--- /dev/null
+++ b/Src/Modules/random.mdd
@@ -0,0 +1,7 @@
+name=zsh/random
+link=either
+load=yes
+
+autofeatures="b:getrandom p:SRANDOM f:zrandom"
+
+objects="random.o"
diff --git a/configure.ac b/configure.ac
index 074141d38..f1fa01274 100644
--- a/configure.ac
+++ b/configure.ac
@@ -675,6 +675,7 @@ fi
  AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
           termios.h sys/param.h sys/filio.h string.h memory.h \
           limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
+                 sys/random.h \
           locale.h errno.h stdio.h stdarg.h varargs.h stdlib.h \
           unistd.h sys/capability.h \
           utmp.h utmpx.h sys/types.h pwd.h grp.h poll.h sys/mman.h \
@@ -1337,6 +1338,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
             cygwin_conv_path \
             nanosleep \
             srand_deterministic \
+               getrandom arc4random \
             setutxent getutxent endutxent getutent)
  AC_FUNC_STRCOLL




             reply	other threads:[~2022-10-23  3:44 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-23  3:43 Clinton Bunch [this message]
2022-10-24  2:01 ` Bart Schaefer
2022-10-24  2:56   ` Clinton Bunch
2022-10-24  4:47     ` Bart Schaefer
2022-10-24 13:20       ` Clinton Bunch
2022-10-24 21:15         ` Clinton Bunch

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c5817309-e7db-686b-d9f2-29de96d503b9@zentaur.org \
    --to=cdb_zsh@zentaur.org \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).