httpd: mess with PATH_INFO (again)

2018-01-17 Thread Henrik Friedrichsen
Hello,

I am running Flask apps with uWSGI as a middleware, communicating with
httpd via FastCGI sockets.

Ever since OpenBSD 6.1 I started running into problems with all of my
Flask apps. They would get caught in a redirect loop for root paths
(see [1]).

I did some debugging, and it seems that Flasks routing engine Werkzeug
has an option called `strict_slashes`[2], which will append a slash
and redirect to directory requests without a trailing slash.

When the root URL of an app is requested, e.g. "http://foo.bar;,
PATH_INFO will be set to an empty string. This causes Werkzeug to
respond with a redirect, but the next request will still come in with
PATH_INFO as "", resulting in a redirect loop.

Attached diff causes PATH_INFO to be "/" in such a case, effectively
fixing the problem for me. However, I am not well versed with the
httpd code-base. Maybe it should be corrected with a different
approach.  Just sending this in to get the ball rolling.

The CGI RFC[3] states that "/" and "" are valid paths. I would assume
that for applications mounted at root, PATH_INFO should be "/" instead
of "" when requesting the index.

[1]: https://github.com/reyk/httpd/issues/71
[2]: http://werkzeug.pocoo.org/docs/0.14/routing/#werkzeug.routing.Rule
[3]: https://tools.ietf.org/html/rfc3875#section-4.1.5
Index: httpd.c
===
RCS file: /cvs/src/usr.sbin/httpd/httpd.c,v
retrieving revision 1.67
diff -u -p -r1.67 httpd.c
--- httpd.c 28 May 2017 10:37:26 -  1.67
+++ httpd.c 18 Jan 2018 07:20:58 -
@@ -722,8 +722,12 @@ path_info(char *path)
*p = ch;
 
/* Break if the initial path component was found */
-   if (ret == 0)
+   if (ret == 0) {
+   /* ensure leading / if path component is a directory */
+   if (S_ISDIR(st.st_mode))
+   return (p - start - 1);
break;
+   }
}
 
return (p - start);


Re: Basic SHA3 support (cryptographic discussion)

2018-01-17 Thread Christian Weisgerber
Daniel Loebenberger:

> - The construction of SHA3 differs considerably from the SHA2
> constructions
> - SHA3's design principles are far better understood than the ones of
> SHA2.

I hear you, but you are missing the point.

> - A possible migration away from SHA2 will be
> faster when including SHA3 in OpenBSD now if it should happen that major
> cryptanalytic advances attacking SHA2 pop up in the future.

You are arguing for cryptographic algorithm agility.  That is a
concept the OpenBSD project has become increasingly critical of,
because it adds complexity and code size for questionable gain.

SHA-2 is baked into numerous protocols.  Off the top of my head:
* signify(1)
* all non-legacy SSH key exchange and authentication methods
* all non-legacy TLS cipher suites and certificates

For all of those, a switchover to SHA-3 would require defining new
protocol variants and then deploying them throughout the ecosystem.
Having a SHA-3 implementation in libc is a rather small part of the
overall effort.  And there is no practical algorithm agility until
you get to the point where you already HAVE deployed the new protocol
variants.

SHA-3 may be better, but so far SHA-2 is good enough.
Algorithm agility is a questionable goal.

So let me repeat the question:
What do you want to USE your SHA-3 implementation for?

-- 
Christian "naddy" Weisgerber  na...@mips.inka.de



Re: malloc.c: correlation between random choices

2018-01-17 Thread Otto Moerbeek
On Wed, Jan 17, 2018 at 01:59:21PM +, kshe wrote:

> Hi,
> 
> In malloc_bytes(), the choice of the chunk_info list to use is
> correlated with that of the offset at which the search for a free chunk
> begins, because both use the same random source.  This is easy to avoid,
> for example by doing something like the diff below.
> 
> --- malloc.c.orig Sun Jan 14 11:18:10 2018
> +++ malloc.c  Tue Jan 16 12:31:29 2018
> @@ -954,7 +954,7 @@ malloc_bytes(struct dir_info *d, size_t size, void *f)
>   wrterror(d, "chunk info corrupted");
>  
>   if (bp->free > 1)
> - bp->rotor += r;
> + bp->rotor += getrbyte(d);
>   i = bp->rotor++ & (bp->total - 1);
>  
>   /* start somewhere in a short */

This has been done to save a random byte. The correlation does not hurt.

> 
> On a related note, however, I have some doubts about the usefulness of
> this "randomisation rotor".
> 
> First, it currently does not really randomise anything, since on most
> architectures the total number of chunks always divides 256, so that
> using merely `r' as the random offset instead of `bp->rotor + r' would
> not change the distribution for the random variable thus obtained.
> Moreover, in the rare cases where it actually has a noticeable effect,
> this distribution is no longer uniform (and very biased) anyway, so the
> proper way to randomise these choices would be to call getrbyte() twice,
> not to add one random byte to a previously used random byte.

The point is that on some arch there are more than 256 chunks in a
page.  e.g. on sparc64 (pagesize is 8k) for 16 bytes chunks. So using
just a byte is not enough to count all chunks. That's why I'm
collecting more bits by adding them to previously generated bits. Bias
is not a big deal here as well.

> 
> Second, it was introduced to "remember the position of the last free bit
> in chunk_info", but it does not do that at all.  In fact, when chunks
> are allocated uniformly (which is always the case on amd64 for example),
> once only two free slots are left, if the search for the first of these
> two takes n steps, the search for the second and last one is then
> guaranteed to take at least n steps, as it will systematically repeat
> the last n-1 unsuccessful steps of the previous one, which is actually
> worse than simply starting at a random offset or, for that matter, from
> the beginning of the bitmap.

Looking at this code again I see your point. I seems some assignment
to the rotor has been lost in the refactoring. 

I'll revisit.

-Otto

> 
> More precisely, if n is the total number of chunks, the average number
> of bits to check in order to find the last two free chunks is
> 
>   (n + 1) / 3 + (n + 1) / 2
> 
> if both starting offsets are chosen randomly and independently from each
> other.  On the other hand, the current average number of bits that will
> be checked is n, or more explicitly
> 
>   (n + 1) / 3 + 2 * (n + 1) / 3 - 1,
> 
> or even more explicitly
> 
>   (sum for i = 1 to n of
>   i * 2 * (n - i) / (n * (n - 1))) +
>   (sum for i = 1 to n of
>   i * 2 * (i - 1) / (n * (n - 1))) - 1.
> 
> This indeed becomes worse than the above for all n greater than 5, that
> is for all cases except the two least important ones (n = 2 and n = 4),
> where no optimisation is necessary anyway.
> 
> Therefore, I think this variable should be removed from chunk_info, as
> it currently does more harm than good.  If this is agreed with, I could
> also provide a diff for it (but the solution, by the way, is not to
> revert to the previous version of this code, which did not make much
> sense either).
> 
> Regards,
> 
> kshe



Re: malloc.c: correlation between random choices

2018-01-17 Thread Marc Espie
On Wed, Jan 17, 2018 at 08:52:36AM -0700, Theo de Raadt wrote:
> So the attacker has numerous small hurdles.  There's a banana on the
> road, but there's snare wire above it.

Okay, now, I can't stop thinking of a Will.E. Coyote-shaped 
Theo unboxing his ACME ordered snare wire at xmas...



Re: malloc.c: correlation between random choices

2018-01-17 Thread Theo de Raadt
> On a related note, however, I have some doubts about the usefulness of
> this "randomisation rotor".
> 
> First, it currently does not really randomise anything, since on most
> architectures the total number of chunks always divides 256, so that
> using merely `r' as the random offset instead of `bp->rotor + r' would
> not change the distribution for the random variable thus obtained.
> Moreover, in the rare cases where it actually has a noticeable effect,
> this distribution is no longer uniform (and very biased) anyway, so the
> proper way to randomise these choices would be to call getrbyte() twice,
> not to add one random byte to a previously used random byte.

Many minor randomizations are surprisingly effective because an
attacker only gets 1 attack try.

Why?  Because other layers have also perturbed their addresses, or
other addresses which an attacker needs.

So the attacker has numerous small hurdles.  There's a banana on the
road, but there's snare wire above it.

It is too easy to fall into the trap of "I'm looking at the only defense".



Re: elf.h: define SHT_SYMTAB_SHNDX

2018-01-17 Thread Martin Pieuchot
On 16/01/18(Tue) 14:17, Karel Gardas wrote:
> [...] 
> The patch looks good if you are OK with adding values which are no longer in
> spec. IMHO I do not see value in those,

What if somebody use them in their code?  Removing them would break
their app for free.  That's why I see value in those ;)

> so I would kill everything which is not in spec and does not break OpenBSD
> build or any of ports. Related comments below.

Updated diff, does it work for you?

Index: sys/exec_elf.h
===
RCS file: /cvs/src/sys/sys/exec_elf.h,v
retrieving revision 1.78
diff -u -p -r1.78 exec_elf.h
--- sys/exec_elf.h  9 Dec 2017 06:35:08 -   1.78
+++ sys/exec_elf.h  17 Jan 2018 11:11:19 -
@@ -106,15 +106,20 @@ typedef __uint16_tElf64_Quarter;
 #define ELFOSABI_HURD  4   /* GNU/Hurd */
 #define ELFOSABI_86OPEN5   /* 86Open common IA32 ABI */
 #define ELFOSABI_SOLARIS   6   /* Solaris */
-#define ELFOSABI_MONTEREY  7   /* Monterey */
+#define ELFOSABI_AIX   7   /* AIX */
 #define ELFOSABI_IRIX  8   /* IRIX */
 #define ELFOSABI_FREEBSD   9   /* FreeBSD */
 #define ELFOSABI_TRU64 10  /* TRU64 UNIX */
 #define ELFOSABI_MODESTO   11  /* Novell Modesto */
 #define ELFOSABI_OPENBSD   12  /* OpenBSD */
+#define ELFOSABI_OPENVMS   13  /* Open VMS */
+#define ELFOSABI_NSK   14  /* HP Non-Stop Kernel */
 #define ELFOSABI_ARM   97  /* ARM */
 #define ELFOSABI_STANDALONE255 /* Standalone (embedded) application */
 
+#define ELFOSABI_NONE  ELFOSABI_SYSV   /* symbol used in old spec */
+#define ELFOSABI_MONTEREY  ELFOSABI_AIX/* Monterey */
+
 /* e_ident */
 #define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
   (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
@@ -164,8 +169,10 @@ typedef struct {
 #define ET_DYN 3   /* shared object file */
 #define ET_CORE4   /* core file */
 #define ET_NUM 5   /* number of types */
-#define ET_LOPROC  0xff00  /* reserved range for processor */
-#define ET_HIPROC  0x  /*  specific e_type */
+#define ET_LOOS0xfe00  /* First operating system 
specific. */
+#define ET_HIOS0xfeff  /* Last operating 
system-specific. */
+#define ET_LOPROC  0xff00  /* First processor-specific. */
+#define ET_HIPROC  0x  /*  Last processor-specific. */
 
 /* e_machine */
 #define EM_NONE0   /* No Machine */
@@ -241,25 +248,31 @@ typedef struct {
 #define SHN_LORESERVE  0xff00  /* lower bounds of reserved indexes */
 #define SHN_LOPROC 0xff00  /* reserved range for processor */
 #define SHN_HIPROC 0xff1f  /*   specific section indexes */
+#define SHN_LOOS   0xff20  /* First operating system-specific. */
+#define SHN_HIOS   0xff3f  /* Last operating system-specific. */
 #define SHN_ABS0xfff1  /* absolute value */
 #define SHN_COMMON 0xfff2  /* common symbol */
 #define SHN_XINDEX 0x  /* Escape -- index stored elsewhere. */
 #define SHN_HIRESERVE  0x  /* upper bounds of reserved indexes */
 
 /* sh_type */
-#define SHT_NULL   0   /* inactive */
-#define SHT_PROGBITS   1   /* program defined information */
-#define SHT_SYMTAB 2   /* symbol table section */
-#define SHT_STRTAB 3   /* string table section */
-#define SHT_RELA   4   /* relocation section with addends*/
-#define SHT_HASH   5   /* symbol hash table section */
-#define SHT_DYNAMIC6   /* dynamic section */
-#define SHT_NOTE   7   /* note section */
-#define SHT_NOBITS 8   /* no space section */
-#define SHT_REL9   /* relation section without 
addends */
-#define SHT_SHLIB  10  /* reserved - purpose unknown */
-#define SHT_DYNSYM 11  /* dynamic symbol table section */
-#define SHT_NUM12  /* number of section types */
+#define SHT_NULL   0   /* inactive */
+#define SHT_PROGBITS   1   /* program defined information */
+#define SHT_SYMTAB 2   /* symbol table section */
+#define SHT_STRTAB 3   /* string table section */
+#define SHT_RELA   4   /* relocation section with addends*/
+#define SHT_HASH   5   /* symbol hash table section */
+#define SHT_DYNAMIC6   /* dynamic section */
+#define SHT_NOTE   7   /* note section */
+#define SHT_NOBITS 8   /* no space section */
+#define SHT_REL9   /* relation section 

Re: [patch] config(8) and KARL usage

2018-01-17 Thread Robert Nagy
On 17/01/18 11:40 +0100, Martin Pieuchot wrote:
> Hello Sebastien,
> 
> On 17/01/18(Wed) 10:19, Sebastien Marie wrote:
> > [...] 
> > kernel modification is desirable in some cases, at least for disabling
> > ulpt(4) when using cups with USB printer.
> 
> Sorry to hijack your thread, but if somebody wants to fix this ulpt(4)
> problem permanently here's the plan:
> 
>  - Add the USBD_EXCLUSIVE_USE to usbd_open_pipe() in ulptopen().
>Actually this flag should be the default everywhere.  This should
>prevent open(2) on /dev/ulpt? to work if a userland driver is using
>your printer.
> 
>  - Do some plumbing between libusb/ugen(4)/usb(4) to make it possible
>to submit bulk transfer via /dev/usb?.  The logic in ugenopen()
>should also have the USBD_EXCLUSIVE_USE flag such that it will fail
>if the corresponding /dev/ultp? has already been opened.
> 
> That should be enough to have CUPS work with GENERIC kernels without
> having to disable anything.  I'm here to help/review diffs but since
> I don't have a printer myself, I can't do the work.
> 

Oh yes please.



Re: [patch] config(8) and KARL usage

2018-01-17 Thread Martin Pieuchot
Hello Sebastien,

On 17/01/18(Wed) 10:19, Sebastien Marie wrote:
> [...] 
> kernel modification is desirable in some cases, at least for disabling
> ulpt(4) when using cups with USB printer.

Sorry to hijack your thread, but if somebody wants to fix this ulpt(4)
problem permanently here's the plan:

 - Add the USBD_EXCLUSIVE_USE to usbd_open_pipe() in ulptopen().
   Actually this flag should be the default everywhere.  This should
   prevent open(2) on /dev/ulpt? to work if a userland driver is using
   your printer.

 - Do some plumbing between libusb/ugen(4)/usb(4) to make it possible
   to submit bulk transfer via /dev/usb?.  The logic in ugenopen()
   should also have the USBD_EXCLUSIVE_USE flag such that it will fail
   if the corresponding /dev/ultp? has already been opened.

That should be enough to have CUPS work with GENERIC kernels without
having to disable anything.  I'm here to help/review diffs but since
I don't have a printer myself, I can't do the work.



[patch] config(8) and KARL usage

2018-01-17 Thread Sebastien Marie
Hi,

I would like to know if a patch for supporting kernel modification
(using config(8)) along with KARL would be accepted ?

Currently, both are incompatibles.

kernel modification is desirable in some cases, at least for disabling
ulpt(4) when using cups with USB printer.

KARL is desirable too.


I would like to add such support in the following way:

- add an argument to config(8) to support non-interactive use.
  Basically, it would be "read from file instead read from stdin".
  
- add a line in kernel Makefile to do kernel modification (only if file
  /etc/ukc.conf is present) as part of KARL process (after relinking and
  before checksuming).

Please note the place of the config(8) call: the kernel modification
would occurs only when KARL is invoked during boot process ("newbsd"
target), and not when the kernel is first generated (during the
release(8) process).

Missing part in the diff is the ukc.conf man page. It would be provided
if the direction seems good.

Please note that I don't have tested full release(8) process (it would
be mandatory for such change).

The config(8) changes in detail: config(8) will use scriptfile as input
stream (instead of `stdin') if provided.

When non-interactive is in use, the following things changes:
- on EOF : assume "quit" command (save and exit) instead of err(3)
- on bad command : exit(1) instead of ignoring the error and asking for
  new command.

For testing the diff:
- compile and install (patched) config(8) first
- don't omit the "make config" before building and installing new kernel



Some example:

# cat /etc/ukc.conf
disable ulpt*
# /usr/libexec/reorder_kernel
# cat /usr/share/relink/kernel/GENERIC.MP/relink.log
(SHA256) /bsd: OK
LD="ld" sh makegap.sh 0x
ld -T ld.script -X --warn-common -nopie -o newbsd ${SYSTEM_HEAD} vers.o ${OBJS}
textdatabss dec hex
8173928 2380088 1093632 11647648b1baa0
mv newbsd newbsd.gdb
ctfstrip -S -o newbsd newbsd.gdb
if [ -f /etc/ukc.conf ]; then config -f -F /etc/ukc.conf -e newbsd; fi
OpenBSD 6.2-current (GENERIC.MP) #85: Wed Jan 17 09:39:30 CET 2018
semarie@bert.local:/home/openbsd/src/sys/arch/i386/compile/GENERIC.MP
Enter 'help' for information
ukc> disable ulpt*
398 ulpt* disabled
ukc> quit
Saving modified kernel.
mv -f newbsd bsd
umask 077 && cp bsd /nbsd && mv /nbsd /bsd &&  sha256 -h /var/db/kernel.SHA256 
/bsd

Kernel has been relinked and is active on next reboot.

SHA256 (/bsd) = 81a4916b8b81f0986d6fd63aad83c7fa4e742faa86c436756f1f79731c7ea184

-- 
Sebastien Marie

Index: config.8
===
RCS file: /cvs/src/usr.sbin/config/config.8,v
retrieving revision 1.65
diff -u -p -r1.65 config.8
--- config.87 Oct 2017 06:41:43 -   1.65
+++ config.817 Jan 2018 09:15:47 -
@@ -45,6 +45,7 @@
 .Nm config
 .Op Fl u
 .Op Fl f | o Ar outfile
+.Op Fl F Ar scriptfile
 .Fl e
 .Ar infile
 .Sh DESCRIPTION
@@ -121,6 +122,12 @@ should be given to specify an alternate 
 .It Fl o Ar outfile
 Write the modified kernel to
 .Ar outfile .
+.It Fl F Ar scriptfile
+Use
+.Ar scriptfile
+as source of commands for kernel modification.
+.Ic quit
+is assumed on eof.
 .It Fl u
 Check to see if the kernel configuration was modified at boot-time
 (i.e.\&
Index: main.c
===
RCS file: /cvs/src/usr.sbin/config/main.c,v
retrieving revision 1.59
diff -u -p -r1.59 main.c
--- main.c  22 Jun 2017 15:57:16 -  1.59
+++ main.c  17 Jan 2018 09:15:48 -
@@ -82,7 +82,7 @@ usage(void)
 
fprintf(stderr,
"usage: %s [-p] [-b builddir] [-s srcdir] [config-file]\n"
-   "   %s [-u] [-f | -o outfile] -e infile\n",
+   "   %s [-u] [-f | -o outfile] [-F scriptfile] -e infile\n",
__progname, __progname);
 
exit(1);
@@ -92,6 +92,7 @@ int pflag = 0;
 char *sflag = NULL;
 char *bflag = NULL;
 char *startdir;
+FILE *input = stdin;
 
 int
 main(int argc, char *argv[])
@@ -105,7 +106,7 @@ main(int argc, char *argv[])
err(1, "pledge");
 
pflag = eflag = uflag = fflag = 0;
-   while ((ch = getopt(argc, argv, "epfb:s:o:u")) != -1) {
+   while ((ch = getopt(argc, argv, "epfF:b:s:o:u")) != -1) {
switch (ch) {
 
case 'o':
@@ -146,6 +147,12 @@ main(int argc, char *argv[])
case 's':
sflag = optarg;
srcdir = optarg;
+   break;
+
+   case 'F':
+   input = fopen(optarg, "r");
+   if (input == NULL)
+   err(2, "cannot read %s", optarg);
break;
 
default:
Index: misc.c
===
RCS file: /cvs/src/usr.sbin/config/misc.c,v
retrieving revision 1.9
diff -u -p -r1.9 misc.c
--- misc.c  2 Oct 2011 

Re: Add "-c command" option to script(1)

2018-01-17 Thread Paul de Weerd
ping

Anyone?  Buehler? :)

Paul

On Mon, Dec 25, 2017 at 12:23:44PM +0100, Paul de Weerd wrote:
| Hi all,
| 
| Sorry to keep harping on this script stuff, but I'd really like to see
| this committed.  I've just upgraded my laptop while doing some
| vlan-bridging debugging and suddenly script(1) lost my new favorite
| feature.
| 
| The manpage bits are OK jmc@; job@ and ian@ (off-list) OK'd the diff.
| Is anyone willing to commit it with those?
| 
| Thanks,
| 
| Paul
| 
| On Sat, Dec 16, 2017 at 09:45:02AM +0100, Paul de Weerd wrote:
| | On Fri, Dec 15, 2017 at 12:24:45PM +0100, Paul de Weerd wrote:
| | | I've updated the diff to add this example as per jmc's suggestion.  It
| | | now has:
| | | 
| | |   - add the `-c command` feature
| | |   - updates usage
| | |   - removes /* ARGSUSED */ lint comments
| | |   - documents the -c feature
| | |   - adds an example to the manpage
| | 
| | jmc@ pointed out a missing colon at the end of the example.  Apologies
| | for the extra noise.  Updated diff (still covers the above five
| | changes) included.
| | 
| | Cheers,
| | 
| | Paul
| | 
| | 
| | Index: script.1
| | ===
| | RCS file: /cvs/src/usr.bin/script/script.1,v
| | retrieving revision 1.14
| | diff -u -p -r1.14 script.1
| | --- script.115 Jan 2012 20:06:40 -  1.14
| | +++ script.116 Dec 2017 08:42:24 -
| | @@ -39,6 +39,7 @@
| |  .Sh SYNOPSIS
| |  .Nm script
| |  .Op Fl a
| | +.Op Fl c Ar command
| |  .Op Ar file
| |  .Sh DESCRIPTION
| |  .Nm
| | @@ -65,9 +66,14 @@ Append the output to
| |  or
| |  .Pa typescript ,
| |  retaining the prior contents.
| | +.It Fl c Ar command
| | +Run
| | +.Ar command
| | +instead of an interactive shell.
| | +To run a command with arguments, enclose both in quotes.
| |  .El
| |  .Pp
| | -The script ends when the forked shell exits (a control-D
| | +The script ends when the forked program exits (a control-D
| |  .Pq Ql ^D
| |  to exit
| |  the Bourne shell
| | @@ -102,6 +108,11 @@ Name of the shell to be forked by
| |  If not set, the Bourne shell is assumed.
| |  (Most shells set this variable automatically.)
| |  .El
| | +.Sh EXAMPLES
| | +Start a virtual machine and log all console output to a file:
| | +.Bd -literal -offset indent
| | +$ script -c "vmctl start myvm -c" myvm.typescript
| | +.Ed
| |  .Sh HISTORY
| |  A predecessor called
| |  .Nm dribble
| | Index: script.c
| | ===
| | RCS file: /cvs/src/usr.bin/script/script.c,v
| | retrieving revision 1.33
| | diff -u -p -r1.33 script.c
| | --- script.c12 Apr 2017 14:49:05 -  1.33
| | +++ script.c14 Dec 2017 07:34:10 -
| | @@ -89,7 +89,7 @@ int   istty;
| |  
| |  __dead void done(int);
| |  void dooutput(void);
| | -void doshell(void);
| | +void doshell(char *);
| |  void fail(void);
| |  void finish(int);
| |  void scriptflush(int);
| | @@ -102,17 +102,23 @@ main(int argc, char *argv[])
| | struct sigaction sa;
| | struct winsize win;
| | char ibuf[BUFSIZ];
| | +   char *cmd;
| | ssize_t cc, off;
| | int aflg, ch;
| |  
| | +   cmd = NULL;
| | aflg = 0;
| | -   while ((ch = getopt(argc, argv, "a")) != -1)
| | +   while ((ch = getopt(argc, argv, "ac:")) != -1)
| | switch(ch) {
| | case 'a':
| | aflg = 1;
| | break;
| | +   case 'c':
| | +   cmd = optarg;
| | +   break;
| | default:
| | -   fprintf(stderr, "usage: %s [-a] [file]\n", __progname);
| | +   fprintf(stderr, "usage: %s [-a] [-c command] [file]\n",
| | +   __progname);
| | exit(1);
| | }
| | argc -= optind;
| | @@ -163,7 +169,7 @@ main(int argc, char *argv[])
| | if (child)
| | dooutput();
| | else
| | -   doshell();
| | +   doshell(cmd);
| | }
| |  
| | bzero(, sizeof sa);
| | @@ -196,7 +202,6 @@ main(int argc, char *argv[])
| | done(sigdeadstatus);
| |  }
| |  
| | -/* ARGSUSED */
| |  void
| |  finish(int signo)
| |  {
| | @@ -215,7 +220,6 @@ finish(int signo)
| | errno = save_errno;
| |  }
| |  
| | -/* ARGSUSED */
| |  void
| |  handlesigwinch(int signo)
| |  {
| | @@ -294,7 +298,6 @@ dooutput(void)
| | done(0);
| |  }
| |  
| | -/* ARGSUSED */
| |  void
| |  scriptflush(int signo)
| |  {
| | @@ -302,9 +305,10 @@ scriptflush(int signo)
| |  }
| |  
| |  void
| | -doshell(void)
| | +doshell(char *cmd)
| |  {
| | char *shell;
| | +   char *argp[] = {"sh", "-c", NULL, NULL};
| |  
| | shell = getenv("SHELL");
| | if (shell == NULL)
| | @@ -313,8 +317,15 @@ doshell(void)
| | (void)close(master);
| | (void)fclose(fscript);
| | login_tty(slave);
| | -   execl(shell, shell, "-i", (char *)NULL);
| | -   warn("%s", shell);
| | +
|