Using -lssh as shared library

Michael Tokarev mjt at tls.msk.ru
Mon Oct 8 09:21:56 EST 2001


Hello!  This is my first post to this list... ;)

I'm not shure if someone will be interested in this topic.
For me, it has interest, as long as I maintain 100+ unix
(linux) servers with dialup access and every package update
cost some significant time to download, so package size is
somewhat important here.

I looked to openssh and realized that package consists of
several programs, all uses common set of routines from
libssh and libopenbsd-compat.  So I thought about building
those libs as shared objects, instead of linking those
routines statically into every program.  After some minor
tweaks, I successefully did that, saving about 1/3 of
total package size (3 rpms -- openssh, openssh-server
and openssh-clients -- was 650Kb befor and 420Kb after).

While tweaking makefiles and so on, I realized one minor
problem with libssl.a: it is not a complete library per
se.  Yes, I know that it isn't intended to be used by
other programs (btw, pam_ssh uses parts of libssh), but
keeping it in a good state may be helpful anyway.  One
issue with this library is that it refers to an external
variable, IPV4or6, that itself isn't in library, but
defined in several source files instead, repeating the
same lines every time.  So, then libssl is a shared
object, programs like ssh-keygen (those that doesn't
define IPV4or6) will not build.

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.

Next, some tweaking for Makefile was required.  libssh.a
and libopenbsd-compat.a was "hardcoded" into link and dep
lines in Makefile, so if there is no libopenbsd-compat
(but it's contents is within -lssh), link will be funny.
Second patch, openssh-2.9.9p2-ssh_libs.diff, introduces
two make variables, SSH_LIBS="libopenbsd-compat.a libssl.a",
for dependence lines, and SSH_LDFLAGS="-lssl -lopenbsd-compat",
for link lines, and replaces hardcoded libssl.a etc with
those 2 variables.

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.
For now (and I doubt I'll be able to do that at all, as long
as I have little expirience with building/using shared libs
on *many* platforms, only linux and solaris), I didn't changed
makefiles etc to actually *use* shared lib -- steps performed
externally -- but those changes allowed me to do what I wanted
to.

Actual steps are performed from rpm's .spec file:  instead of
just `make', I use the following sequence:

--
make libssh.a CC="gcc -fPIC"
make -C openbsd-compat CC="gcc -fPIC"
gcc -shared -Wl,-soname,libssh-%{version}.so -o libssh.so \
 -Wl,--whole-archive libssh.a openbsd-compat/libopenbsd-compat.a \
 -Wl,--no-whole-archive -lcrypto -lz
make SSH_LIBS=libssh.so SSH_LDFLAGS=-lssh
--

and, at install stage, additional

--
install -m755 libssh.so $RPM_BUILD_ROOT%{_libdir}/libssh-%{version}.so
--

line is needed too, after real `make install'.


Adding real shared lib suport into makefile(s) will require to
create separate directory for libssh, or to use some other
extension instead of .o for all it's components, due to difference
in compiler flags (-fPIC for gcc is needed to compile position-
independant code), and those flags together with command to make
shared lib are very platform-dependant.

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).

Thank you for great product!

Regards,
 Michael.
-------------- next part --------------
This diff against 2.9.9p2 creates new file, ipv4or6.c, that holds
`int IPV4or6' variable used in other code.  Instead of defining this
variable in other source files, it is now in this file instead, as
part of libssh library.

diff -rNu1 openssh-2.9.9p2.orig/Makefile.in openssh-2.9.9p2/Makefile.in
--- openssh-2.9.9p2.orig/Makefile.in	Tue Sep 18 09:06:22 2001
+++ openssh-2.9.9p2/Makefile.in	Sun Oct  7 23:05:32 2001
@@ -48,3 +48,3 @@
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o ipv4or6.o
 
diff -rNu1 openssh-2.9.9p2.orig/ipv4or6.c openssh-2.9.9p2/ipv4or6.c
--- openssh-2.9.9p2.orig/ipv4or6.c	Thu Jan  1 03:00:00 1970
+++ openssh-2.9.9p2/ipv4or6.c	Sun Oct  7 23:10:32 2001
@@ -0,0 +1,9 @@
+#include "includes.h"
+
+/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
+   Default value is AF_UNSPEC means both IPv4 and IPv6. */
+#ifdef IPV4_DEFAULT
+int IPv4or6 = AF_INET;
+#else
+int IPv4or6 = AF_UNSPEC;
+#endif
diff -rNu1 openssh-2.9.9p2.orig/ssh-keyscan.c openssh-2.9.9p2/ssh-keyscan.c
--- openssh-2.9.9p2.orig/ssh-keyscan.c	Fri Sep 21 00:30:09 2001
+++ openssh-2.9.9p2/ssh-keyscan.c	Sun Oct  7 23:08:13 2001
@@ -36,9 +36,4 @@
 
-/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
-   Default value is AF_UNSPEC means both IPv4 and IPv6. */
-#ifdef IPV4_DEFAULT
-int IPv4or6 = AF_INET;
-#else
-int IPv4or6 = AF_UNSPEC;
-#endif
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
 
diff -rNu1 openssh-2.9.9p2.orig/ssh.c openssh-2.9.9p2/ssh.c
--- openssh-2.9.9p2.orig/ssh.c	Tue Sep 25 02:04:03 2001
+++ openssh-2.9.9p2/ssh.c	Sun Oct  7 23:09:16 2001
@@ -82,9 +82,4 @@
 
-/* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
-   Default value is AF_UNSPEC means both IPv4 and IPv6. */
-#ifdef IPV4_DEFAULT
-int IPv4or6 = AF_INET;
-#else
-int IPv4or6 = AF_UNSPEC;
-#endif
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
 
diff -rNu1 openssh-2.9.9p2.orig/sshd.c openssh-2.9.9p2/sshd.c
--- openssh-2.9.9p2.orig/sshd.c	Tue Sep 18 08:03:04 2001
+++ openssh-2.9.9p2/sshd.c	Sun Oct  7 23:10:04 2001
@@ -97,11 +97,4 @@
 
-/*
- * Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
- * Default value is AF_UNSPEC means both IPv4 and IPv6.
- */
-#ifdef IPV4_DEFAULT
-int IPv4or6 = AF_INET;
-#else
-int IPv4or6 = AF_UNSPEC;
-#endif
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+extern int IPv4or6;
 
-------------- next part --------------
Do not hardcode libssh and libopenbsd-compat into link lines and dependances,
but use make variables instead.  Can be used to build with shared -lssh.

--- openssh-2.9.9p2.orig/Makefile.in.orig	Sun Oct  7 23:45:01 2001
+++ openssh-2.9.9p2/Makefile.in	Sun Oct  7 23:48:31 2001
@@ -95,32 +96,35 @@
 
-ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+SSH_LIBS = $(LIBCOMPAT) libssh.a
+SSH_LDFLAGS = -lssh -lopenbsd-compat
 
-sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
-	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ssh$(EXEEXT): $(SSH_LIBS) $(SSHOBJS)
+	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
-scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o
-	$(LD) -o $@ scp.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sshd$(EXEEXT): $(SSH_LIBS) $(SSHDOBJS)
+	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
-ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
-	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+scp$(EXEEXT): $(SSH_LIBS) scp.o
+	$(LD) -o $@ scp.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
-ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o
-	$(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-add$(EXEEXT): $(SSH_LIBS) ssh-add.o
+	$(LD) -o $@ ssh-add.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
-	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-agent$(EXEEXT): $(SSH_LIBS) ssh-agent.o
+	$(LD) -o $@ ssh-agent.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
-	$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) 
+ssh-keygen$(EXEEXT): $(SSH_LIBS) ssh-keygen.o
+	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o
-	$(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-keyscan$(EXEEXT): $(SSH_LIBS) ssh-keyscan.o
+	$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o
-	$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sftp-server$(EXEEXT): $(SSH_LIBS) sftp.o sftp-common.o sftp-server.o
+	$(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
+
+sftp$(EXEEXT): $(SSH_LIBS) sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o
+	$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
 # test driver for the loginrec code - not built by default
-logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
-	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
+logintest: logintest.o $(SSH_LIBS) loginrec.o
+	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o $(SSH_LDFLAGS) $(LIBS)
 
-------------- next part --------------
diff -rNu1 openssh-2.9.9p2.orig/Makefile.in openssh-2.9.9p2/Makefile.in
--- openssh-2.9.9p2.orig/Makefile.in	Tue Sep 18 09:06:22 2001
+++ openssh-2.9.9p2/Makefile.in	Mon Oct  8 02:12:04 2001
@@ -32,2 +32,4 @@
 LIBS=@LIBS@
+AUTH_LIBS=@AUTH_LIBS@
+LIBWRAP=@LIBWRAP@
 AR=@AR@
@@ -95,32 +97,35 @@
 
-ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
-	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+SSH_LIBS = $(LIBCOMPAT) libssh.a
+SSH_LDFLAGS = -lssh -lopenbsd-compat
 
-sshd$(EXEEXT): libssh.a	$(LIBCOMPAT) $(SSHDOBJS)
-	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ssh$(EXEEXT): $(SSH_LIBS) $(SSHOBJS)
+	$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
-scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o
-	$(LD) -o $@ scp.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sshd$(EXEEXT): $(SSH_LIBS) $(SSHDOBJS)
+	$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) $(SSH_LDFLAGS) $(AUTH_LIBS) $(LIBWRAP) $(LIBS)
 
-ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
-	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+scp$(EXEEXT): $(SSH_LIBS) scp.o
+	$(LD) -o $@ scp.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
-ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o
-	$(LD) -o $@ ssh-agent.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-add$(EXEEXT): $(SSH_LIBS) ssh-add.o
+	$(LD) -o $@ ssh-add.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
-	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-agent$(EXEEXT): $(SSH_LIBS) ssh-agent.o
+	$(LD) -o $@ ssh-agent.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
-	$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) 
+ssh-keygen$(EXEEXT): $(SSH_LIBS) ssh-keygen.o
+	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o
-	$(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) 
+ssh-keyscan$(EXEEXT): $(SSH_LIBS) ssh-keyscan.o
+	$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
 
-sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o
-	$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sftp-server$(EXEEXT): $(SSH_LIBS) sftp.o sftp-common.o sftp-server.o
+	$(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS) 
+
+sftp$(EXEEXT): $(SSH_LIBS) sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o
+	$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) $(SSH_LDFLAGS) $(LIBS)
 
 # test driver for the loginrec code - not built by default
-logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
-	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
+logintest: logintest.o $(SSH_LIBS) loginrec.o
+	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o $(SSH_LDFLAGS) $(AUTH_LIBS) $(LIBS)
 
diff -rNu1 openssh-2.9.9p2.orig/configure.in openssh-2.9.9p2/configure.in
--- openssh-2.9.9p2.orig/configure.in	Wed Sep 26 02:39:38 2001
+++ openssh-2.9.9p2/configure.in	Mon Oct  8 02:15:29 2001
@@ -337,2 +337,3 @@
 # Checks for libraries.
+AUTH_LIBS=
 if test -z "$no_libnsl" ; then
@@ -344,8 +345,5 @@
 
-dnl SCO OS3 needs this for libwrap
-AC_CHECK_LIB(rpc, innetgr, LIBS="-lrpc -lyp -lrpc $LIBS" , , -lyp -lrpc)
-
-AC_CHECK_LIB(gen, getspnam, LIBS="$LIBS -lgen")
 AC_CHECK_LIB(z, deflate, ,AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***]))
-AC_CHECK_LIB(util, login, AC_DEFINE(HAVE_LIBUTIL_LOGIN) LIBS="$LIBS -lutil")
+AC_CHECK_LIB(gen, getspnam, AUTH_LIBS="$AUTH_LIBS -lgen")
+AC_CHECK_LIB(util, login, AC_DEFINE(HAVE_LIBUTIL_LOGIN) AUTH_LIBS="$AUTH_LIBS -lutil")
 
@@ -455,3 +453,4 @@
 # Check whether user wants TCP wrappers support
-TCPW_MSG="no" 
+TCPW_MSG="no"
+LIBWRAP=
 AC_ARG_WITH(tcp-wrappers,
@@ -460,4 +459,7 @@
 		if test "x$withval" != "xno" ; then
+			LIBWRAP="-lwrap"
+			dnl SCO OS3 needs this for libwrap
+			AC_CHECK_LIB(rpc, innetgr, LIBWRAP="$LIBWRAP -lrpc -lyp -lrpc" , , -lyp -lrpc)
 			saved_LIBS="$LIBS"
-			LIBS="-lwrap $LIBS"
+			LIBS="$LIBWRAP $LIBS"
 			AC_MSG_CHECKING(for libwrap)
@@ -472,2 +474,3 @@
 					AC_DEFINE(LIBWRAP)
+					LIBS="$saved_LIBS"
 					TCPW_MSG="yes" 
@@ -481,2 +484,3 @@
 )
+AC_SUBST(LIBWRAP)
 
@@ -503,3 +507,3 @@
 	[AC_DEFINE(HAVE_LOGIN)],
-	[AC_CHECK_LIB(bsd, login, [LIBS="$LIBS -lbsd"; AC_DEFINE(HAVE_LOGIN)])]
+	[AC_CHECK_LIB(bsd, login, [AUTH_LIBS="$AUTH_LIBS -lbsd"; AC_DEFINE(HAVE_LOGIN)])]
 )
@@ -545,4 +549,4 @@
 
-			AC_CHECK_LIB(dl, dlopen, , )
-			AC_CHECK_LIB(pam, pam_set_item, , AC_MSG_ERROR([*** libpam missing]))
+			AC_CHECK_LIB(dl, dlopen, AUTH_LIBS="-ldl $AUTH_LIBS", )
+			AC_CHECK_LIB(pam, pam_set_item, AUTH_LIBS="-lpam $AUTH_LIBS", AC_MSG_ERROR([*** libpam missing]), $AUTH_LIBS)
 			AC_CHECK_FUNCS(pam_getenvlist)
@@ -743,3 +747,3 @@
 if test "x$PAM_MSG" = "xno" -a "x$check_for_libcrypt_later" = "x1"; then
-	AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
+	AC_CHECK_LIB(crypt, crypt, AUTH_LIBS="$AUTH_LIBS -lcrypt")
 fi
@@ -2047,2 +2051,4 @@
 AC_EXEEXT
+
+AC_SUBST(AUTH_LIBS)
 


More information about the openssh-unix-dev mailing list