Commit graph

4929 commits

Author SHA1 Message Date
6a0f9d9874 client: Support $if Empire in .inputrc
Set the application name to "Empire" to support Empire-specific
customization of readline.  Use in .inputrc looks like this:

    $if Empire
    set bell-style audible
    set history-size 500
    else
    set bell-style visible
    $endif

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
ba484d1389 man/empire: Explain restricted mode a bit better
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
2fe38c1acb client: Enable history file by default unless -r
Make -H take an argument.  Default it to ~/.empire_history, except in
-r restricted mode, where history is off unless you specify -H.
That's because restricted mode restricts the player's access to the
local system, and that includes the history file.  If you want to
grant access to a history file, you have to do so explicitly.

Thanks to the previous commit, there is no need to suppress saving to
~/.empire_history in the test suite.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
de638fd779 client: Use readline only when standard input is a TTY
Readline is for interactive use.  For non-interactive use, it merely
complicates things.  Case in point: it slows down "make check" by almost
10% for me.

Interactive use should always involve a TTY, so use readline only when
standard input is a TTY.  This supresses readline in "make check".

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
a0220e864f client: Use fnameat() to construct history file name
We truncate the user's home directory name to 1000 characters when
constructing the history file name.  Use fnameat() to fix that.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
6b72fefafb include: Factor fnameat.h out of prototypes.h
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:30 +02:00
48fcff36b2 m4: Make MY_WITH_TERMINFO consistent with MY_WITH_READLINE
Tweak help text and failure message.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
56f426ae9e client: New configure --with-readline
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
1cbda2c7dd client: Rewrite readline configuration
AX_LIB_READLINE tries to cope with systems where readline lacks
history support, or lacks headers, or needs headers included in
unorthodox ways.  It puts six HAVE_ macros into config.h, and its
usage example takes 24 lines of code just to include two headers.

Way too complicated for my taste.  Replace with new MY_LIB_READLINE,
which succeeds only when you have a sane readline, and then defines
*one* macro: HAVE_LIBREADLINE.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
60fee0e6ae client: Collect readline-related code in play.c
Move prompt() from servcmd.c to play.c and give it external linkage.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
f83e61cdd2 client: Redistribute work among prompt() and its callers
Two out of three callers want an extra newline.  Letting the callers
do that is simpler, especially now that readline added another case to
prompt().

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
5e82836e3a client: Fix obscure readline hang
If recv_input() can't stuff the whole line into @inbuf, it leaves its
tail in @input_from_rl.  If send_input() then empties @inbuf, the next
iteration will select @input_fd for reading instead of @sock for
writing, because @inbuf is empty.  Since @has_rl_input is still set,
recv_input() will do nothing, and the client hangs.

Fix as follows.  Factor ring_from_rl() out of recv_input().  Also call
it in send_input() to refill @inbuf from @input_from_rl.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
0cb6690600 client: Tie up a few lose readline ends
Document readline in more detail in man/empire.6.

Make @history_file local to main().

main() silently truncates the home directory name to 1000 characters
when constructing the history file name; mark FIXME.

Set @rl_already_prompted just once.

Write history file on unsuccessful exit, too.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
Martin Haukeli
f1fc0df03d client: Add readline support to empire client
Readline provides fancy command line editing such as <Arrow Up> for
previous commands and CTRL+A to jump to the beginning of the line.

This patch does not add any completion on <tab> key, a TODO, if you
will.

A new command line flag, -H, turns on saving the history to disk.
This may have security implications on shared computers, as all
commands are saved as-is.  Thus "change re 1234" would be logged
directly to the file.

Signed-off-by: Martin Haukeli <martin.haukeli@gmail.com>

Rebase on top of preparatory work, fix a few bugs, and tidy up:

* Update the standalone client build, too.

* Fix the Windows build.

* Keep command line options sorted case-insensitively.

* Error out when $HOME is unset and getpwuid() fails, just like we do
  for $LOGNAME.

* Give @input_from_rl, @has_rl_input static linkage.

* @has_rl_input is a flag, not a counter, set and test it accordingly.

* Save all input in history, not just commands.  Martin's attempt to
  recognize commands works only as long as the server sends prompts
  faster than the user sends input.  Drop that part, and update commit
  message accordingly.

* Fix recv_input() not to truncate value of strlen() to int, and to
  use memmove() for updating @input_from_rl in place.

* Clean up whitespace in a few places.

* Tweak commit message.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
594cd20f76 client: Remove unused ring_to_file()
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
b3383c7423 client: Delay additional input processing until after send
We need to copy input to @auxfp to implement command line option -2,
and pass it to save_input() to enable protection against a rogue
server exploiting redirection and execute.  We currently do this right
when input enters the ring buffer, in recv_input().

Calling save_input() before sending input to the server is sloppy: it
can make the client accept "future" redirections and executes.

Delay save_input() until after input is sent.  For simplicity, delay
copying to @auxfp as well.

This is actually pretty close to how things worked before commit
8b7d0b9 (v4.3.11).

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
26372eb85d client: Inline ring_to_file() into new send_input()
In preparation for the next commit.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
53c8794ef8 client: Rearrange ring_to_iovec() for clarity
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
8fe2b949e6 client: Split ring_to_iovec() off ring_to_file()
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
8301e0f144 client: Lift assignment to @input_fd to recv_output()
On successful execute, servercmd() sets @input_fd to the batch file
descriptor.  Return the file descriptor instead, and let its caller
recv_output() set @input_fd.  This permits giving @input_fd static
linkage.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
37e68e5796 client: Fix obscure misdetection of input EOF
recv_input(input_fd, &inbuf) returns zero when @inbuf is full or
@input_fd is at EOF.  We avoid the former by putting @input_fd in
@rdfd only when @inbuf has space, so we can detect EOF easily.  But we
missed the case where adding a cookie fills up @inbuf.  We
misinterpret "can't read into full buffer" as "EOF on input" then.

Fix by checking for space again.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
38097c4986 client: Clear pending interrupt on stdin EOF
The client can send an interrupt cookie after the EOF cookie.
Harmless, as the server throws away input after the EOF cookie.  Clean
it up anyway.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
3135cd39c3 client: Simplify input EOF handling
We increment @send_eof only when read() returns zero, and we read()
only when it's zero.  Therefore, we never increment it beyond one.
Change it from counter to flag.

This effectively reverts commit 51846ec (v4.3.11).  Possible only
because the previous commit got rid of the @send_eof increment on
failed execute.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
b6d0f4e3db client: Signal interrupt instead of EOF on batch file error
The server doesn't currently care for the difference, but interrupt is
more accurate than EOF.  The change also enables the next commit.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
cf7d52fc10 client: Simplify rogue redirection and execute protection further
recv_input() passes full lines to save_input().  Pass characters
instead.  Simpler, and doesn't truncate long lines.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-08-06 11:22:29 +02:00
5cb14f508e client: Fix rogue execute protection
To protect against a rogue server reading your files, the client
honors C_EXECUTE only when it matches recent player input.

This has a somewhat troubled history, detailed in the previous commit.

The remaining major issue comes from commit 8b7d0b9 (v4.3.11): any
suffix of a recent line of input is accepted as C_EXECUTE text.
Before, only text that looked like an argument of an execute command
or a redirection was accepted.

Fix by again requiring the text to be preceded by something that looks
like an execute command.  But do it more carefully: don't break
execute with a prompted for argument, and prevent abuse of
redirections for execute.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-07-24 20:21:40 +02:00
d13950470a client: Simplify rogue redirection and execute protection
Redirections let the server write files and run pipelines, and execute
lets it read files.

Before 4.2.0, the client simply trusted the server.  4.2.0 added
fairly complex code to recognize redirections and execute, replace the
filenames and pipelines by tag strings, remember tag string and
replaced text, and honor redirection and execute only when their text
is a known tag string.  Tag and replaced text were freed on use.

Broken by design because the client cannot know whether a line will
actually be read as a command by the server.  Issues included:

(1) Non-command lines could be messed up.

(2) The memory used for remembering their tags was never freed.

(3) execute prompting for its argument was incorrectly rejected.

(4) A rogue server could use a tag for the wrong purpose.  For
instance, "execute fire" creates a tag for "fire", which a rogue
server could use for a pipeline to command "ire".

4.2.10 dropped the tag strings, and used the actual text as key.  This
took care of (1).

Commit 17d6997 and commit 2456a71 (both v4.3.11) tightened checking of
redirections, which took care of (4) for redirections, but not
execute.  Relatively harmless, because redirection text always starts
with '>' or '|', but filenames rarely do.

Commit 8b7d0b9 (v4.3.11) replaced the protection code wholesale.
Instead of attempting to recognize redirections and execute, we now
save everything in a ring buffer, and require redirections and execute
to match at a line end in the ring buffer.  Much simpler, takes care
of issues (2) and (3), but adds new issues:

(5) When sent-ahead input exceeds the ring buffer, good redirections
and executes get rejected.  Could be avoided by limiting send-ahead,
or remembering input until its output arrives.  However, bogus
rejections haven't been a problem in practice even with a tiny 4KiB
ring buffer.

(6) The protection against rogue execute is *much* weaker, because we
now accept any line suffix.  Before, we accepted any tag,
i.e. anything that looks like a redirection or an execute command.

(7) When we find a match in the ring buffer, we used to drop
everything up to that line right away.  This broke redirected execute
commands.  Commit 02a9af0 (v4.3.11) fixed it by delaying the drop
until the next prompt, but that's overly complicated.

This commit addresses (7): don't drop on use, simply let new input
push old input out of the ring buffer.

The next commit will address (6) and the remainder of (4).

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-07-24 20:21:16 +02:00
a2f6ea968c client: Improve the client's messages
Use a "Warning: " prefix for server output violating the protocol and
for rogue redirections and executes.  Don't shout "WARNING!"

In redir_authorized(), check for server issues (conflicting
redirections, rogue redirections and executes) before enforcing
restrictions (restricted mode, executing batch file), so server issues
aren't masked.

Surprisingly, popen() may not set errno on failure.  Avoid reporting a
bogus errno in dopipe().

doexecute() complains about an "execute file".  We call that a "batch
file" elsewhere.  Reword for consistency.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-07-08 19:17:07 +02:00
8fe0221634 client: Drop extra newlines from the client's messages
servercmd()'s argument arg ends with a newline already.  Broken in
commit 8b7d0b9, v4.3.11.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-07-08 19:17:07 +02:00
63a6288435 client: Fix integer wrap around in ring_peek()
Peeking beyond either end of the ring buffer must return EOF.  We
first compute the index, then check whether it's in range.

Unfortunately, the index computation r->prod - -n can wrap around
while r->prod is still <= RING_SIZE.  If it happens, ring_peek()
returns r->buf[(r->prod - -n) % RING_SIZE] instead of EOF.

Currently harmless, because no caller peeks out of range.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2017-07-08 19:17:07 +02:00
93dfd60c4b man/empire: Trim unwanted space in synopsis
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-13 10:46:58 +01:00
5c28d3685b doc/contributing: Fix git format-patch topic branch example
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-13 10:46:58 +01:00
4bce12ac0b travis: Enable OS X
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:39 +01:00
42a3c10fd9 navigate march: Fix abort not to wipe out concurrent updates
When the player aborts the command at the movement prompt, we write
back stale ships or land units, triggering a generation oops.  Any
updates made by other threads meanwhile are wiped out, triggering a
seqno mismatch oops.

Broken in commit 24000b4, v4.3.33.  Fix by restoring the lost
shp_nav_stay_behind() and lnd_mar_stay_behind() calls.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:39 +01:00
354b6aea3d tests/navi-march: Cover abort at movement prompt
This exposes generation oopses.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:39 +01:00
863fde5a2c march: Fix concurrent updates at sector abandon prompt
When the player declines to abandon a sector, we write back stale land
units, triggering a generation oops.  Any updates made by other
threads meanwhile are wiped out, triggering a seqno mismatch oops.

The culprit is lnd_abandon_askyn(): when the player declines, it
returns without calling check_sect_ok(), check_land_ok().  Broken in
commit 7c1b166, v4.3.33.  Fix it.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:38 +01:00
8daeffbd8f recvclient: Track potential yield on input
recvclient() calls ef_make_stale() only when it does actual I/O, via
io_output() and io_input().  Missed in commit 2fa5f652, v4.3.24.  Call
it directly when it doesn't do actual I/O.

This makes navi-march-test expose a bug in march: when the player
declines to abandon a sector, we write back stale land units,
triggering a generation oops.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:38 +01:00
9645caf6ff configure: Use -fstack-protector-strong when available
Testing whether the compiler supports it is a bit tricky.

The obvious AX_APPEND_COMPILE_FLAGS([-fstack-protector-strong])
doesn't suffice, since some ports of the GNU toolchain reportedly pass
this test, then fail to link.  That's because the compiler accepts the
flag, duly emits references to helper code in libc, but libc doesn't
provide, and linking fails.

Instead, use AX_APPEND_LINK_FLAGS with an input source that makes the
compiler emit the extra stack checking code.  This requires the latest
version from the autoconf-archive, so update m4/ax* to commit e3d948b.
Also update m4/my_append_compile_flags.m4 to keep it in sync with
upstream's ax_append_compile_flags.m4.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:38 +01:00
41263cf8c9 scripts/savecore: Report nicely when there's no core dump
When savecore can't find a core dump, it reports something like

    ls: cannot access core.*: No such file or directory

to stderr, and fails.  If privlog is set, it also mails out a "Could
not save core dump" note.

Suppress the error message, and mail out "Could not find core dump to
save" instead.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:38 +01:00
3f86dd2ecf configure: Use -fno-strict-aliasing -fno-strict-overflow
Contemporary compilers can squeeze out some extra performance by
assuming the program never executes code that has undefined behavior
according to the C standard.  Unfortunately, this can break programs.
Pointing out that these programs are non-conforming is as correct as
it is unhelpful, at least as long as the compiler is unable to
diagnose the non-conformingness.

Since keeping our programs working is a lot more important to us than
running them as fast as possible, forbid some assumptions that are
known to break real-world programs:

* Aliasing: perfectly clean programs don't engage in type-punning, and
  perfectly conforming programs do it only in full accordance with the
  standard's (subtle!) aliasing rules.  Neither kind of perfection is
  realistic for us, therefore -fno-strict-aliasing.

* Signed integer overflow: perfectly clean programs won't ever do
  signed integer arithmetic that overflows.  This is an imperfect
  program, therefore -fno-strict-overflow.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:19:38 +01:00
6e80cf103f tests: Enable GNU libc memory allocation error checking
MALLOC_CHECK_=3 makes glibc check for memory allocation programming
errors.  It's the factory default, but set it anyway just in case
someone disabled it for speed.

Non-zero MALLOC_PERTURB_ makes glibc wipe memory value on allocation
and deallocation.  The actual value determines the bit pattern.  Set
it to the value of environment variable EMPIRE_CHECK_MALLOC_PERTURB or
else a pseudo-random number, and record it in sandbox/malloc-perturb.

See mallopt(3) for more information.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 13:03:08 +01:00
1abd3c5b0b navigate march: Plug memory leaks
When the player aborts the command at the movement prompt, or declines
to abandon a sector, unit_move() returns without freeing the list.
Found with valgrind.  Broken in commit 24000b4 and commit 7c1b166,
both v4.3.33.

Free the list on these returns, too.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:51:07 +01:00
25c7d3798b navigate march retreat lretreat: Fix read beyond buffer
shp_nav_gauntlet() and lnd_mar_gauntlet() read beyond the list head
when the list is empty.  The values read aren't used then.  Could
conceivably crash the server anyway, but it's unlikely.

Empty list happens when shp_nav_dir(), lnd_mar_dir() empty the list
and return zero.  Broken in commit beedf8d, v4.3.33.  Occurs in
navi-march-test (since the last commit) and in retreat-test.

Change shp_nav_dir() and lnd_mar_dir() to return one then.  For
additional safety, make shp_nav_gauntlet() and lnd_mar_gauntlet() oops
on empty list and recover safely.

I think I originally found this bug with -fsanitize, but I've since
upgraded, and I can't diagnose it that way anymore.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:51:07 +01:00
493dc5f941 tests/navi-march: Cover running out of mobility completely
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:51:07 +01:00
6888337afe bomb drop fly paradrop recon sweep: Fix read before array
The code computing the length of the flight path checks whether the
path ends with 'h'.  When getpath() returns an empty path, it accesses
flightpath[-1].  This could set the length to -1 (unlikely), or crash
(even less likely).  The former could be abused to gain mobility for
sufficiently inefficient or short-ranged planes.  Found with valgrind.

Broken in commit 404a76f7, v4.3.27.

Historically, getpath() could return paths with or without 'h', and
the check was necessary.  It returned an empty path only when the
player gave no input, aborting the command.  When the player entered
the assembly point's coordinates, it returned "h".

Commit 404a76f7 accidentally changed it to return "" then.  Also broke
flying to the assembly point's coordinates.  Commit 0f1e14f (v4.3.31)
fixed that part by changing getpath()'s contract: always return paths
without 'h' ("" simply means empty path), and return NULL on invalid
input, including no input.

The flawed check is superfluous since then.  Drop it.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:51:07 +01:00
b9375b14b1 Avoid shifting into sign bit
It's undefined behavior.  Found with gcc -fsanitize=undefined.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:50:54 +01:00
d58bea5458 Convert run-time to build-time assertion
There's just one, in show_product().

Use new BUILD_ASSERT() there, because its contract is even simpler
than BUILD_ASSERT_ONE()'s.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:43:28 +01:00
80bf4ec34b Provide proper build-time assertions for NSC_SITYPE()
We want to cause a diagnostic when NSC_SITYPE()'s argument isn't
implemented.  Commit aa6ad9d's solution is to have the macro expand
into 1/0 then.  Works with GCC, but Clang always warns "division by
zero is undefined".

The better, portable way to conditionally break the build is an array
type with a size that's negative when the build should fail, else
positive.  Implement that wrapped in a sizeof() to make it an
expression as macro BUILD_ASSERT_ONE(), and use it in NSC_SITYPE().

No more warnings from Clang 3.5.0.  GCC still produces its "may be
used uninitialized" false positives.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:42:40 +01:00
d074d29736 subs: Don't squash telegrams together when time goes backwards
We've always squashed them when the time difference is smaller than
TEL_SECONDS, regardless of sign.  This involves passing the difference
to abs(), implicitly casting from time_t to int, which triggers a
Clang warning.

I could clean this up to get rid of the warning, but time should never
go backwards, and trying to make things prettier when it does isn't
worthwhile.  Simply drop the abs().

While there, drop the function comment.  It's been inaccurate since
Empire 3 dropped mail.c, and bogus since commit 17223e8 (v4.3.29)
added tel_cont.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:41:16 +01:00
feb894cf1e info/Nuke-types: Document show columns avail, res, abilities
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2015-12-05 12:41:16 +01:00