libbsd package (was Re: [PATCH] Do not use srand()/rand() if better alternatives exist)

View: New views
9 Messages — Rating Filter:   Alert me  

Parent Message unknown libbsd package (was Re: [PATCH] Do not use srand()/rand() if better alternatives exist)

by Thorsten Glaser-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mikael Berthe dixit:

>* Thorsten Glaser <tg@...> [2008-06-29 23:27 +0200]:
>> Hi!
>>
>> arc4random(3) is a self-seeding PRNG available on a lot of OSes (all BSDs,
>...
>> Debian with the new libbsd package installed
>
>I wanted to try but there's no such package!

Any progress on the libbsd package, now that licence issues are out
of the way? IIRC, plans were to get it ready for all arches in lenny?

10x,
//mirabilos
--
Sometimes they [people] care too much: pretty printers [and syntax highligh-
ting, d.A.] mechanically produce pretty output that accentuates irrelevant
detail in the program, which is as sensible as putting all the prepositions
in English text in bold font. -- Rob Pike in "Notes on Programming in C"


--
To UNSUBSCRIBE, email to debian-bsd-REQUEST@...
with a subject of "unsubscribe". Trouble? Contact listmaster@...


Re: libbsd package

by Thorsten Glaser-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Dixi:

>Any progress on the libbsd package, now that licence issues are out
>of the way? IIRC, plans were to get it ready for all arches in lenny?

There are more problems with the libbsd package:

• debian/copyright is incomplete (only mentions the FreeBSD files)

• src/fgetln.c can never work correctly:
  │      size_t nread = 0;
  │      while (nread == 1) {
  Find attached a working fgetln.c used in MirMake and FreeWRT GNU/Linux

• some files, like src/fmtcheck.c, can have BSDL clause 3 and 4 removed,
  see http://www.netbsd.org/changes/#2clause

• the MD5 code from RSA DSI can be replaced by a Public Domain implemen-
  tation, I think I already sent it to… someone here I don’t remember.
  Attached (replaces md5c.c and md5.copyright)

• I also attached the version of arc4random.c currently used by the mksh
  package for Debian, SuSE and Fedora/RHEL, as the FreeBSD version which
  is currently in libbsd trunk seems to be older

• I had already suggested including setmode/getmode, e.g. from the mksh
  source package (attached for convenience)

• In case someone is interested, I have a somewhat optimised strlcat(3)
  implementation… I'm building it with unifdef, generating 6 source files:
  ‣ unifdef -DHAVE_STRLCPY=0 -DHAVE_STRLCAT=1 strlfun.c >strlcpy.c
  ‣ unifdef -DHAVE_STRLCPY=1 -DHAVE_STRLCAT=0 strlfun.c >strlcat.c
  ‣ unifdef -DSTRXFRM strlfun.c >strxfrm.c
  ‣ unifdef -DHAVE_WCSLCPY=0 -DHAVE_WCSLCAT=1 wcslfun.c >wcslcpy.c
  ‣ unifdef -DHAVE_WCSLCPY=1 -DHAVE_WCSLCAT=0 wcslfun.c >wcslcat.c
  ‣ unifdef -DWCSXFRM wcslfun.c >wcsxfrm.c
  (of course, the strxfrm/wcsxfrm is only a stub, but okay according to
  the specs… strcoll becomes strcmp then)

I'm of course open to discussion and would like to help (even testing)
if I can, so that this will go into lenny.

//mirabilos
--
13:22⎜«neurodamage» mira, what's up man? I have a CVS question for you in #cvs
13:22⎜«neurodamage» since you're so good with it ☺
13:28⎜«neurodamage:#cvs» i love you
13:28⎜«neurodamage:#cvs» you're a handy guy to have around for systems stuff ☺
/* $MirOS: contrib/code/mirmake/dist/contrib/fgetln.c,v 1.3 2008/04/06 22:35:24 tg Exp $ */

/*-
 * Copyright (c) 2007
 * Thorsten Glaser <tg@...>
 *
 * Provided that these terms and disclaimer and all copyright notices
 * are retained or reproduced in an accompanying document, permission
 * is granted to deal in this work without restriction, including un-
 * limited rights to use, publicly perform, distribute, sell, modify,
 * merge, give away, or sublicence.
 *
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
 * the utmost extent permitted by applicable law, neither express nor
 * implied; without malicious intent or gross negligence. In no event
 * may a licensor, author or contributor be held liable for indirect,
 * direct, other damage, loss, or other issues arising in any way out
 * of dealing in the work, even if advised of the possibility of such
 * damage or existence of a defect, except proven that it results out
 * of said person's immediate fault when using the work as intended.
 *-
 * fgetln() wrapper for operating systems with getline()
 */

#define _GNU_SOURCE /* for getline() */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>

__RCSID("$MirOS: contrib/code/mirmake/dist/contrib/fgetln.c,v 1.3 2008/04/06 22:35:24 tg Exp $");

#if !defined(_MIRMAKE_H) || !defined(_MIRMAKE_DEFNS)
char *fgetln(FILE *, size_t *);
#endif

char *
fgetln(FILE *stream, size_t *len)
{
        char *lb = NULL;
        size_t lbsz = 0;

        *len = getline(&lb, &lbsz, stream);
        return ((*len == (size_t)-1) ? NULL : lb);
}

/* $MirOS: contrib/code/Snippets/arc4random.c,v 1.3 2008/03/04 22:53:14 tg Exp $ */

/*-
 * Arc4 random number generator for OpenBSD.
 * Copyright 1996 David Mazieres <dm@...>.
 *
 * Modification and redistribution in source and binary forms is
 * permitted provided that due credit is given to the author and the
 * OpenBSD project by leaving this copyright notice intact.
 */

/*-
 * This code is derived from section 17.1 of Applied Cryptography,
 * second edition, which describes a stream cipher allegedly
 * compatible with RSA Labs "RC4" cipher (the actual description of
 * which is a trade secret).  The same algorithm is used as a stream
 * cipher called "arcfour" in Tatu Ylonen's ssh package.
 *
 * Here the stream cipher has been modified always to include the time
 * when initializing the state.  That makes it impossible to
 * regenerate the same random sequence twice, so this can't be used
 * for encryption, but will generate good random numbers.
 *
 * RC4 is a registered trademark of RSA Laboratories.
 */

/*-
 * Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
 * This is arc4random(3) using urandom.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#if HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#include <fcntl.h>
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct arc4_stream {
        uint8_t i;
        uint8_t j;
        uint8_t s[256];
};

static int rs_initialized;
static struct arc4_stream rs;
static pid_t arc4_stir_pid;

static uint8_t arc4_getbyte(struct arc4_stream *);

u_int32_t arc4random(void);
void arc4random_addrandom(u_char *, int);
void arc4random_stir(void);

static void
arc4_init(struct arc4_stream *as)
{
        int     n;

        for (n = 0; n < 256; n++)
                as->s[n] = n;
        as->i = 0;
        as->j = 0;
}

static void
arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
{
        int     n;
        uint8_t si;

        as->i--;
        for (n = 0; n < 256; n++) {
                as->i = (as->i + 1);
                si = as->s[as->i];
                as->j = (as->j + si + dat[n % datlen]);
                as->s[as->i] = as->s[as->j];
                as->s[as->j] = si;
        }
        as->j = as->i;
}

static void
arc4_stir(struct arc4_stream *as)
{
        int     n, fd;
        struct {
                struct timeval tv;
                u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
        } rdat;
        size_t sz = 0;

        gettimeofday(&rdat.tv, NULL);

        /* /dev/urandom is a multithread interface, sysctl is not. */
        /* Try to use /dev/urandom before sysctl. */
        fd = open("/dev/urandom", O_RDONLY);
        if (fd != -1) {
                sz = (size_t)read(fd, rdat.rnd, sizeof (rdat.rnd));
                close(fd);
        }
        if (sz > sizeof (rdat.rnd))
                sz = 0;
        if (fd == -1 || sz != sizeof (rdat.rnd)) {
                /* /dev/urandom failed? Maybe we're in a chroot. */
//#if defined(CTL_KERN) && defined(KERN_RANDOM) && defined(RANDOM_UUID)
#ifdef _LINUX_SYSCTL_H
                /* XXX this is for Linux, which uses enums */

                int mib[3];
                size_t i = sz / sizeof (u_int), len;

                mib[0] = CTL_KERN;
                mib[1] = KERN_RANDOM;
                mib[2] = RANDOM_UUID;

                while (i < sizeof (rdat.rnd) / sizeof (u_int)) {
                        len = sizeof(u_int);
                        if (sysctl(mib, 3, &rdat.rnd[i++], &len, NULL, 0) == -1) {
                                fprintf(stderr, "warning: no entropy source\n");
                                break;
                        }
                }
#else
                /* XXX kFreeBSD doesn't seem to have KERN_ARND or so */
                ;
#endif
        }

        arc4_stir_pid = getpid();
        /*
         * Time to give up. If no entropy could be found then we will just
         * use gettimeofday.
         */
        arc4_addrandom(as, (void *)&rdat, sizeof(rdat));

        /*
         * Discard early keystream, as per recommendations in:
         * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
         * We discard 256 words. A long word is 4 bytes.
         */
        for (n = 0; n < 256 * 4; n ++)
                arc4_getbyte(as);
}

static uint8_t
arc4_getbyte(struct arc4_stream *as)
{
        uint8_t si, sj;

        as->i = (as->i + 1);
        si = as->s[as->i];
        as->j = (as->j + si);
        sj = as->s[as->j];
        as->s[as->i] = sj;
        as->s[as->j] = si;
        return (as->s[(si + sj) & 0xff]);
}

static uint32_t
arc4_getword(struct arc4_stream *as)
{
        uint32_t val;
        val = arc4_getbyte(as) << 24;
        val |= arc4_getbyte(as) << 16;
        val |= arc4_getbyte(as) << 8;
        val |= arc4_getbyte(as);
        return val;
}

void
arc4random_stir(void)
{
        if (!rs_initialized) {
                arc4_init(&rs);
                rs_initialized = 1;
        }
        arc4_stir(&rs);
}

void
arc4random_addrandom(u_char *dat, int datlen)
{
        if (!rs_initialized)
                arc4random_stir();
        arc4_addrandom(&rs, dat, datlen);
}

u_int32_t
arc4random(void)
{
        if (!rs_initialized || arc4_stir_pid != getpid())
                arc4random_stir();
        return arc4_getword(&rs);
}

/* $OpenBSD: md5.c,v 1.8 2005/08/08 08:05:35 espie Exp $ */

/*
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest. This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
 *
 * Equivalent code is available from RSA Data Security, Inc.
 * This code has been tested against that, and is equivalent,
 * except that you don't need to include two pages of legalese
 * with every copy.
 *
 * To compute the message digest of a chunk of bytes, declare an
 * MD5Context structure, pass it to MD5Init, call MD5Update as
 * needed on buffers full of bytes, and then call MD5Final, which
 * will fill a supplied 16-byte array with the digest.
 */

#include <sys/types.h>
#include <string.h>
#include <md5.h>

#define PUT_64BIT_LE(cp, value) do { \
        (cp)[7] = (value) >> 56; \
        (cp)[6] = (value) >> 48; \
        (cp)[5] = (value) >> 40; \
        (cp)[4] = (value) >> 32; \
        (cp)[3] = (value) >> 24; \
        (cp)[2] = (value) >> 16; \
        (cp)[1] = (value) >> 8; \
        (cp)[0] = (value); } while (0)

#define PUT_32BIT_LE(cp, value) do { \
        (cp)[3] = (value) >> 24; \
        (cp)[2] = (value) >> 16; \
        (cp)[1] = (value) >> 8; \
        (cp)[0] = (value); } while (0)

static u_int8_t PADDING[MD5_BLOCK_LENGTH] = {
        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
void
MD5Init(MD5_CTX *ctx)
{
        ctx->count = 0;
        ctx->state[0] = 0x67452301;
        ctx->state[1] = 0xefcdab89;
        ctx->state[2] = 0x98badcfe;
        ctx->state[3] = 0x10325476;
}

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
void
MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
{
        size_t have, need;

        /* Check how many bytes we already have and how many more we need. */
        have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
        need = MD5_BLOCK_LENGTH - have;

        /* Update bitcount */
        ctx->count += (u_int64_t)len << 3;

        if (len >= need) {
                if (have != 0) {
                        memcpy(ctx->buffer + have, input, need);
                        MD5Transform(ctx->state, ctx->buffer);
                        input += need;
                        len -= need;
                        have = 0;
                }

                /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
                while (len >= MD5_BLOCK_LENGTH) {
                        MD5Transform(ctx->state, input);
                        input += MD5_BLOCK_LENGTH;
                        len -= MD5_BLOCK_LENGTH;
                }
        }

        /* Handle any remaining bytes of data. */
        if (len != 0)
                memcpy(ctx->buffer + have, input, len);
}

/*
 * Pad pad to 64-byte boundary with the bit pattern
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
void
MD5Pad(MD5_CTX *ctx)
{
        u_int8_t count[8];
        size_t padlen;

        /* Convert count to 8 bytes in little endian order. */
        PUT_64BIT_LE(count, ctx->count);

        /* Pad out to 56 mod 64. */
        padlen = MD5_BLOCK_LENGTH -
            ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
        if (padlen < 1 + 8)
                padlen += MD5_BLOCK_LENGTH;
        MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
        MD5Update(ctx, count, 8);
}

/*
 * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
 */
void
MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
{
        int i;

        MD5Pad(ctx);
        if (digest != NULL) {
                for (i = 0; i < 4; i++)
                        PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
                memset(ctx, 0, sizeof(*ctx));
        }
}


/* The four core functions - F1 is optimized somewhat */

/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
void
MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH])
{
        u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];

#if BYTE_ORDER == LITTLE_ENDIAN
        memcpy(in, block, sizeof(in));
#else
        for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
                in[a] = (u_int32_t)(
                    (u_int32_t)(block[a * 4 + 0]) |
                    (u_int32_t)(block[a * 4 + 1]) <<  8 |
                    (u_int32_t)(block[a * 4 + 2]) << 16 |
                    (u_int32_t)(block[a * 4 + 3]) << 24);
        }
#endif

        a = state[0];
        b = state[1];
        c = state[2];
        d = state[3];

        MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
        MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
        MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
        MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
        MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
        MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
        MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
        MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
        MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
        MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
        MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
        MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
        MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
        MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
        MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
        MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

        MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
        MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
        MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
        MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
        MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
        MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
        MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
        MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
        MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
        MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
        MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
        MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
        MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
        MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
        MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
        MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

        MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
        MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
        MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
        MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
        MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
        MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
        MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
        MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
        MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
        MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
        MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
        MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
        MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
        MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
        MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
        MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);

        MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
        MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
        MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
        MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
        MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
        MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
        MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
        MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
        MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f,  6);
        MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
        MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
        MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
        MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82,  6);
        MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
        MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
        MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;
}

/*-
 * Copyright (c) 2006, 2008
 * Thorsten Glaser <tg@...>
 *
 * Provided that these terms and disclaimer and all copyright notices
 * are retained or reproduced in an accompanying document, permission
 * is granted to deal in this work without restriction, including un-
 * limited rights to use, publicly perform, distribute, sell, modify,
 * merge, give away, or sublicence.
 *
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
 * the utmost extent permitted by applicable law, neither express nor
 * implied; without malicious intent or gross negligence. In no event
 * may a licensor, author or contributor be held liable for indirect,
 * direct, other damage, loss, or other issues arising in any way out
 * of dealing in the work, even if advised of the possibility of such
 * damage or existence of a defect, except proven that it results out
 * of said person's immediate fault when using the work as intended.
 *-
 * The original implementations of strlcpy(3) and strlcat(3) are from
 * Todd C. Miller; the licence is reproduced below. However, this ap-
 * plies only to the strlcpy(3) portion of the code, as Thorsten Gla-
 * ser write the following strlcat(3) implementation according to the
 * spec. Both functions below have been optimised according to sugge-
 * stions from Bodo Eggert. Thorsten Glaser also has merged this code
 * with strxfrm(3) for ISO-10646-only systems and wrote the wide char
 * variants wcslcat(3), wcslcpy(3), and wcsxfrm(3) (see wcslfun.c).
 */

#ifdef STRXFRM
#undef HAVE_STRLCPY
#undef HAVE_STRLCAT
#define HAVE_STRLCPY 0
#define HAVE_STRLCAT 1
#define strlcpy strxfrm
#endif

#include <sys/types.h>
#if defined(_KERNEL) || defined(_STANDALONE)
#include <lib/libkern/libkern.h>
#undef HAVE_STRLCPY
#undef HAVE_STRLCAT
#else
#include <stddef.h> /* for size_t in user space (SUSv3) */
#if defined(HAVE_CONFIG_H) && (HAVE_CONFIG_H != 0)
/* usually when packaged with third-party software */
#ifdef CONFIG_H_FILENAME
#include CONFIG_H_FILENAME
#else
#include "config.h"
#endif
#endif
/* do not include <string.h> to prevent redefinition warnings */
extern size_t strlen(const char *);
#endif

#ifndef __RCSID
#undef __IDSTRING
#undef __IDSTRING_CONCAT
#undef __IDSTRING_EXPAND
#define __IDSTRING_CONCAT(l,p) __LINTED__ ## l ## _ ## p
#define __IDSTRING_EXPAND(l,p) __IDSTRING_CONCAT(l,p)
#define __IDSTRING(prefix, string) \
        static const char __IDSTRING_EXPAND(__LINE__,prefix) [] \
            __attribute__((used)) = "@(""#)" #prefix ": " string
#define __RCSID(x) __IDSTRING(rcsid,x)
#endif

#ifndef __predict_true
#define __predict_true(exp) ((exp) != 0)
#endif
#ifndef __predict_false
#define __predict_false(exp) ((exp) != 0)
#endif

#if !defined(_KERNEL) && !defined(_STANDALONE)
__RCSID("$MirOS: src/lib/libc/string/strlfun.c,v 1.16 2008/07/07 12:59:51 tg Stab $");
#endif

/* (multibyte) string functions */
#undef NUL
#undef char_t
#define NUL '\0'
#define char_t char

size_t strlcat(char_t *, const char_t *, size_t);
size_t strlcpy(char_t *, const char_t *, size_t);

#if !defined(HAVE_STRLCAT) || (HAVE_STRLCAT == 0)
/*
 * Appends src to string dst of size dlen (unlike strncat, dlen is the
 * full size of dst, not space left).  At most dlen-1 characters
 * will be copied.  Always NUL terminates (unless dlen <= strlen(dst)).
 * Returns strlen(src) + MIN(dlen, strlen(initial dst)), without the
 * trailing NUL byte counted.  If retval >= dlen, truncation occurred.
 */
size_t
strlcat(char_t *dst, const char_t *src, size_t dlen)
{
        size_t n = 0, slen;

        slen = strlen(src);
        while (__predict_true(n + 1 < dlen && dst[n] != NUL))
                ++n;
        if (__predict_false(dlen == 0 || dst[n] != NUL))
                return (dlen + slen);
        while (__predict_true((slen > 0) && (n < (dlen - 1)))) {
                dst[n++] = *src++;
                --slen;
        }
        dst[n] = NUL;
        return (n + slen);
}
#endif /* !HAVE_STRLCAT */

#if !defined(HAVE_STRLCPY) || (HAVE_STRLCPY == 0)
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */

/*-
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@...>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Copy src to string dst of size siz.  At most siz-1 characters
 * will be copied.  Always NUL terminates (unless siz == 0).
 * Returns strlen(src); if retval >= siz, truncation occurred.
 */
size_t
strlcpy(char_t *dst, const char_t *src, size_t siz)
{
        const char_t *s = src;

        if (__predict_false(siz == 0))
                goto traverse_src;

        /* copy as many chars as will fit */
        while (--siz && (*dst++ = *s++))
                ;

        /* not enough room in dst */
        if (__predict_false(siz == 0)) {
                /* safe to NUL-terminate dst since we copied <= siz-1 chars */
                *dst = NUL;
 traverse_src:
                /* traverse rest of src */
                while (*s++)
                        ;
        }

        /* count does not include NUL */
        return (s - src - 1);
}
#endif /* !HAVE_STRLCPY */

/*-
 * Copyright (c) 2006, 2008
 * Thorsten Glaser <tg@...>
 *
 * Provided that these terms and disclaimer and all copyright notices
 * are retained or reproduced in an accompanying document, permission
 * is granted to deal in this work without restriction, including un-
 * limited rights to use, publicly perform, distribute, sell, modify,
 * merge, give away, or sublicence.
 *
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
 * the utmost extent permitted by applicable law, neither express nor
 * implied; without malicious intent or gross negligence. In no event
 * may a licensor, author or contributor be held liable for indirect,
 * direct, other damage, loss, or other issues arising in any way out
 * of dealing in the work, even if advised of the possibility of such
 * damage or existence of a defect, except proven that it results out
 * of said person's immediate fault when using the work as intended.
 *-
 * The original implementations of strlcpy(3) and strlcat(3) are from
 * Todd C. Miller; the licence is reproduced below. However, this ap-
 * plies only to the strlcpy(3) portion of the code, as Thorsten Gla-
 * ser write the following strlcat(3) implementation according to the
 * spec. Both functions below have been optimised according to sugge-
 * stions from Bodo Eggert. Thorsten Glaser also has merged this code
 * with strxfrm(3) for ISO-10646-only systems and wrote the wide char
 * variants wcslcat(3), wcslcpy(3), and wcsxfrm(3) (see wcslfun.c).
 */

#ifdef WCSXFRM
#undef HAVE_WCSLCPY
#undef HAVE_WCSLCAT
#define HAVE_WCSLCPY 0
#define HAVE_WCSLCAT 1
#define wcslcpy wcsxfrm
#endif

#include <sys/types.h>
#include <wchar.h>

#ifndef __RCSID
#undef __IDSTRING
#undef __IDSTRING_CONCAT
#undef __IDSTRING_EXPAND
#define __IDSTRING_CONCAT(l,p) __LINTED__ ## l ## _ ## p
#define __IDSTRING_EXPAND(l,p) __IDSTRING_CONCAT(l,p)
#define __IDSTRING(prefix, string) \
        static const char __IDSTRING_EXPAND(__LINE__,prefix) [] \
            __attribute__((used)) = "@(""#)" #prefix ": " string
#define __RCSID(x) __IDSTRING(rcsid,x)
#endif

#ifndef __predict_true
#define __predict_true(exp) ((exp) != 0)
#endif
#ifndef __predict_false
#define __predict_false(exp) ((exp) != 0)
#endif

#if !defined(_KERNEL) && !defined(_STANDALONE)
__RCSID("$MirOS: src/lib/libc/string/wcslfun.c,v 1.9 2008/07/07 12:59:52 tg Stab $");
__RCSID("$miros: src/lib/libc/string/strlfun.c,v 1.16 2008/07/07 12:59:51 tg Stab $");
#endif

/* wide character string functions */
#undef NUL
#undef char_t
#define NUL L'\0'
#define char_t wchar_t
#define strlen wcslen
#define strlcat wcslcat
#define strlcpy wcslcpy

#if !defined(HAVE_WCSLCAT) || (HAVE_WCSLCAT == 0)
/*
 * Appends src to wide string dst of size dlen (unlike wcsncat, dlen is the
 * full size of dst, not space left).  At most dlen-1 wide characters
 * will be copied.  Always NUL terminates (unless dlen <= wcslen(dst)).
 * Returns wcslen(src) + MIN(dlen, wcslen(initial dst)), without the
 * trailing wide NUL counted.  If retval >= dlen, truncation occurred.
 */
size_t
strlcat(char_t *dst, const char_t *src, size_t dlen)
{
        size_t n = 0, slen;

        slen = strlen(src);
        while (__predict_true(n + 1 < dlen && dst[n] != NUL))
                ++n;
        if (__predict_false(dlen == 0 || dst[n] != NUL))
                return (dlen + slen);
        while (__predict_true((slen > 0) && (n < (dlen - 1)))) {
                dst[n++] = *src++;
                --slen;
        }
        dst[n] = NUL;
        return (n + slen);
}
#endif /* !HAVE_WCSLCAT */

#if !defined(HAVE_WCSLCPY) || (HAVE_WCSLCPY == 0)
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */

/*-
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@...>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Copy src to wide string dst of size siz.  At most siz-1 wide characters
 * will be copied.  Always NUL terminates (unless siz == 0).
 * Returns wcslen(src); if retval >= siz, truncation occurred.
 */
size_t
strlcpy(char_t *dst, const char_t *src, size_t siz)
{
        const char_t *s = src;

        if (__predict_false(siz == 0))
                goto traverse_src;

        /* copy as many wide chars as will fit */
        while (--siz && (*dst++ = *s++))
                ;

        /* not enough room in dst */
        if (__predict_false(siz == 0)) {
                /* safe to NUL-terminate dst since we copied <= siz-1 wchars */
                *dst = NUL;
 traverse_src:
                /* traverse rest of src */
                while (*s++)
                        ;
        }

        /* count does not include NUL */
        return (s - src - 1);
}
#endif /* !HAVE_WCSLCPY */

/** $MirOS: src/bin/mksh/setmode.c,v 1.11 2008/04/19 22:15:05 tg Exp $ */
/* $OpenBSD: setmode.c,v 1.17 2005/08/08 08:05:34 espie Exp $ */
/* $NetBSD: setmode.c,v 1.15 1997/02/07 22:21:06 christos Exp $ */

/*
 * Copyright (c) 1989, 1993, 1994
 * The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Dave Borman at Cray Research, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if defined(HAVE_CONFIG_H) && (HAVE_CONFIG_H != 0)
/* usually when packaged with third-party software */
#ifdef CONFIG_H_FILENAME
#include CONFIG_H_FILENAME
#else
#include "config.h"
#endif
#endif

#include <sys/types.h>
#include <sys/stat.h>

#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef SETMODE_DEBUG
#include <stdio.h>
#endif

__SCCSID("@(#)setmode.c 8.2 (Berkeley) 3/25/94");
__RCSID("$MirOS: src/bin/mksh/setmode.c,v 1.11 2008/04/19 22:15:05 tg Exp $");
__RCSID("$miros: src/lib/libc/gen/setmode.c,v 1.10 2008/04/19 16:27:23 tg Exp $");

/* for mksh */
#ifdef ksh_isdigit
#undef isdigit
#define isdigit ksh_isdigit
#endif

#ifndef S_ISTXT
#define S_ISTXT 0001000
#endif

#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */

typedef struct bitcmd {
        char cmd;
        char cmd2;
        mode_t bits;
} BITCMD;

#define CMD2_CLR 0x01
#define CMD2_SET 0x02
#define CMD2_GBITS 0x04
#define CMD2_OBITS 0x08
#define CMD2_UBITS 0x10

static BITCMD *addcmd(BITCMD *, int, int, int, unsigned int);
static void compress_mode(BITCMD *);
#ifdef SETMODE_DEBUG
static void dumpmode(BITCMD *);
#endif

/*
 * Given the old mode and an array of bitcmd structures, apply the operations
 * described in the bitcmd structures to the old mode, and return the new mode.
 * Note that there is no '=' command; a strict assignment is just a '-' (clear
 * bits) followed by a '+' (set bits).
 */
mode_t
getmode(const void *bbox, mode_t omode)
{
        const BITCMD *set;
        mode_t clrval, newmode, value;

        set = (const BITCMD *)bbox;
        newmode = omode;
        for (value = 0;; set++)
                switch(set->cmd) {
                /*
                 * When copying the user, group or other bits around, we "know"
                 * where the bits are in the mode so that we can do shifts to
                 * copy them around.  If we don't use shifts, it gets real
                 * grundgy with lots of single bit checks and bit sets.
                 */
                case 'u':
                        value = (newmode & S_IRWXU) >> 6;
                        goto common;

                case 'g':
                        value = (newmode & S_IRWXG) >> 3;
                        goto common;

                case 'o':
                        value = newmode & S_IRWXO;
 common:
                        if (set->cmd2 & CMD2_CLR) {
                                clrval =
                                    (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
                                if (set->cmd2 & CMD2_UBITS)
                                        newmode &= ~((clrval<<6) & set->bits);
                                if (set->cmd2 & CMD2_GBITS)
                                        newmode &= ~((clrval<<3) & set->bits);
                                if (set->cmd2 & CMD2_OBITS)
                                        newmode &= ~(clrval & set->bits);
                        }
                        if (set->cmd2 & CMD2_SET) {
                                if (set->cmd2 & CMD2_UBITS)
                                        newmode |= (value<<6) & set->bits;
                                if (set->cmd2 & CMD2_GBITS)
                                        newmode |= (value<<3) & set->bits;
                                if (set->cmd2 & CMD2_OBITS)
                                        newmode |= value & set->bits;
                        }
                        break;

                case '+':
                        newmode |= set->bits;
                        break;

                case '-':
                        newmode &= ~set->bits;
                        break;

                case 'X':
                        if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
                                newmode |= set->bits;
                        break;

                case '\0':
                default:
#ifdef SETMODE_DEBUG
                        (void)printf("getmode:%04o -> %04o\n", omode, newmode);
#endif
                        return (newmode);
                }
}

#define ADDCMD(a, b, c, d) \
        if (set >= endset) { \
                BITCMD *newset; \
                setlen += SET_LEN_INCR; \
                newset = realloc(saveset, sizeof(BITCMD) * setlen); \
                if (newset == NULL) { \
                        free(saveset); \
                        return (NULL); \
                } \
                set = newset + (set - saveset); \
                saveset = newset; \
                endset = newset + (setlen - 2); \
        } \
        set = addcmd(set, (a), (b), (c), (d))

#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)

void *
setmode(const char *p)
{
        int perm, who;
        char op, *ep;
        BITCMD *set, *saveset, *endset;
        sigset_t signset, sigoset;
        mode_t mask;
        int equalopdone = 0, permXbits, setlen;
        unsigned long perml;

        if (!*p)
                return (NULL);

        /*
         * Get a copy of the mask for the permissions that are mask relative.
         * Flip the bits, we want what's not set.  Since it's possible that
         * the caller is opening files inside a signal handler, protect them
         * as best we can.
         */
        sigfillset(&signset);
        (void)sigprocmask(SIG_BLOCK, &signset, &sigoset);
        (void)umask(mask = umask(0));
        mask = ~mask;
        (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);

        setlen = SET_LEN + 2;

        if ((set = calloc(sizeof(BITCMD), setlen)) == NULL)
                return (NULL);
        saveset = set;
        endset = set + (setlen - 2);

        /*
         * If an absolute number, get it and return; disallow non-octal digits
         * or illegal bits.
         */
        if (isdigit((unsigned char)*p)) {
                perml = strtoul(p, &ep, 8);
                /* The test on perml will also catch overflow. */
                if (*ep != '\0' || (perml & ~(STANDARD_BITS|S_ISTXT))) {
                        free(saveset);
                        errno = ERANGE;
                        return (NULL);
                }
                perm = (mode_t)perml;
                ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
                set->cmd = 0;
                return (saveset);
        }

        /*
         * Build list of structures to set/clear/copy bits as described by
         * each clause of the symbolic mode.
         */
        for (;;) {
                /* First, find out which bits might be modified. */
                for (who = 0;; ++p) {
                        switch (*p) {
                        case 'a':
                                who |= STANDARD_BITS;
                                break;
                        case 'u':
                                who |= S_ISUID|S_IRWXU;
                                break;
                        case 'g':
                                who |= S_ISGID|S_IRWXG;
                                break;
                        case 'o':
                                who |= S_IRWXO;
                                break;
                        default:
                                goto getop;
                        }
                }

 getop:
                if ((op = *p++) != '+' && op != '-' && op != '=') {
                        free(saveset);
                        return (NULL);
                }
                if (op == '=')
                        equalopdone = 0;

                who &= ~S_ISTXT;
                for (perm = 0, permXbits = 0;; ++p) {
                        switch (*p) {
                        case 'r':
                                perm |= S_IRUSR|S_IRGRP|S_IROTH;
                                break;
                        case 's':
                                /*
                                 * If specific bits where requested and
                                 * only "other" bits ignore set-id.
                                 */
                                if (who == 0 || (who & ~S_IRWXO))
                                        perm |= S_ISUID|S_ISGID;
                                break;
                        case 't':
                                /*
                                 * If specific bits where requested and
                                 * only "other" bits ignore sticky.
                                 */
                                if (who == 0 || (who & ~S_IRWXO)) {
                                        who |= S_ISTXT;
                                        perm |= S_ISTXT;
                                }
                                break;
                        case 'w':
                                perm |= S_IWUSR|S_IWGRP|S_IWOTH;
                                break;
                        case 'X':
                                permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
                                break;
                        case 'x':
                                perm |= S_IXUSR|S_IXGRP|S_IXOTH;
                                break;
                        case 'u':
                        case 'g':
                        case 'o':
                                /*
                                 * When ever we hit 'u', 'g', or 'o', we have
                                 * to flush out any partial mode that we have,
                                 * and then do the copying of the mode bits.
                                 */
                                if (perm) {
                                        ADDCMD(op, who, perm, mask);
                                        perm = 0;
                                }
                                if (op == '=')
                                        equalopdone = 1;
                                if (op == '+' && permXbits) {
                                        ADDCMD('X', who, permXbits, mask);
                                        permXbits = 0;
                                }
                                ADDCMD(*p, who, op, mask);
                                break;

                        default:
                                /*
                                 * Add any permissions that we haven't already
                                 * done.
                                 */
                                if (perm || (op == '=' && !equalopdone)) {
                                        if (op == '=')
                                                equalopdone = 1;
                                        ADDCMD(op, who, perm, mask);
                                        perm = 0;
                                }
                                if (permXbits) {
                                        ADDCMD('X', who, permXbits, mask);
                                        permXbits = 0;
                                }
                                goto apply;
                        }
                }

 apply:
                if (!*p)
                        break;
                if (*p != ',')
                        goto getop;
                ++p;
        }
        set->cmd = 0;
#ifdef SETMODE_DEBUG
        (void)printf("Before compress_mode()\n");
        dumpmode(saveset);
#endif
        compress_mode(saveset);
#ifdef SETMODE_DEBUG
        (void)printf("After compress_mode()\n");
        dumpmode(saveset);
#endif
        return (saveset);
}

static BITCMD *
addcmd(BITCMD *set, int op, int who, int oparg, unsigned int mask)
{
        switch (op) {
        case '=':
                set->cmd = '-';
                set->bits = who ? who : STANDARD_BITS;
                set++;

                op = '+';
                /* FALLTHROUGH */
        case '+':
        case '-':
        case 'X':
                set->cmd = op;
                set->bits = (who ? who : (int)mask) & oparg;
                break;

        case 'u':
        case 'g':
        case 'o':
                set->cmd = op;
                if (who) {
                        set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
                                    ((who & S_IRGRP) ? CMD2_GBITS : 0) |
                                    ((who & S_IROTH) ? CMD2_OBITS : 0);
                        set->bits = (mode_t)~0;
                } else {
                        set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
                        set->bits = mask;
                }

                if (oparg == '+')
                        set->cmd2 |= CMD2_SET;
                else if (oparg == '-')
                        set->cmd2 |= CMD2_CLR;
                else if (oparg == '=')
                        set->cmd2 |= CMD2_SET|CMD2_CLR;
                break;
        }
        return (set + 1);
}

#ifdef SETMODE_DEBUG
static void
dumpmode(BITCMD *set)
{
        for (; set->cmd; ++set)
                (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
                    set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
                    set->cmd2 & CMD2_CLR ? " CLR" : "",
                    set->cmd2 & CMD2_SET ? " SET" : "",
                    set->cmd2 & CMD2_UBITS ? " UBITS" : "",
                    set->cmd2 & CMD2_GBITS ? " GBITS" : "",
                    set->cmd2 & CMD2_OBITS ? " OBITS" : "");
}
#endif

/*
 * Given an array of bitcmd structures, compress by compacting consecutive
 * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
 * 'g' and 'o' commands continue to be separate.  They could probably be
 * compacted, but it's not worth the effort.
 */
static void
compress_mode(BITCMD *set)
{
        BITCMD *nset;
        int setbits, clrbits, Xbits, op;

        for (nset = set;;) {
                /* Copy over any 'u', 'g' and 'o' commands. */
                while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
                        *set++ = *nset++;
                        if (!op)
                                return;
                }

                for (setbits = clrbits = Xbits = 0;; nset++) {
                        if ((op = nset->cmd) == '-') {
                                clrbits |= nset->bits;
                                setbits &= ~nset->bits;
                                Xbits &= ~nset->bits;
                        } else if (op == '+') {
                                setbits |= nset->bits;
                                clrbits &= ~nset->bits;
                                Xbits &= ~nset->bits;
                        } else if (op == 'X')
                                Xbits |= nset->bits & ~setbits;
                        else
                                break;
                }
                if (clrbits) {
                        set->cmd = '-';
                        set->cmd2 = 0;
                        set->bits = clrbits;
                        set++;
                }
                if (setbits) {
                        set->cmd = '+';
                        set->cmd2 = 0;
                        set->bits = setbits;
                        set++;
                }
                if (Xbits) {
                        set->cmd = 'X';
                        set->cmd2 = 0;
                        set->bits = Xbits;
                        set++;
                }
        }
}

Re: libbsd package

by Thorsten Glaser-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Dixi:

>• I also attached the version of arc4random.c currently used by the mksh
>  package for Debian, SuSE and Fedora/RHEL, as the FreeBSD version which
>  is currently in libbsd trunk seems to be older

This is the more interesting as the version currently used by you only
exposes part of the standardised interface: only arc4random(), but not,
for instance, arc4random_addrandom(), which should be usable by apps too.
(In fact, I just wrote something intended to use it, again.)

bye,
//mirabilos
--
Sometimes they [people] care too much: pretty printers [and syntax highligh-
ting, d.A.] mechanically produce pretty output that accentuates irrelevant
detail in the program, which is as sensible as putting all the prepositions
in English text in bold font. -- Rob Pike in "Notes on Programming in C"


--
To UNSUBSCRIBE, email to debian-bsd-REQUEST@...
with a subject of "unsubscribe". Trouble? Contact listmaster@...


Re: libbsd package

by Florian Weimer :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

* Thorsten Glaser:

> Any progress on the libbsd package, now that licence issues are out
> of the way? IIRC, plans were to get it ready for all arches in lenny?

We need a thread-safe version of something like arc4random as an element
for various security patches (which will target etch).  Shall we
back-port libbsd as a whole, or should we just spin a separate library
package?

I'd also see a change that limits the number of bytes which is read from
/dev/urandom (32 or fewer should be enough).  I'm concerned about
looping shell scripts darinign entropy from the pool at an unacceptably
high rate.


--
To UNSUBSCRIBE, email to debian-bsd-REQUEST@...
with a subject of "unsubscribe". Trouble? Contact listmaster@...


Re: libbsd package

by Thorsten Glaser-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Florian Weimer dixit:

>I'd also see a change that limits the number of bytes which is read from
>/dev/urandom (32 or fewer should be enough).  I'm concerned about
>looping shell scripts darinign entropy from the pool at an unacceptably
>high rate.

For things like that, the OpenBSD and MirBSD kernels have /dev/arandom,
which itself is also generated from arc4random(9). It's interesting that
things like that haven't yet been picked up by other operating systems.
(While arandom(4) only has 256 bytes (RC4) of internal state, and Linux
random/urandom has 512, OpenBSD/MirBSD has 4096, the security of arandom
increases the more users it has, and our kernel uses it internally quite
heavily too.)

bye,
//mirabilos
--
13:22⎜«neurodamage» mira, what's up man? I have a CVS question for you in #cvs
13:22⎜«neurodamage» since you're so good with it ☺
13:28⎜«neurodamage:#cvs» i love you
13:28⎜«neurodamage:#cvs» you're a handy guy to have around for systems stuff ☺


--
To UNSUBSCRIBE, email to debian-bsd-REQUEST@...
with a subject of "unsubscribe". Trouble? Contact listmaster@...


Re: libbsd package

by Florian Weimer :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

* Thorsten Glaser:

> Florian Weimer dixit:
>
>>I'd also see a change that limits the number of bytes which is read from
>>/dev/urandom (32 or fewer should be enough).  I'm concerned about
>>looping shell scripts darinign entropy from the pool at an unacceptably
>>high rate.
>
> For things like that, the OpenBSD and MirBSD kernels have /dev/arandom,
> which itself is also generated from arc4random(9). It's interesting that
> things like that haven't yet been picked up by other operating systems.

While this is arguably the correct fix (it also addresses the threading
issue), it is not something we can roll out in a security update because
it's unlikely to find its way into upstream kernels.


--
To UNSUBSCRIBE, email to debian-bsd-REQUEST@...
with a subject of "unsubscribe". Trouble? Contact listmaster@...


Re: libbsd package

by Guillem Jover :: Rate this Message: