From 8b1c22b7758511461b359461926e47b093a349d3 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 15 Mar 2000 12:13:01 +1100 Subject: [PATCH] - Created contrib/ subdirectory. Included helpers from Phil Hands' Debian package, README file and chroot patch from Ricardo Cerqueira - Moved gnome-ssh-askpass.c to contrib directory and reomved config option. - Slight cleanup to doc files --- ChangeLog | 6 + INSTALL | 10 - Makefile.in | 13 - configure.in | 19 - contrib/README | 49 ++ contrib/chroot.diff | 134 ++++ .../gnome-ssh-askpass.c | 9 + contrib/make-ssh-known-hosts.1 | 432 ++++++++++ contrib/make-ssh-known-hosts.pl | 737 ++++++++++++++++++ contrib/ssh-copy-id | 45 ++ contrib/ssh-copy-id.1 | 67 ++ 11 files changed, 1479 insertions(+), 42 deletions(-) create mode 100644 contrib/README create mode 100644 contrib/chroot.diff rename gnome-ssh-askpass.c => contrib/gnome-ssh-askpass.c (96%) create mode 100644 contrib/make-ssh-known-hosts.1 create mode 100644 contrib/make-ssh-known-hosts.pl create mode 100644 contrib/ssh-copy-id create mode 100644 contrib/ssh-copy-id.1 diff --git a/ChangeLog b/ChangeLog index 7d2877682..ddb4cba2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,12 @@ problems with gcc/Solaris. - Don't free argument to putenv() after use (in setenv() replacement). Report from Seigo Tanimura + - Created contrib/ subdirectory. Included helpers from Phil Hands' + Debian package, README file and chroot patch from Ricardo Cerqueira + + - Moved gnome-ssh-askpass.c to contrib directory and reomved config + option. + - Slight cleanup to doc files 20000314 - Include macro for IN6_IS_ADDR_V4MAPPED. Report from diff --git a/INSTALL b/INSTALL index 4c1c0f868..d7d6d4edc 100644 --- a/INSTALL +++ b/INSTALL @@ -15,12 +15,6 @@ supports it. PAM is standard on Redhat and Debian Linux and on Solaris. PAM: http://www.kernel.org/pub/linux/libs/pam/ -Dante: -http://www.inet.no/dante - -OpenSSH can also use the Dante SOCKS libraries, version 1.1.1pre1 or higher, -if you have them installed on your system. - If you wish to build the GNOME passphrase requester, you will need the GNOME libraries and headers. @@ -145,10 +139,6 @@ created. --with-xauth=PATH specifies the location of the xauth binary ---with-dante[=DIR] will enable Dante SOCKS library support. If the Dante -libsocks library isn't installed in a library searched by the compiler, -add the directory name as the option. - --with-ipv4-default instructs OpenSSH to use IPv4 by default for new connections. Normally OpenSSH will try attempt to lookup both IPv6 and IPv4 addresses. On Linux/glibc-2.1.2 this causes long delays in name diff --git a/Makefile.in b/Makefile.in index b406d5f7a..a55af98db 100644 --- a/Makefile.in +++ b/Makefile.in @@ -21,7 +21,6 @@ ASKPASS_PROGRAM=$(ASKPASS_LOCATION)/ssh-askpass CC=@CC@ PATHS=-DETCDIR=\"$(sysconfdir)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DSSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" CFLAGS=@CFLAGS@ $(PATHS) @DEFS@ -EXTRA_TARGETS=@GNOME_ASKPASS@ LIBS=@LIBS@ AR=@AR@ RANLIB=@RANLIB@ @@ -29,9 +28,6 @@ INSTALL=@INSTALL@ PERL=@PERL@ LDFLAGS=-L. @LDFLAGS@ -GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` -GNOME_LIBS=`gnome-config --libs gnome gnomeui` - TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o log.o match.o mpaux.o nchan.o packet.o radix.o random.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o @@ -76,9 +72,6 @@ ssh-agent: libssh.a ssh-agent.o log-client.o ssh-keygen: libssh.a ssh-keygen.o log-client.o $(CC) -o $@ ssh-keygen.o log-client.o $(LDFLAGS) -lssh $(LIBS) -gnome-ssh-askpass: gnome-ssh-askpass.c - $(CC) $(CFLAGS) $(GNOME_CFLAGS) -o $@ gnome-ssh-askpass.c $(GNOME_LIBS) - $(MANPAGES) $(CONFIGFILES):: $(FIXPATHSCMD) $(srcdir)/$@ @@ -124,12 +117,6 @@ install: $(TARGETS) -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 - if [ ! -z "@GNOME_ASKPASS@" ] ; then \ - $(INSTALL) -d $(DESTDIR)$(libexecdir) ; \ - $(INSTALL) -d $(DESTDIR)$(libexecdir)/ssh ; \ - $(INSTALL) -s @GNOME_ASKPASS@ $(DESTDIR)${ASKPASS_LOCATION} ; \ - fi - if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config -a ! -f $(DESTDIR)$(sysconfdir)/sshd_config ]; then \ $(INSTALL) -d $(DESTDIR)$(sysconfdir); \ $(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \ diff --git a/configure.in b/configure.in index c643d9e54..7f7326fbd 100644 --- a/configure.in +++ b/configure.in @@ -577,25 +577,6 @@ AC_CHECK_FILE("/dev/ptc", # Options from here on. Some of these are preset by platform above -# Check whether user wants GNOME ssh-askpass -AC_MSG_CHECKING([whether to build GNOME ssh-askpass]) -AC_ARG_WITH(gnome-askpass, - [ --with-gnome-askpass Build the GNOME passphrase requester (default=no)], - [ - if test "x$withval" = "xno" ; then - GNOME_ASKPASS=""; - else - GNOME_ASKPASS="gnome-ssh-askpass"; - fi - ]) -AC_SUBST(GNOME_ASKPASS) - -if test -z "$GNOME_ASKPASS" ; then - AC_MSG_RESULT(no) -else - AC_MSG_RESULT(yes) -fi - # Check for user-specified random device, otherwise check /dev/urandom AC_ARG_WITH(random, [ --with-random=FILE read randomness from FILE (default=/dev/urandom)], diff --git a/contrib/README b/contrib/README new file mode 100644 index 000000000..fda244f6d --- /dev/null +++ b/contrib/README @@ -0,0 +1,49 @@ +Other patches and addons for OpenSSH. Please send submissions to +djm@ibs.com.au + +In this directory +----------------- + +chroot.diff: + +Ricardo Cerqueira's patch to enable chrooting using the +wu-ftpd style magic home directories (containing '/./'). More details in +the head of the patch itself. + +make-ssh-known-hosts: + +Tero Kivinen's PERL script to generate +ssh_known_hosts files by trawling tjhrough the DNS. More details in the +manpage. + +ssh-copy-id: + +Phil Hands' shell script to automate the process of adding +your public key to a remote machine's ~/.ssh/authorized_keys file. + +gnome-ssh-askpass: + +A GNOME passphrase requester of my own creation. Compilation instructions +are in the top of the file. + +Externally maintained +--------------------- + +liblogin: + +liblogin is Andre Lucas' cross platform login library. It handles all the +yucky details of wtmp, utmp and lastlog (which every OS vendor has +seen fit to implement differently) in one clean library. + +OpenSSH will require liblogin in the near future, but for now it is +recommended for users with login logging problems or curiosity. + +http://dspace.dial.pipex.com/andre.lucas/liblogin.html + +X11 SSH Askpass: + +Jim Knoble has written an excellent X11 +passphrase requester. This is highly recommended: + +http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/index.html + diff --git a/contrib/chroot.diff b/contrib/chroot.diff new file mode 100644 index 000000000..850bd8ffc --- /dev/null +++ b/contrib/chroot.diff @@ -0,0 +1,134 @@ +From: Ricardo Cerqueira + +A patch to cause sshd to chroot when it encounters the magic token +'/./' in a users home directory. The directory portion before the +token is the directory to chroot() to, the portion after the +token is the user's home directory relative to the new root. + + + +diff -ruN openssh-1.2.3pre2-orig/acconfig.h openssh-1.2.3pre2/acconfig.h +--- openssh-1.2.3pre2-orig/acconfig.h Sat Mar 11 20:45:40 2000 ++++ openssh-1.2.3pre2/acconfig.h Wed Mar 15 11:44:33 2000 +@@ -159,6 +159,9 @@ + /* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */ + #undef IPV4_IN_IPV6 + ++/* Define if you want to enable chrooted users */ ++#undef CHROOT ++ + @BOTTOM@ + + /* ******************* Shouldn't need to edit below this line ************** */ +diff -ruN openssh-1.2.3pre2-orig/config.h.in openssh-1.2.3pre2/config.h.in +--- openssh-1.2.3pre2-orig/config.h.in Wed Mar 15 11:51:02 2000 ++++ openssh-1.2.3pre2/config.h.in Wed Mar 15 11:46:33 2000 +@@ -140,6 +140,9 @@ + /* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */ + #undef IPV4_IN_IPV6 + ++/* Define if you want to enable chrooted users */ ++#undef CHROOT ++ + /* The number of bytes in a char. */ + #undef SIZEOF_CHAR + +diff -ruN openssh-1.2.3pre2-orig/configure openssh-1.2.3pre2/configure +--- openssh-1.2.3pre2-orig/configure Wed Mar 15 11:51:03 2000 ++++ openssh-1.2.3pre2/configure Wed Mar 15 11:46:34 2000 +@@ -52,6 +52,8 @@ + ac_help="$ac_help + --with-4in6 Check for and convert IPv4 in IPv6 mapped addresses" + ac_help="$ac_help ++ --with-chroot Enable chroot using /./ directory token" ++ac_help="$ac_help + --with-pid-dir=PATH Specify location of ssh.pid file" + + # Initialize some variables set by options. +@@ -3605,6 +3607,22 @@ + + else + echo "$ac_t""no (default)" 1>&6 ++ fi ++ ++ ++fi ++ ++ ++# Whether to enable the magic chroot token ++# Check whether --with-chroot or --without-chroot was given. ++if test "${with_chroot+set}" = set; then ++ withval="$with_chroot" ++ ++ if test "x$withval" != "xno" ; then ++ cat >> confdefs.h <<\EOF ++#define CHROOT 1 ++EOF ++ + fi + + +diff -ruN openssh-1.2.3pre2-orig/configure.in openssh-1.2.3pre2/configure.in +--- openssh-1.2.3pre2-orig/configure.in Sat Mar 11 20:45:41 2000 ++++ openssh-1.2.3pre2/configure.in Wed Mar 15 11:46:04 2000 +@@ -810,6 +810,16 @@ + ] + ) + ++# Whether to enable the magic chroot token ++AC_ARG_WITH(chroot, ++ [ --with-chroot Enable chroot using /./ directory token], ++ [ ++ if test "x$withval" != "xno" ; then ++ AC_DEFINE(CHROOT) ++ fi ++ ] ++) ++ + # Where to place sshd.pid + piddir=/var/run + AC_ARG_WITH(pid-dir, +diff -ruN openssh-1.2.3pre2-orig/sshd.c openssh-1.2.3pre2/sshd.c +--- openssh-1.2.3pre2-orig/sshd.c Sat Mar 11 11:58:29 2000 ++++ openssh-1.2.3pre2/sshd.c Wed Mar 15 11:43:38 2000 +@@ -2365,6 +2365,10 @@ + extern char **environ; + struct stat st; + char *argv[10]; ++#ifdef CHROOT /* patch by rmcc */ ++ char *user_dir; ++ char *new_root; ++#endif /* CHROOT */ + + #ifndef USE_PAM /* pam_nologin handles this */ + /* Check /etc/nologin. */ +@@ -2422,6 +2426,29 @@ + krb_afslog(0, 0); + } + #endif /* AFS */ ++ ++#ifdef CHROOT /* patch by rmcc */ ++ ++ user_dir = xstrdup(pw->pw_dir); ++ new_root = user_dir; ++ ++ while((new_root = strchr(new_root, '.')) != NULL){ ++ new_root--; ++ if(strncmp(new_root, "/./", 3) == 0){ ++ *new_root = 0; ++ new_root += 2; ++ if(chroot(user_dir) != 0){ ++ printf("Couldn't chroot!\n"); ++ exit(1); ++ } ++ pw->pw_dir = new_root; ++ break; ++ } ++ new_root +=2; ++ } ++ ++ ++#endif /* CHROOT */ + + /* Initialize the environment. */ + envsize = 100; diff --git a/gnome-ssh-askpass.c b/contrib/gnome-ssh-askpass.c similarity index 96% rename from gnome-ssh-askpass.c rename to contrib/gnome-ssh-askpass.c index 97e9cc3e2..fd537e676 100644 --- a/gnome-ssh-askpass.c +++ b/contrib/gnome-ssh-askpass.c @@ -1,3 +1,12 @@ +/* + Compile with: + + cc `gnome-config --cflags gnome gnomeui` \ + gnome-ssh-askpass.c -o gnome-ssh-askpass \ + `gnome-config --libs gnome gnomeui` + +*/ + /* ** ** GNOME ssh passphrase requestor diff --git a/contrib/make-ssh-known-hosts.1 b/contrib/make-ssh-known-hosts.1 new file mode 100644 index 000000000..cf0d52f0b --- /dev/null +++ b/contrib/make-ssh-known-hosts.1 @@ -0,0 +1,432 @@ +.\" -*- nroff -*- +.\" ---------------------------------------------------------------------- +.\" make-ssh-known-hosts.1 -- Make ssh-known-hosts file +.\" Copyright (c) 1995 Tero Kivinen +.\" All Rights Reserved. +.\" +.\" Make-ssh-known-hosts is distributed in the hope that it will be +.\" useful, but WITHOUT ANY WARRANTY. No author or distributor accepts +.\" responsibility to anyone for the consequences of using it or for +.\" whether it serves any particular purpose or works at all, unless he +.\" says so in writing. Refer to the General Public License for full +.\" details. +.\" +.\" Everyone is granted permission to copy, modify and redistribute +.\" make-ssh-known-hosts, but only under the conditions described in +.\" the General Public License. A copy of this license is supposed to +.\" have been given to you along with make-ssh-known-hosts so you can +.\" know your rights and responsibilities. It should be in a file named +.\" COPYING. Among other things, the copyright notice and this notice +.\" must be preserved on all copies. +.\" ---------------------------------------------------------------------- +.\" Program: make-ssh-known-hosts.1 +.\" $Source: /var/cvs/openssh/contrib/Attic/make-ssh-known-hosts.1,v $ +.\" Author : $Author: damien $ +.\" +.\" (C) Tero Kivinen 1995 +.\" +.\" Creation : 03:51 Jun 28 1995 kivinen +.\" Last Modification : 03:44 Jun 28 1995 kivinen +.\" Last check in : $Date: 2000/03/15 01:13:03 $ +.\" Revision number : $Revision: 1.1 $ +.\" State : $State: Exp $ +.\" Version : 1.1 +.\" +.\" Description : Manual page for make-ssh-known-hosts.pl +.\" +.\" $Log: make-ssh-known-hosts.1,v $ +.\" Revision 1.1 2000/03/15 01:13:03 damien +.\" - Created contrib/ subdirectory. Included helpers from Phil Hands' +.\" Debian package, README file and chroot patch from Ricardo Cerqueira +.\" +.\" - Moved gnome-ssh-askpass.c to contrib directory and reomved config +.\" option. +.\" - Slight cleanup to doc files +.\" +.\" Revision 1.4 1998/07/08 00:40:14 kivinen +.\" Changed to do similar commercial #ifdef processing than other +.\" files. +.\" +.\" Revision 1.3 1998/06/11 00:07:21 kivinen +.\" Fixed comment characters. +.\" +.\" Revision 1.2 1997/04/27 21:48:28 kivinen +.\" Added F-SECURE stuff. +.\" +.\" Revision 1.1.1.1 1996/02/18 21:38:13 ylo +.\" Imported ssh-1.2.13. +.\" +.\" Revision 1.5 1995/10/02 01:23:23 ylo +.\" Make substitutions by configure. +.\" +.\" Revision 1.4 1995/08/31 09:21:35 ylo +.\" Minor cleanup. +.\" +.\" Revision 1.3 1995/08/29 22:37:10 ylo +.\" Minor cleanup. +.\" +.\" Revision 1.2 1995/07/15 13:26:11 ylo +.\" Changes from kivinen. +.\" +.\" Revision 1.1.1.1 1995/07/12 22:41:05 ylo +.\" Imported ssh-1.0.0. +.\" +.\" +.\" +.\" If you have any useful modifications or extensions please send them to +.\" Tero.Kivinen@hut.fi +.\" +.\" +.\" +.\" +.\" +.\" #ifndef F_SECURE_COMMERCIAL +.TH MAKE-SSH-KNOWN-HOSTS 1 "November 8, 1995" "SSH TOOLS" "SSH TOOLS" +.\" #endif F_SECURE_COMMERCIAL +.SH NAME +make-ssh-known-hosts \- make ssh_known_hosts file from DNS data +.SH SYNOPSIS +.na +.TP +.B make-ssh-known-hosts +.RB "[\|" "\-\-initialdns "\c +.I initial_dns\c +\|] +.br +.RB "[\|" "\-\-server "\c +.I domain_name_server\c +\|] +.br +.RB "[\|" "\-\-subdomains "\c +.I comma_separated_list_of_subdomains\c +\|] +.br +.RB "[\|" "\-\-debug "\c +.I debug_level\c +\|] +.br +.RB "[\|" "\-\-timeout "\c +.I ssh_exec_timeout\c +\|] +.br +.RB "[\|" "\-\-pingtimeout "\c +.I ping_timeout\c +\|] +.br +.RB "[\|" "\-\-passwordtimeout "\c +.I timeout_when_asking_password\c +\|] +.br +.RB "[\|" "\-\-notrustdaemon" "\|]" +.br +.RB "[\|" "\-\-norecursive" "\|]" +.br +.RB "[\|" "\-\-domainnamesplit" "\|]" +.br +.RB "[\|" "\-\-silent" "\|]" +.br +.RB "[\|" "\-\-keyscan" "\|]" +.br +.RB "[\|" "\-\-nslookup "\c +.I path_to_nslookup_program\c +\|] +.br +.RB "[\|" "\-\-ssh "\c +.I path_to_ssh_program\c +\|] +.br +.IR "domain_name " "[\|" "take_regexp " "[\|" "remove_regexp"\|]\|]" + +.SH DESCRIPTION +.LP +.B make-ssh-known-hosts +is a perl5 script that helps create the +.I /etc/ssh_known_hosts +file, which is used by +.B ssh +to contain the host keys of all publicly known hosts. +.B Ssh +does not normally permit login using rhosts or /etc/hosts.equiv +authentication unless the server knows the client's host key. In +addition, the host keys are used to prevent man-in-the-middle attacks. +.LP +In addition to +.IR /etc/ssh_known_hosts ", +.B ssh +also uses the +.I $HOME/.ssh/known_hosts +file. This file, however, is intended to contain only those hosts +that the particular user needs but are not in the global file. It is +intended that the +.I /etc/ssh_known_hosts +file be maintained by the system administration, and periodically +updated to contain the host keys for any new hosts. +.LP +The +.B make-ssh-known-hosts +program finds all the hosts in a domain by making a DNS query to the +master domain name server of the domain. The master domain name server +is located by searching for the SOA record of the domain from the initial +domain name server (which can be specified with the +.B \-\-initialdns +option). The master domain name server can also be given directly with +the +.B \-\-server +option. +.LP +After getting the hostname list +.B make-ssh-known-hosts +tries to get the public key from every host in the domain. It first +tries to connect ssh port to check check if the host is alive, and if +so, it tries to run the command +.B cat /etc/ssh_host_key.pub +on the remote machine using +.BR ssh ". +If the command succeeds, it knows the remote machine has +.B ssh +installed properly, and it then extracts the public key from the +output, and prints the +.B /etc/ssh_known_hosts +entry for it to +.BR STDOUT ". Because +.B make-ssh-known-hosts +is usually run before +remote machines have /etc/ssh_known_hosts file you may have to use +RSA-authentication to allow access to hosts. +.LP +If the command fails for some reason, it checks if the +.B ssh +client still got the public key from the remote host in the initial dialog, +and if so, it will print a proper entry, and if +.B \-\-notrustdaemon +option is given comment it out. +.LP +.I Domain_name +is the domain name for which the file is to be generated. By default +.B make-ssh-known-hosts +extracts also all subdomains of domain. Many sites will want to +include several domains in their +.I /etc/ssh_known_hosts +file. The entries for each domain should be extracted separately by +running +.B make-ssh-known-hosts +once for each domain. The results should then be combined to create +the final file. +.LP +.I Take_regexp +is a perl regular expression that matches the hosts to be taken from the +domain. The data matched contains all the DNS records in the form "\|\c +.B fieldname=value\c +\|". The fields are separated with newline, and the perl match is made in +multiline mode and it is case insensetive. The multiline mode means +that you can use a regexp like "\|\c +.B ^wks=.*telnet.*$\c +\|" to match all hosts that have WKS (well known services) field that +contains value "telnet". +.LP +.I Remove_regexp +is similar but those hosts that match the regexp are not added (it can +be used for example to filter out PCs and Macs using the hinfo field: "\|\c +.B ^hinfo=.*(mac|pc)\c +\|"). + +.SH OPTIONS +.TP +.BI "\-\-initialdns " "initial_dns"\c +.TP +.BI "\-i " "initial_dns"\c +\&Set the initial domain name server used to query the SOA record of the +domain. + +.TP +.BI "\-\-server " "domain_name_server"\c +.TP +.BI "\-se " "domain_name_server"\c +\&Set the master domain name server of the domain. This host is used +to query the DNS list of the domain. + +.TP +.BI "\-\-subdomains " "subdomainlist"\c +.TP +.BI "\-su " "subdomainlist"\c +\&Comma separated list of subdomains that are added to hostnames. For +example, if subdomainlist is "\|\c +.I ,foo, foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c +\|" then when host foobar is added to +.B /etc/ssh_known_hosts +file it has aliases "\|\c +.I foobar, foobar.foo, foobar.foo.bar, foobar.foo.bar.zappa, foobar.foo.bar.zappa.hut.fi\c +\|". The default action is to take all subparts of the host but the +second last on a host by host basis. (The last element is usually the +country code, and something like +.I foobar.foo.bar.zappa.hut +would not make sense.) + +.TP +.BI "\-\-debug " "debug_level"\c +.TP +.BI "\-de " "debug_level"\c +\&Set the debug level. Default is 5, bigger values give more output. +Using a big value (like 999) will print lots of debugging output. + +.TP +.BI "\-\-timeout " "ssh_exec_timeout"\c +.TP +.BI "\-ti " "ssh_exec_timeout"\c +\&Timeout when executing +.B ssh +command. The default is 60 seconds. + +.TP +.BI "\-\-pingtimeout " "ping_timeout"\c +.TP +.BI "\-pi " "ping_timeout"\c +\&Timeout when trying to ping the ssh port. The default is 3 seconds. + +.TP +.BI "\-\-passwordtimeout " "timeout_when_asking_password"\c +.TP +.BI "\-pa " "timeout_when_asking_password"\c +\&Timeout when asking password for ssh command. Default is that no +passwords are queried. Use value 0 to have no timeout for password queries. + +.TP +.BI "\-\-notrustdaemon"\c +.TP +.BI "\-notr"\c +\&If the +.B ssh +command fails, use the public key stored in the local known hosts file +and trust it is the correct key for the host. If this option is not +given such entries are commented out in the generated +.B /etc/ssh_known_hosts +file. + +.TP +.BI "\-\-norecursive"\c +.TP +.BI "\-nor"\c +\&Tell +.B make-ssh-known-hosts +that it should only extract keys for the given domain, and not to be +recursive. + +.TP +.BI "\-\-domainnamesplit"\c +.TP +.BI "\-do"\c +\&Split the domainname to get the list of subdomains. Use this option +if you don't want hostname to splitted to pieces automatically. +Default splitting is done host by host basis. If the domain is +zappa.hut.fi, and the host name is foo.bar then default action adds +entries "\|\c +.I foo, foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c +\|" and this options adds entries "\|\c +.I foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c +\|"). + +.TP +.BI "\-\-silent"\c +.TP +.BI "\-si"\c +\&Be silent. + +.TP +.BI "\-\-keyscan"\c +.TP +.BI "\-k"\c +\&Output list of all hosts in format "ipaddr1,ipaddr2,...ipaddrn +hostname.domain.co,hostname,ipaddr1,ipaddr2,all_other_hostname_entries". +The output of this can be feeded to ssh-keyscan to fetch keys. + +.TP +.BI "\-\-nslookup " "path_to_nslookup_program"\c +.TP +.BI "\-n " "path_to_nslookup_program"\c +\&Path to the +.B nslookup +program. + +.TP +.BI "\-\-ssh " "path_to_ssh_program"\c +.TP +.BI "\-ss " "path_to_ssh_program"\c +\&Path to the +.B ssh +program, including all options. + +.SH EXAMPLES +.LP +The following command: +.IP +.B example# make-ssh-known-hosts cs.hut.fi > \c +.B /etc/ssh_known_hosts +.LP +finds all public keys of the hosts in +.B cs.hut.fi +domain and put them to +.B /etc/ssh_known_hosts +file splitting domain names on a per host basis. +.LP +The command +.IP +.B example% make-ssh-known-hosts hut.fi '^wks=.*ssh' > \c +.B hut-hosts +.LP +finds all hosts in +.B hut.fi +domain, and its subdomains having own name server (cs.hut.fi, +tf.hut.fi, tky.hut.fi) that have ssh service and puts their public key +to hut-hosts file. This would require that the domain name server of +hut.fi would define all hosts running ssh to have entry ssh in their +WKS record. Because nobody yet adds ssh to WKS, it would be better to +use command +.IP +.B example% make-ssh-known-hosts hut.fi '^wks=.*telnet' > \c +.B hut-hosts +.LP +that would take those host having telnet service. This uses default +subdomain list. + +.LP +The command: +.IP +.B example% make-ssh-known-hosts hut.fi 'dipoli.hut.fi' '^hinfo=.*(mac|pc)' > \c +.B dipoli-hosts +.LP +finds all hosts in hut.fi domain that are in dipoli.hut.fi subdomain +(note dipoli.hut.fi does not have own name server so its entries are +in hut.fi-server) and that are not Mac or PC. + +.SH FILES +.ta 3i +/etc/ssh_known_hosts Global host public key list + +.SH "SEE ALSO" +.BR ssh (1), +.BR sshd (8), +.BR ssh-keygen (1), +.BR ping (8), +.BR nslookup (8), +.BR perl (1), +.BR perlre (1) + +.SH AUTHOR +Tero Kivinen + +.SH COPYING +.LP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.LP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.LP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the the author instead of in the original +English. diff --git a/contrib/make-ssh-known-hosts.pl b/contrib/make-ssh-known-hosts.pl new file mode 100644 index 000000000..49c9f618e --- /dev/null +++ b/contrib/make-ssh-known-hosts.pl @@ -0,0 +1,737 @@ +#!/usr/bin/perl -w +# -*- perl -*- +###################################################################### +# make-ssh-known-hosts.pl -- Make ssh-known-hosts file +# Copyright (c) 1995 Tero Kivinen +# All Rights Reserved. +# +# Make-ssh-known-hosts is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY. No author or distributor accepts +# responsibility to anyone for the consequences of using it or for +# whether it serves any particular purpose or works at all, unless he +# says so in writing. Refer to the GNU General Public License for full +# details. +# +# Everyone is granted permission to copy, modify and redistribute +# make-ssh-known-hosts, but only under the conditions described in +# the GNU General Public License. A copy of this license is supposed to +# have been given to you along with make-ssh-known-hosts so you can +# know your rights and responsibilities. It should be in a file named +# gnu-COPYING-GPL. Among other things, the copyright notice and this notice +# must be preserved on all copies. +###################################################################### +# Program: make-ssh-known-hosts.pl +# $Source: /var/cvs/openssh/contrib/Attic/make-ssh-known-hosts.pl,v $ +# Author : $Author: damien $ +# +# (C) Tero Kivinen 1995 +# +# Creation : 19:52 Jun 27 1995 kivinen +# Last Modification : 00:07 Jul 8 1998 kivinen +# Last check in : $Date: 2000/03/15 01:13:03 $ +# Revision number : $Revision: 1.1 $ +# State : $State: Exp $ +# Version : 1.343 +# Edit time : 242 min +# +# Description : Make ssh-known-host file from dns data. +# +# $Log: make-ssh-known-hosts.pl,v $ +# Revision 1.1 2000/03/15 01:13:03 damien +# - Created contrib/ subdirectory. Included helpers from Phil Hands' +# Debian package, README file and chroot patch from Ricardo Cerqueira +# +# - Moved gnome-ssh-askpass.c to contrib directory and reomved config +# option. +# - Slight cleanup to doc files +# +# Revision 1.6 1998/07/08 00:44:23 kivinen +# Fixed to understand bind 8 nslookup output. +# +# Revision 1.5 1998/04/30 01:53:33 kivinen +# Moved kill before close and added sending SIGINT first and +# then 1 second sleep before sending SIGKILL. +# +# Revision 1.4 1998/04/17 00:39:19 kivinen +# Changed to close ssh program filedescriptor before killing it. +# Removed ^ from the password matching prompt. +# +# Revision 1.3 1997/04/17 04:21:27 kivinen +# Changed to use 3des by default. +# +# Revision 1.2 1997/03/26 07:14:01 kivinen +# Added EWOULDBLOCK. +# +# Revision 1.1.1.1 1996/02/18 21:38:10 ylo +# Imported ssh-1.2.13. +# +# Revision 1.4 1995/10/02 01:23:45 ylo +# Ping packet size fixes from Kivinen. +# +# Revision 1.3 1995/08/29 22:37:39 ylo +# Now uses GlobalKnownHostsFile and UserKnownHostsFile. +# +# Revision 1.2 1995/07/15 13:26:37 ylo +# Changes from kivinen. +# +# Revision 1.1.1.1 1995/07/12 22:41:05 ylo +# Imported ssh-1.0.0. +# +# +# +# If you have any useful modifications or extensions please send them to +# Tero.Kivinen@hut.fi +# +###################################################################### +# initialization + +require 5.000; +use Getopt::Long; +use FileHandle; +use POSIX; +use Socket; +use Fcntl; + +$version = ' $Id: make-ssh-known-hosts.pl,v 1.1 2000/03/15 01:13:03 damien Exp $ '; + +$command_line = "$0 "; +foreach $a (@ARGV) { + $command_line .= $a . " "; +} +STDERR->autoflush(1); + +###################################################################### +# default values for options + +$debug = 5; +$defserver = ''; +$bell='\a'; +$public_key = '/etc/ssh_host_key.pub'; +$private_ssh_known_hosts = "/tmp/ssh_known_hosts$$"; +$timeout = 60; +$ping_timeout = 3; +$passwordtimeout = undef; +$trustdaemon = 1; +$domainnamesplit = 0; +$recursive = 1; + +###################################################################### +# Programs and their options + +$nslookup = "nslookup"; + +$ssh="ssh -a -c 3des -x -o 'ConnectionAttempts 1' -o 'FallBackToRsh no' -o 'GlobalKnownHostsFile /dev/null' -o 'KeepAlive yes' -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile $private_ssh_known_hosts'"; +$sshdisablepasswordoption="-o 'BatchMode yes' -o 'PasswordAuthentication no'"; + +###################################################################### +# Cleanup and initialization + +unlink($private_ssh_known_hosts); +$sockaddr = 'S n a4 x8'; +($junk, $junk, $sshport) = getservbyname("ssh", "tcp"); +if (!defined($sshport)) { + $sshport = 22; +} +($tcpprotoname, $junk, $tcpproto) = getprotobyname('tcp'); +defined($tcpprotoname) || die "getprotobyname : $!"; + +###################################################################### +# Parse options + +GetOptions("initialdns=s", "server=s", "subdomains=s", + "debug=i", "timeout=i", "passwordtimeout=i", + "trustdaemon!", "domainnamesplit", "silent", + "nslookup=s", "pingtimeout=i", "recursive!", + "keyscan", + "ssh=s") + || die "Getopt : $!"; + +if (defined($opt_initialdns)) { $defserver = $opt_initialdns; } + +if (defined($opt_server)) { $server = $opt_server; } + +if (defined($opt_subdomains)) { @subdomains = split(/,/, $opt_subdomains); } + +if (defined($opt_debug)) { $debug = $opt_debug; } + +if (defined($opt_timeout)) { $timeout = $opt_timeout; } + +if (defined($opt_pingtimeout)) { $ping_timeout = $opt_pingtimeout; } + +if (defined($opt_passwordtimeout)) { + $passwordtimeout = $opt_passwordtimeout; + $sshdisablepasswordoption = ''; +} + +if (defined($opt_trustdaemon)) { $trustdaemon = $opt_trustdaemon; } + +if (defined($opt_recursive)) { $recursive = $opt_recursive; } + +if (defined($opt_domainnamesplit)) { $domainnamesplit = $opt_domainnamesplit; } + +if (defined($opt_silent)) { $bell = ''; } + +if (defined($opt_nslookup)) { $nslookup = $opt_nslookup; } + +if (defined($opt_ssh)) { $ssh = $opt_ssh; } else { + $ssh = "$ssh $sshdisablepasswordoption"; +} + +if ($#ARGV == 0) { + $domain = "\L$ARGV[0]\E"; + $grep_yes = '.*'; + $grep_no = '^$'; +} elsif ($#ARGV == 1) { + $domain = "\L$ARGV[0]\E"; + $grep_yes = $ARGV[1]; + $grep_no = '^$'; +} elsif ($#ARGV == 2) { + $domain = "\L$ARGV[0]\E"; + $grep_yes = $ARGV[1]; + $grep_no = $ARGV[2]; +} else { + print(STDERR "$0 [--initialdns initial_dns_server] [--server dns_server] [--subdomains sub.sub.domain,sub.sub,sub,] [--debug debug_level] [--timeout ssh_exec_timeout_in_secs] [--pingtimeout ping_timeout_in_secs] [--passwordtimeout timeout_for_password_in_secs] [--notrustdaemon] [--norecursive] [--domainnamesplit] [--silent] [--keyscan] [--nslookup path_to_nslookup] [--ssh path_to_ssh] full.domain [ host_info_take_regexp [ host_info_remove_regex ]]\n"); + exit(1); +} + +###################################################################### +# Check that ssh program exists + +if (system("$ssh > /dev/null 2>&1 ") != 256) { + print(STDERR "Error: Could not run ssh program ($ssh): $!\nError: Try giving the path to it with --ssh option\n"); + exit(1); +} + +###################################################################### +# Generate subdomains list + +if (!$domainnamesplit) { + debug(6, "Auto splitting host entries"); +} elsif (!defined(@subdomains)) { + debug(6, "Generating subdomain list"); + + # split domain to pieces + @domain_pieces = split(/\./, $domain); + + # add empty domain part + push(@subdomains, ''); + + # add rest parts, except the one before full domain name + $entry=''; + for(; $#domain_pieces > 1; ) { + $entry .= "." . shift(@domain_pieces); + push(@subdomains, $entry); + } + + # add full domain name + push(@subdomains, ".$domain"); + debug(5, "Subdomain list: " . join(',', @subdomains)); +} else { + debug(5, "Using given subdomain list:" . join(',', @subdomains)); +} + +###################################################################### +# finding SOA entry for domain + +@other_servers = (); +if (!defined($server)) { + debug(6, "Finding DNS database SOA entry"); + + ($server, @other_servers) = find_soa($domain, $defserver); + + if (!defined($server)) { + print(STDERR "Error: Could not find DNS SOA entry from default dns server\nError: Try giving the initial nameserver with --initialdns option\n"); + exit(1); + } else { + debug(5, "DNS server found : $server"); + } +} else { + debug(5, "Using given DNS server : $server"); +} + +###################################################################### +# Print header + +($name, $junk, $junk, $junk, $junk, $junk, $gecos) = getpwuid($<); +$gecos =~ s/,.*$//g; + +if (!defined($opt_keyscan)) { + print(STDOUT "# This file is generated with make-ssh-known-hosts.pl\n"); + print(STDOUT "#$version\n"); + print(STDOUT "# with command line :\n"); + print(STDOUT "# $command_line\n"); + print(STDOUT "#\n"); + print(STDOUT "# The script was run by $gecos ($name) at " . localtime() . "\n"); + print(STDOUT "# using perl ($^X) version $].\n"); +} + +###################################################################### +# Get DNS database list from server + +do { + $domains_done{$domain} = 1; + delete $domains_waiting{$domain}; + + $hostcnt = 0; + $cnamecnt = 0; + $lines = 0; + $soa = 0; + undef %host; + undef %cname; + undef %hostdata; + + dnsagain: + debug(1, "Getting DNS database for $domain from server $server"); + open(DNS, "echo ls -d $domain | nslookup - $server 2>&1 |") || + die "Error: Could not start nslookup to make dns list : $!\nError: Try giving --nslookup option and telling the path to nslookup program\n"; + + while() { + $lines++; + chomp; + undef $hostname if/^\s*$/; + if (/^\s{0,1}([a-zA-Z0-9-]\S*)/) { + $hostname = "\L$1\E"; + } + next unless defined $hostname; + if (/^.*\s(SOA)\s+(.*)\s*$/ || $hostname eq "SOA") { + undef $soa if(/^.*\s(SOA)\s+(.*)\s*$/); + $data = $_ if ($hostname eq "SOA"); + $data = $2 unless $hostname eq "SOA"; + $data =~ s/\s*;.*$//; + $data =~ s/^\s+//; + if( defined $soa ) { + $soa .= " \L$data\E"; + } else { + $soa = "\L$data\E"; + } + $hostname = "SOA"; + } elsif (/^.*\s(A|CNAME|NS)\s+(.*)\s*$/) { + $host = $hostname; + $field = "\L$1\E"; + $data = "\L$2\E"; + debug(70, "Line = /$host/$field/$data/"); + if ($host !~ /\.$/) { + $host .= ".$domain"; + } else { + $host =~ s/\.$//g; + } + if ($field eq "a") { + if ($host =~ /$domain$/) { + if (defined($host{$host})) { + $host{$host} .= ",$data"; + } else { + $host{$host} = "$data"; + $hostcnt++; + } + debug(30, "$host A == $host{$host}"); + } + } elsif ($field eq "cname") { + if ($data !~ /\.$/ && ! /^\s/ ) { + $data .= ".$domain"; + } else { + $data =~ s/\.$//g; + } + if ($host =~ /$domain$/) { + if (defined($cname{$data})) { + $cname{$data} .= ",$host"; + } else { + $cname{$data} = "$host"; + $cnamecnt++; + } + debug(30, "$host CNAME $data"); + $junk = $data; + $data = $host; + $host = $junk; + } + } elsif ($field eq "ns") { + if (!defined($domains_done{$host})) { + if (!defined($domains_waiting{$host})) { + debug(10, "Adding subdomain $host to domains list, with NS $data"); + $domains_waiting{$host} = $data; + push(@domains_waiting, $host); + } else { + debug(10, "Adding NS $data for domain $host"); + $domains_waiting{$host} .= ",$data"; + } + } + } + if (!defined($hostdata{$host})) { + $hostdata{$host} = "$host\n$field=$data\n"; + } else { + $hostdata{$host} .= "$field=$data\n"; + } + } + } + close(DNS); + if ($hostcnt == 0 && $cnamecnt == 0) { + if ($#other_servers != -1) { + $server = shift(@other_servers); + goto dnsagain; + } + } + debug(1, "Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)"); + if (!defined($opt_keyscan)) { + print(STDOUT "#\n"); + print(STDOUT "# Domain = $domain, server = $server\n"); + print(STDOUT "# Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)\n"); + print(STDOUT "# SOA = $soa\n"); + print(STDOUT "#\n"); + } + +###################################################################### +# Loop through hosts and try to connect to hosts + + foreach $i (sort (keys %host)) { + debug(50, "Host = $i, Hostdata = $hostdata{$i}"); + if ($hostdata{$i} =~ /$grep_yes/im && + $hostdata{$i} !~ /$grep_no/im && + $i !~ /^localhost\./ && + $host{$i} !~ /^127.0.0.1$|^127.0.0.1,|,127.0.0.1$|,127.0.0.1,/) { + debug(2, "Trying host $i"); + + @hostnames = (); + if (defined($cname{$i})) { + expand($i, \@hostnames, \@subdomains); + foreach $j (split(/,/, $cname{$i})) { + expand($j, \@hostnames, \@subdomains); + } + } else { + expand($i, \@hostnames, \@subdomains); + } + foreach $j (split(/,/, $host{$i})) { + push(@hostnames, $j); + } + $hostnames = join(',', (@hostnames)); + + if (defined($opt_keyscan)) { + printf(STDOUT "$host{$i}\t$hostnames\n"); + } elsif (try_ping($i, $host{$i})) { + $trusted = 1; + $err = 'Timeout expired'; + $ssh_key = try_ssh("$i"); + if (!defined($ssh_key)) { + $ssh_key = find_host_from_known_hosts($i); + $trusted = 0; + } + if (defined($ssh_key)) { + if ($trusted) { + debug(2, "Ssh to $i succeded"); + } else { + debug(2, "Ssh to $i failed, using local known_hosts entry"); + } + debug(4, "adding entries : $hostnames"); + $ssh_key =~ s/root@//i; + if (!$trusted && !$trustdaemon) { + print(STDOUT "# $hostnames $ssh_key\n"); + } else { + print(STDOUT "$hostnames $ssh_key\n"); + } + } else { + debug(2, "ssh failed : $err"); + } + } else { + debug(2, "ping failed"); + } + } else { + debug(10, "Skipped host $i"); + } + } + again: + $domain = shift(@domains_waiting); + if (defined($domain)) { + $server = $domains_waiting{$domain}; + @other_servers = split(',', $server); + $server = shift(@other_servers); + ($server, @other_servers) = find_soa($domain, $server); + if(!defined($server)) { + debug(1, "Skipping domain $domain because no DNS SOA entry found"); + $domains_done{$domain} = 1; + delete $domains_waiting{$domain}; + goto again; + } + } +} while ($recursive && defined($domain)); + +unlink($private_ssh_known_hosts); +exit (0); + +###################################################################### +# try_ping -- try to ping to host and return 1 if success +# $success = try_ping($host, $list_ip_addrs); + +sub try_ping { + my($host, $ipaddrs) = @_; + my(@ipaddrs, $ipaddr, $serv, $ip); + my($rin, $rout, $win, $wout, $nfound, $tmout, $buf, $len, $ret, $err); + + $buf = ''; + debug(51,"Trying to ping host $host"); + @ipaddrs = split(/,/, $ipaddrs); + + while ($ipaddr = shift(@ipaddrs)) { + + debug(55,"Trying ipaddr $ipaddr"); + + #initialize socket + socket(PING, PF_INET, SOCK_STREAM, $tcpproto) || + die "socket failed : $!"; + setsockopt(PING, SOL_SOCKET, SO_REUSEADDR, 1) || + die "setsockopt failed : $!"; + PING->autoflush(1); + fcntl(PING, F_SETFL, fcntl(PING, F_GETFL, 0) | POSIX::O_NONBLOCK) || + die "fcntl failed : $!"; + + $ip = pack('C4', split(/\./, $ipaddr, 4)); + $serv = pack($sockaddr, AF_INET, $sshport, $ip); + + again: + # try connect + $ret = connect(PING, $serv); + $err = $!; + if (!$ret) { + debug(60, "Connect failed : $err"); + if ($err == EINTR) { + goto again; + } + # socket not yet connected, wait for result, it will + # wake up for writing when done + $tmout = $ping_timeout; + + $rin = ''; + $win = ''; + vec($rin, fileno(PING), 1) = 1; + vec($win, fileno(PING), 1) = 1; + debug(60, "Waiting in select, rin = " . unpack('H*', $rin) . + ", win = " . unpack('H*', $win)); + ($nfound) = select($rout = $rin, $wout = $win, undef, $tmout); + $err = $!; + debug(80, "Select returned $nfound, rout = " . unpack('H*', $rout) . + ", wout = " . unpack('H*', $wout)); + if ($nfound != 0) { + # connect done, read the status with sysread + $ret = sysread(PING, $buf, 1); + $err = $!; + if (defined($ret) || $err == EAGAIN || $err == EWOULDBLOCK) { + debug(60, "Select ok, read ok ($err), returning ok"); + # connection done, return ok + shutdown(PING, 2); + close(PING); + return 1; + } else { + # connection failed, try next ipaddr + debug(60, "Select ok, read failed : $err, trying next"); + close(PING); + } + } else { + # timeout exceeded, try next ipaddr + debug(60, "Select failed : $err, trying next"); + close(PING); + } + } else { + # connect succeeded, return ok. + debug(60, "Connect ok, returning ok"); + shutdown(PING, 2); + close(PING); + return 1; + } + } + debug(60, "Returning fail"); + return 0; +} + +###################################################################### +# try_ssh -- try ssh connection to host and return ssh_key if success +# if failure return undef, and set $err string to contain error message. +# $ssh_key = try_ssh($host); + +sub try_ssh { + my($host) = @_; + my($buf, $ret, $pos, $pid, $rin, $nfound, $tmout); + + $pid = open(SSH, "$ssh $host cat $public_key 2>&1 |"); + $err = undef; + + if ($pid == 0) { + $err = "could not open ssh connection to host"; + return undef; + } + $ret = 1; + $pos = 0; + $buf = ''; + $tmout = $timeout; + debug(10, "Starting ssh select loop"); + loop: + while (1) { + + $rin = ''; + vec($rin, fileno(SSH), 1) = 1; + ($nfound, $tmout) = select($rin, undef, undef, $tmout); + + # Timeout + if ($nfound <= 0) { + debug(20, "Ssh select timed out"); + kill(2, $pid); sleep(1); kill(9, $pid); + close(SSH); + $err = "Timeout expired"; + return undef; + } + + $ret = sysread(SSH, $buf, 256, $pos); + # EOF or error + if ($ret <= 0) { + # Yes, close the pipe and return + close(SSH); + debug(20, "Ssh select closed status = $?"); + $err = "No reply from ssh"; + return undef; + } + $pos += $ret; + while ($buf =~ /^(.*)\n\r?([\000-\377]*)$/) { + $_ = $1; + $buf = $2; + $pos = length($buf); + debug(20, "Ssh select loop, line = \"$_\""); + if (/^connection.*refused/i) { + $err = "connection refused"; + } elsif (/^permission/i) { + $err = "permission denied"; + } elsif (/$public_key.*no\s+file/i) { + $err = "$public_key file not found"; + } elsif (/$public_key.*permission\s+denied/i) { + $err = "$public_key file permission denied"; + } elsif (/^\d+\s+\d+\s+\d/) { + kill(2, $pid); sleep(1); kill(9, $pid); + close(SSH); + return $_; + } + if (defined($err)) { + kill(2, $pid); sleep(1); kill(9, $pid); + close(SSH); + return undef; + } + } + if ($buf =~ /password: $/i) { + if (defined($passwordtimeout)) { + $tmout = $passwordtimeout; + print(STDERR "$bell\n\rPassword: "); + if ($tmout == 0) { + $tmout = undef; + } + } else { + $tmout = 0; + } + $buf = ''; + $pos = 0; + } + } +} + +###################################################################### +# find_hosts_from_known_hosts -- find host key from private known_hosts file +# $ssh_key = find_host_from_known_hosts($host); + +sub find_host_from_known_hosts { + my($host) = @_; + open(KNOWNHOSTS, "<$private_ssh_known_hosts") || return undef; + while() { + @_ = split(/\s+/, $_); + if ($_[0] =~ /^$host$|^$host,|,$host$/) { + shift(@_); + close(KNOWNHOSTS); + return join(' ', @_); + } + } + close(KNOWNHOSTS); + return undef; +} + +###################################################################### +# expand -- insert expanded hostnames to hostnames table +# expand($hostname, \@hostnames, \@subdomains); + +sub expand { + my($host, $hostnames, $subdomains) = @_; + my($newhost, $sub, $entry); + + if (!$domainnamesplit) { + my(@domain_pieces); + + # split domain to pieces + @domain_pieces = split(/\./, $host); + + # add rest parts, except the one before full domain name + $entry = shift(@domain_pieces); + + debug(20, "Adding autosplit entry $entry"); + push(@$hostnames, $entry); + + for(; $#domain_pieces > 1; ) { + $entry .= "." . shift(@domain_pieces); + debug(20, "Adding autosplit entry $entry"); + push(@$hostnames, $entry); + } + # add full domain name + debug(20, "Adding autosplit entry $host"); + push(@$hostnames, $host); + } else { + if ($host =~ /^(.*)$domain$/i) { + $newhost = $1; + $newhost =~ s/\.$//g; + foreach $sub (@$subdomains) { + $entry = $newhost . $sub; + $entry =~ s/^\.//g; + if ($entry ne '') { + debug(20, "Adding entry $entry"); + push(@$hostnames, $entry); + } + } + } + } +} + +###################################################################### +# Print debug text +# debug(text_debug_level, string) + +sub debug { + my($level, $str) = @_; + if ($debug > $level) { + print(STDERR "$0:debug[$level]: $str\n"); + } +} + +###################################################################### +# find_soa -- find soa entry for domain +# ($soa_origin, @other_servers) = find_soa($domain, $initial_server) + +sub find_soa { + my($domain, $initial_server) = @_; + my($field, $data, $server, @other_servers); + + open(DNS, "$nslookup -type=soa $domain $initial_server 2>&1 |") || + die "Error: Could not start nslookup to find SOA entry for $domain : $!\nError: Try giving the path to it with --nslookup option\n"; + + while () { + if (/^[^=]*origin\s*=\s*(.*)/) { + $server = $1; + debug(10, "Found origin : $1"); + } elsif (/^[^=]*nameserver\s*=\s*(.*)\s*$/) { + push(@other_servers, $1); + debug(10, "Found nameserver : $1"); + } + } + close(DNS); + return($server, @other_servers); +} + +###################################################################### +# make_perl_happy -- use some symbols, so perl doesn't complain so much +# make_perl_happy(); + +sub make_perl_happy { + if (0) { + print $opt_silent; + } +} + +1; diff --git a/contrib/ssh-copy-id b/contrib/ssh-copy-id new file mode 100644 index 000000000..0ab37cae4 --- /dev/null +++ b/contrib/ssh-copy-id @@ -0,0 +1,45 @@ +#!/bin/sh + +# Shell script to install your identity.pub on a remote machine +# Takes the remote machine name as an argument. +# Obviously, the remote machine must accept password authentication, +# or one of the other keys in your ssh-agent, for this to work. + +ID_FILE="${HOME}/.ssh/identity.pub" + +if [ "-i" = "$1" ]; then + shift + # check if we have 2 parameters left, if so the first is the new ID file + if [ -n "$2" ]; then + if expr "$1" : ".*\.pub" ; then + ID_FILE="$1" + else + ID_FILE="$1.pub" + fi + shift # and this should leave $1 as the target name + fi +else + if [ x$SSH_AUTH_SOCK != x ] ; then + GET_ID="$GET_ID ssh-add -L" + fi +fi + +if [ -z "`eval $GET_ID`" -a -r "${ID_FILE}" ] ; then + GET_ID="cat ${ID_FILE}" +fi + +if [ -z "`eval $GET_ID`" ]; then + echo "$0: ERROR: No identities found" + exit 1 +fi + +{ eval "$GET_ID" ; } | ssh $1 "test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys ; chmod g-w . .ssh .ssh/authorized_keys" + +cat < + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. +.. +.TH SSH-COPY-ID 1 "14 November 1999" "OpenSSH" +.SH NAME +ssh-copy-id \- install your identity.pub in a remote machine's authorized_keys +.SH SYNOPSIS +.B ssh-copy-id [-i [identity_file]] +.I "[user@]machine" +.br +.SH DESCRIPTION +.BR ssh-copy-id +is a script that uses ssh to log into a remote machine (presumably +using a login password, so password authentication should be enabled, +unless you've done some clever use of multiple identities) +.PP +It also changes the permissions of the remote user's home, +.BR ~/.ssh , +and +.B ~/.ssh/authorized_keys +to remove group writability (which would otherwise prevent you from logging in, if the remote +.B sshd +has +.B StrictModes +set in its configuration). +.PP +If the +.B -i +option is given then the identity file (defaults to +.BR ~/.ssh/identity.pub ) +is used, regardless of whether there are any keys in your +.BR ssh-agent . +Otherwise, if this: +.PP +.B " ssh-add -L" +.PP +provides any output, it uses that in preference to the identity file. +.PP +If the +.B -i +option is used, or the +.B ssh-add +produced no output, then it uses the contents of the identity +file. Once it has one or more fingerprints (by whatever means) it +uses ssh to append them to +.B ~/.ssh/authorised_keys +on the remote machine (creating the file, and directory, if necessary) + +.SH "SEE ALSO" +.BR ssh (1), +.BR ssh-agent (1), +.BR sshd (8)