Using -lssh as shared library

Michael Tokarev mjt at tls.msk.ru
Mon Oct 8 21:33:22 EST 2001


mouring at etoh.eviladmin.org wrote:
> 
> On Mon, 8 Oct 2001, Michael Tokarev wrote:
> 
> [..]
> > I hacked source a bit, but not like this hack very well.
> > What I did is created one extra file, ipv4or6.c, that
> > contains definition of this variable, added it into
> > list of objects for libssl, and changed actual declarations
> > in ssh.c, sshd.c, ssh-keyscan.c and the like to be simple
> > "extern int IPV4or6".  This allowed me to successefully
> > use shared libssl.so.  I attached a patch named
> > openssh-2.9.9p2-ipv4or6.diff, that does exactly this.
> >
> 
> Hmm... This is wrong.   IPV4or6 variable should be in a header file, not a
> C file.

I agree, but I don't think it belongs to it's own .h file.  Just
like putting the variable itself into own .c file.  I'm not so
familiar with the whole ssh sources to decide where them should
go.  Variable used in e.g. channels.c, but putting it into this
file will result in linking the whole content of this file into
e.g. ssh-keyscan that doesn't uses other routines from this file.
*Really* clean solution IMHO is to use additional argument in
some routines (in channels.c:channel_request_forwarding(),
channels.c:connect_to(), channels.c:channel_connect_by_listen_address()
and so on.  Note that e.g. last one is pretty obvious: instead of
 int channel_connect_by_listen_address(listen_port)
it becomes
 int channel_connect_by_listen_address(listen_port, int family)
).  But having in mind current unclean separation of library
itself (with many global variables and so on) I don't see this
is a good way alone.

In fact, what I did (I already called that "hack", not a real
solution) is not worse at least that was before -- I just followed
some existed "rules" here, as many source files already declared
"extern int IPv4or6" inside)... ;)

[]
> > Note that before the change, ssh-keyscan linked with -lssh
> > twice:
> >  $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
> > Looking into -lssh and -lopenbsd-compat, I don't think it is
> > necessary: there is no "back-references" from -lopenbsd-compat
> > to -lssh.  The patch mentioned above fixes this too.
> 
> Incorrect.  bsd-arc4random.c refers to seed_rng()  which is part of
> entropy.c.  Dynamic linking may remove this issue, but in our current
> compile setup this hack is required.

Hmm... interesting.  I not noticied this when inspecting source nor
when linking with gcc/gld (I verified this line on non-shared lib
too).  Interesting again -- how arc4random implemented in openbsd,
it obviously should not refer to ssh library's seed_rng() (but see
below).

There is a trivial solution for this "library/linker problem"
introduced by my little changes: instead of having SSH_LIBS/SSH_LDFLAGS
as I did, use two separate variables (e.g. LIBSSH/LIBCOMPAT), but
again as *variables* (to stop "hard-coding" them into Makefile).
BTW, all compilers/linkers support "libstuff.a" in place of -lstuff
(so that e.g. LIBCOMPAT can be used in both dependance and link
lines).  The same, at least partially, true for libstuff.so too.

Looking to bsd-arc4random.c, it seems not obvious to call seed_rng()
from here at all -- seed_rng() will be called at least twice in
some apps (that calls it directly and via arc4random()) -- not
good, esp with implementation without /dev/[u]random.  Note also
that apps used arc4random() *only* (I don't know if such an
application exists in openssh -- it seems that ssh-keyscan is
an example here) will be linked with all the routines from
entropy.c file.  Having that said, I think that a) seed_rng()
should be separated from entropy.c, b) arc4random()
should be moved from openbsd-compat into libssh (may be into
the same source file as seed_rng itself) and c) "first_time"
from arc4random() should be made global and available from
seed_rng() as well (this last point isn't obvious, as it
will stop calling seed_rgn() more than once if *required*).

> > And one more issue/question at the end.  I noticied that *all*
> > openssh programs linked with -lpam, -lwrap, -lutil and so on --
> > libraries really needed for sshd *only*.  I can't say this is
> > "bug", but looks somewhat inaccurate.  Looking into configure.in,
> > it is relatively hard to "clean up" things.  3rd patch attached,
> > openssh-2.9.9p2-libs.diff, an *alternative* to ssh_libs patch
> > (both touches the same lines in Makefile.in), is an attempt to
> > fix this too.  It is only first step into this direction, some
> > more cleanups should be done (for example, there is no -lz needed
> > for ssh-keygen, kerberos and s/key libs should be checked too and
> > so on).
> >
> 
> It would be nice to support this, but how much more work will it be to
> maintain?  Right now it is pretty easy to maintain.  I think we need to
> clean up configure.in before implementing this.

Cleaning up configure.in is defenitely a good idea.  Supporting this
isn't a big issue in clean configure.in, but somewhat hard without
this cleanup.  At least some things was done by this patch -- a small
example, I don't look to "libraries may be needed on SCO for libwrap"
unless tcp-wrappers was really requested.

> Too bad most linkers are brain damaged and don't strip unused dynamically
> linked libraries.

This isn't a "brain-damage" but a feature.  Well, ok, questionable
one but *still* a feature.  Imagine your app uses dlopen() etc to
load some .so at run time (like e.g. pam applications and the like).
That .so may require symbols not present in app itself and in any
library that app linked with.  One may link .so with a library with
those symbols, *or* can link app with that library.  Moreower, .so
may be linked with one such lib, *and* app with another (like
samba's smbshell) -- thus .so will use symbols from app's library
instead of it's own library.  Kind of "LD_PRELOAD" for an .so.
Or, .so is linked with libtermcap, but app "wants" it to be libcurses
but not uses curses itself -- just add -lcurses to app's link line
and "be happy", .so will use curses's tcgetstr() instead of termcap's
one.  There are *very rare cases* when this may be useful (and most
of the time, this can be done programmatically), but them still
exists.

What I really call a MIS-feature of most linkers is that linkers
"propagates" libs "linked with" other dynamic libs to applications.
For example, when -lssh (dynamic) linked with -lz, and one links
an app with -lssh but without -lz, app will list -lz in it's
runtime dependances, while *not uses* -lz directly.  Next, when
I upgrade -lssh (example only!), keeping interface intact, *and* -lz
at the same time, breaking interface, app will stop working, as it
will depend on *old* -lz but new -lssh will use *new* -lz.  I once
worked around this problem, by building "dummy" -lssh (again, example
only!) with all it's own symbols inside but without any code,
then linking app with this dummy -lssh and only after that building
and linking real -lssh with real -lz.  Only this way I managed to
remove -lz from app's dependances and was free to munge both -lssh
and -lz (keeping -lssh's interface intact!) as I wanted to...
(I once realized more "clean" solution for this: building -lssh
with *static* -lz, instead of editing -lssh to be dummy, is a
better way to go; but rebuilding -lssh *after* all apps already
linked with it still required).

Regards,
 Michael.



More information about the openssh-unix-dev mailing list