NEWS
====
+------------------------------------------
+0.5.7 (to be announced) "semantic density"
+------------------------------------------
+- Speedup of the base64 decoder.
+- One of the two source browsers has been removed from the web pages.
+ The doxygen API reference still contains an HTML version of each
+ source file.
+- Two race conditions in para_server have been fixed.
+- ls -p is now deprecated in favor of -F or -b. See the help text of
+ the ls command for details.
+- The openssl code has been adjusted to work also with openssl-1.1.
+
+Download: [tarball](./releases/paraslash-git.tar.bz2)
+
---------------------------------------
0.5.6 (2016-07-10) "cascading gradient"
---------------------------------------
#include <neaacdec.h>
NeAACDecHandle aac_open(void);
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
unsigned long *decoder_length);
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip);
-
-static inline unsigned aac_read_int32(unsigned char *buf)
-{
- uint8_t *d = (uint8_t*)buf;
- return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
-}
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip);
#include "para.h"
#include "error.h"
+#include "portable_io.h"
#include "afh.h"
#include "string.h"
#include "aac.h"
#include "fd.h"
-static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip)
+static int aac_find_stsz(char *buf, size_t buflen, off_t *skip)
{
int i;
for (i = 0; i + 16 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
unsigned sample_count, sample_size;
if (p[0] != 's' || p[1] != 't' || p[2] != 's' || p[3] != 'z')
continue;
PARA_DEBUG_LOG("found stsz@%d\n", i);
i += 8;
- sample_size = aac_read_int32(buf + i);
+ sample_size = read_u32_be(buf + i);
PARA_DEBUG_LOG("sample size: %d\n", sample_size);
i += 4;
- sample_count = aac_read_int32(buf + i);
+ sample_count = read_u32_be(buf + i);
i += 4;
PARA_DEBUG_LOG("sample count: %d\n", sample_count);
*skip = i;
return -E_STSZ;
}
-static int atom_cmp(const unsigned char *buf1, const char *buf2)
+static int atom_cmp(const char *buf1, const char *buf2)
{
return memcmp(buf1, buf2, 4)? 1 : 0;
}
-static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char type[5])
+static int read_atom_header(char *buf, uint64_t *subsize, char type[5])
{
- int i;
- uint64_t size = aac_read_int32(buf);
+ uint64_t size = read_u32_be(buf);
memcpy(type, buf + 4, 4);
type[4] = '\0';
}
buf += 4;
size = 0;
- for (i = 0; i < 8; i++)
- size |= ((uint64_t)buf[i]) << ((7 - i) * 8);
+ size = read_u64_be(buf);
*subsize = size;
return 16;
}
-static char *get_tag(unsigned char *p, int size)
+static char *get_tag(char *p, int size)
{
char *buf;
return buf;
}
-static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_tags(char *buf, size_t buflen, struct afh_info *afhi)
{
- unsigned char *p = buf;
+ char *p = buf;
while (p + 32 < buf + buflen) {
- unsigned char *q, type1[5], type2[5];
+ char *q, type1[5], type2[5];
uint64_t size1, size2;
int ret, ret2;
}
}
-static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi)
+static void read_meta(char *buf, size_t buflen, struct afh_info *afhi)
{
- unsigned char *p = buf;
+ char *p = buf;
while (p + 4 < buf + buflen) {
}
}
-static void aac_get_taginfo(unsigned char *buf, size_t buflen,
- struct afh_info *afhi)
+static void aac_get_taginfo(char *buf, size_t buflen, struct afh_info *afhi)
{
int i;
uint64_t subsize;
- unsigned char type[5];
+ char type[5];
for (i = 0; i + 24 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
if (p[0] != 'm' || p[1] != 'e' || p[2] != 't' || p[3] != 'a')
continue;
PARA_INFO_LOG("found metadata at offset %d\n", i);
}
static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
- unsigned char *map, size_t numbytes)
+ char *map, size_t numbytes)
{
int ret, i;
size_t sum = 0;
for (i = 1; i <= afhi->chunks_total; i++) {
if (skip + 4 > numbytes)
break;
- sum += aac_read_int32(map + skip);
+ sum += read_u32_be(map + skip);
afhi->chunk_table[i] = sum;
skip += 4;
// if (i < 10 || i + 10 > afhi->chunks_total)
unsigned char channels = 0;
mp4AudioSpecificConfig mp4ASC;
NeAACDecHandle handle = NULL;
- unsigned char *umap = (unsigned char *) map;
- ret = aac_find_esds(umap, numbytes, &skip, &decoder_len);
+ ret = aac_find_esds(map, numbytes, &skip, &decoder_len);
if (ret < 0)
goto out;
- aac_get_taginfo(umap, numbytes, afhi);
+ aac_get_taginfo(map, numbytes, afhi);
handle = aac_open();
ret = -E_AAC_AFH_INIT;
- if (NeAACDecInit(handle, umap + skip, decoder_len, &rate, &channels))
+ if (NeAACDecInit(handle, (unsigned char *)map + skip, decoder_len,
+ &rate, &channels))
goto out;
if (!channels)
goto out;
PARA_DEBUG_LOG("rate: %lu, channels: %d\n", rate, channels);
ret = -E_MP4ASC;
- if (NeAACDecAudioSpecificConfig(umap + skip, numbytes - skip, &mp4ASC))
+ if (NeAACDecAudioSpecificConfig((unsigned char *)map + skip,
+ numbytes - skip, &mp4ASC))
goto out;
if (!mp4ASC.samplingFrequency)
goto out;
- ret = aac_compute_chunk_table(afhi, umap, numbytes);
+ ret = aac_compute_chunk_table(afhi, map, numbytes);
if (ret < 0)
goto out;
skip = ret;
ret = aac_set_chunk_tv(afhi, &mp4ASC, &afhi->seconds_total);
if (ret < 0)
goto out;
- ret = aac_find_entry_point(umap + skip, numbytes - skip, &skip);
+ ret = aac_find_entry_point(map + skip, numbytes - skip, &skip);
if (ret < 0)
goto out;
afhi->chunk_table[0] = ret;
#include "para.h"
#include "aac.h"
#include "error.h"
+#include "portable_io.h"
/**
* Get a new libfaad decoder handle.
return h;
}
-static unsigned long aac_read_decoder_length(unsigned char *buf, int *description_len)
+static unsigned long aac_read_decoder_length(char *buf, int *description_len)
{
uint8_t b;
uint8_t numBytes = 0;
*
* \return positive on success, negative on errors
*/
-int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip,
+int aac_find_esds(char *buf, size_t buflen, size_t *skip,
unsigned long *decoder_length)
{
size_t i;
for (i = 0; i + 4 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
int description_len;
if (p[0] != 'e' || p[1] != 's' || p[2] != 'd' || p[3] != 's')
* \return the position of the first entry in the table on success,
* -E_STCO on errors.
*/
-ssize_t aac_find_entry_point(unsigned char *buf, size_t buflen, size_t *skip)
+ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip)
{
ssize_t ret;
size_t i;
for (i = 0; i + 20 < buflen; i++) {
- unsigned char *p = buf + i;
+ char *p = buf + i;
if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o')
continue;
PARA_INFO_LOG("found stco@%zu\n", i);
i += 12;
- ret = aac_read_int32(buf + i); /* first offset */
+ ret = read_u32_be(buf + i); /* first offset */
i += 4;
PARA_INFO_LOG("entry point: %zd\n", ret);
*skip = i;
struct btr_node *btrn = fn->btrn;
struct private_aacdec_data *padd = fn->private_data;
int i, ret;
- unsigned char *p, *inbuf, *outbuffer;
+ char *p, *inbuf, *outbuffer;
char *btr_buf;
size_t len, skip, consumed, loaded;
if (ret == 0)
return 0;
btr_merge(btrn, fn->min_iqs);
- len = btr_next_buffer(btrn, (char **)&inbuf);
+ len = btr_next_buffer(btrn, &inbuf);
len = PARA_MIN(len, (size_t)8192);
consumed = 0;
if (!padd->initialized) {
ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length);
if (ret < 0) {
PARA_INFO_LOG("%s\n", para_strerror(-ret));
- ret = NeAACDecInit(padd->handle, inbuf,
+ ret = NeAACDecInit(padd->handle, (unsigned char *)inbuf,
len, &rate, &channels);
PARA_INFO_LOG("decoder init: %d\n", ret);
if (ret < 0) {
consumed += skip;
p = inbuf + consumed;
ret = -E_AACDEC_INIT;
- if (NeAACDecInit2(padd->handle, p,
+ if (NeAACDecInit2(padd->handle, (unsigned char *)p,
padd->decoder_length, &rate,
&channels) != 0)
goto out;
p = inbuf + consumed;
//PARA_CRIT_LOG("consumed: %zu (%zu + %zu), have: %zu\n", padd->consumed_total + consumed,
// padd->consumed_total, consumed, len - consumed);
- outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
- len - consumed);
+ outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info,
+ (unsigned char *)p, len - consumed);
if (padd->frame_info.error) {
int err = padd->frame_info.error;
ret = -E_AAC_DECODE;
/** Id3 tags, vorbis comments, aac tags. */
struct taginfo tags;
/**
- * The table that specifies the offset of the individual pieces in
- * the current audio file.
- */
+ * The table that specifies the offset of the individual pieces in
+ * the current audio file.
+ */
uint32_t *chunk_table;
/** Period of time between sending data chunks. */
struct timeval chunk_tv;
* which means that this audio format does not need any special header
* treatment. The audio format handler does not need to set this to
* zero in this case.
- */
+ */
uint32_t header_len;
/** The number of channels. */
uint8_t channels;
register_command_task(cookie, &s);
s.default_timeout.tv_sec = 0;
s.default_timeout.tv_usec = 999 * 1000;
+ ret = write(socket_fd, "\0", 1);
+ if (ret != 1) {
+ if (ret == 0)
+ errno = EINVAL;
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto out_close;
+ }
ret = schedule(&s);
sched_shutdown(&s);
out_close:
H: m: mbox listing mode
H: c: chunk-table listing mode
H:
-H: -p List full paths. If this option is not specified, only the basename
+H: -F List full paths. If this option is not specified, only the basename
H: of each file is printed.
+H: -p Synonym for -F. Deprecated.
+H:
+H: -b Print only the basename of each matching file. This is the default, so
+H: the option is currently a no-op. It is recommended to specify this option,
+H: though, as the default might change in a future release.
H:
H: -a List only files that are admissible with respect to the current mood or
H: playlist.
H:
H: -d Print dates as seconds after the epoch.
H:
-H: -s=order Change sort order. Defaults to alphabetical path sort if not given.
+H: -s=order
+H: Change sort order. Defaults to alphabetical path sort if not given.
H:
H: Possible values for order:
H: p: by path
return -E_AFT_SYNTAX;
}
}
- if (!strcmp(arg, "-p")) {
+ if (!strcmp(arg, "-p") || !strcmp(arg, "-F")) {
flags |= LS_FLAG_FULL_PATH;
continue;
}
+ if (!strcmp(arg, "-b")) {
+ flags &= ~LS_FLAG_FULL_PATH;
+ continue;
+ }
if (!strcmp(arg, "-a")) {
flags |= LS_FLAG_ADMISSIBLE_ONLY;
continue;
--- /dev/null
+/*
+ * The code in this file was taken from openssh-5.2p1, Copyright (c) 1996 by
+ * Internet Software Consortium. Portions Copyright (c) 1995 by International
+ * Business Machines, Inc.
+ */
+
+/** \file base64.c Uudecode and base64decode implementation. */
+
+#include <regex.h>
+
+#include "para.h"
+#include "error.h"
+#include "base64.h"
+#include "string.h"
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const unsigned char base64_tab[256] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 00-07 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 08-0f */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 10-17 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 18-1f */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 20-2f */
+ 255, 255, 255, 62, 255, 255, 255, 63, /* 28-2f */
+ 52 , 53, 54, 55, 56, 57, 58, 59, /* 30-37 */
+ 60 , 61, 255, 255, 255, 255, 255, 255, /* 38-3f */
+ 255, 0, 1, 2, 3, 4, 5, 6, /* 40-47 */
+ 7 , 8, 9, 10, 11, 12, 13, 14, /* 48-4f */
+ 15 , 16, 17, 18, 19, 20, 21, 22, /* 50-57 */
+ 23 , 24, 25, 255, 255, 255, 255, 255, /* 58-5f */
+ 255, 26, 27, 28, 29, 30, 31, 32, /* 60-6f */
+ 33 , 34, 35, 36, 37, 38, 39, 40, /* 68-6f */
+ 41 , 42, 43, 44, 45, 46, 47, 48, /* 70-77 */
+ 49 , 50, 51, 255, 255, 255, 255, 255, /* 78-7f */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 80-87 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 88-8f */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 90-97 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* 98-9f */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* a0-a7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* a8-af */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* b0-b7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* b8-bf */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* c0-c7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* c8-cf */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* d0-d7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* d8-df */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* e0-e7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* e8-ef */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* f0-f7 */
+ 255, 255, 255, 255, 255, 255, 255, 255, /* f8-ff */
+};
+
+/** Maximal possible size of the decoded data. */
+#define BASE64_MAX_DECODED_SIZE(_encoded_size) ((_encoded_size) / 4 * 3)
+
+#define PAD64 '='
+/**
+ * base64-decode a buffer.
+ *
+ * \param src The buffer to decode.
+ * \param encoded_size The special value -1 means: look for terminating zero byte.
+ * \param result Points to dynamically allocated target buffer on success.
+ * \param decoded_size Number of bytes written to \a result.
+ *
+ * Skips all whitespace anywhere. Converts characters, four at a time, starting
+ * at (or after) src from base - 64 numbers into three 8 bit bytes in the
+ * target area.
+ *
+ * It is OK to pass a \p NULL pointer as \a decoded_size. The result is
+ * terminated with a zero byte.
+ *
+ * \return Standard. The contents of result \a and \a decoded_size are
+ * undefined on failure.
+ */
+int base64_decode(char const *src, size_t encoded_size, char **result,
+ size_t *decoded_size)
+{
+ size_t i, j, state; /* source/target indices */
+ const char *end = src + encoded_size, *p;
+ unsigned char *target, uch;
+
+ if (encoded_size == (size_t)-1)
+ encoded_size = strlen(src);
+ target = para_malloc(BASE64_MAX_DECODED_SIZE(encoded_size) + 1);
+
+ for (
+ i = 0, j = 0, state = 0;
+ i < encoded_size && (uch = src[i]) != '\0';
+ i++
+ ) {
+ if (para_isspace(uch)) /* Skip whitespace anywhere. */
+ continue;
+ if (uch == PAD64)
+ break;
+ if (base64_tab[uch] == 255) /* A non-base64 character. */
+ goto fail;
+ uch = base64_tab[uch];
+ switch (state) {
+ case 0:
+ target[j] = uch << 2;
+ break;
+ case 1:
+ target[j] |= uch >> 4;
+ j++;
+ target[j] = (uch & 0x0f) << 4;
+ break;
+ case 2:
+ target[j] |= uch >> 2;
+ j++;
+ target[j] = (uch & 0x03) << 6;
+ break;
+ case 3:
+ target[j] |= uch;
+ j++;
+ break;
+ }
+ state = (state + 1) % 4;
+ }
+ p = (i < encoded_size)? src + i : NULL;
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+ if (p && *p == PAD64) { /* We got a pad char. Skip it, get next. */
+ p++;
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ goto fail;
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for (; p < end && *p != '\0'; p++)
+ if (!para_isspace(*p))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (*p != PAD64)
+ goto fail;
+ /* Fall through to "single trailing =" case. */
+ p++;
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for (; p < end && *p != '\0'; p++)
+ if (!para_isspace(*p))
+ goto fail;
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target[j] != 0)
+ goto fail;
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ goto fail;
+ }
+ /* success */
+ target[j] = '\0'; /* just to be sure */
+ if (decoded_size)
+ *decoded_size = j;
+ *result = (char *)target;
+ return 1;
+fail:
+ free(target);
+ return -E_BASE64;
+}
+
+/**
+ * Decode a buffer using the uuencode Base64 algorithm.
+ *
+ * \param src The buffer to decode.
+ * \param encoded_size Number of input bytes in the source buffer.
+ * \param result Contains the decoded data on success.
+ * \param decoded_size Number of output bytes on success.
+ *
+ * This is just a simple wrapper for \ref base64_decode() which strips
+ * whitespace.
+ *
+ * \return The return value of the underlying call to \ref base64_decode().
+ *
+ * \sa uuencode(1), uudecode(1).
+ */
+int uudecode(char const *src, size_t encoded_size, char **result,
+ size_t *decoded_size)
+{
+ const char *end = src + encoded_size, *p;
+
+ /* skip whitespace and data */
+ for (p = src; p < end && (*p == ' ' || *p == '\t'); p++)
+ ;
+ for (; p < end && *p != '\0' && *p != ' ' && *p != '\t'; p++)
+ ;
+ /* and remove trailing whitespace because base64_decode needs this */
+ return base64_decode(src, p - src, result, decoded_size);
+}
--- /dev/null
+int uudecode(char const *src, size_t encoded_size, char **result,
+ size_t *decoded_size);
+int base64_decode(char const *src, size_t encoded_size, char **result,
+ size_t *decoded_size);
char *opts[] = {
"--", "-l", "-l=s", "-l=l", "-l=v", "-l=p", "-l=m", "-l=c",
"-p", "-a", "-r", "-d", "-s=p", "-s=l", "-s=s", "-s=n", "-s=f",
- "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", NULL
+ "-s=c", "-s=i", "-s=y", "-s=b", "-s=d", "-s=a", "-F", "-b", NULL
};
if (ci->word[0] == '-')
i9e_complete_option(opts, ci, cr);
if (ret < 0 || n == 0)
goto out;
ct->features = parse_features(buf);
- if (!has_feature("sideband", ct)) {
- PARA_ERROR_LOG("server has no sideband support\n");
- ret = -E_INCOMPAT_FEAT;
- goto out;
- }
ct->status = CL_RECEIVED_WELCOME;
return 0;
case CL_RECEIVED_WELCOME: /* send auth command */
}
struct connection_features {
- bool sideband_requested;
bool aes_ctr128_requested;
};
create_argv(p, ",", &features);
for (i = 0; features[i]; i++) {
if (strcmp(features[i], "sideband") == 0)
- cf->sideband_requested = true;
- else if (strcmp(features[i], "aes_ctr128") == 0)
+ continue;
+ if (strcmp(features[i], "aes_ctr128") == 0)
cf->aes_ctr128_requested = true;
else {
ret = -E_BAD_FEATURE;
ret = parse_auth_request(buf, ret, &cc->u, &cf);
if (ret < 0)
goto net_err;
- if (!cf.sideband_requested) { /* sideband is mandatory */
- PARA_ERROR_LOG("client did not request sideband\n");
- ret = -E_BAD_FEATURE;
- goto net_err;
- }
if (cc->u) {
get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
close_on_fork
mm
crypt_common
+ base64
ipc
dccp_send
fd
client_common
buffer_tree
crypt_common
+ base64
version
ggo
"
stat
net
crypt_common
+ base64
sideband
time
grab_client
#include "crypt.h"
#include "fd.h"
#include "crypt_backend.h"
+#include "base64.h"
struct asymmetric_key {
RSA *rsa;
struct asymmetric_key *key = NULL;
void *map = NULL;
unsigned char *blob = NULL;
- size_t map_size, blob_size, decoded_size;
+ size_t map_size, encoded_size, decoded_size;
int ret, ret2;
char *cp;
goto out;
}
cp = map + ret;
+ encoded_size = map_size - ret;
PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
- ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW);
- if (map_size > INT_MAX / 4)
- goto out_unmap;
- blob_size = 2 * map_size;
- blob = para_malloc(blob_size);
- ret = uudecode(cp, blob, blob_size);
+ ret = uudecode(cp, encoded_size, (char **)&blob, &decoded_size);
if (ret < 0)
goto out_unmap;
- decoded_size = ret;
ret = check_ssh_key_header(blob, decoded_size);
if (ret < 0)
goto out_unmap;
size_t is_ssh_rsa_key(char *data, size_t size);
uint32_t read_ssh_u32(const void *vp);
-int uudecode(const char *src, unsigned char *target, size_t targsize);
int check_ssh_key_header(const unsigned char *blob, int blen);
int check_key_file(const char *file, bool private_key);
-int base64_decode(char const *src, unsigned char *target, size_t targsize);
return cp - data;
}
-/*
- * This base64/uudecode stuff below is taken from openssh-5.2p1, Copyright (c)
- * 1996 by Internet Software Consortium. Portions Copyright (c) 1995 by
- * International Business Machines, Inc.
- */
-
-static const char Base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char Pad64 = '=';
-
-/**
- * base64-decode a buffer.
- *
- * \param src The buffer to decode.
- * \param target Result is stored here.
- * \param targsize Number of bytes of \a target.
- *
- * Skips all whitespace anywhere. Converts characters, four at a time, starting
- * at (or after) src from base - 64 numbers into three 8 bit bytes in the
- * target area.
- *
- * \return The number of data bytes stored at the target, -E_BASE64 on errors.
- */
-int base64_decode(char const *src, unsigned char *target, size_t targsize)
-{
- unsigned int tarindex, state;
- int ch;
- char *pos;
-
- state = 0;
- tarindex = 0;
-
- while ((ch = *src++) != '\0') {
- if (para_isspace(ch)) /* Skip whitespace anywhere. */
- continue;
-
- if (ch == Pad64)
- break;
-
- pos = strchr(Base64, ch);
- if (pos == NULL) /* A non-base64 character. */
- return -E_BASE64;
-
- switch (state) {
- case 0:
- if (tarindex >= targsize)
- return -E_BASE64;
- target[tarindex] = (pos - Base64) << 2;
- state = 1;
- break;
- case 1:
- if (tarindex + 1 >= targsize)
- return -E_BASE64;
- target[tarindex] |= (pos - Base64) >> 4;
- target[tarindex + 1] = ((pos - Base64) & 0x0f) << 4;
- tarindex++;
- state = 2;
- break;
- case 2:
- if (tarindex + 1 >= targsize)
- return -E_BASE64;
- target[tarindex] |= (pos - Base64) >> 2;
- target[tarindex + 1] = ((pos - Base64) & 0x03) << 6;
- tarindex++;
- state = 3;
- break;
- case 3:
- if (tarindex >= targsize)
- return -E_BASE64;
- target[tarindex] |= pos - Base64;
- tarindex++;
- state = 0;
- break;
- }
- }
-
- /*
- * We are done decoding Base-64 chars. Let's see if we ended
- * on a byte boundary, and/or with erroneous trailing characters.
- */
-
- if (ch == Pad64) { /* We got a pad char. */
- ch = *src++; /* Skip it, get next. */
- switch (state) {
- case 0: /* Invalid = in first position */
- case 1: /* Invalid = in second position */
- return -E_BASE64;
-
- case 2: /* Valid, means one byte of info */
- /* Skip any number of spaces. */
- for (; ch != '\0'; ch = *src++)
- if (!isspace(ch))
- break;
- /* Make sure there is another trailing = sign. */
- if (ch != Pad64)
- return -E_BASE64;
- ch = *src++; /* Skip the = */
- /* Fall through to "single trailing =" case. */
- /* FALLTHROUGH */
-
- case 3: /* Valid, means two bytes of info */
- /*
- * We know this char is an =. Is there anything but
- * whitespace after it?
- */
- for (; ch != '\0'; ch = *src++)
- if (!isspace(ch))
- return -E_BASE64;
-
- /*
- * Now make sure for cases 2 and 3 that the "extra"
- * bits that slopped past the last full byte were
- * zeros. If we don't check them, they become a
- * subliminal channel.
- */
- if (target[tarindex] != 0)
- return -E_BASE64;
- }
- } else {
- /*
- * We ended by seeing the end of the string. Make sure we
- * have no partial bytes lying around.
- */
- if (state != 0)
- return -E_BASE64;
- }
-
- return tarindex;
-}
-
-/**
- * uudecode a buffer.
- *
- * \param src The buffer to decode.
- * \param target Result buffer.
- * \param targsize The length of \a target in bytes.
- *
- * This is just a simple wrapper for base64_decode() which strips whitespace.
- *
- * \return The return value of the underlying call to base64_decode().
- */
-int uudecode(const char *src, unsigned char *target, size_t targsize)
-{
- int len;
- char *encoded, *p;
-
- /* copy the 'readonly' source */
- encoded = para_strdup(src);
- /* skip whitespace and data */
- for (p = encoded; *p == ' ' || *p == '\t'; p++)
- ;
- for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
- ;
- /* and remove trailing whitespace because base64_decode needs this */
- *p = '\0';
- len = base64_decode(encoded, target, targsize);
- free(encoded);
- return len;
-}
-
/**
* Read a 4-byte number from a buffer in big-endian format.
*
return me->flags & flag;
}
-static void dummy_sighandler(__a_unused int s)
-{
-}
-
/**
* Do the usual stuff to become a daemon.
*
*
* Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
* parent_waits is false, the parent process terminates immediately.
- * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
- * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
- * daemon process should not detach from the console until the child process
- * has completed its setup.
+ * Otherwise, a pipe is created prior to the fork() and the parent tries to
+ * read a single byte from the reading end of the pipe. The child is supposed
+ * to write to the writing end of the pipe after it completed its setup
+ * procedure successfully. This behaviour is useful to let the parent process
+ * die with an error if the child process aborts early, since in this case the
+ * read() will return non-positive.
+ *
+ * \return This function either succeeds or calls exit(3). If parent_waits is
+ * true, the return value is the file descriptor of the writing end of the
+ * pipe. Otherwise the function returns zero.
*
* \sa fork(2), setsid(2), dup(2), pause(2).
*/
-void daemonize(bool parent_waits)
+int daemonize(bool parent_waits)
{
pid_t pid;
- int null;
+ int null, pipe_fd[2];
- PARA_INFO_LOG("daemonizing\n");
+ if (parent_waits && pipe(pipe_fd) < 0)
+ goto err;
+ PARA_INFO_LOG("subsequent log messages go to %s\n", me->logfile_name?
+ me->logfile_name : "/dev/null");
pid = fork();
if (pid < 0)
goto err;
- if (pid) {
+ if (pid) { /* parent exits */
if (parent_waits) {
- signal(SIGTERM, dummy_sighandler);
- signal(SIGCHLD, dummy_sighandler);
- pause();
+ char c;
+ close(pipe_fd[1]);
+ exit(read(pipe_fd[0], &c, 1) <= 0?
+ EXIT_FAILURE : EXIT_SUCCESS);
}
- exit(EXIT_SUCCESS); /* parent exits */
+ exit(EXIT_SUCCESS);
}
+ if (parent_waits)
+ close(pipe_fd[0]);
/* become session leader */
if (setsid() < 0)
goto err;
if (dup2(null, STDERR_FILENO) < 0)
goto err;
close(null);
- return;
+ return parent_waits? pipe_fd[1] : 0;
err:
PARA_EMERG_LOG("fatal: %s\n", strerror(errno));
exit(EXIT_FAILURE);
/** \file daemon.h exported symbols from daemon.c */
-void daemonize(bool parent_waits);
+int daemonize(bool parent_waits);
void daemon_open_log_or_die(void);
void daemon_close_log(void);
void daemon_log_welcome(const char *whoami);
PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
PARA_ERROR(SERVER_CMD_SUCCESS, "command terminated successfully"), \
PARA_ERROR(SERVER_CMD_FAILURE, "command failed"), \
- PARA_ERROR(INCOMPAT_FEAT, "client/server incompatibility"), \
#define NET_ERRORS \
#define CRYPT_COMMON_ERRORS \
PARA_ERROR(SSH_KEY_HEADER, "ssh key header not found"), \
- PARA_ERROR(BASE64, "failed to base64-decode ssh public key"), \
PARA_ERROR(KEY_PERM, "unprotected private key"), \
+#define BASE64_ERRORS \
+ PARA_ERROR(BASE64, "base64 decode error"), \
#define CRYPT_ERRORS \
PARA_ERROR(PRIVATE_KEY, "can not read private key"), \
#include "crypt.h"
#include "crypt_backend.h"
#include "fd.h"
+#include "base64.h"
//#define GCRYPT_DEBUG 1
key[j++] = begin[i];
}
key[j] = '\0';
- blob_size = key_size * 2;
- blob = para_malloc(blob_size);
- ret = base64_decode(key, blob, blob_size);
+ ret = base64_decode(key, j, (char **)&blob, &blob_size);
free(key);
if (ret < 0)
goto free_unmap;
+ ret = blob_size;
goto unmap;
free_unmap:
free(blob);
gcry_mpi_t e = NULL, n = NULL;
PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
- if (size > INT_MAX / 4)
- return -ERRNO_TO_PARA_ERROR(EOVERFLOW);
- blob = para_malloc(2 * size);
- ret = uudecode((char *)data, blob, 2 * size);
+ ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
if (ret < 0)
goto free_blob;
- decoded_size = ret;
end = blob + decoded_size;
dump_buffer("decoded key", blob, decoded_size);
ret = check_ssh_key_header(blob, decoded_size);
pt->rn.receiver = afh_recv;
ret = afh_recv->open(&pt->rn);
if (ret < 0) {
- PARA_ERROR_LOG("could not open %s: %s\n", path,
- para_strerror(-ret));
+ PARA_ERROR_LOG("could not open %s\n", path);
goto fail;
}
pt->audio_format_num = ret;
/* set up decoding filter */
af = audio_format_name(pt->audio_format_num);
tmp = make_message("%sdec", af);
+ PARA_INFO_LOG("decoder: %s\n", tmp);
ret = check_filter_arg(tmp, &pt->fn.conf);
freep(&tmp);
if (ret < 0)
.handler = decoder->execute, .context = &pt->fn));
if (decoder->open)
decoder->open(&pt->fn);
+ PARA_INFO_LOG("buffer tree:\n");
+ btr_log_tree(pt->rn.btrn, LL_INFO);
/* setup default writer */
pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num);
pt->next_file = pt->current_file;
ret = load_file(pt);
if (ret < 0) {
+ PARA_ERROR_LOG("%s: marking file as invalid\n",
+ para_strerror(-ret));
pt->invalid[pt->next_file] = true;
pt->rq = CRT_NONE;
goto again;
* Licensed under the GPL v2. For licencing details see COPYING.
*/
-/** \file portable_io.h Inline functions for endian-independent binary IO. */
+/** \file portable_io.h Inline functions for binary IO. */
static inline uint64_t read_portable(unsigned bits, const char *buf)
{
return ret;
}
+static inline uint64_t read_portable_be(unsigned bits, const char *buf)
+{
+ uint64_t ret = 0;
+ int i, num_bytes = bits / 8;
+
+ for (i = 0; i < num_bytes; i++) {
+ unsigned char c = buf[i];
+ ret += ((uint64_t)c << (8 * (num_bytes - i - 1)));
+ }
+ return ret;
+}
+
static inline uint64_t read_u64(const char *buf)
{
return read_portable(64, buf);
return read_portable(8, buf);
}
+static inline uint64_t read_u64_be(const char *buf)
+{
+ return read_portable_be(64, buf);
+}
+
+static inline uint32_t read_u32_be(const char *buf)
+{
+ return read_portable_be(32, buf);
+}
+
+static inline uint16_t read_u16_be(const char *buf)
+{
+ return read_portable_be(16, buf);
+}
+
static inline void write_portable(unsigned bits, char *buf, uint64_t val)
{
int i, num_bytes = bits / 8;
-// fprintf(stderr, "val: %lu\n", val);
for (i = 0; i < num_bytes; i++) {
buf[i] = val & 0xff;
-// fprintf(stderr, "buf[%d]=%x\n", i, buf[i]);
+ val = val >> 8;
+ }
+}
+
+static inline void write_portable_be(unsigned bits, char *buf, uint64_t val)
+{
+ int i, num_bytes = bits / 8;
+ for (i = 0; i < num_bytes; i++) {
+ buf[num_bytes - i - 1] = val & 0xff;
val = val >> 8;
}
}
{
write_portable(8, buf, (uint64_t) val);
}
+
+static inline void write_u64_be(char *buf, uint64_t val)
+{
+ write_portable_be(64, buf, val);
+}
+
+static inline void write_u32_be(char *buf, uint32_t val)
+{
+ write_portable_be(32, buf, (uint64_t) val);
+}
+
+static inline void write_u16_be(char *buf, uint16_t val)
+{
+ write_portable_be(16, buf, (uint64_t) val);
+}
{
int ret, afs_server_socket[2];
pid_t afs_pid;
+ char c;
- ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
+ ret = socketpair(PF_UNIX, SOCK_STREAM, 0, afs_server_socket);
if (ret < 0)
exit(EXIT_FAILURE);
get_random_bytes_or_die((unsigned char *)&afs_socket_cookie,
exit(EXIT_FAILURE);
if (afs_pid == 0) { /* child (afs) */
int i;
+
for (i = argc - 1; i >= 0; i--)
memset(argv[i], 0, strlen(argv[i]));
sprintf(argv[0], "para_server (afs)");
}
mmd->afs_pid = afs_pid;
close(afs_server_socket[1]);
+ if (read(afs_server_socket[0], &c, 1) <= 0) {
+ PARA_EMERG_LOG("early afs exit\n");
+ exit(EXIT_FAILURE);
+ }
ret = mark_fd_nonblocking(afs_server_socket[0]);
if (ret < 0)
exit(EXIT_FAILURE);
.check_ambiguity = 0,
.print_errors = 1
};
- int afs_socket;
+ int afs_socket, daemon_pipe = -1;
valid_fd_012();
init_random_seed_or_die();
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
- daemonize(true /* parent waits for SIGTERM */);
+ daemon_pipe = daemonize(true /* parent waits for us */);
PARA_NOTICE_LOG("initializing audio format handlers\n");
afh_init();
PARA_NOTICE_LOG("initializing virtual streaming system\n");
init_vss_task(afs_socket, &sched);
init_server_command_task(argc, argv);
- if (conf.daemon_given)
- kill(getppid(), SIGTERM);
+ if (daemon_pipe >= 0) {
+ if (write(daemon_pipe, "\0", 1) < 0) {
+ PARA_EMERG_LOG("daemon_pipe: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ close(daemon_pipe);
+ }
PARA_NOTICE_LOG("server init complete\n");
}
test_duration()
{
local t=$(exec 2>&1 1>/dev/null; time -p "$@")
- result=$(awk '{print $2 * 1000}' <<< $t)
+ result=$(awk '{print $2 * 1000; exit 0}' <<< "$t")
}
test_expect_success()
<h2> Source code documentation </h2>
<ul>
-
- <li> <a href="doxygen/html/index.html">API
- Reference</a>. </li>
-
- <li> <a href="HTML/index.html">Browsable source</a>. </li>
-
+ <li> <a href="doxygen/html/index.html">API Reference</a> </li>
</ul>
check out any of the four integration branches maint,
master, next, pu (see the
- <a href="manual.html#git_branches">git_branches</a>
+ <a href="manual.html#Git.branches">Git branches</a>
section of the manual). All previous releases
correspond to tagged commits and may be checked out