Portability: use explicitly unsigned operands when doing
bit-wise shift operations on data larger than a character.
-20050709-14
-
- Migration of data object sizes from int->ssize_t and
- unsigned->size_t for better portability to LP64 and LLP64
- systems. Simply changing everything to size_t would be
- dangerous. A lot of code was written assuming signed
- arithmetic; for example, it recognizes negative lengths as
- an indication of integer overflow. Files: util/vbuf.[hc],
- util/mymalloc.[hc], util/vstring.[hc], util/vstream.[hc],
- util/timed_read.c, util/timed_write.c and functions that
- override timed_read/write.c; in a later round updated pretty
- much everything that contains a length of, or an offset
- into, a buffer. This eliminates unnecessary conversions
- back and forth between 32-bit and 64-bit integers.
-
-20050710-3
+20050709-15
+
+ Migration of data object sizes and offsets from int->ssize_t
+ and unsigned->size_t for better portability to LP64 and
+ LLP64 systems where *size_t is 64 bits wide. This change
+ has no effect on 32-bit systems.
+
+ This change not only eliminated some obscure portability
+ bugs (see two paragraphs down), it also eliminated many
+ unnecessary conversions back and forth between 32-bit and
+ 64-bit integers, because all relevant system library functions
+ take *size_t arguments or return *size_t results.
+
+ Simply changing every data object size or offset to size_t
+ (which is unsigned!) would be dangerous. A lot of code was
+ written assuming signed arithmetic and rejects negative
+ lengths, which can happen as the result of integer overflow.
Portability: on LP64 systems, integer expressions are int,
but sizeof() and pointer difference expressions are larger.
- Fixed a few discrepancies with functions that expect int:
- util/clean_env.c, util/argv.c, util/attr_print*.c.
+ The above changes fixed a few discrepancies with function
+ calls where *size_t was passed while the old code expected
+ an int: clean_env() versus argv_addn(), and code that sent
+ binary blobs via the TLS session cache manager protocol.
20050711
that were incompatible with pre-DSN Postfix versions. File:
cleanup/cleanup_out_recipient.c.
+20050716
+
+ Bugfix: the smtpd_sasl_authenticated_header code did not
+ check if SASL was actually enabled. File: smtpd/smtpd.c.
+
Open problems:
Look for systems with XPG basename() declared in <libgen.h>,
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding.
+Incompatibility with snapshot 20050715
+======================================
+
+Internal interfaces have changed; this may break third-party patches
+because the text of function argument and result type definitions
+has changed. The type of buffer lengths and offsets were changed
+from "(unsigned) int" (32 bit on 32-bit and LP64 systems) to
+"(s)size_t" (64 bit on LP64 systems, 32 bit on 32-bit systems).
+
+Otherwise, this change makes no difference on 32-bit systems. On
+LP64 systems, however, software may mis-behave 1) when Postfix is
+linked with pre-compiled code that was compiled with old Postfix
+interface definitions and 2) when compiling Postfix source that was
+modified by a third-party patch: incorrect code may be generated
+when the patch passes the wrong integer argument type in contexts
+that disable automatic argument type conversions. Examples of such
+contexts are formatting with printf-like arguments, and invoking
+functions that write Postfix request or reply attributes across
+inter-process communication channels. Unfortunately, gcc does not
+report "(unsigned) int" versus "(s)size_t" format string argument
+mis-matches on 32-bit systems; they can be found only on 64-bit
+systems.
+
+Major changes with snapshot 20050715
+====================================
+
+Improved portability to LP64 systems, by converting the type of
+buffer lengths and offsets from "(unsigned) int" to "(s)size_t".
+This change has zero effect on 32-bit systems. On LP64 platforms,
+however, this change not only eliminates some obscure portability
+bugs, it also eliminates unnecessary conversions between 32/64 bit
+integer types, because many system library routines take "(s)size_t"
+arguments or return "(s)size_t" values.
+
Incompatibility with snapshot 20050707
======================================
?*) error "Don't set LD_LIBRARY_PATH";;
esac
case "${CC}" in
+ *" "*) ;;
*ucb*) error "Don't use /usr/ucb/cc or ucblib";;
cc*) case `which ${CC}` in
*ucb*) error "Don't use /usr/ucb/cc or ucblib";;
# Snapshot only.
CCARGS="$CCARGS -DSNAPSHOT"
+# Non-production, i.e. needs thorough testing.
+#CCARGS="$CCARGS -DNONPROD"
+
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE
AR = $AR
/* bounce_print - line_wrap callback */
-static void bounce_print(const char *str, ssize_t len, ssize_t indent, char *context)
+static void bounce_print(const char *str, int len, int indent, char *context)
{
VSTREAM *bounce = (VSTREAM *) context;
- post_mail_fprintf(bounce, "%*s%.*s", (int) indent, "", (int) len, str);
+ post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
}
/* bounce_print_wrap - print and wrap a line */
* Initialize the reply buffer.
*/
if (reply->buf == 0) {
- reply->buf = mymalloc(DEF_DNS_REPLY_SIZE);
+ reply->buf = (unsigned char *) mymalloc(DEF_DNS_REPLY_SIZE);
reply->buf_len = DEF_DNS_REPLY_SIZE;
}
reply_header = (HEADER *) reply->buf;
if (reply_header->tc == 0 || reply->buf_len >= MAX_DNS_REPLY_SIZE)
break;
- reply->buf = myrealloc(reply->buf, 2 * reply->buf_len);
+ reply->buf = (unsigned char *)
+ myrealloc((char *) reply->buf, 2 * reply->buf_len);
reply->buf_len *= 2;
}
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20050714"
+#define MAIL_RELEASE_DATE "20050716"
#define MAIL_VERSION_NUMBER "2.3"
-#define VAR_MAIL_VERSION "mail_version"
#ifdef SNAPSHOT
-#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER "-" MAIL_RELEASE_DATE
+# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
+#else
+# define MAIL_VERSION_DATE
+#endif
+
+#ifdef NONPROD
+# define MAIL_VERSION_PROD "-nonprod"
#else
-#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER
+# define MAIL_VERSION_PROD
#endif
+
+#define VAR_MAIL_VERSION "mail_version"
+#define DEF_MAIL_VERSION MAIL_VERSION_NUMBER MAIL_VERSION_DATE MAIL_VERSION_PROD
+
extern char *var_mail_version;
/*
/* pipe_command_write - write to command with time limit */
-static ssize_t pipe_command_write(int fd, void *buf, ssize_t len)
+static ssize_t pipe_command_write(int fd, void *buf, size_t len,
+ int unused_timeout,
+ void *unused_context)
{
int maxtime = (pipe_command_timeout == 0) ? pipe_command_maxtime : 0;
char *myname = "pipe_command_write";
/* pipe_command_read - read from command with time limit */
-static ssize_t pipe_command_read(int fd, void *buf, ssize_t len)
+static ssize_t pipe_command_read(int fd, void *buf, ssize_t len,
+ int unused_timeout,
+ void *unused_context)
{
int maxtime = (pipe_command_timeout == 0) ? pipe_command_maxtime : 0;
char *myname = "pipe_command_read";
int rec_put(VSTREAM *stream, int type, const char *data, ssize_t len)
{
ssize_t len_rest;
- ssize_t len_byte;
+ int len_byte;
if (type < 0 || type > 255)
msg_panic("rec_put: bad record type %d", type);
VSTRING_TERMINATE(buf);
if (msg_verbose > 2)
msg_info("%s: type %c len %ld data %.10s", myname,
- type, (unsigned long) len, vstring_str(buf));
+ type, (long) len, vstring_str(buf));
return (type);
}
void smtp_fputs(const char *cp, ssize_t todo, VSTREAM *stream)
{
- size_t err;
+ ssize_t err;
if (todo < 0)
msg_panic("smtp_fputs: negative todo %ld", (long) todo);
void smtp_fwrite(const char *cp, ssize_t todo, VSTREAM *stream)
{
- size_t err;
+ ssize_t err;
if (todo < 0)
msg_panic("smtp_fwrite: negative todo %ld", (long) todo);
/* print_line - line_wrap callback */
-static void print_line(const char *str, ssize_t len, ssize_t indent, char *context)
+static void print_line(const char *str, int len, int indent, char *context)
{
VSTREAM *notice = (VSTREAM *) context;
- post_mail_fprintf(notice, " %*s%.*s", (int) indent, "", (int) len, str);
+ post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
}
/* lmtp_chat_notify - notify postmaster */
0,
};
- /*
- * Silly little macros.
- */
-#define STR(x) vstring_str(x)
-
/*
* Macros to handle API differences between SASLv1 and SASLv2. Specifics:
*
DELIVER_REQUEST *request; /* envelope info, offsets */
struct SMTP_SESSION *session; /* network connection */
int status; /* delivery status */
- int space_left; /* output length control */
+ ssize_t space_left; /* output length control */
/*
* Connection cache support. The (nexthop_lookup_mx, nexthop_domain,
/* print_line - line_wrap callback */
-static void print_line(const char *str, ssize_t len, ssize_t indent, char *context)
+static void print_line(const char *str, int len, int indent, char *context)
{
VSTREAM *notice = (VSTREAM *) context;
- post_mail_fprintf(notice, " %*s%.*s", (int) indent, "", (int) len, str);
+ post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
}
/* smtp_chat_notify - notify postmaster */
0,
};
- /*
- * Silly little macros.
- */
-#define STR(x) vstring_str(x)
-
/*
* Macros to handle API differences between SASLv1 and SASLv2. Specifics:
*
}
#endif
#ifdef USE_SASL_AUTH
- if (var_smtpd_sasl_auth_hdr && state->sasl_username) {
+ if (var_smtpd_sasl_enable && var_smtpd_sasl_auth_hdr && state->sasl_username) {
username = VSTRING_STRDUP(state->sasl_username);
comment_sanitize(username);
out_fprintf(out_stream, REC_TYPE_NORM,
/* print_line - line_wrap callback */
-static void print_line(const char *str, ssize_t len, ssize_t indent, char *context)
+static void print_line(const char *str, int len, int indent, char *context)
{
VSTREAM *notice = (VSTREAM *) context;
- post_mail_fprintf(notice, " %*s%.*s", (int) indent, "", (int) len, str);
+ post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
}
/* smtpd_chat_notify - notify postmaster */
RR_ADDR_TYPES, T_MX, 0);
if (dns_status == DNS_NOTFOUND)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
- var_unk_name_code, "4.1.0",
+ var_unk_name_code, "4.7.1",
"<%s>: %s rejected: Host not found",
reply_name, reply_class));
else if (dns_status != DNS_OK)
DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
- 450, "4.1.0",
+ 450, "4.7.1",
"<%s>: %s rejected: Host not found",
reply_name, reply_class);
return (SMTPD_CHECK_DUNNO);
STR(message_buffer), LEN(message_buffer),
STR(sender_buffer), LEN(sender_buffer),
STR(recipient_buffer), LEN(recipient_buffer),
- (ssize_t) 0);
+ (char *) 0);
netstring_fflush(session->stream);
/*
/* TLS_SCACHE *cache;
/* const char *cache_id;
/* const char *session;
-/* int session_len;
+/* ssize_t session_len;
/*
/* int tls_scache_sequence(cache, first_next, out_cache_id,
/* VSTRING *out_session)
const char *blame = 0;
const char *rcpt_domain;
ssize_t addr_len;
- int loop_count;
- int loop_max;
+ ssize_t loop_count;
+ ssize_t loop_max;
char *local;
char *oper;
char *junk;
* disrupt the operation of an MTA.
*/
if (loop_count > loop_max) {
- msg_warn("resolve_addr: <%s>: giving up after %d iterations",
- addr, loop_count);
+ msg_warn("resolve_addr: <%s>: giving up after %ld iterations",
+ addr, (long) loop_count);
break;
}
/* findenv - given name, locate name=value */
-static char **findenv(const char *name, int len)
+static char **findenv(const char *name, ssize_t len)
{
char **envp;
char *getenv(const char *name)
{
- int len = namelength(name);
+ ssize_t len = namelength(name);
char **envp = findenv(name, len);
return (envp ? *envp + len + 1 : 0);
{
char *destination;
char **envp;
- int l_name; /* length of name part */
+ ssize_t l_name; /* length of name part */
unsigned int l_nameval; /* length of name=value */
/* Permit name= and =value. */
proto_info = inet_proto_init(argv[0], argv[1]);
argv += 1;
- inet_addr_list_init(&list);
-
while (--argc && *++argv) {
+ inet_addr_list_init(&list);
if (inet_addr_host(&list, *argv) == 0)
msg_fatal("not found: %s", *argv);
for (sa = list.addrs; sa < list.addrs + list.used; sa++) {
SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
&hostaddr, (MAI_SERVPORT_STR *) 0, 0);
- vstream_printf("%s\n", hostaddr.buf);
+ vstream_printf("%s\t%s\n", *argv, hostaddr.buf);
}
vstream_fflush(VSTREAM_OUT);
+ inet_addr_list_free(&list);
}
- inet_addr_list_free(&list);
return (0);
}
/* line_wrap - wrap long lines upon output */
-void line_wrap(const char *str, ssize_t len, ssize_t indent, LINE_WRAP_FN output_fn,
+void line_wrap(const char *str, int len, int indent, LINE_WRAP_FN output_fn,
char *context)
{
const char *start_line;
const char *word;
const char *next_word;
const char *next_space;
- ssize_t line_len;
- ssize_t curr_len;
- ssize_t curr_indent;
+ int line_len;
+ int curr_len;
+ int curr_indent;
if (indent < 0) {
curr_indent = -indent;
/*
* External interface.
*/
-typedef void (*LINE_WRAP_FN) (const char *, ssize_t, ssize_t, char *);
-extern void line_wrap(const char *, ssize_t, ssize_t, LINE_WRAP_FN, char *);
+typedef void (*LINE_WRAP_FN) (const char *, int, int, char *);
+extern void line_wrap(const char *, int, int, LINE_WRAP_FN, char *);
/* LICENSE
/* .ad
/* void netstring_put(stream, data, len)
/* VSTREAM *stream;
/* const char *data;
-/* int ssize_t;
+/* ssize_t len;
/*
/* void netstring_put_multi(stream, data, len, data, len, ..., 0)
/* VSTREAM *stream;
/* VSTRING *netstring_memcpy(buf, data, len)
/* VSTRING *buf;
/* const char *data;
-/* int ssize_t;
+/* ssize_t len;
/*
/* VSTRING *netstring_memcat(buf, data, len)
/* VSTRING *buf;
#define vstring_str(vp) ((char *) (vp)->vbuf.data)
#define VSTRING_LEN(vp) ((ssize_t) ((vp)->vbuf.ptr - (vp)->vbuf.data))
#define vstring_end(vp) ((char *) (vp)->vbuf.ptr)
-#define VSTRING_TERMINATE(vp) { if ((vp)->vbuf.cnt <= 0) \
+#define VSTRING_TERMINATE(vp) do { \
+ if ((vp)->vbuf.cnt <= 0) \
VSTRING_SPACE((vp),1); \
- *(vp)->vbuf.ptr = 0; }
-#define VSTRING_RESET(vp) { (vp)->vbuf.ptr = (vp)->vbuf.data; \
- (vp)->vbuf.cnt = (vp)->vbuf.len; }
+ *(vp)->vbuf.ptr = 0; \
+ } while (0)
+#define VSTRING_RESET(vp) do { \
+ (vp)->vbuf.ptr = (vp)->vbuf.data; \
+ (vp)->vbuf.cnt = (vp)->vbuf.len; \
+ } while (0)
#define VSTRING_ADDCH(vp, ch) VBUF_PUT(&(vp)->vbuf, ch)
-#define VSTRING_SKIP(vp) { while ((vp)->vbuf.cnt > 0 && *(vp)->vbuf.ptr) \
- (vp)->vbuf.ptr++, (vp)->vbuf.cnt--; }
+#define VSTRING_SKIP(vp) do { \
+ while ((vp)->vbuf.cnt > 0 && *(vp)->vbuf.ptr) \
+ (vp)->vbuf.ptr++, (vp)->vbuf.cnt--; \
+ } while (0)
#define vstring_avail(vp) ((vp)->vbuf.cnt)
/*
* The following macro is not part of the public interface, because it can
* really screw up a buffer by positioning past allocated memory.
*/
-#define VSTRING_AT_OFFSET(vp, offset) { \
+#define VSTRING_AT_OFFSET(vp, offset) do { \
(vp)->vbuf.ptr = (vp)->vbuf.data + (offset); \
(vp)->vbuf.cnt = (vp)->vbuf.len - (offset); \
- }
+ } while (0)
extern VSTRING *vstring_vsprintf(VSTRING *, const char *, va_list);
extern VSTRING *vstring_vsprintf_append(VSTRING *, const char *, va_list);
/* int vstring_get_bound(vp, fp, bound)
/* VSTRING *vp;
/* VSTREAM *fp;
-/* int bound;
+/* ssize_t bound;
/*
/* int vstring_get_nonl_bound(vp, fp, bound)
/* VSTRING *vp;
/* VSTREAM *fp;
-/* int bound;
+/* ssize_t bound;
/*
/* int vstring_get_null_bound(vp, fp, bound)
/* VSTRING *vp;
/* VSTREAM *fp;
-/* int bound;
+/* ssize_t bound;
/* DESCRIPTION
/* The routines in this module each read one newline or null-terminated
/* string from an input stream. In all cases the result is either the
/* vstring_get_bound - read line from file, keep newline, up to bound */
-int vstring_get_bound(VSTRING *vp, VSTREAM *fp, int bound)
+int vstring_get_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
{
int c;
if (bound <= 0)
- msg_panic("vstring_get_bound: invalid bound %d", bound);
+ msg_panic("vstring_get_bound: invalid bound %ld", (long) bound);
VSTRING_RESET(vp);
while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
/* vstring_get_nonl_bound - read line from file, strip newline, up to bound */
-int vstring_get_nonl_bound(VSTRING *vp, VSTREAM *fp, int bound)
+int vstring_get_nonl_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
{
int c;
if (bound <= 0)
- msg_panic("vstring_get_nonl_bound: invalid bound %d", bound);
+ msg_panic("vstring_get_nonl_bound: invalid bound %ld", (long) bound);
VSTRING_RESET(vp);
while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != '\n')
/* vstring_get_null_bound - read null-terminated string from file */
-int vstring_get_null_bound(VSTRING *vp, VSTREAM *fp, int bound)
+int vstring_get_null_bound(VSTRING *vp, VSTREAM *fp, ssize_t bound)
{
int c;
if (bound <= 0)
- msg_panic("vstring_get_nonl_bound: invalid bound %d", bound);
+ msg_panic("vstring_get_nonl_bound: invalid bound %ld", (long) bound);
VSTRING_RESET(vp);
while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
extern int vstring_get(VSTRING *, VSTREAM *);
extern int vstring_get_nonl(VSTRING *, VSTREAM *);
extern int vstring_get_null(VSTRING *, VSTREAM *);
-extern int vstring_get_bound(VSTRING *, VSTREAM *, int);
-extern int vstring_get_nonl_bound(VSTRING *, VSTREAM *, int);
-extern int vstring_get_null_bound(VSTRING *, VSTREAM *, int);
+extern int vstring_get_bound(VSTRING *, VSTREAM *, ssize_t);
+extern int vstring_get_nonl_bound(VSTRING *, VSTREAM *, ssize_t);
+extern int vstring_get_null_bound(VSTRING *, VSTREAM *, ssize_t);
/*
* Backwards compatibility for code that still uses the vstring_fgets()
ssize_t write_buf(int fd, const char *buf, ssize_t len, int timeout)
{
+ const char *start = buf;
ssize_t count;
while (len > 0) {
buf += count;
len -= count;
}
- return (len);
+ return (buf - start);
}