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>
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>
... when referring to a function's parameter or a struct/union's
member.
The idea of using FOO comes from the GNU coding standards:
The comment on a function is much clearer if you use the argument
names to speak about the argument values. The variable name
itself should be lower case, but write it in upper case when you
are speaking about the value rather than the variable itself.
Thus, "the inode number NODE_NUM" rather than "an inode".
Upcasing names is problematic for a case-sensitive language like C,
because it can create ambiguity. Moreover, it's too much shouting for
my taste.
GTK-Doc's convention to prefix the identifier with @ makes references
to variables stand out nicely. The rest of the GTK-Doc conventions
make no sense for us, however.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
The client rejects unauthorized redirection and execute. Its
authorized check always fails for arguments with non-ASCII characters.
The culprit is ring_search(): It compares plain char to unsigned char,
which breaks when char is signed. Believed to be broken in commit
8b7d0b91, v4.3.11.
Note that non-ASCII characters only work in UTF-8 sessions. In ASCII
sessions, the server replaces them, and the authorized check fails.
Works as designed.
Why upgrade? I'm not a lawyer, but here's my take on the differences
to version 2:
* Software patents: better protection against abuse of patents to
prevent users from exercising the rights under the GPL. I doubt
we'll get hit with a patent suit, but it's a good move just on
general principles.
* License compatibility: compatible with more free licenses, i.e. can
"steal" more free software for use in Empire. I don't expect to steal
much, but it's nice to have the option.
* Definition of "source code": modernization of some details for today's
networked world, to make it easier to distribute the software. Not
really relevant to us now, as we normally distribute full source code.
* Tivoization: this is about putting GPL-licensed software in hardware,
then make the hardware refuse to run modified software. "Neat" trick
to effectively deny its users their rights under the GPL. Abuse was
"pioneered" by TiVo (popular digital video recorders). GPLv3 forbids
it. Unlikely to become a problem for us.
* Internationalization: more careful wording, to harden the license
outside the US. The lawyers tell us it better be done that way.
* License violations: friendlier way to deal with license violations.
This has come out of past experience enforcing the GPL.
* Additional permissions: Probably not relevant to us.
Also include myself in the list of principal authors.
Unlike POSIX sockets, Windows sockets are not file descriptors, but
"OS handles", with a completely separate set of functions.
However, Windows can create a file descriptor for a socket, and return
a file descriptor's underlying handle. Use that instead of our gross
hacks to keep up the illusion that sockets are file descriptors.
Slightly dirty: we put file descriptors into fd_set. Works because
both boil down to int. Change w32_select(), w32_socket(),
w32_connect(), w32_recv(), w32_writev_socket(), w32_send() to take and
return only file descriptors, and map to sockets internally. Replace
w32_close_socket() by w32_close(), and drop the close() macro hackery
that made tcp_connect(), host_connect() use w32_close_socket(). New
fd_is_socket().
Windows provides select()-like functions only for handles. Because of
that, the client used a handle for reading script files, and stored it
in file descriptor input_fd. Drop this dirty hack, use a file
descriptor instead. Works because we can get its underlying handle.
Remove the dirty macro hackery that made play(), ring_from_file() and
doexecute() unwittingly work with a handle. Remove w32_openhandle()
and w32_close_handle(). Replace w32_readv_handle() by w32_readv_fd().
Update w32_select().
Remove w32_openfd(), it's not really needed.
The old code stuffed WSA error codes into errno, which doesn't work.
Use new w32_set_winsock_errno() to convert & stuff.
Fix signed vs. unsigned warnings in Windows client.
Move the struct sigaction replacement next to the sigaction()
replacement.
Rename sysdep_init() to w32_sysdep_init() for consistency.
w32_writev_socket, w32_close_socket, getpass, w32_openfd,
w32_openhandle, w32_readv_handle, w32_close_handle,
sysdep_init, sysdep_stdin_init, w32_select, w32_signal_handler,
sigaction, stdin_read_thread, w32_ring_from_file_to_bounce_buf)
[_WIN32]: New w32 equivalent functions for POSIX functions.
(recvline, sendcmd, tcp_connect, hostconnect, getpass,
main, intr, play, ring_to_file, ring_from_file, doexecute,
doredir) [_WIN32]: Use new WIN32 equivalent functions.
(main) [_WIN32]: Add sysdep_init() to support system dependent
initialization for equivalence functions.
(play) [_WIN32]: Add sysdef_stdin_init() to support system
dependent initialization for reading stdin.
(recv_input, play) [_WIN32]: Replace the calls to ring_to_file()
and select() with WIN32 specific enhanced versions.
Makefile.in: update dependencies with new files.
Make.mk: Add using of getopt.c and getopt.h
from src/lib/w32 directory. Add getopt.c and getopt.h
to tar for client.
(EOF_COOKIE, INTR_COOKIE, input_fd, send_intr, recv_output)
(recv_input, intr, play): New playing phase code. No native Windows
support yet. Sends just one EOF cookie on EOF on standard input
instead of up to three. Old servers (before recvclient.c rev. 1.16)
fail to terminate the session when they receive an EOF cookie at an
argument prompt. The session then hangs; use SIGINT to get out. No
longer blocks on sending input, which could deadlock the session.
Closes#827090. Fixes error handling for select(). Fixes race
condition that could cause server output to be discarded on EOF on
standard input.
(main): Replace old playing phase code by a call to play().
(intr, sock, interrupt, handleintr): Replaced by play(), remove.
[_WIN32] (hStdIn): Ditto.
(auxfp): New.
(servercmd, prompt, doexecute): Remove parameter auxfi, use auxfp.
(eight_bit_clean): Move to servcmd.c.
(servercmd): Work on a single non-C_DATA line instead of getting lines
from an ioqueue.
(servercmd, output, screen, outch): Deal with all ids in servercmd()
rather than some there and some in output(). Don't treat C_NOECHO,
C_ABORT, C_CMDERR, C_BADCMD specially. Fix C_FLASH and C_EXIT to
ignore redirections; they used to ignore them only for some parts.
Replace output() by outch(), fold screen into outch().
(servercmd): Truncate long prompts and telegram infos to prevent
buffer overflow.
(prompt): Use new parameters code, prompt, teles instead of global
variables mode, the_prompt, num_teles.
(num_teles, the_prompt, mode, nbtu, nmin): Remove.
(prompt): Don't write an empty line before argument prompts to auxfp.
(servercmd): Don't strip newline from redirections and execute,
doredir(), dopipe() and doexecute() need it now.
(doredir, dopipe, doexecute): Use new seen_input() instead of gettag().
(doexecute): Set input_fd and leave reading the script file to play().
(serverio, termio, sendeof): Replaced by play(), remove.
(LBUF_LEN_MAX, lbuf, lbuf_init, lbuf_len, lbuf_full, lbuf_line)
(lbuf_putc): New.
(RING_SIZE, ring, ring_init, ring_len, ring_space, ring_peek)
(ring_getc, ring_putc, ring_putm, ring_discard, ring_search)
(ring_from_file, ring_to_file): New.
(clear_recent_input, save_input, seen_input): New.
(MAX): New.
(ioqueue, io, ioq_init, ioq_dequeue, ioq_read, ioq_write, ioq_qsize)
(ioq_drain, ioq_gets, ioqtobuf, enqueuecc, dequeuecc): Unused, remove.
(QEMPTY, qelem, insque, remque, initque): Unused, remove.
(tagstruct, taglist, io_init, gettag): Unused, remove.