summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/README49
-rw-r--r--contrib/chroot.diff134
-rw-r--r--contrib/gnome-ssh-askpass.c134
-rw-r--r--contrib/make-ssh-known-hosts.1432
-rw-r--r--contrib/make-ssh-known-hosts.pl737
-rw-r--r--contrib/ssh-copy-id45
-rw-r--r--contrib/ssh-copy-id.167
7 files changed, 1598 insertions, 0 deletions
diff --git a/contrib/README b/contrib/README
new file mode 100644
index 000000000..fda244f6d
--- /dev/null
+++ b/contrib/README
@@ -0,0 +1,49 @@
1Other patches and addons for OpenSSH. Please send submissions to
2djm@ibs.com.au
3
4In this directory
5-----------------
6
7chroot.diff:
8
9Ricardo Cerqueira's <rmcc@clix.pt> patch to enable chrooting using the
10wu-ftpd style magic home directories (containing '/./'). More details in
11the head of the patch itself.
12
13make-ssh-known-hosts:
14
15Tero Kivinen's <Tero.Kivinen@hut.fi> PERL script to generate
16ssh_known_hosts files by trawling tjhrough the DNS. More details in the
17manpage.
18
19ssh-copy-id:
20
21Phil Hands' <phil@hands.com> shell script to automate the process of adding
22your public key to a remote machine's ~/.ssh/authorized_keys file.
23
24gnome-ssh-askpass:
25
26A GNOME passphrase requester of my own creation. Compilation instructions
27are in the top of the file.
28
29Externally maintained
30---------------------
31
32liblogin:
33
34liblogin is Andre Lucas' cross platform login library. It handles all the
35yucky details of wtmp, utmp and lastlog (which every OS vendor has
36seen fit to implement differently) in one clean library.
37
38OpenSSH will require liblogin in the near future, but for now it is
39recommended for users with login logging problems or curiosity.
40
41http://dspace.dial.pipex.com/andre.lucas/liblogin.html
42
43X11 SSH Askpass:
44
45Jim Knoble <jmknoble@pobox.com> has written an excellent X11
46passphrase requester. This is highly recommended:
47
48http://www.ntrnet.net/~jmknoble/software/x11-ssh-askpass/index.html
49
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 @@
1From: Ricardo Cerqueira <rmcc@clix.pt>
2
3A patch to cause sshd to chroot when it encounters the magic token
4'/./' in a users home directory. The directory portion before the
5token is the directory to chroot() to, the portion after the
6token is the user's home directory relative to the new root.
7
8
9
10diff -ruN openssh-1.2.3pre2-orig/acconfig.h openssh-1.2.3pre2/acconfig.h
11--- openssh-1.2.3pre2-orig/acconfig.h Sat Mar 11 20:45:40 2000
12+++ openssh-1.2.3pre2/acconfig.h Wed Mar 15 11:44:33 2000
13@@ -159,6 +159,9 @@
14 /* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */
15 #undef IPV4_IN_IPV6
16
17+/* Define if you want to enable chrooted users */
18+#undef CHROOT
19+
20 @BOTTOM@
21
22 /* ******************* Shouldn't need to edit below this line ************** */
23diff -ruN openssh-1.2.3pre2-orig/config.h.in openssh-1.2.3pre2/config.h.in
24--- openssh-1.2.3pre2-orig/config.h.in Wed Mar 15 11:51:02 2000
25+++ openssh-1.2.3pre2/config.h.in Wed Mar 15 11:46:33 2000
26@@ -140,6 +140,9 @@
27 /* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */
28 #undef IPV4_IN_IPV6
29
30+/* Define if you want to enable chrooted users */
31+#undef CHROOT
32+
33 /* The number of bytes in a char. */
34 #undef SIZEOF_CHAR
35
36diff -ruN openssh-1.2.3pre2-orig/configure openssh-1.2.3pre2/configure
37--- openssh-1.2.3pre2-orig/configure Wed Mar 15 11:51:03 2000
38+++ openssh-1.2.3pre2/configure Wed Mar 15 11:46:34 2000
39@@ -52,6 +52,8 @@
40 ac_help="$ac_help
41 --with-4in6 Check for and convert IPv4 in IPv6 mapped addresses"
42 ac_help="$ac_help
43+ --with-chroot Enable chroot using /./ directory token"
44+ac_help="$ac_help
45 --with-pid-dir=PATH Specify location of ssh.pid file"
46
47 # Initialize some variables set by options.
48@@ -3605,6 +3607,22 @@
49
50 else
51 echo "$ac_t""no (default)" 1>&6
52+ fi
53+
54+
55+fi
56+
57+
58+# Whether to enable the magic chroot token
59+# Check whether --with-chroot or --without-chroot was given.
60+if test "${with_chroot+set}" = set; then
61+ withval="$with_chroot"
62+
63+ if test "x$withval" != "xno" ; then
64+ cat >> confdefs.h <<\EOF
65+#define CHROOT 1
66+EOF
67+
68 fi
69
70
71diff -ruN openssh-1.2.3pre2-orig/configure.in openssh-1.2.3pre2/configure.in
72--- openssh-1.2.3pre2-orig/configure.in Sat Mar 11 20:45:41 2000
73+++ openssh-1.2.3pre2/configure.in Wed Mar 15 11:46:04 2000
74@@ -810,6 +810,16 @@
75 ]
76 )
77
78+# Whether to enable the magic chroot token
79+AC_ARG_WITH(chroot,
80+ [ --with-chroot Enable chroot using /./ directory token],
81+ [
82+ if test "x$withval" != "xno" ; then
83+ AC_DEFINE(CHROOT)
84+ fi
85+ ]
86+)
87+
88 # Where to place sshd.pid
89 piddir=/var/run
90 AC_ARG_WITH(pid-dir,
91diff -ruN openssh-1.2.3pre2-orig/sshd.c openssh-1.2.3pre2/sshd.c
92--- openssh-1.2.3pre2-orig/sshd.c Sat Mar 11 11:58:29 2000
93+++ openssh-1.2.3pre2/sshd.c Wed Mar 15 11:43:38 2000
94@@ -2365,6 +2365,10 @@
95 extern char **environ;
96 struct stat st;
97 char *argv[10];
98+#ifdef CHROOT /* patch by rmcc */
99+ char *user_dir;
100+ char *new_root;
101+#endif /* CHROOT */
102
103 #ifndef USE_PAM /* pam_nologin handles this */
104 /* Check /etc/nologin. */
105@@ -2422,6 +2426,29 @@
106 krb_afslog(0, 0);
107 }
108 #endif /* AFS */
109+
110+#ifdef CHROOT /* patch by rmcc */
111+
112+ user_dir = xstrdup(pw->pw_dir);
113+ new_root = user_dir;
114+
115+ while((new_root = strchr(new_root, '.')) != NULL){
116+ new_root--;
117+ if(strncmp(new_root, "/./", 3) == 0){
118+ *new_root = 0;
119+ new_root += 2;
120+ if(chroot(user_dir) != 0){
121+ printf("Couldn't chroot!\n");
122+ exit(1);
123+ }
124+ pw->pw_dir = new_root;
125+ break;
126+ }
127+ new_root +=2;
128+ }
129+
130+
131+#endif /* CHROOT */
132
133 /* Initialize the environment. */
134 envsize = 100;
diff --git a/contrib/gnome-ssh-askpass.c b/contrib/gnome-ssh-askpass.c
new file mode 100644
index 000000000..fd537e676
--- /dev/null
+++ b/contrib/gnome-ssh-askpass.c
@@ -0,0 +1,134 @@
1/*
2 Compile with:
3
4 cc `gnome-config --cflags gnome gnomeui` \
5 gnome-ssh-askpass.c -o gnome-ssh-askpass \
6 `gnome-config --libs gnome gnomeui`
7
8*/
9
10/*
11**
12** GNOME ssh passphrase requestor
13**
14** Damien Miller <djm@ibs.com.au>
15**
16** Copyright 1999 Internet Business Solutions
17**
18** Permission is hereby granted, free of charge, to any person
19** obtaining a copy of this software and associated documentation
20** files (the "Software"), to deal in the Software without
21** restriction, including without limitation the rights to use, copy,
22** modify, merge, publish, distribute, sublicense, and/or sell copies
23** of the Software, and to permit persons to whom the Software is
24** furnished to do so, subject to the following conditions:
25**
26** The above copyright notice and this permission notice shall be
27** included in all copies or substantial portions of the Software.
28**
29** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
30** KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
31** WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
32** AND NONINFRINGEMENT. IN NO EVENT SHALL DAMIEN MILLER OR INTERNET
33** BUSINESS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
35** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
36** OR OTHER DEALINGS IN THE SOFTWARE.
37**
38** Except as contained in this notice, the name of Internet Business
39** Solutions shall not be used in advertising or otherwise to promote
40** the sale, use or other dealings in this Software without prior
41** written authorization from Internet Business Solutions.
42**
43*/
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <gnome.h>
49#include <X11/Xlib.h>
50#include <gdk/gdkx.h>
51
52int passphrase_dialog(char **passphrase_p, char *message)
53{
54 char *passphrase;
55 int result;
56
57 GtkWidget *dialog, *entry, *label;
58
59 dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
60 GNOME_STOCK_BUTTON_CANCEL, NULL);
61
62 label = gtk_label_new(message);
63 gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), label, FALSE,
64 FALSE, 0);
65
66 entry = gtk_entry_new();
67 gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE,
68 FALSE, 0);
69 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
70 gtk_widget_grab_focus(entry);
71
72 /* Center window and prepare for grab */
73 gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
74 gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
75 gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
76 gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
77 gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
78 gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox), GNOME_PAD);
79 gtk_widget_show_all(dialog);
80
81 /* Grab focus */
82 XGrabServer(GDK_DISPLAY());
83 gdk_pointer_grab(dialog->window, TRUE, 0, NULL, NULL, GDK_CURRENT_TIME);
84 gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME);
85
86 /* Make <enter> close dialog */
87 gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
88
89 /* Run dialog */
90 result = gnome_dialog_run(GNOME_DIALOG(dialog));
91
92 /* Ungrab */
93 XUngrabServer(GDK_DISPLAY());
94 gdk_pointer_ungrab(GDK_CURRENT_TIME);
95 gdk_keyboard_ungrab(GDK_CURRENT_TIME);
96 gdk_flush();
97
98 passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
99
100 /* Take copy of passphrase if user selected OK */
101 if (result == 0)
102 *passphrase_p = strdup(passphrase);
103 else
104 *passphrase_p = NULL;
105
106 /* Zero existing passphrase */
107 memset(passphrase, '\0', strlen(passphrase));
108 gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
109
110 gnome_dialog_close(GNOME_DIALOG(dialog));
111
112 return (result == 0);
113}
114
115int main(int argc, char **argv)
116{
117 char *passphrase;
118 char *message;
119
120 gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
121
122 if (argc == 2)
123 message = argv[1];
124 else
125 message = "Enter your OpenSSH passphrase:";
126
127 if (passphrase_dialog(&passphrase, message))
128 {
129 puts(passphrase);
130 memset(passphrase, '\0', strlen(passphrase));
131 }
132
133 return 0;
134}
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 @@
1.\" -*- nroff -*-
2.\" ----------------------------------------------------------------------
3.\" make-ssh-known-hosts.1 -- Make ssh-known-hosts file
4.\" Copyright (c) 1995 Tero Kivinen
5.\" All Rights Reserved.
6.\"
7.\" Make-ssh-known-hosts is distributed in the hope that it will be
8.\" useful, but WITHOUT ANY WARRANTY. No author or distributor accepts
9.\" responsibility to anyone for the consequences of using it or for
10.\" whether it serves any particular purpose or works at all, unless he
11.\" says so in writing. Refer to the General Public License for full
12.\" details.
13.\"
14.\" Everyone is granted permission to copy, modify and redistribute
15.\" make-ssh-known-hosts, but only under the conditions described in
16.\" the General Public License. A copy of this license is supposed to
17.\" have been given to you along with make-ssh-known-hosts so you can
18.\" know your rights and responsibilities. It should be in a file named
19.\" COPYING. Among other things, the copyright notice and this notice
20.\" must be preserved on all copies.
21.\" ----------------------------------------------------------------------
22.\" Program: make-ssh-known-hosts.1
23.\" $Source: /var/cvs/openssh/contrib/Attic/make-ssh-known-hosts.1,v $
24.\" Author : $Author: damien $
25.\"
26.\" (C) Tero Kivinen 1995 <Tero.Kivinen@hut.fi>
27.\"
28.\" Creation : 03:51 Jun 28 1995 kivinen
29.\" Last Modification : 03:44 Jun 28 1995 kivinen
30.\" Last check in : $Date: 2000/03/15 01:13:03 $
31.\" Revision number : $Revision: 1.1 $
32.\" State : $State: Exp $
33.\" Version : 1.1
34.\"
35.\" Description : Manual page for make-ssh-known-hosts.pl
36.\"
37.\" $Log: make-ssh-known-hosts.1,v $
38.\" Revision 1.1 2000/03/15 01:13:03 damien
39.\" - Created contrib/ subdirectory. Included helpers from Phil Hands'
40.\" Debian package, README file and chroot patch from Ricardo Cerqueira
41.\" <rmcc@clix.pt>
42.\" - Moved gnome-ssh-askpass.c to contrib directory and reomved config
43.\" option.
44.\" - Slight cleanup to doc files
45.\"
46.\" Revision 1.4 1998/07/08 00:40:14 kivinen
47.\" Changed to do similar commercial #ifdef processing than other
48.\" files.
49.\"
50.\" Revision 1.3 1998/06/11 00:07:21 kivinen
51.\" Fixed comment characters.
52.\"
53.\" Revision 1.2 1997/04/27 21:48:28 kivinen
54.\" Added F-SECURE stuff.
55.\"
56.\" Revision 1.1.1.1 1996/02/18 21:38:13 ylo
57.\" Imported ssh-1.2.13.
58.\"
59.\" Revision 1.5 1995/10/02 01:23:23 ylo
60.\" Make substitutions by configure.
61.\"
62.\" Revision 1.4 1995/08/31 09:21:35 ylo
63.\" Minor cleanup.
64.\"
65.\" Revision 1.3 1995/08/29 22:37:10 ylo
66.\" Minor cleanup.
67.\"
68.\" Revision 1.2 1995/07/15 13:26:11 ylo
69.\" Changes from kivinen.
70.\"
71.\" Revision 1.1.1.1 1995/07/12 22:41:05 ylo
72.\" Imported ssh-1.0.0.
73.\"
74.\"
75.\"
76.\" If you have any useful modifications or extensions please send them to
77.\" Tero.Kivinen@hut.fi
78.\"
79.\"
80.\"
81.\"
82.\"
83.\" #ifndef F_SECURE_COMMERCIAL
84.TH MAKE-SSH-KNOWN-HOSTS 1 "November 8, 1995" "SSH TOOLS" "SSH TOOLS"
85.\" #endif F_SECURE_COMMERCIAL
86.SH NAME
87make-ssh-known-hosts \- make ssh_known_hosts file from DNS data
88.SH SYNOPSIS
89.na
90.TP
91.B make-ssh-known-hosts
92.RB "[\|" "\-\-initialdns "\c
93.I initial_dns\c
94\|]
95.br
96.RB "[\|" "\-\-server "\c
97.I domain_name_server\c
98\|]
99.br
100.RB "[\|" "\-\-subdomains "\c
101.I comma_separated_list_of_subdomains\c
102\|]
103.br
104.RB "[\|" "\-\-debug "\c
105.I debug_level\c
106\|]
107.br
108.RB "[\|" "\-\-timeout "\c
109.I ssh_exec_timeout\c
110\|]
111.br
112.RB "[\|" "\-\-pingtimeout "\c
113.I ping_timeout\c
114\|]
115.br
116.RB "[\|" "\-\-passwordtimeout "\c
117.I timeout_when_asking_password\c
118\|]
119.br
120.RB "[\|" "\-\-notrustdaemon" "\|]"
121.br
122.RB "[\|" "\-\-norecursive" "\|]"
123.br
124.RB "[\|" "\-\-domainnamesplit" "\|]"
125.br
126.RB "[\|" "\-\-silent" "\|]"
127.br
128.RB "[\|" "\-\-keyscan" "\|]"
129.br
130.RB "[\|" "\-\-nslookup "\c
131.I path_to_nslookup_program\c
132\|]
133.br
134.RB "[\|" "\-\-ssh "\c
135.I path_to_ssh_program\c
136\|]
137.br
138.IR "domain_name " "[\|" "take_regexp " "[\|" "remove_regexp"\|]\|]"
139
140.SH DESCRIPTION
141.LP
142.B make-ssh-known-hosts
143is a perl5 script that helps create the
144.I /etc/ssh_known_hosts
145file, which is used by
146.B ssh
147to contain the host keys of all publicly known hosts.
148.B Ssh
149does not normally permit login using rhosts or /etc/hosts.equiv
150authentication unless the server knows the client's host key. In
151addition, the host keys are used to prevent man-in-the-middle attacks.
152.LP
153In addition to
154.IR /etc/ssh_known_hosts ",
155.B ssh
156also uses the
157.I $HOME/.ssh/known_hosts
158file. This file, however, is intended to contain only those hosts
159that the particular user needs but are not in the global file. It is
160intended that the
161.I /etc/ssh_known_hosts
162file be maintained by the system administration, and periodically
163updated to contain the host keys for any new hosts.
164.LP
165The
166.B make-ssh-known-hosts
167program finds all the hosts in a domain by making a DNS query to the
168master domain name server of the domain. The master domain name server
169is located by searching for the SOA record of the domain from the initial
170domain name server (which can be specified with the
171.B \-\-initialdns
172option). The master domain name server can also be given directly with
173the
174.B \-\-server
175option.
176.LP
177After getting the hostname list
178.B make-ssh-known-hosts
179tries to get the public key from every host in the domain. It first
180tries to connect ssh port to check check if the host is alive, and if
181so, it tries to run the command
182.B cat /etc/ssh_host_key.pub
183on the remote machine using
184.BR ssh ".
185If the command succeeds, it knows the remote machine has
186.B ssh
187installed properly, and it then extracts the public key from the
188output, and prints the
189.B /etc/ssh_known_hosts
190entry for it to
191.BR STDOUT ". Because
192.B make-ssh-known-hosts
193is usually run before
194remote machines have /etc/ssh_known_hosts file you may have to use
195RSA-authentication to allow access to hosts.
196.LP
197If the command fails for some reason, it checks if the
198.B ssh
199client still got the public key from the remote host in the initial dialog,
200and if so, it will print a proper entry, and if
201.B \-\-notrustdaemon
202option is given comment it out.
203.LP
204.I Domain_name
205is the domain name for which the file is to be generated. By default
206.B make-ssh-known-hosts
207extracts also all subdomains of domain. Many sites will want to
208include several domains in their
209.I /etc/ssh_known_hosts
210file. The entries for each domain should be extracted separately by
211running
212.B make-ssh-known-hosts
213once for each domain. The results should then be combined to create
214the final file.
215.LP
216.I Take_regexp
217is a perl regular expression that matches the hosts to be taken from the
218domain. The data matched contains all the DNS records in the form "\|\c
219.B fieldname=value\c
220\|". The fields are separated with newline, and the perl match is made in
221multiline mode and it is case insensetive. The multiline mode means
222that you can use a regexp like "\|\c
223.B ^wks=.*telnet.*$\c
224\|" to match all hosts that have WKS (well known services) field that
225contains value "telnet".
226.LP
227.I Remove_regexp
228is similar but those hosts that match the regexp are not added (it can
229be used for example to filter out PCs and Macs using the hinfo field: "\|\c
230.B ^hinfo=.*(mac|pc)\c
231\|").
232
233.SH OPTIONS
234.TP
235.BI "\-\-initialdns " "initial_dns"\c
236.TP
237.BI "\-i " "initial_dns"\c
238\&Set the initial domain name server used to query the SOA record of the
239domain.
240
241.TP
242.BI "\-\-server " "domain_name_server"\c
243.TP
244.BI "\-se " "domain_name_server"\c
245\&Set the master domain name server of the domain. This host is used
246to query the DNS list of the domain.
247
248.TP
249.BI "\-\-subdomains " "subdomainlist"\c
250.TP
251.BI "\-su " "subdomainlist"\c
252\&Comma separated list of subdomains that are added to hostnames. For
253example, if subdomainlist is "\|\c
254.I ,foo, foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c
255\|" then when host foobar is added to
256.B /etc/ssh_known_hosts
257file it has aliases "\|\c
258.I foobar, foobar.foo, foobar.foo.bar, foobar.foo.bar.zappa, foobar.foo.bar.zappa.hut.fi\c
259\|". The default action is to take all subparts of the host but the
260second last on a host by host basis. (The last element is usually the
261country code, and something like
262.I foobar.foo.bar.zappa.hut
263would not make sense.)
264
265.TP
266.BI "\-\-debug " "debug_level"\c
267.TP
268.BI "\-de " "debug_level"\c
269\&Set the debug level. Default is 5, bigger values give more output.
270Using a big value (like 999) will print lots of debugging output.
271
272.TP
273.BI "\-\-timeout " "ssh_exec_timeout"\c
274.TP
275.BI "\-ti " "ssh_exec_timeout"\c
276\&Timeout when executing
277.B ssh
278command. The default is 60 seconds.
279
280.TP
281.BI "\-\-pingtimeout " "ping_timeout"\c
282.TP
283.BI "\-pi " "ping_timeout"\c
284\&Timeout when trying to ping the ssh port. The default is 3 seconds.
285
286.TP
287.BI "\-\-passwordtimeout " "timeout_when_asking_password"\c
288.TP
289.BI "\-pa " "timeout_when_asking_password"\c
290\&Timeout when asking password for ssh command. Default is that no
291passwords are queried. Use value 0 to have no timeout for password queries.
292
293.TP
294.BI "\-\-notrustdaemon"\c
295.TP
296.BI "\-notr"\c
297\&If the
298.B ssh
299command fails, use the public key stored in the local known hosts file
300and trust it is the correct key for the host. If this option is not
301given such entries are commented out in the generated
302.B /etc/ssh_known_hosts
303file.
304
305.TP
306.BI "\-\-norecursive"\c
307.TP
308.BI "\-nor"\c
309\&Tell
310.B make-ssh-known-hosts
311that it should only extract keys for the given domain, and not to be
312recursive.
313
314.TP
315.BI "\-\-domainnamesplit"\c
316.TP
317.BI "\-do"\c
318\&Split the domainname to get the list of subdomains. Use this option
319if you don't want hostname to splitted to pieces automatically.
320Default splitting is done host by host basis. If the domain is
321zappa.hut.fi, and the host name is foo.bar then default action adds
322entries "\|\c
323.I foo, foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c
324\|" and this options adds entries "\|\c
325.I foo.bar, foo.bar.zappa, foo.bar.zappa.hut.fi\c
326\|").
327
328.TP
329.BI "\-\-silent"\c
330.TP
331.BI "\-si"\c
332\&Be silent.
333
334.TP
335.BI "\-\-keyscan"\c
336.TP
337.BI "\-k"\c
338\&Output list of all hosts in format "ipaddr1,ipaddr2,...ipaddrn
339hostname.domain.co,hostname,ipaddr1,ipaddr2,all_other_hostname_entries".
340The output of this can be feeded to ssh-keyscan to fetch keys.
341
342.TP
343.BI "\-\-nslookup " "path_to_nslookup_program"\c
344.TP
345.BI "\-n " "path_to_nslookup_program"\c
346\&Path to the
347.B nslookup
348program.
349
350.TP
351.BI "\-\-ssh " "path_to_ssh_program"\c
352.TP
353.BI "\-ss " "path_to_ssh_program"\c
354\&Path to the
355.B ssh
356program, including all options.
357
358.SH EXAMPLES
359.LP
360The following command:
361.IP
362.B example# make-ssh-known-hosts cs.hut.fi > \c
363.B /etc/ssh_known_hosts
364.LP
365finds all public keys of the hosts in
366.B cs.hut.fi
367domain and put them to
368.B /etc/ssh_known_hosts
369file splitting domain names on a per host basis.
370.LP
371The command
372.IP
373.B example% make-ssh-known-hosts hut.fi '^wks=.*ssh' > \c
374.B hut-hosts
375.LP
376finds all hosts in
377.B hut.fi
378domain, and its subdomains having own name server (cs.hut.fi,
379tf.hut.fi, tky.hut.fi) that have ssh service and puts their public key
380to hut-hosts file. This would require that the domain name server of
381hut.fi would define all hosts running ssh to have entry ssh in their
382WKS record. Because nobody yet adds ssh to WKS, it would be better to
383use command
384.IP
385.B example% make-ssh-known-hosts hut.fi '^wks=.*telnet' > \c
386.B hut-hosts
387.LP
388that would take those host having telnet service. This uses default
389subdomain list.
390
391.LP
392The command:
393.IP
394.B example% make-ssh-known-hosts hut.fi 'dipoli.hut.fi' '^hinfo=.*(mac|pc)' > \c
395.B dipoli-hosts
396.LP
397finds all hosts in hut.fi domain that are in dipoli.hut.fi subdomain
398(note dipoli.hut.fi does not have own name server so its entries are
399in hut.fi-server) and that are not Mac or PC.
400
401.SH FILES
402.ta 3i
403/etc/ssh_known_hosts Global host public key list
404
405.SH "SEE ALSO"
406.BR ssh (1),
407.BR sshd (8),
408.BR ssh-keygen (1),
409.BR ping (8),
410.BR nslookup (8),
411.BR perl (1),
412.BR perlre (1)
413
414.SH AUTHOR
415Tero Kivinen <kivinen@hut.fi>
416
417.SH COPYING
418.LP
419Permission is granted to make and distribute verbatim copies of
420this manual provided the copyright notice and this permission notice
421are preserved on all copies.
422.LP
423Permission is granted to copy and distribute modified versions of this
424manual under the conditions for verbatim copying, provided that the
425entire resulting derived work is distributed under the terms of a
426permission notice identical to this one.
427.LP
428Permission is granted to copy and distribute translations of this
429manual into another language, under the above conditions for modified
430versions, except that this permission notice may be included in
431translations approved by the the author instead of in the original
432English.
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 @@
1#!/usr/bin/perl -w
2# -*- perl -*-
3######################################################################
4# make-ssh-known-hosts.pl -- Make ssh-known-hosts file
5# Copyright (c) 1995 Tero Kivinen
6# All Rights Reserved.
7#
8# Make-ssh-known-hosts is distributed in the hope that it will be
9# useful, but WITHOUT ANY WARRANTY. No author or distributor accepts
10# responsibility to anyone for the consequences of using it or for
11# whether it serves any particular purpose or works at all, unless he
12# says so in writing. Refer to the GNU General Public License for full
13# details.
14#
15# Everyone is granted permission to copy, modify and redistribute
16# make-ssh-known-hosts, but only under the conditions described in
17# the GNU General Public License. A copy of this license is supposed to
18# have been given to you along with make-ssh-known-hosts so you can
19# know your rights and responsibilities. It should be in a file named
20# gnu-COPYING-GPL. Among other things, the copyright notice and this notice
21# must be preserved on all copies.
22######################################################################
23# Program: make-ssh-known-hosts.pl
24# $Source: /var/cvs/openssh/contrib/Attic/make-ssh-known-hosts.pl,v $
25# Author : $Author: damien $
26#
27# (C) Tero Kivinen 1995 <Tero.Kivinen@hut.fi>
28#
29# Creation : 19:52 Jun 27 1995 kivinen
30# Last Modification : 00:07 Jul 8 1998 kivinen
31# Last check in : $Date: 2000/03/15 01:13:03 $
32# Revision number : $Revision: 1.1 $
33# State : $State: Exp $
34# Version : 1.343
35# Edit time : 242 min
36#
37# Description : Make ssh-known-host file from dns data.
38#
39# $Log: make-ssh-known-hosts.pl,v $
40# Revision 1.1 2000/03/15 01:13:03 damien
41# - Created contrib/ subdirectory. Included helpers from Phil Hands'
42# Debian package, README file and chroot patch from Ricardo Cerqueira
43# <rmcc@clix.pt>
44# - Moved gnome-ssh-askpass.c to contrib directory and reomved config
45# option.
46# - Slight cleanup to doc files
47#
48# Revision 1.6 1998/07/08 00:44:23 kivinen
49# Fixed to understand bind 8 nslookup output.
50#
51# Revision 1.5 1998/04/30 01:53:33 kivinen
52# Moved kill before close and added sending SIGINT first and
53# then 1 second sleep before sending SIGKILL.
54#
55# Revision 1.4 1998/04/17 00:39:19 kivinen
56# Changed to close ssh program filedescriptor before killing it.
57# Removed ^ from the password matching prompt.
58#
59# Revision 1.3 1997/04/17 04:21:27 kivinen
60# Changed to use 3des by default.
61#
62# Revision 1.2 1997/03/26 07:14:01 kivinen
63# Added EWOULDBLOCK.
64#
65# Revision 1.1.1.1 1996/02/18 21:38:10 ylo
66# Imported ssh-1.2.13.
67#
68# Revision 1.4 1995/10/02 01:23:45 ylo
69# Ping packet size fixes from Kivinen.
70#
71# Revision 1.3 1995/08/29 22:37:39 ylo
72# Now uses GlobalKnownHostsFile and UserKnownHostsFile.
73#
74# Revision 1.2 1995/07/15 13:26:37 ylo
75# Changes from kivinen.
76#
77# Revision 1.1.1.1 1995/07/12 22:41:05 ylo
78# Imported ssh-1.0.0.
79#
80#
81#
82# If you have any useful modifications or extensions please send them to
83# Tero.Kivinen@hut.fi
84#
85######################################################################
86# initialization
87
88require 5.000;
89use Getopt::Long;
90use FileHandle;
91use POSIX;
92use Socket;
93use Fcntl;
94
95$version = ' $Id: make-ssh-known-hosts.pl,v 1.1 2000/03/15 01:13:03 damien Exp $ ';
96
97$command_line = "$0 ";
98foreach $a (@ARGV) {
99 $command_line .= $a . " ";
100}
101STDERR->autoflush(1);
102
103######################################################################
104# default values for options
105
106$debug = 5;
107$defserver = '';
108$bell='\a';
109$public_key = '/etc/ssh_host_key.pub';
110$private_ssh_known_hosts = "/tmp/ssh_known_hosts$$";
111$timeout = 60;
112$ping_timeout = 3;
113$passwordtimeout = undef;
114$trustdaemon = 1;
115$domainnamesplit = 0;
116$recursive = 1;
117
118######################################################################
119# Programs and their options
120
121$nslookup = "nslookup";
122
123$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'";
124$sshdisablepasswordoption="-o 'BatchMode yes' -o 'PasswordAuthentication no'";
125
126######################################################################
127# Cleanup and initialization
128
129unlink($private_ssh_known_hosts);
130$sockaddr = 'S n a4 x8';
131($junk, $junk, $sshport) = getservbyname("ssh", "tcp");
132if (!defined($sshport)) {
133 $sshport = 22;
134}
135($tcpprotoname, $junk, $tcpproto) = getprotobyname('tcp');
136defined($tcpprotoname) || die "getprotobyname : $!";
137
138######################################################################
139# Parse options
140
141GetOptions("initialdns=s", "server=s", "subdomains=s",
142 "debug=i", "timeout=i", "passwordtimeout=i",
143 "trustdaemon!", "domainnamesplit", "silent",
144 "nslookup=s", "pingtimeout=i", "recursive!",
145 "keyscan",
146 "ssh=s")
147 || die "Getopt : $!";
148
149if (defined($opt_initialdns)) { $defserver = $opt_initialdns; }
150
151if (defined($opt_server)) { $server = $opt_server; }
152
153if (defined($opt_subdomains)) { @subdomains = split(/,/, $opt_subdomains); }
154
155if (defined($opt_debug)) { $debug = $opt_debug; }
156
157if (defined($opt_timeout)) { $timeout = $opt_timeout; }
158
159if (defined($opt_pingtimeout)) { $ping_timeout = $opt_pingtimeout; }
160
161if (defined($opt_passwordtimeout)) {
162 $passwordtimeout = $opt_passwordtimeout;
163 $sshdisablepasswordoption = '';
164}
165
166if (defined($opt_trustdaemon)) { $trustdaemon = $opt_trustdaemon; }
167
168if (defined($opt_recursive)) { $recursive = $opt_recursive; }
169
170if (defined($opt_domainnamesplit)) { $domainnamesplit = $opt_domainnamesplit; }
171
172if (defined($opt_silent)) { $bell = ''; }
173
174if (defined($opt_nslookup)) { $nslookup = $opt_nslookup; }
175
176if (defined($opt_ssh)) { $ssh = $opt_ssh; } else {
177 $ssh = "$ssh $sshdisablepasswordoption";
178}
179
180if ($#ARGV == 0) {
181 $domain = "\L$ARGV[0]\E";
182 $grep_yes = '.*';
183 $grep_no = '^$';
184} elsif ($#ARGV == 1) {
185 $domain = "\L$ARGV[0]\E";
186 $grep_yes = $ARGV[1];
187 $grep_no = '^$';
188} elsif ($#ARGV == 2) {
189 $domain = "\L$ARGV[0]\E";
190 $grep_yes = $ARGV[1];
191 $grep_no = $ARGV[2];
192} else {
193 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");
194 exit(1);
195}
196
197######################################################################
198# Check that ssh program exists
199
200if (system("$ssh > /dev/null 2>&1 ") != 256) {
201 print(STDERR "Error: Could not run ssh program ($ssh): $!\nError: Try giving the path to it with --ssh option\n");
202 exit(1);
203}
204
205######################################################################
206# Generate subdomains list
207
208if (!$domainnamesplit) {
209 debug(6, "Auto splitting host entries");
210} elsif (!defined(@subdomains)) {
211 debug(6, "Generating subdomain list");
212
213 # split domain to pieces
214 @domain_pieces = split(/\./, $domain);
215
216 # add empty domain part
217 push(@subdomains, '');
218
219 # add rest parts, except the one before full domain name
220 $entry='';
221 for(; $#domain_pieces > 1; ) {
222 $entry .= "." . shift(@domain_pieces);
223 push(@subdomains, $entry);
224 }
225
226 # add full domain name
227 push(@subdomains, ".$domain");
228 debug(5, "Subdomain list: " . join(',', @subdomains));
229} else {
230 debug(5, "Using given subdomain list:" . join(',', @subdomains));
231}
232
233######################################################################
234# finding SOA entry for domain
235
236@other_servers = ();
237if (!defined($server)) {
238 debug(6, "Finding DNS database SOA entry");
239
240 ($server, @other_servers) = find_soa($domain, $defserver);
241
242 if (!defined($server)) {
243 print(STDERR "Error: Could not find DNS SOA entry from default dns server\nError: Try giving the initial nameserver with --initialdns option\n");
244 exit(1);
245 } else {
246 debug(5, "DNS server found : $server");
247 }
248} else {
249 debug(5, "Using given DNS server : $server");
250}
251
252######################################################################
253# Print header
254
255($name, $junk, $junk, $junk, $junk, $junk, $gecos) = getpwuid($<);
256$gecos =~ s/,.*$//g;
257
258if (!defined($opt_keyscan)) {
259 print(STDOUT "# This file is generated with make-ssh-known-hosts.pl\n");
260 print(STDOUT "#$version\n");
261 print(STDOUT "# with command line :\n");
262 print(STDOUT "# $command_line\n");
263 print(STDOUT "#\n");
264 print(STDOUT "# The script was run by $gecos ($name) at " . localtime() . "\n");
265 print(STDOUT "# using perl ($^X) version $].\n");
266}
267
268######################################################################
269# Get DNS database list from server
270
271do {
272 $domains_done{$domain} = 1;
273 delete $domains_waiting{$domain};
274
275 $hostcnt = 0;
276 $cnamecnt = 0;
277 $lines = 0;
278 $soa = 0;
279 undef %host;
280 undef %cname;
281 undef %hostdata;
282
283 dnsagain:
284 debug(1, "Getting DNS database for $domain from server $server");
285 open(DNS, "echo ls -d $domain | nslookup - $server 2>&1 |") ||
286 die "Error: Could not start nslookup to make dns list : $!\nError: Try giving --nslookup option and telling the path to nslookup program\n";
287
288 while(<DNS>) {
289 $lines++;
290 chomp;
291 undef $hostname if/^\s*$/;
292 if (/^\s{0,1}([a-zA-Z0-9-]\S*)/) {
293 $hostname = "\L$1\E";
294 }
295 next unless defined $hostname;
296 if (/^.*\s(SOA)\s+(.*)\s*$/ || $hostname eq "SOA") {
297 undef $soa if(/^.*\s(SOA)\s+(.*)\s*$/);
298 $data = $_ if ($hostname eq "SOA");
299 $data = $2 unless $hostname eq "SOA";
300 $data =~ s/\s*;.*$//;
301 $data =~ s/^\s+//;
302 if( defined $soa ) {
303 $soa .= " \L$data\E";
304 } else {
305 $soa = "\L$data\E";
306 }
307 $hostname = "SOA";
308 } elsif (/^.*\s(A|CNAME|NS)\s+(.*)\s*$/) {
309 $host = $hostname;
310 $field = "\L$1\E";
311 $data = "\L$2\E";
312 debug(70, "Line = /$host/$field/$data/");
313 if ($host !~ /\.$/) {
314 $host .= ".$domain";
315 } else {
316 $host =~ s/\.$//g;
317 }
318 if ($field eq "a") {
319 if ($host =~ /$domain$/) {
320 if (defined($host{$host})) {
321 $host{$host} .= ",$data";
322 } else {
323 $host{$host} = "$data";
324 $hostcnt++;
325 }
326 debug(30, "$host A == $host{$host}");
327 }
328 } elsif ($field eq "cname") {
329 if ($data !~ /\.$/ && ! /^\s/ ) {
330 $data .= ".$domain";
331 } else {
332 $data =~ s/\.$//g;
333 }
334 if ($host =~ /$domain$/) {
335 if (defined($cname{$data})) {
336 $cname{$data} .= ",$host";
337 } else {
338 $cname{$data} = "$host";
339 $cnamecnt++;
340 }
341 debug(30, "$host CNAME $data");
342 $junk = $data;
343 $data = $host;
344 $host = $junk;
345 }
346 } elsif ($field eq "ns") {
347 if (!defined($domains_done{$host})) {
348 if (!defined($domains_waiting{$host})) {
349 debug(10, "Adding subdomain $host to domains list, with NS $data");
350 $domains_waiting{$host} = $data;
351 push(@domains_waiting, $host);
352 } else {
353 debug(10, "Adding NS $data for domain $host");
354 $domains_waiting{$host} .= ",$data";
355 }
356 }
357 }
358 if (!defined($hostdata{$host})) {
359 $hostdata{$host} = "$host\n$field=$data\n";
360 } else {
361 $hostdata{$host} .= "$field=$data\n";
362 }
363 }
364 }
365 close(DNS);
366 if ($hostcnt == 0 && $cnamecnt == 0) {
367 if ($#other_servers != -1) {
368 $server = shift(@other_servers);
369 goto dnsagain;
370 }
371 }
372 debug(1, "Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)");
373 if (!defined($opt_keyscan)) {
374 print(STDOUT "#\n");
375 print(STDOUT "# Domain = $domain, server = $server\n");
376 print(STDOUT "# Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)\n");
377 print(STDOUT "# SOA = $soa\n");
378 print(STDOUT "#\n");
379 }
380
381######################################################################
382# Loop through hosts and try to connect to hosts
383
384 foreach $i (sort (keys %host)) {
385 debug(50, "Host = $i, Hostdata = $hostdata{$i}");
386 if ($hostdata{$i} =~ /$grep_yes/im &&
387 $hostdata{$i} !~ /$grep_no/im &&
388 $i !~ /^localhost\./ &&
389 $host{$i} !~ /^127.0.0.1$|^127.0.0.1,|,127.0.0.1$|,127.0.0.1,/) {
390 debug(2, "Trying host $i");
391
392 @hostnames = ();
393 if (defined($cname{$i})) {
394 expand($i, \@hostnames, \@subdomains);
395 foreach $j (split(/,/, $cname{$i})) {
396 expand($j, \@hostnames, \@subdomains);
397 }
398 } else {
399 expand($i, \@hostnames, \@subdomains);
400 }
401 foreach $j (split(/,/, $host{$i})) {
402 push(@hostnames, $j);
403 }
404 $hostnames = join(',', (@hostnames));
405
406 if (defined($opt_keyscan)) {
407 printf(STDOUT "$host{$i}\t$hostnames\n");
408 } elsif (try_ping($i, $host{$i})) {
409 $trusted = 1;
410 $err = 'Timeout expired';
411 $ssh_key = try_ssh("$i");
412 if (!defined($ssh_key)) {
413 $ssh_key = find_host_from_known_hosts($i);
414 $trusted = 0;
415 }
416 if (defined($ssh_key)) {
417 if ($trusted) {
418 debug(2, "Ssh to $i succeded");
419 } else {
420 debug(2, "Ssh to $i failed, using local known_hosts entry");
421 }
422 debug(4, "adding entries : $hostnames");
423 $ssh_key =~ s/root@//i;
424 if (!$trusted && !$trustdaemon) {
425 print(STDOUT "# $hostnames $ssh_key\n");
426 } else {
427 print(STDOUT "$hostnames $ssh_key\n");
428 }
429 } else {
430 debug(2, "ssh failed : $err");
431 }
432 } else {
433 debug(2, "ping failed");
434 }
435 } else {
436 debug(10, "Skipped host $i");
437 }
438 }
439 again:
440 $domain = shift(@domains_waiting);
441 if (defined($domain)) {
442 $server = $domains_waiting{$domain};
443 @other_servers = split(',', $server);
444 $server = shift(@other_servers);
445 ($server, @other_servers) = find_soa($domain, $server);
446 if(!defined($server)) {
447 debug(1, "Skipping domain $domain because no DNS SOA entry found");
448 $domains_done{$domain} = 1;
449 delete $domains_waiting{$domain};
450 goto again;
451 }
452 }
453} while ($recursive && defined($domain));
454
455unlink($private_ssh_known_hosts);
456exit (0);
457
458######################################################################
459# try_ping -- try to ping to host and return 1 if success
460# $success = try_ping($host, $list_ip_addrs);
461
462sub try_ping {
463 my($host, $ipaddrs) = @_;
464 my(@ipaddrs, $ipaddr, $serv, $ip);
465 my($rin, $rout, $win, $wout, $nfound, $tmout, $buf, $len, $ret, $err);
466
467 $buf = '';
468 debug(51,"Trying to ping host $host");
469 @ipaddrs = split(/,/, $ipaddrs);
470
471 while ($ipaddr = shift(@ipaddrs)) {
472
473 debug(55,"Trying ipaddr $ipaddr");
474
475 #initialize socket
476 socket(PING, PF_INET, SOCK_STREAM, $tcpproto) ||
477 die "socket failed : $!";
478 setsockopt(PING, SOL_SOCKET, SO_REUSEADDR, 1) ||
479 die "setsockopt failed : $!";
480 PING->autoflush(1);
481 fcntl(PING, F_SETFL, fcntl(PING, F_GETFL, 0) | POSIX::O_NONBLOCK) ||
482 die "fcntl failed : $!";
483
484 $ip = pack('C4', split(/\./, $ipaddr, 4));
485 $serv = pack($sockaddr, AF_INET, $sshport, $ip);
486
487 again:
488 # try connect
489 $ret = connect(PING, $serv);
490 $err = $!;
491 if (!$ret) {
492 debug(60, "Connect failed : $err");
493 if ($err == EINTR) {
494 goto again;
495 }
496 # socket not yet connected, wait for result, it will
497 # wake up for writing when done
498 $tmout = $ping_timeout;
499
500 $rin = '';
501 $win = '';
502 vec($rin, fileno(PING), 1) = 1;
503 vec($win, fileno(PING), 1) = 1;
504 debug(60, "Waiting in select, rin = " . unpack('H*', $rin) .
505 ", win = " . unpack('H*', $win));
506 ($nfound) = select($rout = $rin, $wout = $win, undef, $tmout);
507 $err = $!;
508 debug(80, "Select returned $nfound, rout = " . unpack('H*', $rout) .
509 ", wout = " . unpack('H*', $wout));
510 if ($nfound != 0) {
511 # connect done, read the status with sysread
512 $ret = sysread(PING, $buf, 1);
513 $err = $!;
514 if (defined($ret) || $err == EAGAIN || $err == EWOULDBLOCK) {
515 debug(60, "Select ok, read ok ($err), returning ok");
516 # connection done, return ok
517 shutdown(PING, 2);
518 close(PING);
519 return 1;
520 } else {
521 # connection failed, try next ipaddr
522 debug(60, "Select ok, read failed : $err, trying next");
523 close(PING);
524 }
525 } else {
526 # timeout exceeded, try next ipaddr
527 debug(60, "Select failed : $err, trying next");
528 close(PING);
529 }
530 } else {
531 # connect succeeded, return ok.
532 debug(60, "Connect ok, returning ok");
533 shutdown(PING, 2);
534 close(PING);
535 return 1;
536 }
537 }
538 debug(60, "Returning fail");
539 return 0;
540}
541
542######################################################################
543# try_ssh -- try ssh connection to host and return ssh_key if success
544# if failure return undef, and set $err string to contain error message.
545# $ssh_key = try_ssh($host);
546
547sub try_ssh {
548 my($host) = @_;
549 my($buf, $ret, $pos, $pid, $rin, $nfound, $tmout);
550
551 $pid = open(SSH, "$ssh $host cat $public_key 2>&1 |");
552 $err = undef;
553
554 if ($pid == 0) {
555 $err = "could not open ssh connection to host";
556 return undef;
557 }
558 $ret = 1;
559 $pos = 0;
560 $buf = '';
561 $tmout = $timeout;
562 debug(10, "Starting ssh select loop");
563 loop:
564 while (1) {
565
566 $rin = '';
567 vec($rin, fileno(SSH), 1) = 1;
568 ($nfound, $tmout) = select($rin, undef, undef, $tmout);
569
570 # Timeout
571 if ($nfound <= 0) {
572 debug(20, "Ssh select timed out");
573 kill(2, $pid); sleep(1); kill(9, $pid);
574 close(SSH);
575 $err = "Timeout expired";
576 return undef;
577 }
578
579 $ret = sysread(SSH, $buf, 256, $pos);
580 # EOF or error
581 if ($ret <= 0) {
582 # Yes, close the pipe and return
583 close(SSH);
584 debug(20, "Ssh select closed status = $?");
585 $err = "No reply from ssh";
586 return undef;
587 }
588 $pos += $ret;
589 while ($buf =~ /^(.*)\n\r?([\000-\377]*)$/) {
590 $_ = $1;
591 $buf = $2;
592 $pos = length($buf);
593 debug(20, "Ssh select loop, line = \"$_\"");
594 if (/^connection.*refused/i) {
595 $err = "connection refused";
596 } elsif (/^permission/i) {
597 $err = "permission denied";
598 } elsif (/$public_key.*no\s+file/i) {
599 $err = "$public_key file not found";
600 } elsif (/$public_key.*permission\s+denied/i) {
601 $err = "$public_key file permission denied";
602 } elsif (/^\d+\s+\d+\s+\d/) {
603 kill(2, $pid); sleep(1); kill(9, $pid);
604 close(SSH);
605 return $_;
606 }
607 if (defined($err)) {
608 kill(2, $pid); sleep(1); kill(9, $pid);
609 close(SSH);
610 return undef;
611 }
612 }
613 if ($buf =~ /password: $/i) {
614 if (defined($passwordtimeout)) {
615 $tmout = $passwordtimeout;
616 print(STDERR "$bell\n\rPassword: ");
617 if ($tmout == 0) {
618 $tmout = undef;
619 }
620 } else {
621 $tmout = 0;
622 }
623 $buf = '';
624 $pos = 0;
625 }
626 }
627}
628
629######################################################################
630# find_hosts_from_known_hosts -- find host key from private known_hosts file
631# $ssh_key = find_host_from_known_hosts($host);
632
633sub find_host_from_known_hosts {
634 my($host) = @_;
635 open(KNOWNHOSTS, "<$private_ssh_known_hosts") || return undef;
636 while(<KNOWNHOSTS>) {
637 @_ = split(/\s+/, $_);
638 if ($_[0] =~ /^$host$|^$host,|,$host$/) {
639 shift(@_);
640 close(KNOWNHOSTS);
641 return join(' ', @_);
642 }
643 }
644 close(KNOWNHOSTS);
645 return undef;
646}
647
648######################################################################
649# expand -- insert expanded hostnames to hostnames table
650# expand($hostname, \@hostnames, \@subdomains);
651
652sub expand {
653 my($host, $hostnames, $subdomains) = @_;
654 my($newhost, $sub, $entry);
655
656 if (!$domainnamesplit) {
657 my(@domain_pieces);
658
659 # split domain to pieces
660 @domain_pieces = split(/\./, $host);
661
662 # add rest parts, except the one before full domain name
663 $entry = shift(@domain_pieces);
664
665 debug(20, "Adding autosplit entry $entry");
666 push(@$hostnames, $entry);
667
668 for(; $#domain_pieces > 1; ) {
669 $entry .= "." . shift(@domain_pieces);
670 debug(20, "Adding autosplit entry $entry");
671 push(@$hostnames, $entry);
672 }
673 # add full domain name
674 debug(20, "Adding autosplit entry $host");
675 push(@$hostnames, $host);
676 } else {
677 if ($host =~ /^(.*)$domain$/i) {
678 $newhost = $1;
679 $newhost =~ s/\.$//g;
680 foreach $sub (@$subdomains) {
681 $entry = $newhost . $sub;
682 $entry =~ s/^\.//g;
683 if ($entry ne '') {
684 debug(20, "Adding entry $entry");
685 push(@$hostnames, $entry);
686 }
687 }
688 }
689 }
690}
691
692######################################################################
693# Print debug text
694# debug(text_debug_level, string)
695
696sub debug {
697 my($level, $str) = @_;
698 if ($debug > $level) {
699 print(STDERR "$0:debug[$level]: $str\n");
700 }
701}
702
703######################################################################
704# find_soa -- find soa entry for domain
705# ($soa_origin, @other_servers) = find_soa($domain, $initial_server)
706
707sub find_soa {
708 my($domain, $initial_server) = @_;
709 my($field, $data, $server, @other_servers);
710
711 open(DNS, "$nslookup -type=soa $domain $initial_server 2>&1 |") ||
712 die "Error: Could not start nslookup to find SOA entry for $domain : $!\nError: Try giving the path to it with --nslookup option\n";
713
714 while (<DNS>) {
715 if (/^[^=]*origin\s*=\s*(.*)/) {
716 $server = $1;
717 debug(10, "Found origin : $1");
718 } elsif (/^[^=]*nameserver\s*=\s*(.*)\s*$/) {
719 push(@other_servers, $1);
720 debug(10, "Found nameserver : $1");
721 }
722 }
723 close(DNS);
724 return($server, @other_servers);
725}
726
727######################################################################
728# make_perl_happy -- use some symbols, so perl doesn't complain so much
729# make_perl_happy();
730
731sub make_perl_happy {
732 if (0) {
733 print $opt_silent;
734 }
735}
736
7371;
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 @@
1#!/bin/sh
2
3# Shell script to install your identity.pub on a remote machine
4# Takes the remote machine name as an argument.
5# Obviously, the remote machine must accept password authentication,
6# or one of the other keys in your ssh-agent, for this to work.
7
8ID_FILE="${HOME}/.ssh/identity.pub"
9
10if [ "-i" = "$1" ]; then
11 shift
12 # check if we have 2 parameters left, if so the first is the new ID file
13 if [ -n "$2" ]; then
14 if expr "$1" : ".*\.pub" ; then
15 ID_FILE="$1"
16 else
17 ID_FILE="$1.pub"
18 fi
19 shift # and this should leave $1 as the target name
20 fi
21else
22 if [ x$SSH_AUTH_SOCK != x ] ; then
23 GET_ID="$GET_ID ssh-add -L"
24 fi
25fi
26
27if [ -z "`eval $GET_ID`" -a -r "${ID_FILE}" ] ; then
28 GET_ID="cat ${ID_FILE}"
29fi
30
31if [ -z "`eval $GET_ID`" ]; then
32 echo "$0: ERROR: No identities found"
33 exit 1
34fi
35
36{ eval "$GET_ID" ; } | ssh $1 "test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys ; chmod g-w . .ssh .ssh/authorized_keys"
37
38cat <<EOF
39Now try logging into the machine, with "ssh '$1'", and check in:
40
41 .ssh/authorized_keys
42
43to make sure we haven't added extra keys that you weren't expecting.
44
45EOF
diff --git a/contrib/ssh-copy-id.1 b/contrib/ssh-copy-id.1
new file mode 100644
index 000000000..df4f88d9b
--- /dev/null
+++ b/contrib/ssh-copy-id.1
@@ -0,0 +1,67 @@
1.ig \" -*- nroff -*-
2Copyright (c) 1999 Philip Hands Computing <http://www.hands.com/>
3
4Permission is granted to make and distribute verbatim copies of
5this manual provided the copyright notice and this permission notice
6are preserved on all copies.
7
8Permission is granted to copy and distribute modified versions of this
9manual under the conditions for verbatim copying, provided that the
10entire resulting derived work is distributed under the terms of a
11permission notice identical to this one.
12
13Permission is granted to copy and distribute translations of this
14manual into another language, under the above conditions for modified
15versions, except that this permission notice may be included in
16translations approved by the Free Software Foundation instead of in
17the original English.
18..
19.TH SSH-COPY-ID 1 "14 November 1999" "OpenSSH"
20.SH NAME
21ssh-copy-id \- install your identity.pub in a remote machine's authorized_keys
22.SH SYNOPSIS
23.B ssh-copy-id [-i [identity_file]]
24.I "[user@]machine"
25.br
26.SH DESCRIPTION
27.BR ssh-copy-id
28is a script that uses ssh to log into a remote machine (presumably
29using a login password, so password authentication should be enabled,
30unless you've done some clever use of multiple identities)
31.PP
32It also changes the permissions of the remote user's home,
33.BR ~/.ssh ,
34and
35.B ~/.ssh/authorized_keys
36to remove group writability (which would otherwise prevent you from logging in, if the remote
37.B sshd
38has
39.B StrictModes
40set in its configuration).
41.PP
42If the
43.B -i
44option is given then the identity file (defaults to
45.BR ~/.ssh/identity.pub )
46is used, regardless of whether there are any keys in your
47.BR ssh-agent .
48Otherwise, if this:
49.PP
50.B " ssh-add -L"
51.PP
52provides any output, it uses that in preference to the identity file.
53.PP
54If the
55.B -i
56option is used, or the
57.B ssh-add
58produced no output, then it uses the contents of the identity
59file. Once it has one or more fingerprints (by whatever means) it
60uses ssh to append them to
61.B ~/.ssh/authorised_keys
62on the remote machine (creating the file, and directory, if necessary)
63
64.SH "SEE ALSO"
65.BR ssh (1),
66.BR ssh-agent (1),
67.BR sshd (8)