From: Andre Noll Date: Mon, 26 Dec 2016 12:27:01 +0000 (+0100) Subject: Merge branch 'refs/heads/t/ls-p_deprecation' X-Git-Tag: v0.5.7~13 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=a80869e84654120689bd63b4a0f944bd1124332e;hp=2b9aa8a29a6bcc28a76289934d6dc6ca5606336f Merge branch 'refs/heads/t/ls-p_deprecation' Preparation for changing the semantics of the -p option to com_ls() of para_server. Cooking for four months. * refs/heads/t/ls-p_deprecation: server: Deprecate ls -p. --- diff --git a/NEWS.md b/NEWS.md index 71eb6cb2..37d855b9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,19 @@ 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. + +Download: [tarball](./releases/paraslash-git.tar.bz2) + --------------------------------------- 0.5.6 (2016-07-10) "cascading gradient" --------------------------------------- diff --git a/aac.h b/aac.h index f31d723a..eeed2528 100644 --- a/aac.h +++ b/aac.h @@ -9,12 +9,6 @@ #include 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); diff --git a/aac_afh.c b/aac_afh.c index c49f30de..a30be96f 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -15,27 +15,28 @@ #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; @@ -44,15 +45,14 @@ static int aac_find_stsz(unsigned char *buf, size_t buflen, off_t *skip) 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'; @@ -64,13 +64,12 @@ static int read_atom_header(unsigned char *buf, uint64_t *subsize, unsigned char } 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; @@ -83,12 +82,12 @@ static char *get_tag(unsigned char *p, int size) 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; @@ -117,9 +116,9 @@ static void read_tags(unsigned char *buf, size_t buflen, struct afh_info *afhi) } } -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) { @@ -132,15 +131,14 @@ static void read_meta(unsigned char *buf, size_t buflen, struct afh_info *afhi) } } -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); @@ -154,7 +152,7 @@ static void aac_get_taginfo(unsigned char *buf, size_t buflen, } 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; @@ -169,7 +167,7 @@ static ssize_t aac_compute_chunk_table(struct afh_info *afhi, 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) @@ -212,32 +210,33 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd, 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; diff --git a/aac_common.c b/aac_common.c index fe9b7295..70a9d77d 100644 --- a/aac_common.c +++ b/aac_common.c @@ -13,6 +13,7 @@ #include "para.h" #include "aac.h" #include "error.h" +#include "portable_io.h" /** * Get a new libfaad decoder handle. @@ -31,7 +32,7 @@ NeAACDecHandle aac_open(void) 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; @@ -59,13 +60,13 @@ static unsigned long aac_read_decoder_length(unsigned char *buf, int *descriptio * * \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') @@ -108,19 +109,19 @@ int aac_find_esds(unsigned char *buf, size_t buflen, size_t *skip, * \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; diff --git a/aacdec_filter.c b/aacdec_filter.c index ac8148e8..9791175e 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -86,7 +86,7 @@ static int aacdec_post_select(__a_unused struct sched *s, void *context) 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; @@ -97,7 +97,7 @@ next_buffer: 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) { @@ -106,7 +106,7 @@ next_buffer: 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) { @@ -120,7 +120,7 @@ next_buffer: 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; @@ -158,8 +158,8 @@ next_buffer: 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; diff --git a/afh.h b/afh.h index dad67351..a6f9c500 100644 --- a/afh.h +++ b/afh.h @@ -36,9 +36,9 @@ struct afh_info { /** 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; @@ -48,7 +48,7 @@ struct afh_info { * 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; diff --git a/afs.c b/afs.c index 0accc451..071f657c 100644 --- a/afs.c +++ b/afs.c @@ -1024,6 +1024,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) 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: diff --git a/base64.c b/base64.c new file mode 100644 index 00000000..7b8fe292 --- /dev/null +++ b/base64.c @@ -0,0 +1,205 @@ +/* + * 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 + +#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); +} diff --git a/base64.h b/base64.h new file mode 100644 index 00000000..4bfaa99d --- /dev/null +++ b/base64.h @@ -0,0 +1,4 @@ +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); diff --git a/client_common.c b/client_common.c index cd1ccc61..eea7510f 100644 --- a/client_common.c +++ b/client_common.c @@ -292,11 +292,6 @@ static int client_post_select(struct sched *s, void *context) 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 */ diff --git a/command.c b/command.c index 93de2d2d..0eb4efc2 100644 --- a/command.c +++ b/command.c @@ -807,7 +807,6 @@ static void reset_signals(void) } struct connection_features { - bool sideband_requested; bool aes_ctr128_requested; }; @@ -835,8 +834,8 @@ static int parse_auth_request(char *buf, int len, struct user **u, 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; @@ -949,11 +948,6 @@ __noreturn void handle_connect(int fd, const char *peername) 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), diff --git a/configure.ac b/configure.ac index f9115fd6..8d4ce59a 100644 --- a/configure.ac +++ b/configure.ac @@ -418,6 +418,7 @@ if test -n "$CRYPTOLIB" && test $HAVE_OSL = yes; then close_on_fork mm crypt_common + base64 ipc dccp_send fd @@ -480,6 +481,7 @@ if test -n "$CRYPTOLIB"; then client_common buffer_tree crypt_common + base64 version ggo " @@ -523,6 +525,7 @@ if test -n "$CRYPTOLIB"; then stat net crypt_common + base64 sideband time grab_client diff --git a/crypt.c b/crypt.c index 610d2057..f227eb39 100644 --- a/crypt.c +++ b/crypt.c @@ -23,6 +23,7 @@ #include "crypt.h" #include "fd.h" #include "crypt_backend.h" +#include "base64.h" struct asymmetric_key { RSA *rsa; @@ -158,7 +159,7 @@ int get_asymmetric_key(const char *key_file, int private, 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; @@ -180,16 +181,11 @@ int get_asymmetric_key(const char *key_file, int private, 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; diff --git a/crypt_backend.h b/crypt_backend.h index 06c86d74..f9a69d94 100644 --- a/crypt_backend.h +++ b/crypt_backend.h @@ -13,7 +13,5 @@ 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); diff --git a/crypt_common.c b/crypt_common.c index 022692ad..b39ee5e4 100644 --- a/crypt_common.c +++ b/crypt_common.c @@ -45,166 +45,6 @@ size_t is_ssh_rsa_key(char *data, size_t size) 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. * diff --git a/daemon.c b/daemon.c index 7c625bbe..20cdc6ae 100644 --- a/daemon.c +++ b/daemon.c @@ -155,10 +155,6 @@ static bool daemon_test_flag(unsigned flag) return me->flags & flag; } -static void dummy_sighandler(__a_unused int s) -{ -} - /** * Do the usual stuff to become a daemon. * @@ -166,30 +162,42 @@ static void dummy_sighandler(__a_unused int s) * * 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; @@ -205,7 +213,7 @@ void daemonize(bool parent_waits) 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); diff --git a/daemon.h b/daemon.h index c7153605..989678df 100644 --- a/daemon.h +++ b/daemon.h @@ -1,7 +1,7 @@ /** \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); diff --git a/error.h b/error.h index 337160c9..ff85c8d1 100644 --- a/error.h +++ b/error.h @@ -306,7 +306,6 @@ extern const char **para_errlist[]; 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 \ @@ -440,9 +439,10 @@ extern const char **para_errlist[]; #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"), \ diff --git a/gcrypt.c b/gcrypt.c index 3c6c1ad1..289748e8 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -15,6 +15,7 @@ #include "crypt.h" #include "crypt_backend.h" #include "fd.h" +#include "base64.h" //#define GCRYPT_DEBUG 1 @@ -239,12 +240,11 @@ static int decode_key(const char *key_file, const char *header_str, 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); @@ -606,13 +606,9 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result 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); diff --git a/play.c b/play.c index d2539ee1..108db598 100644 --- a/play.c +++ b/play.c @@ -328,8 +328,7 @@ static int open_new_file(struct play_task *pt) 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; @@ -388,6 +387,7 @@ static int load_file(struct play_task *pt) /* 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) @@ -399,6 +399,8 @@ static int load_file(struct play_task *pt) .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); @@ -453,6 +455,8 @@ again: 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; diff --git a/portable_io.h b/portable_io.h index f1a38929..4e10c2e3 100644 --- a/portable_io.h +++ b/portable_io.h @@ -4,7 +4,7 @@ * 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) { @@ -18,6 +18,18 @@ 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); @@ -38,13 +50,35 @@ static inline uint8_t read_u8(const char *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; } } @@ -68,3 +102,18 @@ static inline void write_u8(char *buf, uint8_t val) { 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); +} diff --git a/server.c b/server.c index 088cc8b1..ca71c4d8 100644 --- a/server.c +++ b/server.c @@ -411,8 +411,9 @@ static int init_afs(int argc, char **argv) { 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, @@ -422,6 +423,7 @@ static int init_afs(int argc, char **argv) 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)"); @@ -430,6 +432,10 @@ static int init_afs(int argc, char **argv) } 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); @@ -457,7 +463,7 @@ static void server_init(int argc, char **argv) .check_ambiguity = 0, .print_errors = 1 }; - int afs_socket; + int afs_socket, daemon_pipe = -1; valid_fd_012(); init_random_seed_or_die(); @@ -477,7 +483,7 @@ static void server_init(int argc, char **argv) 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(); @@ -503,8 +509,13 @@ static void server_init(int argc, char **argv) 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"); } diff --git a/t/test-lib.sh b/t/test-lib.sh index 99e575d3..1f9913e3 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -156,7 +156,7 @@ test_require_executables() 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() diff --git a/web/documentation.in.html b/web/documentation.in.html index f292af25..b226943b 100644 --- a/web/documentation.in.html +++ b/web/documentation.in.html @@ -36,10 +36,5 @@

Source code documentation

diff --git a/web/download.in.html b/web/download.in.html index dd0b9c78..a09fd1c8 100644 --- a/web/download.in.html +++ b/web/download.in.html @@ -19,7 +19,7 @@ provided at this point. There are several ways to download the source: check out any of the four integration branches maint, master, next, pu (see the - git_branches + Git branches section of the manual). All previous releases correspond to tagged commits and may be checked out