diff options
Diffstat (limited to 'lib/ssh')
87 files changed, 46107 insertions, 0 deletions
diff --git a/lib/ssh/AUTHORS b/lib/ssh/AUTHORS new file mode 100644 index 0000000000..8b1db86657 --- /dev/null +++ b/lib/ssh/AUTHORS @@ -0,0 +1,11 @@ +Original Authors: + +Tony Rogvall - first version +Ingela Anderton Andin - ssh-1.0 + +Contributors: + +Magnus Tho�ng +H�kan Mattsson +Jakob Cederlund +Ingela Anderton Andin diff --git a/lib/ssh/Makefile b/lib/ssh/Makefile new file mode 100644 index 0000000000..1ad69a9ca1 --- /dev/null +++ b/lib/ssh/Makefile @@ -0,0 +1,39 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# +# Macros +# + +SUB_DIRECTORIES = src doc/src + +include vsn.mk +VSN = $(SSH_VSN) + +SPECIAL_TARGETS = + +# +# Default Subdir Targets +# +include $(ERL_TOP)/make/otp_subdir.mk + + diff --git a/lib/ssh/doc/html/.gitignore b/lib/ssh/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssh/doc/html/.gitignore diff --git a/lib/ssh/doc/man3/.gitignore b/lib/ssh/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssh/doc/man3/.gitignore diff --git a/lib/ssh/doc/pdf/.gitignore b/lib/ssh/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssh/doc/pdf/.gitignore diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile new file mode 100644 index 0000000000..d2907a39d7 --- /dev/null +++ b/lib/ssh/doc/src/Makefile @@ -0,0 +1,205 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(SSH_VSN) +APPLICATION=ssh + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + ssh.xml \ + ssh_channel.xml \ + ssh_connection.xml\ + ssh_sftp.xml \ + ssh_sftpd.xml \ + +XML_PART_FILES = part_notes.xml part_notes_history.xml +XML_CHAPTER_FILES = notes.xml notes_history.xml + +BOOK_FILES = book.xml + +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +# notes_history.html \ + + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + + +debug opt: + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 +endif +endif + +endif + +release_spec: diff --git a/lib/ssh/doc/src/book.xml b/lib/ssh/doc/src/book.xml new file mode 100644 index 0000000000..0375c441af --- /dev/null +++ b/lib/ssh/doc/src/book.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>2005</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>SSH</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>2007-10-06</date> + <rev>%VSN%</rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>SSH</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <applications> + <xi:include href="ref_man.xml"/> + </applications> + <releasenotes> + <xi:include href="notes.xml"/> + </releasenotes> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/lib/ssh/doc/src/fascicules.xml b/lib/ssh/doc/src/fascicules.xml new file mode 100644 index 0000000000..43090b4aed --- /dev/null +++ b/lib/ssh/doc/src/fascicules.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> + +<fascicules> + <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> + Reference Manual + </fascicule> + <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> + Release Notes + </fascicule> + <fascicule file="" href="../../../../doc/print.html" entry="no"> + Off-Print + </fascicule> +</fascicules> + diff --git a/lib/ssh/doc/src/make.dep b/lib/ssh/doc/src/make.dep new file mode 100644 index 0000000000..cfe2f9617b --- /dev/null +++ b/lib/ssh/doc/src/make.dep @@ -0,0 +1,19 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex ref_man.tex ssh.tex ssh_channel.tex \ + ssh_connection.tex ssh_sftp.tex ssh_sftpd.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml new file mode 100644 index 0000000000..54e0cf9059 --- /dev/null +++ b/lib/ssh/doc/src/notes.xml @@ -0,0 +1,588 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>SSH Release Notes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev>%VSN%</rev> + <file>notes.xml</file> + </header> + + <section><title>Ssh 1.1.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Now clear all processes when a connnection is terminated.</p> + <p> + Own Id: OTP-8121 Aux Id:</p> + </item> + <item> + <p> + In some rare cases the connection handler could enter an infinite loop.</p> + <p> + Own Id: OTP-8277 Aux Id: seq11428</p> + </item> + <item> + <p> + If an SFTP server did not respond with EOF, the function + ssh_sftp:list_dir/2/3 would enter an infinite loop.</p> + <p> + Own Id: OTP-8278 Aux Id: seq11450</p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.</p> + <p> + Own Id: OTP-8201 Aux Id:</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + ssh_sftp:start_channel did not handle all possible return + values from ssh_channel:start correctly. + </p> + <p> + Own Id: OTP-8176 Aux Id: </p> + </item> + <item> + <p> + SFTPD did not handle rename command (version 4) correctly. + </p> + <p> + Own Id: OTP-8175 Aux Id: seq11373</p> + </item> + <item> + <p> + If a connection manager already had been terminated it could cause a channel + to generate a crash report when it was about to stop. + </p> + <p> + Own Id: OTP-8174 Aux Id: seq11377</p> + </item> + <item> + <p> + Requests could result in badarg or badmatch EXIT messages in the connection + manager if the channel no longer existed.</p> + <p> + Own Id: OTP-8173 Aux Id: seq11379</p> + </item> + <item> + <p> + ssh_transport:unpack/3 could cause a badarg error.</p> + <p> + Own Id: OTP-8162 Aux Id:</p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The encryption algorithm aes128-cbc is now supported. + Requires that crypto-1.6.1 is available.</p> + <p> + Own Id: OTP-8110 Aux Id:</p> + </item> + </list> + </section> + + </section> + + + <section><title>Ssh 1.1.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + ssh_sftp:start_channel/3 did not handle timout correctly.</p> + <p> + Own Id: OTP-8159 Aux Id: seq11386</p> + </item> + <item> + <p> + If a progress message was not recieved after invoking ssh:connect/3 + the call could hang for ever. A timeout option has also been added.</p> + <p> + Own Id: OTP-8160 Aux Id: seq11386</p> + </item> + <item> + <p> + A comma has been missing in the ssh.appup file since SSH-1.0.2.</p> + <p> + Own Id: OTP-8161 Aux Id:</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + SSH sometimes caused a crash report at disconnect.</p> + <p> + Own Id: OTP-8071 Aux Id: seq11319</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The operation ssh_sftp:stop_channel/1 returned an + exception if the connection already had been closed.</p> + <p> + Own Id: OTP-7996 Aux Id: seq11281</p> + </item> + <item> + <p> + SSH did not handle if supervisor:start_child/2 returned + {error, already_present}.</p> + <p> + Own Id: OTP-8034 Aux Id: seq11307</p> + </item> + <item> + <p> + SSH no longer cause supervisor reports when a connection is + terminated in a controlled manner.</p> + <p> + Own Id: OTP-8035 Aux Id: seq11308</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Ssh confused local and remote channel id's, which in some + cases resulted in that messages were discarded.</p> + <p> + Own Id: OTP-7914 Aux Id: seq11234</p> + </item> + <item> + <p> + Ssh could not handle echo values other than 0 and 1.</p> + <p> + Own Id: OTP-7917 Aux Id: seq11238</p> + </item> + <item> + <p> + A crash occurred if a non-valid channel reference was received.</p> + <p> + Own Id: OTP-7918 Aux Id: seq11238</p> + </item> + <item> + <p> + Sftpd connections was not closed after receiving eof from a client.</p> + <p> + Own Id: OTP-7921 Aux Id: seq11222</p> + </item> + <item> + <p> + It was not possible to start a SFTP subsystem on certain platforms, + i.e. those who do not support symbolic links.</p> + <p> + Own Id: OTP-7930 Aux Id: </p> + </item> + <item> + <p> + In some cases the message {ssh_cm, ssh_connection_ref(), {closed, ssh_channel_id()}} + was not passed to the registered callback module.</p> + <p> + Own Id: OTP-7957 Aux Id: </p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + By using the sftpd option {max_files, Integer}, the message + size for READDIR commands can be reduced.</p> + <p> + Own Id: OTP-7919 Aux Id: seq11230</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The erlang ssh server has presented itself incorrectly, + using the special version ssh-1.99, although it never has + supported versions below 2.0. Since ssh-1.1 client + versions below 2.0 are correctly rejected instead of + letting the server crash later on. Alas the problem with + the presentation string was not discovered until after + ssh.1.1 was released. Now the server will present itself + as ssh-2.0.</p> + <p> + Own Id: OTP-7795</p> + </item> + <item> + <p> + An internal function call used an incorrect parameter, which + caused problem when the old listen API was used. This was + introduced in Ssh-1.1.</p> + <p> + Own Id: OTP-7920 Aux Id: seq11211</p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Ssh timeouts will now behave as expected e.i. defaults to + infinity only the user of the ssh application can know of + a reasonable timeout value for their application.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7807</p> + </item> + <item> + <p> + The implementation of timeouts added as a patch in + ssh-1.0.1 was slightly changed and is now documented.</p> + <p> + Own Id: OTP-7808</p> + </item> + <item> + <p> + To honor the multiplexing of channels over one ssh + connection concept ssh_sftp:connect/ [1,2,3] is + deprecated and replaced by ssh_sftp:start_channel/[1,2,3] + and ssh_sftp:stop/1 is deprecated and replaced by + ssh_sftp:stop_channel/1 and to stop the ssh connection + ssh:close/ 1 should be called.</p> + <p> + Own Id: OTP-7809</p> + </item> + <item> + <p> + Added the message {ssh_channel_up, ChannelId, + ConnectionManager} that shall be handled by the channel + callback handle_msg/2. This makes the function + handle_msg/2 a mandatory function for ssh channels + implementations which it was not in ssh-1.1.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7828</p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A flaw in the implementation of the supervision tree + caused the ssh daemon to close the connections to all + currently logged in users if one user logged out. Another + problem related to the supervision tree caused the closing + down of clients to leak processes e.i. all processes was + not shutdown correctly.</p> + <p> + Own Id: OTP-7676</p> + </item> + <item> + <p> + Tabs could cause ssh_cli to print things in a surprising + way.</p> + <p> + Own Id: OTP-7683 Aux Id: seq11102 </p> + </item> + <item> + <p> + [sftp, sftpd] - Added patch to make sftp timestamps more + correct, in the long run it would be nice to have better + support in file to be able to make it always behave + correctly now it will be correct 99 % of time instead of + almost never correct, at least on unix-based platforms.</p> + <p> + Own Id: OTP-7685 Aux Id: seq11082 </p> + </item> + <item> + <p> + [sftpd] - Added patch to further improve handling of + symbolic links in the sftp-server.</p> + <p> + Own Id: OTP-7766 Aux Id: seq11101 </p> + </item> + <item> + <p> + Ssh incorrectly sent the local id instead of the remote + id of a channel to the peer. For simpler cases these ids + often happen to have the same value. One case when they + do not is when the client sends an exec command two times + in a raw on the same ssh connection (different channels + of course as the channel will be closed when the exec + command has been evaluated) .</p> + <p> + Own Id: OTP-7767</p> + </item> + <item> + <p> + Packet data could be lost under high load due to the fact + that buffered data was sometimes wrongly discarded before + it had been sent.</p> + <p> + Own Id: OTP-7768</p> + </item> + <item> + <p> + Improved ipv6-handling as some assumptions about inet + functions where incorrect.</p> + <p> + Own Id: OTP-7770</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Added new API function ssh:connection_info/2.</p> + <p> + Own Id: OTP-7456</p> + </item> + <item> + <p> + Now starts ssh channel processes later avoiding + synchronization problems between processes.</p> + <p> + Own Id: OTP-7516</p> + </item> + <item> + <p> + Ssh now rejects old versions of the ssh protocol for + security reasons. (Even if they where not correctly + rejected before the connection would probably have failed + anyway due to other reasons.)</p> + <p> + Own Id: OTP-7645 Aux Id: seq11094 </p> + </item> + <item> + <p> + New API module ssh_channel has been added. This is a + behaviour to facilitate the implementation of ssh clients + and plug in subsystems to the ssh daemon. Note that this + slightly changes the options to the API function + ssh:daemon/[1,2,3] deprecating all no longer documented + options. Note that the new API enforces the "logical way" + of using the old API e.i. making the subsystem process + part of the ssh applications supervisor tree, so missuses + of the old API are not compatible with the new API.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7769</p> + </item> + </list> + </section> + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + Public keys protected by a password are currently not + handled by the erlang ssh application.</p> + <p> + Own Id: OTP-6400 Aux Id: 10595 </p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.0.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + [sftpd] - Listing of symbolic link directories should now + work as expected.</p> + <p> + Own Id: OTP-7141 Aux Id: seq10856 </p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + [sftp] - When listing a directory with more than 100 + files only the first 100 where listed. This has now been + fixed.</p> + <p> + Own Id: OTP-7318 Aux Id: seq10953 </p> + </item> + <item> + <p> + When restarting an ssh-system the expected return value + from ssh_system_sup:restart_acceptor/2 was incorrect, + this is no longer the case.</p> + <p> + Own Id: OTP-7564 Aux Id: seq11055 </p> + </item> + <item> + <p> + A few minor bugs where fixed in ssh_userreg.erl and + ssh_connection_manager and a a ssh_cli option was added + to restore backwards compatibility with the old ssh_cm - + API.</p> + <p> + Own Id: OTP-7565</p> + </item> + <item> + <p> + Fixed bug in ipv6 support and added option to disable + ipv6 as a workaround for badly configured computers.</p> + <p> + Own Id: OTP-7566</p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + [sftp] - Option added to set timeout value in sftp.</p> + <p> + Own Id: OTP-7305 Aux Id: seq10945 </p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 1.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Removed some special handling of prompts that made ssh + behave differently than openssh.</p> + <p> + Own Id: OTP-7485 Aux Id: seq11025 </p> + </item> + <item> + <p> + Bug in encoding of pty opts has been fixed.</p> + <p> + Own Id: OTP-7504</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The architecture of the ssh processes has been + reconstructed to fit in a supervision tree as to become a + real OTP application and benefit from this when starting + and stopping.</p> + <p> + Own Id: OTP-7356 Aux Id: seq10899 </p> + </item> + <item> + <p> + Support for pty option echo off added. Requires kernel + from R12B-4.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7502 Aux Id: seq10959 </p> + </item> + <item> + <p> + The ssh API has been enhanced a lot of old API functions + has become deprecated.</p> + <p> + Own Id: OTP-7503</p> + </item> + </list> + </section> + + <!-- p>For information about older versions see + <url href="part_notes_history_frame.html">release notes history</url>.</p --> + </section> +</chapter> + diff --git a/lib/ssh/doc/src/notes_history.xml b/lib/ssh/doc/src/notes_history.xml new file mode 100644 index 0000000000..bfebcd4bf4 --- /dev/null +++ b/lib/ssh/doc/src/notes_history.xml @@ -0,0 +1,737 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2009</year> + <year>2009</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>SSH Release Notes History</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev>A</rev> + <file>notes_history.xml</file> + </header> + + <section><title>Ssh 0.9.9.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Updated asn1 file due to change in the asn1 compiler. + This has no semantical effect on the ssh application.</p> + <p> + Own Id: OTP-7246</p> + </item> + <item> + <p> + Allows for the option {fd, FD} in listen and connect + calls. The option is passed on to gen_tcp:listen and + gen_tcp:connect</p> + <p> + Own Id: OTP-7247</p> + </item> + </list> + </section> +</section> + + <section><title>Ssh 0.9.9.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Putty version 0.60 sends ignore messages, which hanged + the OTP ssh server.</p> + <p> + Own Id: OTP-7076</p> + </item> + <item> + <p> + ssh_cm hanged when connection was closed during + handshake. (Triggered by putty 0.60 client.)</p> + <p> + Own Id: OTP-7089</p> + </item> + <item> + <p> + Fixed crash in server when receiving an empty ignore-msg. + (From the putty 0.60 client.)</p> + <p> + Own Id: OTP-7135</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Now uses the base 64 encode/decode function in stdlib.</p> + <p> + Own Id: OTP-6486</p> + </item> + <item> + <p> + Removed runtime dependency on asn1.</p> + <p> + Own Id: OTP-6570</p> + </item> + <item> + <p> + Documentation update of ssh.</p> + <p> + Own Id: OTP-7063 Aux Id: seq10789 </p> + </item> + <item> + <p> + Same listener is used for both sshd and sftpd. Previously + the sftpd server had to be run on a separate port, now + the sshd listener will start an sftpd server when an sftp + client connects.</p> + <p> + Own Id: OTP-7090 Aux Id: seq10675 </p> + </item> + <item> + <p> + Kebord-interactive support, according to rfc 4256, has + been added to the ssh client. Also the option + <c>quiet_mode</c> has been added so that unwanted banners + may be suppressed.</p> + <p> + Own Id: OTP-7106 Aux Id: seq10841 </p> + </item> + </list> + </section> + + </section> + + <section><title>Ssh 0.9.9.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + [sftpd] - Root parameter now behaves as expected, + instead of making sftpd malfunction.</p> + <p> + Own Id: OTP-7057 Aux Id: seq10830 </p> + </item> + </list> + </section> + </section> + + <section><title>Ssh 0.9.9.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The sftp-server could crash if a "ls" was done on the + client, and a file was removed while ssh_sftpd:list_dir + was reading the directory, an error code from + read_file_info wasn't handled properly. This fix makes ls + return an error code instead.</p> + <p> + Own Id: OTP-6854 Aux Id: seq10740 </p> + </item> + <item> + <p> + Fixed bugs in prompting in ssl_cli. Prompts like \003> + were written as \300>. Also, newlines and returns was + removed.</p> + <p> + Own Id: OTP-6917 Aux Id: seq10773 </p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + [sftpd] - New option "root" to set the root of the + sftp-server and the callback module for file handling now + has a state parameter.</p> + <p> + Own Id: OTP-7075 Aux Id: seq10675 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9.2</title> + <section> + <title>Better error-handling in ssh_sshd:listen</title> + <list type="bulleted"> + <item> + <p>The caller was hanged when listening with ssh_sshd:listen + (or ssh_sftpd:listen) on a port and IP already in use. + Now an error is returned instead.</p> + <p>Own Id: OTP-6727</p> + </item> + </list> + </section> + + <section> + <title>Fix in ssh_sftpd</title> + <list type="bulleted"> + <item> + <p>Cd ../.. didn't work when connecting to a ssh_sftpd server.</p> + <p>Own Id: OTP-6727</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9.1</title> + + <section> + <title>Minor Makefile changes</title> + <list type="bulleted"> + <item> + <p>Removed use of <c><![CDATA[erl_flags]]></c> from Makefile.</p> + <p>Own Id: OTP-6689</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A race condition that could make the server crash if a + client sent a SSH_MSG_USERAUTH_REQUEST packet immediately + after its SSH_MSG_SERVICE_REQUEST, is removed.</p> + <p>Own Id: OTP-6379 Aux Id: seq10523 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.8</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Corrected minor bugs and removed dead code found by + dialyzer.</p> + <p>Own Id: OTP-6524</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.7</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>[sftp] - The function ssh_sftp:make_symlink/3 was not + fully implemented.</p> + <p>Own Id: OTP-6446</p> + </item> + <item> + <p>[ssh] - An internal value was, due to a bug, always set + to undefined even when it was not, this could lead to + connections being wrongly refused.</p> + <p>Own Id: OTP-6450</p> + </item> + <item> + <p>A pattern matching was missing "/binary" resulting in + that the internal function ssh_xfer:decode_acl/2 did not + work as expected.</p> + <p>Own Id: OTP-6458</p> + </item> + <item> + <p>[sftp] - read_link/2 did not return the documented value</p> + <p>Own Id: OTP-6471</p> + </item> + <item> + <p>Removed debugg printouts from ssh_cli.erl</p> + <p>Own Id: OTP-6483</p> + </item> + <item> + <p>[sftp, ssh] - The connection timeout was overridden by an + internal gen_server default timeout.</p> + <p>Own Id: OTP-6488 Aux Id: seq10569 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.6</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Removed debug printout from production code.</p> + <p>Own Id: OTP-6348 Aux Id: seq10510 </p> + </item> + <item> + <p>[sftpd] - When the sftp client ends the session the + server will now behave correctly and not leave the client + hanging.</p> + <p>Own Id: OTP-6349 Aux Id: seq10510 </p> + </item> + <item> + <p>[sftpd] - No longer used files were not closed until the + session was ended.</p> + <p>Own Id: OTP-6350 Aux Id: seq10514 </p> + </item> + <item> + <p>[sftpd] - File rename requests sent by sftp version 3 + clients were not handled.</p> + <p>Own Id: OTP-6352 Aux Id: seq10513 </p> + </item> + <item> + <p>[sftpd] - Request that did not fit into one ssh message + were not handled.</p> + <p>Own Id: OTP-6353 Aux Id: seq10515 </p> + </item> + <item> + <p>Removed error logging of auth method none, as this is not + an error but rather a feature, that is used to get + initial information from the server.</p> + <p>Own Id: OTP-6414</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>[sftpd] - Added new option to specify a callback module + for the sftpd-server file handling. The default callback + module uses file and filelib.</p> + <p>Own Id: OTP-6356 Aux Id: seq10519 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The data window in SSH wasn't resized in the ssh_cli + receive data, this made the ssh_cli-server hang if more + than 64K data was received at one time. The option + tcp_nodelay was added, for nodelay in tcp connections.</p> + <p>Own Id: OTP-6231</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.4</title> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Unnecessary explicit start of crypto application + in ssh application. This has been removed. The + app-file specifies that ssh depends on the crypto app. + This is enough. See also the + <seealso marker="ssh">ssh</seealso> module.</p> + <p>Also changed some error reports to info reports.</p> + <p>Own Id: OTP-6183</p> + <p>Aux Id: Seq 10383</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Added way for cli to get peer name</p> + <p>Own Id: OTP-6138</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Added some options to listen</p> + <p>Own Id: OTP-6070</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.1</title> + <section><title>Ssh 0.9.9.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + [sftpd] - Root parameter now behaves as expected, + instead of making sftpd malfunction.</p> + <p> + Own Id: OTP-7057 Aux Id: seq10830 </p> + </item> + </list> + </section> + </section> + + <section><title>Ssh 0.9.9.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The sftp-server could crash if a "ls" was done on the + client, and a file was removed while ssh_sftpd:list_dir + was reading the directory, an error code from + read_file_info wasn't handled properly. This fix makes ls + return an error code instead.</p> + <p> + Own Id: OTP-6854 Aux Id: seq10740 </p> + </item> + <item> + <p> + Fixed bugs in prompting in ssl_cli. Prompts like \003> + were written as \300>. Also, newlines and returns was + removed.</p> + <p> + Own Id: OTP-6917 Aux Id: seq10773 </p> + </item> + </list> + </section> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + [sftpd] - New option "root" to set the root of the + sftp-server and the callback module for file handling now + has a state parameter.</p> + <p> + Own Id: OTP-7075 Aux Id: seq10675 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9.2</title> + <section> + <title>Better error-handling in ssh_sshd:listen</title> + <list type="bulleted"> + <item> + <p>The caller was hanged when listening with ssh_sshd:listen + (or ssh_sftpd:listen) on a port and IP already in use. + Now an error is returned instead.</p> + <p>Own Id: OTP-6727</p> + </item> + </list> + </section> + + <section> + <title>Fix in ssh_sftpd</title> + <list type="bulleted"> + <item> + <p>Cd ../.. didn't work when connecting to a ssh_sftpd server.</p> + <p>Own Id: OTP-6727</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9.1</title> + + <section> + <title>Minor Makefile changes</title> + <list type="bulleted"> + <item> + <p>Removed use of <c><![CDATA[erl_flags]]></c> from Makefile.</p> + <p>Own Id: OTP-6689</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A race condition that could make the server crash if a + client sent a SSH_MSG_USERAUTH_REQUEST packet immediately + after its SSH_MSG_SERVICE_REQUEST, is removed.</p> + <p>Own Id: OTP-6379 Aux Id: seq10523 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.8</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Corrected minor bugs and removed dead code found by + dialyzer.</p> + <p>Own Id: OTP-6524</p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.7</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>[sftp] - The function ssh_sftp:make_symlink/3 was not + fully implemented.</p> + <p>Own Id: OTP-6446</p> + </item> + <item> + <p>[ssh] - An internal value was, due to a bug, always set + to undefined even when it was not, this could lead to + connections being wrongly refused.</p> + <p>Own Id: OTP-6450</p> + </item> + <item> + <p>A pattern matching was missing "/binary" resulting in + that the internal function ssh_xfer:decode_acl/2 did not + work as expected.</p> + <p>Own Id: OTP-6458</p> + </item> + <item> + <p>[sftp] - read_link/2 did not return the documented value</p> + <p>Own Id: OTP-6471</p> + </item> + <item> + <p>Removed debugg printouts from ssh_cli.erl</p> + <p>Own Id: OTP-6483</p> + </item> + <item> + <p>[sftp, ssh] - The connection timeout was overridden by an + internal gen_server default timeout.</p> + <p>Own Id: OTP-6488 Aux Id: seq10569 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.6</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Removed debug printout from production code.</p> + <p>Own Id: OTP-6348 Aux Id: seq10510 </p> + </item> + <item> + <p>[sftpd] - When the sftp client ends the session the + server will now behave correctly and not leave the client + hanging.</p> + <p>Own Id: OTP-6349 Aux Id: seq10510 </p> + </item> + <item> + <p>[sftpd] - No longer used files were not closed until the + session was ended.</p> + <p>Own Id: OTP-6350 Aux Id: seq10514 </p> + </item> + <item> + <p>[sftpd] - File rename requests sent by sftp version 3 + clients were not handled.</p> + <p>Own Id: OTP-6352 Aux Id: seq10513 </p> + </item> + <item> + <p>[sftpd] - Request that did not fit into one ssh message + were not handled.</p> + <p>Own Id: OTP-6353 Aux Id: seq10515 </p> + </item> + <item> + <p>Removed error logging of auth method none, as this is not + an error but rather a feature, that is used to get + initial information from the server.</p> + <p>Own Id: OTP-6414</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>[sftpd] - Added new option to specify a callback module + for the sftpd-server file handling. The default callback + module uses file and filelib.</p> + <p>Own Id: OTP-6356 Aux Id: seq10519 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Ssh 0.9.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The data window in SSH wasn't resized in the ssh_cli + receive data, this made the ssh_cli-server hang if more + than 64K data was received at one time. The option + tcp_nodelay was added, for nodelay in tcp connections.</p> + <p>Own Id: OTP-6231</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.4</title> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Unnecessary explicit start of crypto application + in ssh application. This has been removed. The + app-file specifies that ssh depends on the crypto app. + This is enough. See also the + <seealso marker="ssh">ssh</seealso> module.</p> + <p>Also changed some error reports to info reports.</p> + <p>Own Id: OTP-6183</p> + <p>Aux Id: Seq 10383</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Added way for cli to get peer name</p> + <p>Own Id: OTP-6138</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Added some options to listen</p> + <p>Own Id: OTP-6070</p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Fixes in ssh_sftp, changes of timeout handling, + expand_fun moved to io:setopts</p> + <p>Own Id: OTP-5877 Aux Id: OTP-5781 </p> + </item> + </list> + </section> + </section> + + <section> + <title>SSH 0.9</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The previously undocumented and UNSUPPORTED <c><![CDATA[ssh]]></c> + application has been updated and documented. This release + of the <c><![CDATA[ssh]]></c> application is still considered to be a + beta release and (if necessary) there could still be + changes in its API before it reaches 1.0.</p> + <p>Also, more cryptographic algorithms have been added to + the <c><![CDATA[crypto]]></c> application.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5631</p> + </item> + </list> + </section> + </section> + </section> + +</chapter> + + diff --git a/lib/ssh/doc/src/part_notes.xml b/lib/ssh/doc/src/part_notes.xml new file mode 100644 index 0000000000..f87efffe5c --- /dev/null +++ b/lib/ssh/doc/src/part_notes.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>SSH Release Notes</title> + <prepared>Jakob Cederlund</prepared> + <docno></docno> + <date></date> + <rev>%VSN%</rev> + <file>part_notes.sgml</file> + </header> + <description> + <p>This document describes the changes made to the SSH application. + </p> + <p>For information about older versions see + <url href="part_notes_history_frame.html">release notes history</url>.</p> </description> + <xi:include file="notes.xml"/> +</part> + diff --git a/lib/ssh/doc/src/part_notes_history.xml b/lib/ssh/doc/src/part_notes_history.xml new file mode 100644 index 0000000000..49f72fd3db --- /dev/null +++ b/lib/ssh/doc/src/part_notes_history.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part> + <header> + <copyright> + <year>2004</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>Ssh</title> + <prepared>Ingela Anderton Andin</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>part_notes.xml</file> + </header> + <include file="notes_history"></include> +</part> + + diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml new file mode 100644 index 0000000000..c05c3051b0 --- /dev/null +++ b/lib/ssh/doc/src/ref_man.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>SSH Reference Manual</title> + <prepared>Jakob Cederlund</prepared> + <docno></docno> + <date>2007-10-06</date> + <rev>%VSN%</rev> + <file>application.sgml</file> + </header> + <description> + <p>The SSH application is an erlang implementation of the + secure shell protocol.</p> + </description> + <xi:include href="ssh.xml"/> + <xi:include href="ssh_channel.xml"/> + <xi:include href="ssh_connection.xml"/> + <xi:include href="ssh_sftp.xml"/> + <xi:include href="ssh_sftpd.xml"/> +</application> + diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml new file mode 100644 index 0000000000..aca5c9cdc4 --- /dev/null +++ b/lib/ssh/doc/src/ssh.xml @@ -0,0 +1,337 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>ssh</title> + <prepared>Ingela Anderton Andin</prepared> + <responsible>Håkan Mattsson</responsible> + <docno></docno> + <approved>Håkan Mattsson</approved> + <checked></checked> + <date>2007-10-06</date> + <rev>PA1</rev> + </header> + <module>ssh</module> + <modulesummary>Main API of the SSH application</modulesummary> + <description> + <p>Interface module for the SSH application</p> + </description> + + + <section> + <title>COMMON DATA TYPES </title> + <p>Type definitions that are used more than once in + this module:</p> + <p><c>boolean() = true | false </c></p> + <p><c>string() = list of ASCII characters</c></p> + <p><c>ssh_daemon_ref() - opaque to the user + returned by ssh:daemon/[1,2,3]</c></p> + <p><c>ssh_connection_ref() - opaque to the user + returned by ssh:connect/3</c></p> + <p><c>ip_address() - {N1,N2,N3,N4} % IPv4 | + {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6</c></p> + <p><c>subsystem_spec() = {subsystem_name(), {channel_callback(), channel_init_args()}} </c></p> + <p><c>subsystem_name() = string() </c></p> + <p><c>channel_callback() = atom() - Name of the erlang module + implementing the subsystem using the ssh_channel behavior see</c> + <seealso marker="ssh_channel">ssh_channel(3)</seealso></p> + <p><c>channel_init_args() = list()</c></p> + </section> + + <funcs> + + <func> + <name>close(ConnectionRef) -> ok </name> + <fsummary>Closes a ssh connection</fsummary> + <type> + <v>ConnectionRef = ssh_connection_ref()</v> + </type> + <desc><p>Closes a ssh connection.</p> + </desc> + </func> + + <func> + <name>connect(Host, Port, Options) -> </name> + <name>connect(Host, Port, Options, Timeout) -> {ok, ssh_connection_ref()} + | {error, Reason}</name> + <fsummary>Connect to an ssh server.</fsummary> + <type> + <v>Host = string()</v> + <v>Port = integer()</v> + <d>The default is <c><![CDATA[22]]></c>, the registered port for SSH.</d> + <v>Options = [{Option, Value}]</v> + <v>Timeout = infinity | integer(milliseconds)</v> + </type> + <desc> + <p>Connects to an SSH server. No channel is started this is done + by calling ssh_connect:session_channel/2.</p> + <p>Options are:</p> + <taglist> + <tag><c><![CDATA[{user_dir, String}]]></c></tag> + <item> + <p>Sets the user directory e.i. the directory containing + ssh configuration files for the user such as + <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa, id_dsa]]></c> and + <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally + referred to as <c><![CDATA[~/.ssh]]></c> </p> + </item> + <tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag> + <item> + <p>When true hosts are added to the + file <c><![CDATA[known_hosts]]></c> without asking the user. + Defaults to false. + </p> + </item> + <tag><c><![CDATA[{user_interaction, boolean()}]]></c></tag> + <item> + <p>If false disables the client to connect to the server + if any user interaction is needed such as accepting that + the server will be added to the <c>known_hosts</c> file or + supplying a password. Defaults to true. + Even if user interaction is allowed it can be + suppressed by other options such as silently_accept_hosts and + password. Do note that it may not always be desirable to use + those options from a security point of view.</p> + </item> + <tag><c><![CDATA[{public_key_alg, ssh_rsa | ssh_dsa}]]></c></tag> + <item> + <p>Sets the preferred public key algorithm to use for user + authentication. If the the preferred algorithm fails of + some reason, the other algorithm is tried. The default is + to try <c><![CDATA[ssh_rsa]]></c> first.</p> + </item> + <tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag> + <item> + <p>Sets a timeout on the transport layer connection. Defaults to infinity.</p> + </item> + <tag><c><![CDATA[{user, String}]]></c></tag> + <item> + <p>Provide a user name. If this option is not given, ssh + reads from the environment (<c><![CDATA[LOGNAME]]></c> or + <c><![CDATA[USER]]></c> on unix, + <c><![CDATA[USERNAME]]></c> on Windows).</p> + </item> + <tag><c><![CDATA[{password, string()}]]></c></tag> + <item> + <p>Provide a password for password authentication. If + this option is not given, the user will be asked for a + password if the password authentication method is + attempted.</p> + </item> + <tag><c><![CDATA[{user_auth, Fun/3}]]></c></tag> + <item> + <p>Provide a fun for password authentication. The fun + will be called as <c><![CDATA[fun(User, Password, Opts)]]></c> and + should return <c><![CDATA[true]]></c> or <c><![CDATA[false]]></c>.</p> + </item> + <tag><c><![CDATA[{key_cb, atom() = KeyCallbackModule}]]></c></tag> + <item> + <p>Provide a special call-back module for key handling. + The call-back module should be modeled after the + <c><![CDATA[ssh_file]]></c> module. The functions that must + be exported are: + <c><![CDATA[private_host_rsa_key/2]]></c>, + <c><![CDATA[private_host_dsa_key/2]]></c>, + <c><![CDATA[lookup_host_key/3]]></c> and + <c><![CDATA[add_host_key/3]]></c>. This is considered + somewhat experimental and will be better documented later on.</p> + </item> + <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag> + <item> + <p>Allow an existing file-descriptor to be used + (simply passed on to the transport protocol).</p></item> + </taglist> + </desc> + </func> + + <func> + <name>connection_info(ConnectionRef, [Option]) ->[{Option, Value}] </name> + <fsummary> Retrieves information about a connection. </fsummary> + <type> + <v>Option = client_version | server_version | peer</v> + <v>Value = term() </v> + </type> + <desc> + <p> Retrieves information about a connection. + </p> + </desc> + </func> + + <func> + <name>daemon(Port) -> </name> + <name>daemon(Port, Options) -> </name> + <name>daemon(HostAddress, Port, Options) -> ssh_daemon_ref()</name> + <fsummary>Starts a server listening for SSH connections + on the given port.</fsummary> + <type> + <v>Port = integer()</v> + <v>HostAddress = ip_address() | any</v> + <v>Options = [{Option, Value}]</v> + <v>Option = atom()</v> + <v>Value = term()</v> + </type> + <desc> + <p>Starts a server listening for SSH connections on the given port.</p> + + <p>Options are:</p> + <taglist> + <tag><c><![CDATA[{subsystems, [subsystem_spec()]]]></c></tag> + <item> + Provides specifications for handling of subsystems. The + "sftp" subsystem-spec can be retrieved by calling + ssh_sftd:subsystem_spec/1. If the subsystems option in not present + the value of <c>[ssh_sftd:subsystem_spec([])]</c> will be used. + It is of course possible to set the option to the empty list + if you do not want the daemon to run any subsystems at all. + </item> + <tag><c><![CDATA[{shell, {Module, Function, Args} | fun(string() = User) - > pid() | + fun(string() = User, ip_address() = PeerAddr) -> pid()}]]></c></tag> + <item> + Defines the read-eval-print loop used when a shell is requested + by the client. Example use the + erlang shell: <c><![CDATA[{shell, start, []}]]></c> which is + the default behavior. + </item> + <tag><c><![CDATA[{ssh_cli,{channel_callback(), channel_init_args()}}]]></c></tag> + <item> + Provide your own cli implementation, e.i. a channel callback + module that implements a shell and command execution. Note + that you may customize the shell read-eval-print loop using the + option <c>shell</c> which is much less work than implementing + your own cli channel. + </item> + <tag><c><![CDATA[{system_dir, string()}]]></c></tag> + <item> + <p>Sets the system directory, containing the host files + that identifies the host for ssh. The default is + <c><![CDATA[/etc/ssh]]></c>, note that SSH normally + requires the host files there to be readable only by + root.</p> + </item> + <tag><c><![CDATA[{user_passwords, [{string() = User, string() = Password}]}]]></c></tag> + <item> + <p>Provide passwords for password authentication.They will + be used when someone tries to connect to the server and + public key user authentication fails. The option provides + a list of valid user names and the corresponding password. + </p> + </item> + <tag><c><![CDATA[{password, string()}]]></c></tag> + <item> + <p>Provide a global password that will authenticate any + user. From a security perspective this option makes + the server very vulnerable.</p> + </item> + <tag><c><![CDATA[{pwdfun, fun/2}]]></c></tag> + <item> + <p>Provide a function for password validation. This is called + with user and password as strings, and should return + <c><![CDATA[true]]></c> if the password is valid and + <c><![CDATA[false]]></c> otherwise.</p> + </item> + <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag> + <item> + <p>Allow an existing file-descriptor to be used + (simply passed on to the transport protocol).</p></item> + </taglist> + </desc> + </func> + + <func> + <name>shell(Host) -> </name> + <name>shell(Host, Option) -> </name> + <name>shell(Host, Port, Option) -> _</name> + <fsummary> </fsummary> + <type> + <v> Host = string()</v> + <v> Port = integer()</v> + <v> Options - see ssh:connect/3</v> + </type> + <desc> + <p>Starts an interactive shell to an SSH server on the + given <c>Host</c>. The function waits for user input, + and will not return until the remote shell is ended (e.g. on + exit from the shell). + </p> + </desc> + </func> + + <func> + <name>start() -> </name> + <name>start(Type) -> ok | {error, Reason}</name> + <fsummary>Starts the Ssh application. </fsummary> + <type> + <v>Type = permanent | transient | temporary</v> + <v>Reason = term() </v> + </type> + <desc> + <p>Starts the Ssh application. Default type + is temporary. See also + <seealso marker="kernel:application">application(3)</seealso> + Requires that the crypto application has been started. + </p> + </desc> + </func> + + <func> + <name>stop() -> ok </name> + <fsummary>Stops the Ssh application.</fsummary> + <desc> + <p>Stops the Ssh application. See also + <seealso marker="kernel:application">application(3)</seealso></p> + </desc> + </func> + + <func> + <name>stop_daemon(DaemonRef) -> </name> + <name>stop_daemon(Address, Port) -> ok </name> + <fsummary>Stops the listener and all connections started by + the listener.</fsummary> + <type> + <v>DaemonRef = ssh_daemon_ref()</v> + <v>Address = ip_address()</v> + <v>Port = integer()</v> + </type> + <desc> + <p>Stops the listener and all connections started by + the listener.</p> + </desc> + </func> + + <func> + <name>stop_listener(DaemonRef) -> </name> + <name>stop_listener(Address, Port) -> ok </name> + <fsummary>Stops the listener, but leaves existing connections started + by the listener up and running.</fsummary> + <type> + <v>DaemonRef = ssh_daemon_ref()</v> + <v>Address = ip_address()</v> + <v>Port = integer()</v> + </type> + <desc> + <p>Stops the listener, but leaves existing connections started + by the listener up and running.</p> + </desc> + </func> + </funcs> + +</erlref> diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml new file mode 100644 index 0000000000..c2b7aa94a5 --- /dev/null +++ b/lib/ssh/doc/src/ssh_channel.xml @@ -0,0 +1,520 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2009</year> + <year>2009</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>ssh_channel</title> + <prepared>Ingela Anderton Andin</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev></rev> + </header> + <module>ssh_channel</module> + <modulesummary>Generic Ssh Channel Behavior + </modulesummary> + <description> + <p>Ssh services are implemented as channels that are multiplexed + over an ssh connection and communicates via the ssh connection + protocol. This module provides a callback API that takes care of + generic channel aspects such as flow control and close messages + and lets the callback functions take care of the service specific + parts. + </p> + </description> + + <section> + <title>COMMON DATA TYPES </title> + + <p>Type definitions that are used more than once in this module + and/or abstractions to indicate the intended use of the data + type:</p> + + <p><c>boolean() = true | false </c></p> + <p><c>string() = list of ASCII characters</c></p> + <p><c>timeout() = infinity | integer() - in milliseconds.</c></p> + <p><c>ssh_connection_ref() - opaque to the user returned by + ssh:connect/3 or sent to a ssh channel process</c></p> + <p><c>ssh_channel_id() = integer() </c></p> + <p><c>ssh_data_type_code() = 1 ("stderr") | 0 ("normal") are + currently valid values see RFC 4254 section 5.2.</c></p> + </section> + + <funcs> + <func> + <name>call(ChannelRef, Msg) -></name> + <name>call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason}</name> + <fsummary> Makes a synchronous call to a channel.</fsummary> + <type> + <v>ChannelRef = pid() </v> + <d>As returned by start_link/4 </d> + <v>Msg = term() </v> + <v>Timeout = timeout() </v> + <v>Reply = term() </v> + <v>Reason = closed | timeout </v> + </type> + <desc> + <p>Makes a synchronous call to the channel process by sending + a message and waiting until a reply arrives or a timeout + occurs. The channel will call + <c>CallbackModule:handle_call/3</c> to handle the message. + If the channel process does not exist <c>{error, closed}</c> is returned. + </p> + </desc> + </func> + + <func> + <name>cast(ChannelRef, Msg) -> ok </name> + <fsummary>Sends an asynchronous message to the channel + ChannelRef and returns ok.</fsummary> + <type> + <v>ChannelRef = pid() </v> + <d>As returned by start_link/4 </d> + <v>Msg = term() </v> + </type> + <desc> + <p>Sends an asynchronous message to the channel process and + returns ok immediately, ignoring if the destination node or + channel process does not exist. The channel will call + <c>CallbackModule:handle_cast/2</c> to handle the message. + </p> + </desc> + </func> + + <func> + <name>enter_loop(State) -> _ </name> + <fsummary> Makes an existing process into a ssh_channel process. </fsummary> + <type> + <v> State = term() - as returned by ssh_channel:init/1</v> + </type> + <desc> + <p> Makes an existing process into a <c>ssh_channel</c> + process. Does not return, instead the calling process will + enter the <c>ssh_channel</c> process receive loop and become a + <c>ssh_channel process.</c> The process must have been started using + one of the start functions in proc_lib, see <seealso + marker="stdlib:proc_lib">proc_lib(3)</seealso>. The + user is responsible for any initialization of the process + and needs to call ssh_channel:init/1. + </p> + </desc> + </func> + + <func> + <name>init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} </name> + <fsummary> Initiates a ssh_channel process.</fsummary> + <type> + <v> Options = [{Option, Value}]</v> + </type> + <desc> + <p> + The following options must be present: + </p> + <taglist> + <tag><c><![CDATA[{channel_cb, atom()}]]></c></tag> + <item>The module that implements the channel behavior.</item> + + <tag><c><![CDATA[{init_args(), list()}]]></c></tag> + <item> The list of arguments to the callback modules + init function.</item> + + <tag><c><![CDATA[{cm, connection_ref()}]]></c></tag> + <item> Reference to the ssh connection.</item> + + <tag><c><![CDATA[{channel_id, channel_id()}]]></c></tag> + <item> Id of the ssh channel.</item> + + </taglist> + + <note><p>This function is normally not called by the user, it is + only needed if for some reason the channel process needs + to be started with help of <c>proc_lib</c> instead calling + <c>ssh_channel:start/4</c> or <c>ssh_channel:start_link/4</c> </p> + </note> + </desc> + </func> + + <func> + <name>reply(Client, Reply) -> _</name> + <fsummary>Send a reply to a client.</fsummary> + <type> + <v>Client - opaque to the user, see explanation below</v> + <v>Reply = term()</v> + </type> + <desc> + <p>This function can be used by a channel to explicitly send a + reply to a client that called <c>call/[2,3]</c> when the reply + cannot be defined in the return value of + <c>CallbackModule:handle_call/3</c>.</p> + <p><c>Client</c> must be the <c>From</c> argument provided to + the callback function <c>handle_call/3</c>. + <c>Reply</c> is an arbitrary term, + which will be given back to the client as the return value of + <c>ssh_channel:call/[2,3].</c></p> + </desc> + </func> + + <func> + <name>start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> </name> + <name>start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> + {ok, ChannelRef} | {error, Reason}</name> + <fsummary> Starts a processes that handles a ssh channel. </fsummary> + <type> + <v>SshConnection = ssh_connection_ref()</v> + <v>ChannelId = ssh_channel_id() </v> + <d> As returned by ssh_connection:session_channel/[2,4]</d> + <v>ChannelCb = atom()</v> + <d> The name of the module implementing the service specific parts + of the channel.</d> + <v>CbInitArgs = [term()]</v> + <d>Argument list for the init function in the callback module. </d> + <v>ChannelRef = pid()</v> + </type> + <desc> + <p>Starts a processes that handles a ssh channel. Will be + called internally by the ssh daemon or explicitly by the ssh + client implementations. A channel process traps exit signals + by default. + </p> + </desc> + </func> + + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + + <p>The functions init/1, terminate/2, handle_ssh_msg/2 and + handle_msg/2 are the functions that are required to provide the + implementation for a server side channel, such as a ssh subsystem + channel that can be plugged into the erlang ssh daemon see + <seealso marker="ssh">ssh:daemon/[2, 3]</seealso>. The + handle_call/3, handle_cast/2 code_change/3 and enter_loop/1 + functions are only relevant when implementing a client side + channel.</p> + </section> + + <section> + <marker id="cb_timeouts"></marker> + <title> CALLBACK TIMEOUTS</title> + <p> If an integer timeout value is provided in a return value of + one of the callback functions, a timeout will occur unless a + message is received within <c>Timeout</c> milliseconds. A timeout + is represented by the atom <c>timeout</c> which should be handled + by the <seealso marker="#handle_msg">handle_msg/2</seealso> + callback function. The atom infinity can be used to wait + indefinitely, this is the default value. </p> + </section> + + <funcs> + <func> + <name>CallbackModule:code_change(OldVsn, State, Extra) -> {ok, + NewState}</name> + <fsummary> Converts process state when code is changed.</fsummary> + <type> + <v> Converts process state when code is changed.</v> + </type> + <desc> + <p>This function is called by a client side channel when it + should update its internal state during a release + upgrade/downgrade, i.e. when the instruction + <c>{update,Module,Change,...}</c> where + <c>Change={advanced,Extra}</c> is given in the <c>appup</c> + file. See <seealso + marker="doc/design_principles:release_handling#instr">OTP + Design Principles</seealso> for more information. Any new + connection will benefit from a server side upgrade but + already started connections on the server side will not be + affected. + </p> + + <note><p>If there are long lived ssh connections and more + than one upgrade in a short time this may cause the old + connections to fail as only two versions of the code may + be loaded simultaneously.</p></note> + + <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and + in the case of a downgrade, <c>OldVsn</c> is + <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c> + attribute(s) of the old version of the callback module + <c>Module</c>. If no such attribute is defined, the version + is the checksum of the BEAM file.</p> + <p><c>State</c> is the internal state of the channel.</p> + <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c> + part of the update instruction.</p> + <p>The function should return the updated internal state.</p> + </desc> + </func> + + <func> + <name>CallbackModule:init(Args) -> {ok, State} | {ok, State, Timeout} | + {stop, Reason}</name> + <fsummary> Makes necessary initializations and returns the + initial channel state if the initializations succeed.</fsummary> + <type> + <v> Args = term() </v> + <d> Last argument to ssh_channel:start_link/4.</d> + <v> State = term() </v> + <v>Timeout = timeout() </v> + <v> Reason = term() </v> + </type> + <desc> + <p> Makes necessary initializations and returns the initial channel + state if the initializations succeed. + </p> + <p>For more detailed information on timeouts see the section + <seealso marker="#cb_timeouts">CALLBACK TIMEOUTS</seealso>. </p> + </desc> + </func> + + <func> + <name>CallbackModule:handle_call(Msg, From, State) -> Result</name> + <fsummary> Handles messages sent by calling + <c>ssh_channel:call/[2,3]</c></fsummary> + <type> + <v>Msg = term()</v> + <v>From = opaque to the user should be used as argument to + ssh_channel:reply/2</v> + <v>State = term()</v> + <v>Result = {reply, Reply, NewState} | {reply, Reply, NewState, Timeout} + | {noreply, NewState} | {noreply , NewState, Timeout} + | {stop, Reason, Reply, NewState} | {stop, Reason, NewState} </v> + <v>Reply = term() - will be the return value of ssh_channel:call/[2,3]</v> + <v>Timeout = timeout() </v> + <v>NewState = term() - a possible updated version of State</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Handles messages sent by calling + <c>ssh_channel:call/[2,3]</c> + </p> + <p>For more detailed information on timeouts see the section + <seealso marker="#cb_timeouts">CALLBACK TIMEOUTS</seealso>. </p> + </desc> + </func> + + <func> + <name>CallbackModule:handle_cast(Msg, State) -> Result</name> + <fsummary> Handles messages sent by calling + <c>ssh_channel:cact/2</c></fsummary> + <type> + <v>Msg = term()</v> + <v>State = term()</v> + <v>Result = {noreply, NewState} | {noreply, NewState, Timeout} + | {stop, Reason, NewState}</v> + <v>NewState = term() - a possible updated version of State</v> + <v>Timeout = timeout() </v> + <v>Reason = term()</v> + </type> + <desc> + <p> Handles messages sent by calling + <c>ssh_channel:cast/2</c> + </p> + <p>For more detailed information on timeouts see the section + <seealso marker="#cb_timeouts">CALLBACK TIMEOUTS</seealso>. </p> + <marker id="handle_msg"></marker> + </desc> + </func> + + <func> + <name>CallbackModule:handle_msg(Msg, State) -> {ok, State} | + {stop, ChannelId, State}</name> + + <fsummary> Handle other messages than ssh connection protocol, + call or cast messages sent to the channel.</fsummary> + <type> + <v>Msg = timeout | term()</v> + <v>State = term() </v> + </type> + <desc> + <p>Handle other messages than ssh connection protocol, call or + cast messages sent to the channel. + </p> + + <p> Possible erlang 'EXIT'-messages should be handled by this + function and all channels should handle the following message.</p> + + <taglist> + <tag><c><![CDATA[{ssh_channel_up, ssh_channel_id(), + ssh_connection_ref()}]]></c></tag> + <item>This is the first messages that will be received + by the channel, it is sent just before + the ssh_channel:init/1 function returns successfully. + This is especially useful if the server wants + to send a message to the client without first receiving + a message from the client. If the message is not useful + for your particular problem just ignore it by immediately + returning {ok, State}. + </item> + </taglist> + </desc> + </func> + + <func> + <name>CallbackModule:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + ssh_channel_id(), State}</name> + <fsummary> Handles ssh connection protocol messages. </fsummary> + <type> + <v>Msg = {ssh_cm, ssh_connection_ref(), SshMsg}</v> + <v> SshMsg = tuple() - see message list below</v> + <v>State = term()</v> + </type> + <desc> + <p> Handles ssh connection protocol messages that may need + service specific attention. + </p> + + <p> All channels should handle the following messages. For + channels implementing subsystems the handle_ssh_msg-callback + will not be called for any other messages. </p> + + <taglist> + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {data, ssh_channel_id(), + ssh_data_type_code(), binary() = Data}}]]></c></tag> + <item> Data has arrived on the channel. When the callback + for this message returns the channel behavior will adjust + the ssh flow control window.</item> + + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {eof, + ssh_channel_id()}}]]></c></tag> + <item>Indicteas that the other side will not send any more + data.</item> + + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {signal, + ssh_channel_id(), ssh_signal()}} ]]></c></tag> + <item>A signal can be delivered to the remote + process/service using the following message. Some systems + may not implement signals, in which case they should ignore + this message.</item> + + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), + {exit_signal, ssh_channel_id(), string() = exit_signal, + string() = ErrorMsg, string() = + LanguageString}}]]></c></tag> + <item>A remote execution may terminate violently due to a + signal then this message may be received. For details on valid string + values see RFC 4254 section 6.10</item> + + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {exit_status, + ssh_channel_id(), integer() = ExitStatus}}]]></c></tag> + <item> When the command running at the other end terminates, + the following message can be sent to return the exit status + of the command. A zero 'exit_status' usually means that the + command terminated successfully.</item> + </taglist> + + <p> Channels implementing a shell and command execution on the server side + should also handle the following messages. </p> + + <taglist> + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {env, ssh_channel_id(), + boolean() = WantReply, string() = Var, string() = Value}}]]></c></tag> + <item> Environment variables may be passed to the + shell/command to be started later. Note that before the + callback returns it should call the function + ssh_connection:reply_request/4 with the boolean value of <c> + WantReply</c> as the second argument. + </item> + + <tag><c><![CDATA[{ssh_cm, ConnectionRef, {exec, ssh_channel_id(), + boolean() = WantReply, string() = Cmd}}]]></c></tag> + <item> This message will request that the server start the + execution of the given command. Note that before the + callback returns it should call the function + ssh_connection:reply_request/4 with the boolean value of <c> + WantReply</c> as the second argument.</item> + + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {pty, ssh_channel_id(), + boolean() = WantReply, {string() = Terminal, integer() = CharWidth, + integer() = RowHeight, integer() = PixelWidth, integer() = PixelHight, + [{atom() | integer() = Opcode, + integer() = Value}] = TerminalModes}}}]]></c></tag> + <item>A pseudo-terminal has been requested for the + session. Terminal is the value of the TERM environment + variable value (e.g., vt100). Zero dimension parameters must + be ignored. The character/row dimensions override the pixel + dimensions (when nonzero). Pixel dimensions refer to the + drawable area of the window. The <c>Opcode</c> in the + <c>TerminalModes</c> list is the mnemonic name, represented + as an lowercase erlang atom, defined in RFC 4254 section 8, + or the opcode if the mnemonic name is not listed in the + RFC. Example <c>OP code: 53, mnemonic name ECHO erlang atom: + echo</c>. Note that before the callback returns it should + call the function ssh_connection:reply_request/4 with the + boolean value of <c> WantReply</c> as the second + argument.</item> + + <tag><c><![CDATA[{ssh_cm, ConnectionRef, {shell, boolean() = + WantReply}}]]></c></tag> + <item> This message will request that the user's default + shell be started at the other end. Note that before the + callback returns it should call the function + ssh_connection:reply_request/4 with the value of <c> + WantReply</c> as the second argument. + </item> + + <tag><c><![CDATA[ {ssh_cm, ssh_connection_ref(), {window_change, + ssh_channel_id(), integer() = CharWidth, integer() = RowHeight, + integer() = PixWidth, integer() = PixHeight}}]]></c></tag> + <item> When the window (terminal) size changes on the client + side, it MAY send a message to the other side to inform it + of the new dimensions.</item> + </taglist> + + <p> The following message is completely taken care of by the + ssh channel behavior</p> + + <taglist> + <tag><c><![CDATA[{ssh_cm, ssh_connection_ref(), {closed, + ssh_channel_id()}}]]></c></tag> + <item> The channel behavior will send a close message to the + other side if such a message has not already been sent and + then terminate the channel with reason normal.</item> + </taglist> + </desc> + </func> + + <func> + <name>CallbackModule:terminate(Reason, State) -> _</name> + <fsummary> </fsummary> + <type> + <v>Reason = term()</v> + <v>State = term()</v> + </type> + <desc> + <p>This function is called by a channel process when it is + about to terminate. Before this function is called ssh_connection:close/2 + will be called if it has not been called earlier. + This function should be the opposite of <c>CallbackModule:init/1</c> + and do any necessary cleaning up. When it returns, the + channel process terminates with reason <c>Reason</c>. The return value is + ignored. + </p> + </desc> + </func> + + </funcs> + +</erlref> diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml new file mode 100644 index 0000000000..499cbbeabe --- /dev/null +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2008</year> + <year>2008</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>ssh_connection</title> + <prepared>Ingela Anderton Andin</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev></rev> + </header> + <module>ssh_connection</module> + <modulesummary>This module provides an API to the ssh connection protocol. + </modulesummary> + <description> + <p>This module provides an API to the ssh connection protocol. + Not all features of the connection protocol are officially supported yet. + Only the ones supported are documented here.</p> + </description> + + <section> + <title>COMMON DATA TYPES </title> + <p>Type definitions that are used more than once in this module and/or + abstractions to indicate the intended use of the data type:</p> + + <p><c>boolean() = true | false </c></p> + <p><c>string() = list of ASCII characters</c></p> + <p><c>timeout() = infinity | integer() - in milliseconds.</c></p> + <p><c>ssh_connection_ref() - opaque to the user returned by + ssh:connect/3 or sent to a ssh channel processes</c></p> + <p><c>ssh_channel_id() = integer() </c></p> + <p><c>ssh_data_type_code() = 1 ("stderr") | 0 ("normal") are + currently valid values see RFC 4254 section 5.2.</c></p> + <p><c>ssh_request_status() = success | failure</c></p> + </section> + + <section> + <title>MESSAGES SENT TO CHANNEL PROCESSES</title> + + <p>As a result of the ssh connection protocol messages on the form + <c><![CDATA[{ssh_cm, ssh_connection_ref(), term()}]]></c> + will be sent to a channel process. The term will contain + information regarding the ssh connection protocol event, + for details see the ssh channel behavior callback <seealso + marker="ssh_channel">handle_ssh_msg/2 </seealso> </p> + </section> + + <funcs> + + <func> + <name>adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok</name> + <fsummary>Adjusts the ssh flowcontrol window. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id() </v> + <v> NumOfBytes = integer()</v> + </type> + <desc> + <p>Adjusts the ssh flowcontrol window. </p> + + <note><p>This will be taken care of by the ssh_channel + behavior when the callback <seealso marker="ssh_channel"> + handle_ssh_msg/2 </seealso> has returned after processing a + {ssh_cm, ssh_connection_ref(), {data, ssh_channel_id(), + ssh_data_type_code(), binary()}} + message, and should normally not be called explicitly.</p></note> + </desc> + </func> + + <func> + <name>close(ConnectionRef, ChannelId) -> ok</name> + <fsummary>Sends a close message on the channel <c>ChannelId</c>. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + </type> + <desc> + <p>Sends a close message on the channel <c>ChannelId</c> + </p> + + <note><p>This function will be called by the ssh channel + behavior when the channel is terminated see <seealso + marker="ssh_channel"> ssh_channel(3) </seealso> and should + normally not be called explicitly.</p></note> + </desc> + </func> + + <func> + <name>exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() </name> + <fsummary>Will request that the server start the + execution of the given command. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + <v> Command = string()</v> + <v>Timeout = timeout() </v> + </type> + <desc> + <p>Will request that the server start the execution of the + given command, the result will be received as:</p> + + <taglist> + <tag><c> N X {ssh_cm, + ssh_connection_ref(), {data, ssh_channel_id(), ssh_data_type_code(), + binary() = Data}} </c></tag> + <item>The result of executing the command may be only one line + or thousands of lines depending on the command.</item> + + <tag><c> 1 X {ssh_cm, ssh_connection_ref(), {eof, ssh_channel_id()}}</c></tag> + <item>Indicates that no more data will be sent.</item> + + <tag><c>0 or 1 X {ssh_cm, + ssh_connection_ref(), {exit_signal, + ssh_channel_id(), string() = ExitSignal, string() = ErrorMsg, string() = LanguageString}}</c></tag> + <item>Not all systems send signals. For details on valid string + values see RFC 4254 section 6.10 </item> + + <tag><c>0 or 1 X {ssh_cm, ssh_connection_ref(), {exit_status, + ssh_channel_id(), integer() = ExitStatus}}</c></tag> + <item>It is recommended by the <c>ssh connection protocol</c> that this + message shall be sent, but that may not always be the case.</item> + + <tag><c> 1 X {ssh_cm, ssh_connection_ref(), + {closed, ssh_channel_id()}}</c></tag> + <item>Indicates that the ssh channel started for the + execution of the command has now been shutdown.</item> + </taglist> + + <p> These message should be handled by the + client. The <seealso marker="ssh_channel">ssh channel + behavior</seealso> can be used when writing a client. + </p> + </desc> + </func> + + + <func> + <name>exit_status(ConnectionRef, ChannelId, Status) -> ok</name> + <fsummary>Sends the exit status of a command to the client.</fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + <v> Status = integer()</v> + </type> + <desc> + <p>Sends the exit status of a command to the client.</p> + </desc> + </func> + + <func> + <name>reply_request(ConnectionRef, WantReply, Status, CannelId) -> ok</name> + <fsummary>Send status replies to requests that want such replies. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> WantReply = boolean()</v> + <v> Status = ssh_request_status() </v> + <v> ChannelId = ssh_channel_id()</v> + </type> + <desc> + <p>Sends status replies to requests where the requester has + stated that they want a status report e.i .<c> WantReply = true</c>, + if <c> WantReply</c> is false calling this function will be a + "noop". Should be called after handling an ssh connection + protocol message containing a <c>WantReply</c> boolean + value. See the ssh_channel behavior callback <seealso + marker="ssh_channel"> handle_ssh_msg/2 </seealso> + </p> + </desc> + </func> + + <func> + <name>send(ConnectionRef, ChannelId, Data) -></name> + <name>send(ConnectionRef, ChannelId, Data, Timeout) -></name> + <name>send(ConnectionRef, ChannelId, Type, Data) -></name> + <name>send(ConnectionRef, ChannelId, Type, Data, TimeOut) -> + ok | {error, timeout}</name> + <fsummary>Sends channel data </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + <v> Data = binary()</v> + <v> Type = ssh_data_type_code()</v> + <v> Timeout = timeout()</v> + </type> + <desc> + <p>Sends channel data. + </p> + </desc> + </func> + + <func> + <name>send_eof(ConnectionRef, ChannelId) -> ok </name> + <fsummary>Sends eof on the channel <c>ChannelId</c>. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + </type> + <desc> + <p>Sends eof on the channel <c>ChannelId</c>. + </p> + </desc> + </func> + + <func> + <name>session_channel(ConnectionRef, Timeout) -> </name> + <name>session_channel(ConnectionRef, InitialWindowSize, + MaxPacketSize, Timeout) -> {ok, ssh_channel_id()} | {error, Reason}</name> + <fsummary>Opens a channel for a ssh session. A session is a + remote execution of a program. The program may be a shell, an + application, a system command, or some built-in subsystem. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref()</v> + <v> InitialWindowSize = integer() </v> + <v> MaxPacketSize = integer() </v> + <v> Timeout = timeout()</v> + <v> Reason = term() </v> + </type> + <desc> + <p>Opens a channel for a ssh session. A session is a + remote execution of a program. The program may be a shell, an + application, a system command, or some built-in subsystem. + </p> + </desc> + </func> + + <func> + <name>setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status()</name> + <fsummary> Environment variables may be passed to the + shell/command to be started later.</fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + <v> Var = string()</v> + <v> Value = string()</v> + <v> Timeout = timeout()</v> + </type> + <desc> + <p> Environment variables may be passed to the shell/command to be + started later. + </p> + </desc> + </func> + + <func> + <name>shell(ConnectionRef, ChannelId) -> ssh_request_status() + </name> + <fsummary> Will request that the user's default shell (typically + defined in /etc/passwd in UNIX systems) be started at the other + end. </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + </type> + <desc> + <p> Will request that the user's default shell (typically + defined in /etc/passwd in UNIX systems) be started at the + other end. + </p> + </desc> + </func> + + <func> + <name>subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status()</name> + <fsummary> </fsummary> + <type> + <v> ConnectionRef = ssh_connection_ref() </v> + <v> ChannelId = ssh_channel_id()</v> + <v> Subsystem = string()</v> + <v> Timeout = timeout()</v> + </type> + <desc> + <p> Sends a request to execute a predefined subsystem. + </p> + </desc> + </func> + + </funcs> + +</erlref> diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml new file mode 100644 index 0000000000..208b2b4e72 --- /dev/null +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -0,0 +1,501 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2005</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>ssh_sftp</title> + <prepared>Jakob Cederlund</prepared> + <responsible></responsible> + <docno>1</docno> + <approved></approved> + <checked></checked> + <date>2005-09-22</date> + <rev>PA1</rev> + <file>ssh_sftp.sgml</file> + </header> + <module>ssh_sftp</module> + <modulesummary>SFTP client.</modulesummary> + <description> + <p>This module implements an SFTP (SSH FTP) client. SFTP is a + secure, encrypted file transfer service available for + SSH.</p> + </description> + + <section> + <title>COMMON DATA TYPES </title> + <p>Type definitions that are used more than once in this module + and/or abstractions to indicate the intended use of the data type: + </p> + <p><c>ssh_connection_ref() - opaque to the user + returned by ssh:connect/3</c></p> + <p><c>timeout() = infinity | integer() - in milliseconds.</c></p> + </section> + + <section> + <title>TIMEOUTS </title> + <p>If the request functions for the sftp channel return {error, timeout} + it does not mean that the request did not reach the server and was + not performed, it only means that we did not receive an answer from the + server within the time that was expected.</p> + </section> + + <funcs> + <func> + <name>start_channel(ConnectionRef) -> </name> + <name>start_channel(ConnectionRef, Options) -> </name> + <name>start_channel(Host, Options) -></name> + <name>start_channel(Host, Port, Options) -> {ok, Pid} | {ok, Pid, ConnectionRef} | + {error, Reason}</name> + <fsummary>Starts a sftp client</fsummary> + <type> + <v>Host = string()</v> + <v>ConnectionRef = ssh_connection_ref()</v> + <v>Port = integer()</v> + <v>Options = [{Option, Value}]</v> + <v>Reason = term()</v> + </type> + <desc> + <p>If not provided, setups a ssh connection in this case a + connection reference will be returned too. A ssh channel + process is started to handle the communication with the SFTP + server, the returned pid for this process should be used as + input to all other API functions in this module.</p> + + <p>Options are:</p> + <taglist> + <tag><c><![CDATA[{timeout, timeout()}]]></c></tag> + <item> + <p>The timeout is passed to the ssh_channel start function, + and defaults to infinity.</p> + </item> + </taglist> + <p>All other options are directly passed to + <seealso marker="ssh">ssh:connect/3</seealso> or ignored if a + connection is already provided. </p> + </desc> + </func> + + <func> + <name>stop_channel(ChannelPid) -> ok</name> + <fsummary>Stops the sftp client channel.</fsummary> + <type> + <v>ChannelPid = pid()</v> + </type> + <desc> + <p>Stops a sftp channel. If the ssh connection should be closed + call <seealso marker="ssh">ssh:close/1</seealso>.</p> + </desc> + </func> + + <func> + <name>read_file(ChannelPid, File) -> </name> + <name>read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, Reason}</name> + <fsummary>Read a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>File = string()</v> + <v>Data = binary()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Reads a file from the server, and returns the data in a binary, + like <c><![CDATA[file:read_file/1]]></c>.</p> + </desc> + </func> + <func> + <name>write_file(ChannelPid, File, Iolist) -> </name> + <name>write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, Reason}</name> + <fsummary>Write a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>File = string()</v> + <v>Iolist = iolist()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Writes a file to the server, like <c><![CDATA[file:write_file/2]]></c>. + The file is created if it's not there.</p> + </desc> + </func> + <func> + <name>list_dir(ChannelPid, Path) -> </name> + <name>list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, Reason}</name> + <fsummary>List directory</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Path = string()</v> + <v>Filenames = [Filename]</v> + <v>Filename = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Lists the given directory on the server, returning the + filenames as a list of strings.</p> + </desc> + </func> + <func> + <name>open(ChannelPid, File, Mode) -> </name> + <name>open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Open a file and return a handle</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>File = string()</v> + <v>Mode = [Modeflag]</v> + <v>Modeflag = read | write | creat | trunc | append | binary</v> + <v>Timeout = timeout()</v> + <v>Handle = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Opens a file on the server, and returns a handle that + is used for reading or writing.</p> + </desc> + </func> + <func> + <name>opendir(ChannelPid, Path) -> </name> + <name>opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, Reason}</name> + <fsummary>Open a directory and return a handle</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Path = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Opens a handle to a directory on the server, the handle + is used for reading directory contents.</p> + </desc> + </func> + <func> + <name>close(ChannelPid, Handle) -> </name> + <name>close(ChannelPid, Handle, Timeout) -> ok | {error, Reason}</name> + <fsummary>Close an open handle</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Closes a handle to an open file or directory on the server.</p> + </desc> + </func> + <func> + <name>read(ChannelPid, Handle, Len) -> </name> + <name>read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, Error}</name> + <name>pread(ChannelPid, Handle, Position, Len) -> </name> + <name>pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, Error}</name> + <fsummary>Read from an open file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Position = integer()</v> + <v>Len = integer()</v> + <v>Timeout = timeout()</v> + <v>Data = string() | binary()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Reads <c><![CDATA[Len]]></c> bytes from the file referenced by + <c><![CDATA[Handle]]></c>. Returns <c><![CDATA[{ok, Data}]]></c>, or <c><![CDATA[eof]]></c>, or + <c><![CDATA[{error, Reason}]]></c>. If the file is opened with <c><![CDATA[binary]]></c>, + <c><![CDATA[Data]]></c> is a binary, otherwise it is a string.</p> + <p>If the file is read past eof, only the remaining bytes + will be read and returned. If no bytes are read, <c><![CDATA[eof]]></c> + is returned.</p> + <p>The <c><![CDATA[pread]]></c> function reads from a specified position, + combining the <c><![CDATA[position]]></c> and <c><![CDATA[read]]></c> functions.</p> + </desc> + </func> + <func> + <name>aread(ChannelPid, Handle, Len) -> {async, N} | {error, Error}</name> + <name>apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, Error}</name> + <fsummary>Read asynchronously from an open file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Position = integer()</v> + <v>Len = integer()</v> + <v>N = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Reads from an open file, without waiting for the result. If the + handle is valid, the function returns <c><![CDATA[{async, N}]]></c>, where N + is a term guaranteed to be unique between calls of <c><![CDATA[aread]]></c>. + The actual data is sent as a message to the calling process. This + message has the form <c><![CDATA[{async_reply, N, Result}]]></c>, where + <c><![CDATA[Result]]></c> is the result from the read, either <c><![CDATA[{ok, Data}]]></c>, + or <c><![CDATA[eof]]></c>, or <c><![CDATA[{error, Error}]]></c>.</p> + <p>The <c><![CDATA[apread]]></c> function reads from a specified position, + combining the <c><![CDATA[position]]></c> and <c><![CDATA[aread]]></c> functions.</p> + </desc> + </func> + <func> + <name>write(ChannelPid, Handle, Data) -></name> + <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, Error}</name> + <name>pwrite(ChannelPid, Handle, Position, Data) -> ok </name> + <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, Error}</name> + <fsummary>Write to an open file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Position = integer()</v> + <v>Data = iolist()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Write <c><![CDATA[data]]></c> to the file referenced by <c><![CDATA[Handle]]></c>. + The file should be opened with <c><![CDATA[write]]></c> or <c><![CDATA[append]]></c> + flag. Returns <c><![CDATA[ok]]></c> if successful and <c><![CDATA[{error, Reason}]]></c> + otherwise.</p> + <p>Typical error reasons are:</p> + <taglist> + <tag><c><![CDATA[ebadf]]></c></tag> + <item> + <p>The file is not opened for writing.</p> + </item> + <tag><c><![CDATA[enospc]]></c></tag> + <item> + <p>There is a no space left on the device.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>awrite(ChannelPid, Handle, Data) -> ok | {error, Reason} </name> + <name>apwrite(ChannelPid, Handle, Position, Data) -> ok | {error, Reason}</name> + <fsummary>Write asynchronously to an open file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Position = integer()</v> + <v>Len = integer()</v> + <v>Data = binary()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Writes to an open file, without waiting for the result. If the + handle is valid, the function returns <c><![CDATA[{async, N}]]></c>, where N + is a term guaranteed to be unique between calls of + <c><![CDATA[awrite]]></c>. The result of the <c><![CDATA[write]]></c> operation is sent + as a message to the calling process. This message has the form + <c><![CDATA[{async_reply, N, Result}]]></c>, where <c><![CDATA[Result]]></c> is the result + from the write, either <c><![CDATA[ok]]></c>, or <c><![CDATA[{error, Error}]]></c>.</p> + <p>The <c><![CDATA[apwrite]]></c> writes on a specified position, combining + the <c><![CDATA[position]]></c> and <c><![CDATA[awrite]]></c> operations.</p> + </desc> + </func> + <func> + <name>position(ChannelPid, Handle, Location) -> </name> + <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, Error}</name> + <fsummary>Seek position in open file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Handle = term()</v> + <v>Location = Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof</v> + <v>Offset = int()</v> + <v>Timeout = timeout()</v> + <v>NewPosition = integer()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Sets the file position of the file referenced by <c><![CDATA[Handle]]></c>. + Returns <c><![CDATA[{ok, NewPosition]]></c> (as an absolute offset) if + successful, otherwise <c><![CDATA[{error, Reason}]]></c>. <c><![CDATA[Location]]></c> is + one of the following:</p> + <taglist> + <tag><c><![CDATA[Offset]]></c></tag> + <item> + <p>The same as <c><![CDATA[{bof, Offset}]]></c>.</p> + </item> + <tag><c><![CDATA[{bof, Offset}]]></c></tag> + <item> + <p>Absolute offset.</p> + </item> + <tag><c><![CDATA[{cur, Offset}]]></c></tag> + <item> + <p>Offset from the current position.</p> + </item> + <tag><c><![CDATA[{eof, Offset}]]></c></tag> + <item> + <p>Offset from the end of file.</p> + </item> + <tag><c><![CDATA[bof | cur | eof]]></c></tag> + <item> + <p>The same as above with <c><![CDATA[Offset]]></c> 0.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>read_file_info(ChannelPid, Name) -> </name> + <name>read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, Reason}</name> + <fsummary>Get information about a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Handle = term()</v> + <v>Timeout = timeout()</v> + <v>FileInfo = record()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Returns a <c><![CDATA[file_info]]></c> record from the file specified by + <c><![CDATA[Name]]></c> or <c><![CDATA[Handle]]></c>, like <c><![CDATA[file:read_file_info/2]]></c>.</p> + </desc> + </func> + <func> + <name>read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, Reason}</name> + <name>read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, Reason}</name> + <fsummary>Get information about a symbolic link</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Handle = term()</v> + <v>Timeout = timeout()</v> + <v>FileInfo = record()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Returns a <c><![CDATA[file_info]]></c> record from the symbolic + link specified by <c><![CDATA[Name]]></c> or <c><![CDATA[Handle]]></c>, like + <c><![CDATA[file:read_link_info/2]]></c>.</p> + </desc> + </func> + <func> + <name>write_file_info(ChannelPid, Name, Info) -> </name> + <name>write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, Reason}</name> + <fsummary>Write information for a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Info = record()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Writes file information from a <c><![CDATA[file_info]]></c> record to the + file specified by <c><![CDATA[Name]]></c>, like <c><![CDATA[file:write_file_info]]></c>.</p> + </desc> + </func> + <func> + <name>read_link(ChannelPid, Name) -> </name> + <name>read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, Reason}</name> + <fsummary>Read symbolic link</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Target = string()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Read the link target from the symbolic link specified + by <c><![CDATA[name]]></c>, like <c><![CDATA[file:read_link/1]]></c>.</p> + </desc> + </func> + <func> + <name>make_symlink(ChannelPid, Name, Target) -> </name> + <name>make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, Reason}</name> + <fsummary>Create symbolic link</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Target = string()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Creates a symbolic link pointing to <c><![CDATA[Target]]></c> with the + name <c><![CDATA[Name]]></c>, like <c><![CDATA[file:make_symlink/2]]></c>.</p> + </desc> + </func> + <func> + <name>rename(ChannelPid, OldName, NewName) -> </name> + <name>rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, Reason}</name> + <fsummary>Rename a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>OldName = string()</v> + <v>NewName = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Renames a file named <c><![CDATA[OldName]]></c>, and gives it the name + <c><![CDATA[NewName]]></c>, like <c><![CDATA[file:rename/2]]></c></p> + </desc> + </func> + <func> + <name>delete(ChannelPid, Name) -> </name> + <name>delete(ChannelPid, Name, Timeout) -> ok | {error, Reason}</name> + <fsummary>Delete a file</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Deletes the file specified by <c><![CDATA[Name]]></c>, like + <c><![CDATA[file:delete/1]]></c></p> + </desc> + </func> + <func> + <name>make_dir(ChannelPid, Name) -> </name> + <name>make_dir(ChannelPid, Name, Timeout) -> ok | {error, Reason}</name> + <fsummary>Create a directory</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Creates a directory specified by <c><![CDATA[Name]]></c>. <c><![CDATA[Name]]></c> should + be a full path to a new directory. The directory can only be + created in an existing directory.</p> + </desc> + </func> + <func> + <name>del_dir(ChannelPid, Name) -> </name> + <name>del_dir(ChannelPid, Name, Timeout) -> ok | {error, Reason}</name> + <fsummary>Delete an empty directory</fsummary> + <type> + <v>ChannelPid = pid()</v> + <v>Name = string()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Deletes a directory specified by <c><![CDATA[Name]]></c>. The directory + should be empty.</p> + </desc> + </func> + + </funcs> + +</erlref> + diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml new file mode 100644 index 0000000000..c857983565 --- /dev/null +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2005</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>ssh_sftpd</title> + <prepared>Ingela Anderton Andin</prepared> + <responsible></responsible> + <docno>1</docno> + <approved></approved> + <checked></checked> + <date>2005-09-22</date> + <rev>PA1</rev> + <file>ssh_sftpd.sgml</file> + </header> + <module>ssh_sftpd</module> + <modulesummary>Specifies a channel process to handle a sftp subsystem.</modulesummary> + <description> + <p>Specifies a channel process to handle a sftp subsystem.</p> + </description> + + <section> + <title>COMMON DATA TYPES </title> + <p><c>subsystem_spec() = {subsystem_name(), {channel_callback(), channel_init_args()}} </c></p> + <p><c>subsystem_name() = "sftp"</c></p> + <p><c>channel_callback() = atom()</c> - Name of the erlang module implementing the + subsystem using the ssh_channel behavior see + <seealso marker="ssh_channel">ssh_channel(3)</seealso></p> + <p><c> channel_init_args() = list() - The one given as argument to function + subsystem_spec/1.</c></p> + </section> + <funcs> + <func> + <name>subsystem_spec(Options) -> subsystem_spec()</name> + <fsummary>Returns the subsystem specification that allows an ssh daemon to handle the subsystem "sftp".</fsummary> + <type> + <v>Options = [{Option, Value}]</v> + </type> + <desc> + <p>Should be used together with ssh:daemon/[1,2,3]</p> + <p>Options are:</p> + <taglist> + <tag><c><![CDATA[{cwd, String}]]></c></tag> + <item> + <p>Sets the initial current working directory for the + server.</p> + </item> + <tag><c><![CDATA[{file_handler, CallbackModule}]]></c></tag> + <item> + <p>Determines which module to call for communicating with + the file server. Default value is <c>ssh_sftpd_file</c> that uses the + file and filelib API:s to access the standard OTP file + server. This option may be used to plug in the use of + other file servers.</p> + </item> + <tag><c><![CDATA[{max_files, Integer}]]></c></tag> + <item> + <p>The default value is <c>0</c>, which means that there is no upper limit. + If supplied, the number of filenames returned to the sftp client per <c>READDIR</c> + request, is limited to at most the given value.</p> + </item> + <tag><c><![CDATA[{root, String}]]></c></tag> + <item> + <p>Sets the sftp root directory. The user will then not be + able to see any files above this root. If for instance + the root is set to <c>/tmp</c> the user will see this + directory as <c>/</c> and if the user does cd <c>/etc</c> + the user will end up in <c>/tmp/etc</c>. + </p> + </item> + </taglist> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/ssh/doc/src/user_guide.gif b/lib/ssh/doc/src/user_guide.gif Binary files differnew file mode 100644 index 0000000000..e6275a803d --- /dev/null +++ b/lib/ssh/doc/src/user_guide.gif diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps new file mode 100644 index 0000000000..d766a933b4 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.2.ps @@ -0,0 +1,3315 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Fri Oct 31 13:31:26 2003 +%%Orientation: Portrait +%%Pages: 15 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Network Working Group T. Ylonen) s +5 690 M +(Internet-Draft SSH Communications Security Corp) s +5 679 M +(Expires: March 31, 2004 D. Moffat, Ed.) s +5 668 M +( Sun Microsystems, Inc) s +5 657 M +( Oct 2003) s +5 624 M +( SSH Protocol Architecture) s +5 613 M +( draft-ietf-secsh-architecture-15.txt) s +5 591 M +(Status of this Memo) s +5 569 M +( This document is an Internet-Draft and is in full conformance with) s +5 558 M +( all provisions of Section 10 of RFC2026.) s +5 536 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 525 M +( Task Force \(IETF\), its areas, and its working groups. Note that other) s +5 514 M +( groups may also distribute working documents as Internet-Drafts.) s +5 492 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 481 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 470 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 459 M +( material or to cite them other than as "work in progress.") s +5 437 M +( The list of current Internet-Drafts can be accessed at http://) s +5 426 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 404 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 393 M +( http://www.ietf.org/shadow.html.) s +5 371 M +( This Internet-Draft will expire on March 31, 2004.) s +5 349 M +(Copyright Notice) s +5 327 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 305 M +(Abstract) s +5 283 M +( SSH is a protocol for secure remote login and other secure network) s +5 272 M +( services over an insecure network. This document describes the) s +5 261 M +( architecture of the SSH protocol, as well as the notation and) s +5 250 M +( terminology used in SSH protocol documents. It also discusses the SSH) s +5 239 M +( algorithm naming system that allows local extensions. The SSH) s +5 228 M +( protocol consists of three major components: The Transport Layer) s +5 217 M +( Protocol provides server authentication, confidentiality, and) s +5 206 M +( integrity with perfect forward secrecy. The User Authentication) s +5 195 M +( Protocol authenticates the client to the server. The Connection) s +5 184 M +( Protocol multiplexes the encrypted tunnel into several logical) s +5 173 M +( channels. Details of these protocols are described in separate) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( documents.) s +5 668 M +(Table of Contents) s +5 646 M +( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 635 M +( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 624 M +( 3. Specification of Requirements . . . . . . . . . . . . . . . 3) s +5 613 M +( 4. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 602 M +( 4.1 Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 4) s +5 591 M +( 4.2 Extensibility . . . . . . . . . . . . . . . . . . . . . . . 5) s +5 580 M +( 4.3 Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 5) s +5 569 M +( 4.4 Security Properties . . . . . . . . . . . . . . . . . . . . 6) s +5 558 M +( 4.5 Packet Size and Overhead . . . . . . . . . . . . . . . . . . 6) s +5 547 M +( 4.6 Localization and Character Set Support . . . . . . . . . . . 7) s +5 536 M +( 5. Data Type Representations Used in the SSH Protocols . . . . 8) s +5 525 M +( 6. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . 10) s +5 514 M +( 7. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 11) s +5 503 M +( 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . 11) s +5 492 M +( 9. Security Considerations . . . . . . . . . . . . . . . . . . 12) s +5 481 M +( 9.1 Pseudo-Random Number Generation . . . . . . . . . . . . . . 12) s +5 470 M +( 9.2 Transport . . . . . . . . . . . . . . . . . . . . . . . . . 13) s +5 459 M +( 9.2.1 Confidentiality . . . . . . . . . . . . . . . . . . . . . . 13) s +5 448 M +( 9.2.2 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 16) s +5 437 M +( 9.2.3 Replay . . . . . . . . . . . . . . . . . . . . . . . . . . . 16) s +5 426 M +( 9.2.4 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . 17) s +5 415 M +( 9.2.5 Denial-of-service . . . . . . . . . . . . . . . . . . . . . 19) s +5 404 M +( 9.2.6 Covert Channels . . . . . . . . . . . . . . . . . . . . . . 19) s +5 393 M +( 9.2.7 Forward Secrecy . . . . . . . . . . . . . . . . . . . . . . 20) s +5 382 M +( 9.3 Authentication Protocol . . . . . . . . . . . . . . . . . . 20) s +5 371 M +( 9.3.1 Weak Transport . . . . . . . . . . . . . . . . . . . . . . . 21) s +5 360 M +( 9.3.2 Debug messages . . . . . . . . . . . . . . . . . . . . . . . 21) s +5 349 M +( 9.3.3 Local security policy . . . . . . . . . . . . . . . . . . . 21) s +5 338 M +( 9.3.4 Public key authentication . . . . . . . . . . . . . . . . . 22) s +5 327 M +( 9.3.5 Password authentication . . . . . . . . . . . . . . . . . . 22) s +5 316 M +( 9.3.6 Host based authentication . . . . . . . . . . . . . . . . . 23) s +5 305 M +( 9.4 Connection protocol . . . . . . . . . . . . . . . . . . . . 23) s +5 294 M +( 9.4.1 End point security . . . . . . . . . . . . . . . . . . . . . 23) s +5 283 M +( 9.4.2 Proxy forwarding . . . . . . . . . . . . . . . . . . . . . . 23) s +5 272 M +( 9.4.3 X11 forwarding . . . . . . . . . . . . . . . . . . . . . . . 24) s +5 261 M +( Normative References . . . . . . . . . . . . . . . . . . . . 24) s +5 250 M +( Informative References . . . . . . . . . . . . . . . . . . . 25) s +5 239 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 27) s +5 228 M +( Intellectual Property and Copyright Statements . . . . . . . 28) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +(1. Contributors) s +5 668 M +( The major original contributors of this document were: Tatu Ylonen,) s +5 657 M +( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s +5 646 M +( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s +5 635 M +( Jyvaskyla\)) s +5 613 M +( The document editor is: [email protected]. Comments on this) s +5 602 M +( internet draft should be sent to the IETF SECSH working group,) s +5 591 M +( details at: http://ietf.org/html.charters/secsh-charter.html) s +5 569 M +(2. Introduction) s +5 547 M +( SSH is a protocol for secure remote login and other secure network) s +5 536 M +( services over an insecure network. It consists of three major) s +5 525 M +( components:) s +5 514 M +( o The Transport Layer Protocol [SSH-TRANS] provides server) s +5 503 M +( authentication, confidentiality, and integrity. It may optionally) s +5 492 M +( also provide compression. The transport layer will typically be) s +5 481 M +( run over a TCP/IP connection, but might also be used on top of any) s +5 470 M +( other reliable data stream.) s +5 459 M +( o The User Authentication Protocol [SSH-USERAUTH] authenticates the) s +5 448 M +( client-side user to the server. It runs over the transport layer) s +5 437 M +( protocol.) s +5 426 M +( o The Connection Protocol [SSH-CONNECT] multiplexes the encrypted) s +5 415 M +( tunnel into several logical channels. It runs over the user) s +5 404 M +( authentication protocol.) s +5 382 M +( The client sends a service request once a secure transport layer) s +5 371 M +( connection has been established. A second service request is sent) s +5 360 M +( after user authentication is complete. This allows new protocols to) s +5 349 M +( be defined and coexist with the protocols listed above.) s +5 327 M +( The connection protocol provides channels that can be used for a wide) s +5 316 M +( range of purposes. Standard methods are provided for setting up) s +5 305 M +( secure interactive shell sessions and for forwarding \("tunneling"\)) s +5 294 M +( arbitrary TCP/IP ports and X11 connections.) s +5 272 M +(3. Specification of Requirements) s +5 250 M +( All documents related to the SSH protocols shall use the keywords) s +5 239 M +( "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",) s +5 228 M +( "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" to describe) s +5 217 M +( requirements. They are to be interpreted as described in [RFC2119].) s +5 195 M +(4. Architecture) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +(4.1 Host Keys) s +5 668 M +( Each server host SHOULD have a host key. Hosts MAY have multiple) s +5 657 M +( host keys using multiple different algorithms. Multiple hosts MAY) s +5 646 M +( share the same host key. If a host has keys at all, it MUST have at) s +5 635 M +( least one key using each REQUIRED public key algorithm \(DSS) s +5 624 M +( [FIPS-186]\).) s +5 602 M +( The server host key is used during key exchange to verify that the) s +5 591 M +( client is really talking to the correct server. For this to be) s +5 580 M +( possible, the client must have a priori knowledge of the server's) s +5 569 M +( public host key.) s +5 547 M +( Two different trust models can be used:) s +5 536 M +( o The client has a local database that associates each host name \(as) s +5 525 M +( typed by the user\) with the corresponding public host key. This) s +5 514 M +( method requires no centrally administered infrastructure, and no) s +5 503 M +( third-party coordination. The downside is that the database of) s +5 492 M +( name-to-key associations may become burdensome to maintain.) s +5 481 M +( o The host name-to-key association is certified by some trusted) s +5 470 M +( certification authority. The client only knows the CA root key,) s +5 459 M +( and can verify the validity of all host keys certified by accepted) s +5 448 M +( CAs.) s +5 426 M +( The second alternative eases the maintenance problem, since) s +5 415 M +( ideally only a single CA key needs to be securely stored on the) s +5 404 M +( client. On the other hand, each host key must be appropriately) s +5 393 M +( certified by a central authority before authorization is possible.) s +5 382 M +( Also, a lot of trust is placed on the central infrastructure.) s +5 360 M +( The protocol provides the option that the server name - host key) s +5 349 M +( association is not checked when connecting to the host for the first) s +5 338 M +( time. This allows communication without prior communication of host) s +5 327 M +( keys or certification. The connection still provides protection) s +5 316 M +( against passive listening; however, it becomes vulnerable to active) s +5 305 M +( man-in-the-middle attacks. Implementations SHOULD NOT normally allow) s +5 294 M +( such connections by default, as they pose a potential security) s +5 283 M +( problem. However, as there is no widely deployed key infrastructure) s +5 272 M +( available on the Internet yet, this option makes the protocol much) s +5 261 M +( more usable during the transition time until such an infrastructure) s +5 250 M +( emerges, while still providing a much higher level of security than) s +5 239 M +( that offered by older solutions \(e.g. telnet [RFC-854] and rlogin) s +5 228 M +( [RFC-1282]\).) s +5 206 M +( Implementations SHOULD try to make the best effort to check host) s +5 195 M +( keys. An example of a possible strategy is to only accept a host key) s +5 184 M +( without checking the first time a host is connected, save the key in) s +5 173 M +( a local database, and compare against that key on all future) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( connections to that host.) s +5 668 M +( Implementations MAY provide additional methods for verifying the) s +5 657 M +( correctness of host keys, e.g. a hexadecimal fingerprint derived from) s +5 646 M +( the SHA-1 hash of the public key. Such fingerprints can easily be) s +5 635 M +( verified by using telephone or other external communication channels.) s +5 613 M +( All implementations SHOULD provide an option to not accept host keys) s +5 602 M +( that cannot be verified.) s +5 580 M +( We believe that ease of use is critical to end-user acceptance of) s +5 569 M +( security solutions, and no improvement in security is gained if the) s +5 558 M +( new solutions are not used. Thus, providing the option not to check) s +5 547 M +( the server host key is believed to improve the overall security of) s +5 536 M +( the Internet, even though it reduces the security of the protocol in) s +5 525 M +( configurations where it is allowed.) s +5 503 M +(4.2 Extensibility) s +5 481 M +( We believe that the protocol will evolve over time, and some) s +5 470 M +( organizations will want to use their own encryption, authentication) s +5 459 M +( and/or key exchange methods. Central registration of all extensions) s +5 448 M +( is cumbersome, especially for experimental or classified features.) s +5 437 M +( On the other hand, having no central registration leads to conflicts) s +5 426 M +( in method identifiers, making interoperability difficult.) s +5 404 M +( We have chosen to identify algorithms, methods, formats, and) s +5 393 M +( extension protocols with textual names that are of a specific format.) s +5 382 M +( DNS names are used to create local namespaces where experimental or) s +5 371 M +( classified extensions can be defined without fear of conflicts with) s +5 360 M +( other implementations.) s +5 338 M +( One design goal has been to keep the base protocol as simple as) s +5 327 M +( possible, and to require as few algorithms as possible. However, all) s +5 316 M +( implementations MUST support a minimal set of algorithms to ensure) s +5 305 M +( interoperability \(this does not imply that the local policy on all) s +5 294 M +( hosts would necessary allow these algorithms\). The mandatory) s +5 283 M +( algorithms are specified in the relevant protocol documents.) s +5 261 M +( Additional algorithms, methods, formats, and extension protocols can) s +5 250 M +( be defined in separate drafts. See Section Algorithm Naming \(Section) s +5 239 M +( 6\) for more information.) s +5 217 M +(4.3 Policy Issues) s +5 195 M +( The protocol allows full negotiation of encryption, integrity, key) s +5 184 M +( exchange, compression, and public key algorithms and formats.) s +5 173 M +( Encryption, integrity, public key, and compression algorithms can be) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( different for each direction.) s +5 668 M +( The following policy issues SHOULD be addressed in the configuration) s +5 657 M +( mechanisms of each implementation:) s +5 646 M +( o Encryption, integrity, and compression algorithms, separately for) s +5 635 M +( each direction. The policy MUST specify which is the preferred) s +5 624 M +( algorithm \(e.g. the first algorithm listed in each category\).) s +5 613 M +( o Public key algorithms and key exchange method to be used for host) s +5 602 M +( authentication. The existence of trusted host keys for different) s +5 591 M +( public key algorithms also affects this choice.) s +5 580 M +( o The authentication methods that are to be required by the server) s +5 569 M +( for each user. The server's policy MAY require multiple) s +5 558 M +( authentication for some or all users. The required algorithms MAY) s +5 547 M +( depend on the location where the user is trying to log in from.) s +5 536 M +( o The operations that the user is allowed to perform using the) s +5 525 M +( connection protocol. Some issues are related to security; for) s +5 514 M +( example, the policy SHOULD NOT allow the server to start sessions) s +5 503 M +( or run commands on the client machine, and MUST NOT allow) s +5 492 M +( connections to the authentication agent unless forwarding such) s +5 481 M +( connections has been requested. Other issues, such as which TCP/) s +5 470 M +( IP ports can be forwarded and by whom, are clearly issues of local) s +5 459 M +( policy. Many of these issues may involve traversing or bypassing) s +5 448 M +( firewalls, and are interrelated with the local security policy.) s +5 426 M +(4.4 Security Properties) s +5 404 M +( The primary goal of the SSH protocol is improved security on the) s +5 393 M +( Internet. It attempts to do this in a way that is easy to deploy,) s +5 382 M +( even at the cost of absolute security.) s +5 371 M +( o All encryption, integrity, and public key algorithms used are) s +5 360 M +( well-known, well-established algorithms.) s +5 349 M +( o All algorithms are used with cryptographically sound key sizes) s +5 338 M +( that are believed to provide protection against even the strongest) s +5 327 M +( cryptanalytic attacks for decades.) s +5 316 M +( o All algorithms are negotiated, and in case some algorithm is) s +5 305 M +( broken, it is easy to switch to some other algorithm without) s +5 294 M +( modifying the base protocol.) s +5 272 M +( Specific concessions were made to make wide-spread fast deployment) s +5 261 M +( easier. The particular case where this comes up is verifying that) s +5 250 M +( the server host key really belongs to the desired host; the protocol) s +5 239 M +( allows the verification to be left out \(but this is NOT RECOMMENDED\).) s +5 228 M +( This is believed to significantly improve usability in the short) s +5 217 M +( term, until widespread Internet public key infrastructures emerge.) s +5 195 M +(4.5 Packet Size and Overhead) s +5 173 M +( Some readers will worry about the increase in packet size due to new) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( headers, padding, and MAC. The minimum packet size is in the order) s +5 679 M +( of 28 bytes \(depending on negotiated algorithms\). The increase is) s +5 668 M +( negligible for large packets, but very significant for one-byte) s +5 657 M +( packets \(telnet-type sessions\). There are, however, several factors) s +5 646 M +( that make this a non-issue in almost all cases:) s +5 635 M +( o The minimum size of a TCP/IP header is 32 bytes. Thus, the) s +5 624 M +( increase is actually from 33 to 51 bytes \(roughly\).) s +5 613 M +( o The minimum size of the data field of an Ethernet packet is 46) s +5 602 M +( bytes [RFC-894]. Thus, the increase is no more than 5 bytes. When) s +5 591 M +( Ethernet headers are considered, the increase is less than 10) s +5 580 M +( percent.) s +5 569 M +( o The total fraction of telnet-type data in the Internet is) s +5 558 M +( negligible, even with increased packet sizes.) s +5 536 M +( The only environment where the packet size increase is likely to have) s +5 525 M +( a significant effect is PPP [RFC-1134] over slow modem lines \(PPP) s +5 514 M +( compresses the TCP/IP headers, emphasizing the increase in packet) s +5 503 M +( size\). However, with modern modems, the time needed to transfer is in) s +5 492 M +( the order of 2 milliseconds, which is a lot faster than people can) s +5 481 M +( type.) s +5 459 M +( There are also issues related to the maximum packet size. To) s +5 448 M +( minimize delays in screen updates, one does not want excessively) s +5 437 M +( large packets for interactive sessions. The maximum packet size is) s +5 426 M +( negotiated separately for each channel.) s +5 404 M +(4.6 Localization and Character Set Support) s +5 382 M +( For the most part, the SSH protocols do not directly pass text that) s +5 371 M +( would be displayed to the user. However, there are some places where) s +5 360 M +( such data might be passed. When applicable, the character set for the) s +5 349 M +( data MUST be explicitly specified. In most places, ISO 10646 with) s +5 338 M +( UTF-8 encoding is used [RFC-2279]. When applicable, a field is also) s +5 327 M +( provided for a language tag [RFC-3066].) s +5 305 M +( One big issue is the character set of the interactive session. There) s +5 294 M +( is no clear solution, as different applications may display data in) s +5 283 M +( different formats. Different types of terminal emulation may also be) s +5 272 M +( employed in the client, and the character set to be used is) s +5 261 M +( effectively determined by the terminal emulation. Thus, no place is) s +5 250 M +( provided for directly specifying the character set or encoding for) s +5 239 M +( terminal session data. However, the terminal emulation type \(e.g.) s +5 228 M +( "vt100"\) is transmitted to the remote site, and it implicitly) s +5 217 M +( specifies the character set and encoding. Applications typically use) s +5 206 M +( the terminal type to determine what character set they use, or the) s +5 195 M +( character set is determined using some external means. The terminal) s +5 184 M +( emulation may also allow configuring the default character set. In) s +5 173 M +( any case, the character set for the terminal session is considered) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( primarily a client local issue.) s +5 668 M +( Internal names used to identify algorithms or protocols are normally) s +5 657 M +( never displayed to users, and must be in US-ASCII.) s +5 635 M +( The client and server user names are inherently constrained by what) s +5 624 M +( the server is prepared to accept. They might, however, occasionally) s +5 613 M +( be displayed in logs, reports, etc. They MUST be encoded using ISO) s +5 602 M +( 10646 UTF-8, but other encodings may be required in some cases. It) s +5 591 M +( is up to the server to decide how to map user names to accepted user) s +5 580 M +( names. Straight bit-wise binary comparison is RECOMMENDED.) s +5 558 M +( For localization purposes, the protocol attempts to minimize the) s +5 547 M +( number of textual messages transmitted. When present, such messages) s +5 536 M +( typically relate to errors, debugging information, or some externally) s +5 525 M +( configured data. For data that is normally displayed, it SHOULD be) s +5 514 M +( possible to fetch a localized message instead of the transmitted) s +5 503 M +( message by using a numerical code. The remaining messages SHOULD be) s +5 492 M +( configurable.) s +5 470 M +(5. Data Type Representations Used in the SSH Protocols) s +5 459 M +( byte) s +5 437 M +( A byte represents an arbitrary 8-bit value \(octet\) [RFC-1700].) s +5 426 M +( Fixed length data is sometimes represented as an array of bytes,) s +5 415 M +( written byte[n], where n is the number of bytes in the array.) s +5 393 M +( boolean) s +5 371 M +( A boolean value is stored as a single byte. The value 0) s +5 360 M +( represents FALSE, and the value 1 represents TRUE. All non-zero) s +5 349 M +( values MUST be interpreted as TRUE; however, applications MUST NOT) s +5 338 M +( store values other than 0 and 1.) s +5 316 M +( uint32) s +5 294 M +( Represents a 32-bit unsigned integer. Stored as four bytes in the) s +5 283 M +( order of decreasing significance \(network byte order\). For) s +5 272 M +( example, the value 699921578 \(0x29b7f4aa\) is stored as 29 b7 f4) s +5 261 M +( aa.) s +5 239 M +( uint64) s +5 217 M +( Represents a 64-bit unsigned integer. Stored as eight bytes in) s +5 206 M +( the order of decreasing significance \(network byte order\).) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( string) s +5 668 M +( Arbitrary length binary string. Strings are allowed to contain) s +5 657 M +( arbitrary binary data, including null characters and 8-bit) s +5 646 M +( characters. They are stored as a uint32 containing its length) s +5 635 M +( \(number of bytes that follow\) and zero \(= empty string\) or more) s +5 624 M +( bytes that are the value of the string. Terminating null) s +5 613 M +( characters are not used.) s +5 591 M +( Strings are also used to store text. In that case, US-ASCII is) s +5 580 M +( used for internal names, and ISO-10646 UTF-8 for text that might) s +5 569 M +( be displayed to the user. The terminating null character SHOULD) s +5 558 M +( NOT normally be stored in the string.) s +5 536 M +( For example, the US-ASCII string "testing" is represented as 00 00) s +5 525 M +( 00 07 t e s t i n g. The UTF8 mapping does not alter the encoding) s +5 514 M +( of US-ASCII characters.) s +5 492 M +( mpint) s +5 470 M +( Represents multiple precision integers in two's complement format,) s +5 459 M +( stored as a string, 8 bits per byte, MSB first. Negative numbers) s +5 448 M +( have the value 1 as the most significant bit of the first byte of) s +5 437 M +( the data partition. If the most significant bit would be set for a) s +5 426 M +( positive number, the number MUST be preceded by a zero byte.) s +5 415 M +( Unnecessary leading bytes with the value 0 or 255 MUST NOT be) s +5 404 M +( included. The value zero MUST be stored as a string with zero) s +5 393 M +( bytes of data.) s +5 371 M +( By convention, a number that is used in modular computations in) s +5 360 M +( Z_n SHOULD be represented in the range 0 <= x < n.) s +5 338 M +( Examples:) s +5 327 M +( value \(hex\) representation \(hex\)) s +5 316 M +( ---------------------------------------------------------------) s +5 305 M +( 0 00 00 00 00) s +5 294 M +( 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7) s +5 283 M +( 80 00 00 00 02 00 80) s +5 272 M +( -1234 00 00 00 02 ed cc) s +5 261 M +( -deadbeef 00 00 00 05 ff 21 52 41 11) s +5 217 M +( name-list) s +5 195 M +( A string containing a comma separated list of names. A name list) s +5 184 M +( is represented as a uint32 containing its length \(number of bytes) s +5 173 M +( that follow\) followed by a comma-separated list of zero or more) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( names. A name MUST be non-zero length, and it MUST NOT contain a) s +5 679 M +( comma \(','\). Context may impose additional restrictions on the) s +5 668 M +( names; for example, the names in a list may have to be valid) s +5 657 M +( algorithm identifier \(see Algorithm Naming below\), or [RFC-3066]) s +5 646 M +( language tags. The order of the names in a list may or may not be) s +5 635 M +( significant, also depending on the context where the list is is) s +5 624 M +( used. Terminating NUL characters are not used, neither for the) s +5 613 M +( individual names, nor for the list as a whole.) s +5 591 M +( Examples:) s +5 580 M +( value representation \(hex\)) s +5 569 M +( ---------------------------------------) s +5 558 M +( \(\), the empty list 00 00 00 00) s +5 547 M +( \("zlib"\) 00 00 00 04 7a 6c 69 62) s +5 536 M +( \("zlib", "none"\) 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65) s +5 481 M +(6. Algorithm Naming) s +5 459 M +( The SSH protocols refer to particular hash, encryption, integrity,) s +5 448 M +( compression, and key exchange algorithms or protocols by names.) s +5 437 M +( There are some standard algorithms that all implementations MUST) s +5 426 M +( support. There are also algorithms that are defined in the protocol) s +5 415 M +( specification but are OPTIONAL. Furthermore, it is expected that) s +5 404 M +( some organizations will want to use their own algorithms.) s +5 382 M +( In this protocol, all algorithm identifiers MUST be printable) s +5 371 M +( US-ASCII non-empty strings no longer than 64 characters. Names MUST) s +5 360 M +( be case-sensitive.) s +5 338 M +( There are two formats for algorithm names:) s +5 327 M +( o Names that do not contain an at-sign \(@\) are reserved to be) s +5 316 M +( assigned by IETF consensus \(RFCs\). Examples include `3des-cbc',) s +5 305 M +( `sha-1', `hmac-sha1', and `zlib' \(the quotes are not part of the) s +5 294 M +( name\). Names of this format MUST NOT be used without first) s +5 283 M +( registering them. Registered names MUST NOT contain an at-sign) s +5 272 M +( \(@\) or a comma \(,\).) s +5 261 M +( o Anyone can define additional algorithms by using names in the) s +5 250 M +( format name@domainname, e.g. "[email protected]". The) s +5 239 M +( format of the part preceding the at sign is not specified; it MUST) s +5 228 M +( consist of US-ASCII characters except at-sign and comma. The part) s +5 217 M +( following the at-sign MUST be a valid fully qualified internet) s +5 206 M +( domain name [RFC-1034] controlled by the person or organization) s +5 195 M +( defining the name. It is up to each domain how it manages its) s +5 184 M +( local namespace.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +(7. Message Numbers) s +5 668 M +( SSH packets have message numbers in the range 1 to 255. These numbers) s +5 657 M +( have been allocated as follows:) s +5 624 M +( Transport layer protocol:) s +5 602 M +( 1 to 19 Transport layer generic \(e.g. disconnect, ignore, debug,) s +5 591 M +( etc.\)) s +5 580 M +( 20 to 29 Algorithm negotiation) s +5 569 M +( 30 to 49 Key exchange method specific \(numbers can be reused for) s +5 558 M +( different authentication methods\)) s +5 536 M +( User authentication protocol:) s +5 514 M +( 50 to 59 User authentication generic) s +5 503 M +( 60 to 79 User authentication method specific \(numbers can be) s +5 492 M +( reused for different authentication methods\)) s +5 470 M +( Connection protocol:) s +5 448 M +( 80 to 89 Connection protocol generic) s +5 437 M +( 90 to 127 Channel related messages) s +5 415 M +( Reserved for client protocols:) s +5 393 M +( 128 to 191 Reserved) s +5 371 M +( Local extensions:) s +5 349 M +( 192 to 255 Local extensions) s +5 305 M +(8. IANA Considerations) s +5 283 M +( The initial state of the IANA registry is detailed in [SSH-NUMBERS].) s +5 261 M +( Allocation of the following types of names in the SSH protocols is) s +5 250 M +( assigned by IETF consensus:) s +5 239 M +( o SSH encryption algorithm names,) s +5 228 M +( o SSH MAC algorithm names,) s +5 217 M +( o SSH public key algorithm names \(public key algorithm also implies) s +5 206 M +( encoding and signature/encryption capability\),) s +5 195 M +( o SSH key exchange method names, and) s +5 184 M +( o SSH protocol \(service\) names.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( These names MUST be printable US-ASCII strings, and MUST NOT contain) s +5 679 M +( the characters at-sign \('@'\), comma \(','\), or whitespace or control) s +5 668 M +( characters \(ASCII codes 32 or less\). Names are case-sensitive, and) s +5 657 M +( MUST NOT be longer than 64 characters.) s +5 635 M +( Names with the at-sign \('@'\) in them are allocated by the owner of) s +5 624 M +( DNS name after the at-sign \(hierarchical allocation in [RFC-2343]\),) s +5 613 M +( otherwise the same restrictions as above.) s +5 591 M +( Each category of names listed above has a separate namespace.) s +5 580 M +( However, using the same name in multiple categories SHOULD be avoided) s +5 569 M +( to minimize confusion.) s +5 547 M +( Message numbers \(see Section Message Numbers \(Section 7\)\) in the) s +5 536 M +( range of 0..191 are allocated via IETF consensus; message numbers in) s +5 525 M +( the 192..255 range \(the "Local extensions" set\) are reserved for) s +5 514 M +( private use.) s +5 492 M +(9. Security Considerations) s +5 470 M +( In order to make the entire body of Security Considerations more) s +5 459 M +( accessible, Security Considerations for the transport,) s +5 448 M +( authentication, and connection documents have been gathered here.) s +5 426 M +( The transport protocol [1] provides a confidential channel over an) s +5 415 M +( insecure network. It performs server host authentication, key) s +5 404 M +( exchange, encryption, and integrity protection. It also derives a) s +5 393 M +( unique session id that may be used by higher-level protocols.) s +5 371 M +( The authentication protocol [2] provides a suite of mechanisms which) s +5 360 M +( can be used to authenticate the client user to the server.) s +5 349 M +( Individual mechanisms specified in the in authentication protocol use) s +5 338 M +( the session id provided by the transport protocol and/or depend on) s +5 327 M +( the security and integrity guarantees of the transport protocol.) s +5 305 M +( The connection protocol [3] specifies a mechanism to multiplex) s +5 294 M +( multiple streams [channels] of data over the confidential and) s +5 283 M +( authenticated transport. It also specifies channels for accessing an) s +5 272 M +( interactive shell, for 'proxy-forwarding' various external protocols) s +5 261 M +( over the secure transport \(including arbitrary TCP/IP protocols\), and) s +5 250 M +( for accessing secure 'subsystems' on the server host.) s +5 228 M +(9.1 Pseudo-Random Number Generation) s +5 206 M +( This protocol binds each session key to the session by including) s +5 195 M +( random, session specific data in the hash used to produce session) s +5 184 M +( keys. Special care should be taken to ensure that all of the random) s +5 173 M +( numbers are of good quality. If the random data here \(e.g., DH) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( parameters\) are pseudo-random then the pseudo-random number generator) s +5 679 M +( should be cryptographically secure \(i.e., its next output not easily) s +5 668 M +( guessed even when knowing all previous outputs\) and, furthermore,) s +5 657 M +( proper entropy needs to be added to the pseudo-random number) s +5 646 M +( generator. RFC 1750 [1750] offers suggestions for sources of random) s +5 635 M +( numbers and entropy. Implementors should note the importance of) s +5 624 M +( entropy and the well-meant, anecdotal warning about the difficulty in) s +5 613 M +( properly implementing pseudo-random number generating functions.) s +5 591 M +( The amount of entropy available to a given client or server may) s +5 580 M +( sometimes be less than what is required. In this case one must) s +5 569 M +( either resort to pseudo-random number generation regardless of) s +5 558 M +( insufficient entropy or refuse to run the protocol. The latter is) s +5 547 M +( preferable.) s +5 525 M +(9.2 Transport) s +5 503 M +(9.2.1 Confidentiality) s +5 481 M +( It is beyond the scope of this document and the Secure Shell Working) s +5 470 M +( Group to analyze or recommend specific ciphers other than the ones) s +5 459 M +( which have been established and accepted within the industry. At the) s +5 448 M +( time of this writing, ciphers commonly in use include 3DES, ARCFOUR,) s +5 437 M +( twofish, serpent and blowfish. AES has been accepted by The) s +5 426 M +( published as a US Federal Information Processing Standards [FIPS-197]) s +5 415 M +( and the cryptographic community as being acceptable for this purpose) s +5 404 M +( as well has accepted AES. As always, implementors and users should) s +5 393 M +( check current literature to ensure that no recent vulnerabilities) s +5 382 M +( have been found in ciphers used within products. Implementors should) s +5 371 M +( also check to see which ciphers are considered to be relatively) s +5 360 M +( stronger than others and should recommend their use to users over) s +5 349 M +( relatively weaker ciphers. It would be considered good form for an) s +5 338 M +( implementation to politely and unobtrusively notify a user that a) s +5 327 M +( stronger cipher is available and should be used when a weaker one is) s +5 316 M +( actively chosen.) s +5 294 M +( The "none" cipher is provided for debugging and SHOULD NOT be used) s +5 283 M +( except for that purpose. It's cryptographic properties are) s +5 272 M +( sufficiently described in RFC 2410, which will show that its use does) s +5 261 M +( not meet the intent of this protocol.) s +5 239 M +( The relative merits of these and other ciphers may also be found in) s +5 228 M +( current literature. Two references that may provide information on) s +5 217 M +( the subject are [SCHNEIER] and [KAUFMAN,PERLMAN,SPECINER]. Both of) s +5 206 M +( these describe the CBC mode of operation of certain ciphers and the) s +5 195 M +( weakness of this scheme. Essentially, this mode is theoretically) s +5 184 M +( vulnerable to chosen cipher-text attacks because of the high) s +5 173 M +( predictability of the start of packet sequence. However, this attack) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( is still deemed difficult and not considered fully practicable) s +5 679 M +( especially if relatively longer block sizes are used.) s +5 657 M +( Additionally, another CBC mode attack may be mitigated through the) s +5 646 M +( insertion of packets containing SSH_MSG_IGNORE. Without this) s +5 635 M +( technique, a specific attack may be successful. For this attack) s +5 624 M +( \(commonly known as the Rogaway attack) s +5 613 M +( [ROGAWAY],[DAI],[BELLARE,KOHNO,NAMPREMPRE]\) to work, the attacker) s +5 602 M +( would need to know the IV of the next block that is going to be) s +5 591 M +( encrypted. In CBC mode that is the output of the encryption of the) s +5 580 M +( previous block. If the attacker does not have any way to see the) s +5 569 M +( packet yet \(i.e it is in the internal buffers of the ssh) s +5 558 M +( implementation or even in the kernel\) then this attack will not work.) s +5 547 M +( If the last packet has been sent out to the network \(i.e the attacker) s +5 536 M +( has access to it\) then he can use the attack.) s +5 514 M +( In the optimal case an implementor would need to add an extra packet) s +5 503 M +( only if the packet has been sent out onto the network and there are) s +5 492 M +( no other packets waiting for transmission. Implementors may wish to) s +5 481 M +( check to see if there are any unsent packets awaiting transmission,) s +5 470 M +( but unfortunately it is not normally easy to obtain this information) s +5 459 M +( from the kernel or buffers. If there are not, then a packet) s +5 448 M +( containing SSH_MSG_IGNORE SHOULD be sent. If a new packet is added) s +5 437 M +( to the stream every time the attacker knows the IV that is supposed) s +5 426 M +( to be used for the next packet, then the attacker will not be able to) s +5 415 M +( guess the correct IV, thus the attack will never be successfull.) s +5 393 M +( As an example, consider the following case:) s +5 360 M +( Client Server) s +5 349 M +( ------ ------) s +5 338 M +( TCP\(seq=x, len=500\) ->) s +5 327 M +( contains Record 1) s +5 305 M +( [500 ms passes, no ACK]) s +5 283 M +( TCP\(seq=x, len=1000\) ->) s +5 272 M +( contains Records 1,2) s +5 250 M +( ACK) s +5 217 M +( 1. The Nagle algorithm + TCP retransmits mean that the two records) s +5 206 M +( get coalesced into a single TCP segment) s +5 195 M +( 2. Record 2 is *not* at the beginning of the TCP segment and never) s +5 184 M +( will be, since it gets ACKed.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( 3. Yet, the attack is possible because Record 1 has already been) s +5 679 M +( seen.) s +5 657 M +( As this example indicates, it's totally unsafe to use the existence) s +5 646 M +( of unflushed data in the TCP buffers proper as a guide to whether you) s +5 635 M +( need an empty packet, since when you do the second write\(\), the) s +5 624 M +( buffers will contain the un-ACKed Record 1.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( On the other hand, it's perfectly safe to have the following) s +5 679 M +( situation:) s +5 646 M +( Client Server) s +5 635 M +( ------ ------) s +5 624 M +( TCP\(seq=x, len=500\) ->) s +5 613 M +( contains SSH_MSG_IGNORE) s +5 591 M +( TCP\(seq=y, len=500\) ->) s +5 580 M +( contains Data) s +5 558 M +( Provided that the IV for second SSH Record is fixed after the data for) s +5 547 M +( the Data packet is determined -i.e. you do:) s +5 536 M +( read from user) s +5 525 M +( encrypt null packet) s +5 514 M +( encrypt data packet) s +5 481 M +(9.2.2 Data Integrity) s +5 459 M +( This protocol does allow the Data Integrity mechanism to be disabled.) s +5 448 M +( Implementors SHOULD be wary of exposing this feature for any purpose) s +5 437 M +( other than debugging. Users and administrators SHOULD be explicitly) s +5 426 M +( warned anytime the "none" MAC is enabled.) s +5 404 M +( So long as the "none" MAC is not used, this protocol provides data) s +5 393 M +( integrity.) s +5 371 M +( Because MACs use a 32 bit sequence number, they might start to leak) s +5 360 M +( information after 2**32 packets have been sent. However, following) s +5 349 M +( the rekeying recommendations should prevent this attack. The) s +5 338 M +( transport protocol [1] recommends rekeying after one gigabyte of) s +5 327 M +( data, and the smallest possible packet is 16 bytes. Therefore,) s +5 316 M +( rekeying SHOULD happen after 2**28 packets at the very most.) s +5 294 M +(9.2.3 Replay) s +5 272 M +( The use of a MAC other than 'none' provides integrity and) s +5 261 M +( authentication. In addition, the transport protocol provides a) s +5 250 M +( unique session identifier \(bound in part to pseudo-random data that) s +5 239 M +( is part of the algorithm and key exchange process\) that can be used) s +5 228 M +( by higher level protocols to bind data to a given session and prevent) s +5 217 M +( replay of data from prior sessions. For example, the authentication) s +5 206 M +( protocol uses this to prevent replay of signatures from previous) s +5 195 M +( sessions. Because public key authentication exchanges are) s +5 184 M +( cryptographically bound to the session \(i.e., to the initial key) s +5 173 M +( exchange\) they cannot be successfully replayed in other sessions.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 16]) s +_R +S +PStoPSsaved restore +%%Page: (16,17) 9 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 17 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( Note that the session ID can be made public without harming the) s +5 679 M +( security of the protocol.) s +5 657 M +( If two session happen to have the same session ID [hash of key) s +5 646 M +( exchanges] then packets from one can be replayed against the other.) s +5 635 M +( It must be stressed that the chances of such an occurrence are,) s +5 624 M +( needless to say, minimal when using modern cryptographic methods.) s +5 613 M +( This is all the more so true when specifying larger hash function) s +5 602 M +( outputs and DH parameters.) s +5 580 M +( Replay detection using monotonically increasing sequence numbers as) s +5 569 M +( input to the MAC, or HMAC in some cases, is described in [RFC2085] />) s +5 558 M +( [RFC2246], [RFC2743], [RFC1964], [RFC2025], and [RFC1510]. The) s +5 547 M +( underlying construct is discussed in [RFC2104]. Essentially a) s +5 536 M +( different sequence number in each packet ensures that at least this) s +5 525 M +( one input to the MAC function will be unique and will provide a) s +5 514 M +( nonrecurring MAC output that is not predictable to an attacker. If) s +5 503 M +( the session stays active long enough, however, this sequence number) s +5 492 M +( will wrap. This event may provide an attacker an opportunity to) s +5 481 M +( replay a previously recorded packet with an identical sequence number) s +5 470 M +( but only if the peers have not rekeyed since the transmission of the) s +5 459 M +( first packet with that sequence number. If the peers have rekeyed,) s +5 448 M +( then the replay will be detected as the MAC check will fail. For) s +5 437 M +( this reason, it must be emphasized that peers MUST rekey before a) s +5 426 M +( wrap of the sequence numbers. Naturally, if an attacker does attempt) s +5 415 M +( to replay a captured packet before the peers have rekeyed, then the) s +5 404 M +( receiver of the duplicate packet will not be able to validate the MAC) s +5 393 M +( and it will be discarded. The reason that the MAC will fail is) s +5 382 M +( because the receiver will formulate a MAC based upon the packet) s +5 371 M +( contents, the shared secret, and the expected sequence number. Since) s +5 360 M +( the replayed packet will not be using that expected sequence number) s +5 349 M +( \(the sequence number of the replayed packet will have already been) s +5 338 M +( passed by the receiver\) then the calculated MAC will not match the) s +5 327 M +( MAC received with the packet.) s +5 305 M +(9.2.4 Man-in-the-middle) s +5 283 M +( This protocol makes no assumptions nor provisions for an) s +5 272 M +( infrastructure or means for distributing the public keys of hosts. It) s +5 261 M +( is expected that this protocol will sometimes be used without first) s +5 250 M +( verifying the association between the server host key and the server) s +5 239 M +( host name. Such usage is vulnerable to man-in-the-middle attacks.) s +5 228 M +( This section describes this and encourages administrators and users) s +5 217 M +( to understand the importance of verifying this association before any) s +5 206 M +( session is initiated.) s +5 184 M +( There are three cases of man-in-the-middle attacks to consider. The) s +5 173 M +( first is where an attacker places a device between the client and the) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 17]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 18 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( server before the session is initiated. In this case, the attack) s +5 679 M +( device is trying to mimic the legitimate server and will offer its) s +5 668 M +( public key to the client when the client initiates a session. If it) s +5 657 M +( were to offer the public key of the server, then it would not be able) s +5 646 M +( to decrypt or sign the transmissions between the legitimate server) s +5 635 M +( and the client unless it also had access to the private-key of the) s +5 624 M +( host. The attack device will also, simultaneously to this, initiate) s +5 613 M +( a session to the legitimate server masquerading itself as the client.) s +5 602 M +( If the public key of the server had been securely distributed to the) s +5 591 M +( client prior to that session initiation, the key offered to the) s +5 580 M +( client by the attack device will not match the key stored on the) s +5 569 M +( client. In that case, the user SHOULD be given a warning that the) s +5 558 M +( offered host key does not match the host key cached on the client.) s +5 547 M +( As described in Section 3.1 of [ARCH], the user may be free to accept) s +5 536 M +( the new key and continue the session. It is RECOMMENDED that the) s +5 525 M +( warning provide sufficient information to the user of the client) s +5 514 M +( device so they may make an informed decision. If the user chooses to) s +5 503 M +( continue the session with the stored public-key of the server \(not) s +5 492 M +( the public-key offered at the start of the session\), then the session) s +5 481 M +( specific data between the attacker and server will be different) s +5 470 M +( between the client-to-attacker session and the attacker-to-server) s +5 459 M +( sessions due to the randomness discussed above. From this, the) s +5 448 M +( attacker will not be able to make this attack work since the attacker) s +5 437 M +( will not be able to correctly sign packets containing this session) s +5 426 M +( specific data from the server since he does not have the private key) s +5 415 M +( of that server.) s +5 393 M +( The second case that should be considered is similar to the first) s +5 382 M +( case in that it also happens at the time of connection but this case) s +5 371 M +( points out the need for the secure distribution of server public) s +5 360 M +( keys. If the server public keys are not securely distributed then) s +5 349 M +( the client cannot know if it is talking to the intended server. An) s +5 338 M +( attacker may use social engineering techniques to pass off server) s +5 327 M +( keys to unsuspecting users and may then place a man-in-the-middle) s +5 316 M +( attack device between the legitimate server and the clients. If this) s +5 305 M +( is allowed to happen then the clients will form client-to-attacker) s +5 294 M +( sessions and the attacker will form attacker-to-server sessions and) s +5 283 M +( will be able to monitor and manipulate all of the traffic between the) s +5 272 M +( clients and the legitimate servers. Server administrators are) s +5 261 M +( encouraged to make host key fingerprints available for checking by) s +5 250 M +( some means whose security does not rely on the integrity of the) s +5 239 M +( actual host keys. Possible mechanisms are discussed in Section 3.1) s +5 228 M +( of [SSH-ARCH] and may also include secured Web pages, physical pieces) s +5 217 M +( of paper, etc. Implementors SHOULD provide recommendations on how) s +5 206 M +( best to do this with their implementation. Because the protocol is) s +5 195 M +( extensible, future extensions to the protocol may provide better) s +5 184 M +( mechanisms for dealing with the need to know the server's host key) s +5 173 M +( before connecting. For example, making the host key fingerprint) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 18]) s +_R +S +PStoPSsaved restore +%%Page: (18,19) 10 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 19 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( available through a secure DNS lookup, or using kerberos over gssapi) s +5 679 M +( during key exchange to authenticate the server are possibilities.) s +5 657 M +( In the third man-in-the-middle case, attackers may attempt to) s +5 646 M +( manipulate packets in transit between peers after the session has) s +5 635 M +( been established. As described in the Replay part of this section, a) s +5 624 M +( successful attack of this nature is very improbable. As in the) s +5 613 M +( Replay section, this reasoning does assume that the MAC is secure and) s +5 602 M +( that it is infeasible to construct inputs to a MAC algorithm to give) s +5 591 M +( a known output. This is discussed in much greater detail in Section) s +5 580 M +( 6 of RFC 2104. If the MAC algorithm has a vulnerability or is weak) s +5 569 M +( enough, then the attacker may be able to specify certain inputs to) s +5 558 M +( yield a known MAC. With that they may be able to alter the contents) s +5 547 M +( of a packet in transit. Alternatively the attacker may be able to) s +5 536 M +( exploit the algorithm vulnerability or weakness to find the shared) s +5 525 M +( secret by reviewing the MACs from captured packets. In either of) s +5 514 M +( those cases, an attacker could construct a packet or packets that) s +5 503 M +( could be inserted into an SSH stream. To prevent that, implementors) s +5 492 M +( are encouraged to utilize commonly accepted MAC algorithms and) s +5 481 M +( administrators are encouraged to watch current literature and) s +5 470 M +( discussions of cryptography to ensure that they are not using a MAC) s +5 459 M +( algorithm that has a recently found vulnerability or weakness.) s +5 437 M +( In summary, the use of this protocol without a reliable association) s +5 426 M +( of the binding between a host and its host keys is inherently) s +5 415 M +( insecure and is NOT RECOMMENDED. It may however be necessary in) s +5 404 M +( non-security critical environments, and will still provide protection) s +5 393 M +( against passive attacks. Implementors of protocols and applications) s +5 382 M +( running on top of this protocol should keep this possibility in mind.) s +5 360 M +(9.2.5 Denial-of-service) s +5 338 M +( This protocol is designed to be used over a reliable transport. If) s +5 327 M +( transmission errors or message manipulation occur, the connection is) s +5 316 M +( closed. The connection SHOULD be re-established if this occurs.) s +5 305 M +( Denial of service attacks of this type \("wire cutter"\) are almost) s +5 294 M +( impossible to avoid.) s +5 272 M +( In addition, this protocol is vulnerable to Denial of Service attacks) s +5 261 M +( because an attacker can force the server to go through the CPU and) s +5 250 M +( memory intensive tasks of connection setup and key exchange without) s +5 239 M +( authenticating. Implementors SHOULD provide features that make this) s +5 228 M +( more difficult. For example, only allowing connections from a subset) s +5 217 M +( of IPs known to have valid users.) s +5 195 M +(9.2.6 Covert Channels) s +5 173 M +( The protocol was not designed to eliminate covert channels. For) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 19]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 20 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( example, the padding, SSH_MSG_IGNORE messages, and several other) s +5 679 M +( places in the protocol can be used to pass covert information, and) s +5 668 M +( the recipient has no reliable way to verify whether such information) s +5 657 M +( is being sent.) s +5 635 M +(9.2.7 Forward Secrecy) s +5 613 M +( It should be noted that the Diffie-Hellman key exchanges may provide) s +5 602 M +( perfect forward secrecy \(PFS\). PFS is essentially defined as the) s +5 591 M +( cryptographic property of a key-establishment protocol in which the) s +5 580 M +( compromise of a session key or long-term private key after a given) s +5 569 M +( session does not cause the compromise of any earlier session. [ANSI) s +5 558 M +( T1.523-2001] SSHv2 sessions resulting from a key exchange using) s +5 547 M +( diffie-hellman-group1-sha1 are secure even if private keying/) s +5 536 M +( authentication material is later revealed, but not if the session) s +5 525 M +( keys are revealed. So, given this definition of PFS, SSHv2 does have) s +5 514 M +( PFS. It is hoped that all other key exchange mechanisms proposed and) s +5 503 M +( used in the future will also provide PFS. This property is not) s +5 492 M +( commuted to any of the applications or protocols using SSH as a) s +5 481 M +( transport however. The transport layer of SSH provides) s +5 470 M +( confidentiality for password authentication and other methods that) s +5 459 M +( rely on secret data.) s +5 437 M +( Of course, if the DH private parameters for the client and server are) s +5 426 M +( revealed then the session key is revealed, but these items can be) s +5 415 M +( thrown away after the key exchange completes. It's worth pointing) s +5 404 M +( out that these items should not be allowed to end up on swap space) s +5 393 M +( and that they should be erased from memory as soon as the key) s +5 382 M +( exchange completes.) s +5 360 M +(9.3 Authentication Protocol) s +5 338 M +( The purpose of this protocol is to perform client user) s +5 327 M +( authentication. It assumes that this run over a secure transport) s +5 316 M +( layer protocol, which has already authenticated the server machine,) s +5 305 M +( established an encrypted communications channel, and computed a) s +5 294 M +( unique session identifier for this session.) s +5 272 M +( Several authentication methods with different security) s +5 261 M +( characteristics are allowed. It is up to the server's local policy) s +5 250 M +( to decide which methods \(or combinations of methods\) it is willing to) s +5 239 M +( accept for each user. Authentication is no stronger than the weakest) s +5 228 M +( combination allowed.) s +5 206 M +( The server may go into a "sleep" period after repeated unsuccessful) s +5 195 M +( authentication attempts to make key search more difficult for) s +5 184 M +( attackers. Care should be taken so that this doesn't become a) s +5 173 M +( self-denial of service vector.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 20]) s +_R +S +PStoPSsaved restore +%%Page: (20,21) 11 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 21 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +(9.3.1 Weak Transport) s +5 668 M +( If the transport layer does not provide confidentiality,) s +5 657 M +( authentication methods that rely on secret data SHOULD be disabled.) s +5 646 M +( If it does not provide strong integrity protection, requests to) s +5 635 M +( change authentication data \(e.g. a password change\) SHOULD be) s +5 624 M +( disabled to prevent an attacker from modifying the ciphertext) s +5 613 M +( without being noticed, or rendering the new authentication data) s +5 602 M +( unusable \(denial of service\).) s +5 580 M +( The assumption as stated above that the Authentication Protocol only) s +5 569 M +( run over a secure transport that has previously authenticated the) s +5 558 M +( server is very important to note. People deploying SSH are reminded) s +5 547 M +( of the consequences of man-in-the-middle attacks if the client does) s +5 536 M +( not have a very strong a priori association of the server with the) s +5 525 M +( host key of that server. Specifically for the case of the) s +5 514 M +( Authentication Protocol the client may form a session to a) s +5 503 M +( man-in-the-middle attack device and divulge user credentials such as) s +5 492 M +( their username and password. Even in the cases of authentication) s +5 481 M +( where no user credentials are divulged, an attacker may still gain) s +5 470 M +( information they shouldn't have by capturing key-strokes in much the) s +5 459 M +( same way that a honeypot works.) s +5 437 M +(9.3.2 Debug messages) s +5 415 M +( Special care should be taken when designing debug messages. These) s +5 404 M +( messages may reveal surprising amounts of information about the host) s +5 393 M +( if not properly designed. Debug messages can be disabled \(during) s +5 382 M +( user authentication phase\) if high security is required.) s +5 371 M +( Administrators of host machines should make all attempts to) s +5 360 M +( compartmentalize all event notification messages and protect them) s +5 349 M +( from unwarranted observation. Developers should be aware of the) s +5 338 M +( sensitive nature of some of the normal event messages and debug) s +5 327 M +( messages and may want to provide guidance to administrators on ways) s +5 316 M +( to keep this information away from unauthorized people. Developers) s +5 305 M +( should consider minimizing the amount of sensitive information) s +5 294 M +( obtainable by users during the authentication phase in accordance) s +5 283 M +( with the local policies. For this reason, it is RECOMMENDED that) s +5 272 M +( debug messages be initially disabled at the time of deployment and) s +5 261 M +( require an active decision by an administrator to allow them to be) s +5 250 M +( enabled. It is also RECOMMENDED that a message expressing this) s +5 239 M +( concern be presented to the administrator of a system when the action) s +5 228 M +( is taken to enable debugging messages.) s +5 206 M +(9.3.3 Local security policy) s +5 184 M +( Implementer MUST ensure that the credentials provided validate the) s +5 173 M +( professed user and also MUST ensure that the local policy of the) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 21]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 22 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( server permits the user the access requested. In particular, because) s +5 679 M +( of the flexible nature of the SSH connection protocol, it may not be) s +5 668 M +( possible to determine the local security policy, if any, that should) s +5 657 M +( apply at the time of authentication because the kind of service being) s +5 646 M +( requested is not clear at that instant. For example, local policy) s +5 635 M +( might allow a user to access files on the server, but not start an) s +5 624 M +( interactive shell. However, during the authentication protocol, it is) s +5 613 M +( not known whether the user will be accessing files or attempting to) s +5 602 M +( use an interactive shell, or even both. In any event, where local) s +5 591 M +( security policy for the server host exists, it MUST be applied and) s +5 580 M +( enforced correctly.) s +5 558 M +( Implementors are encouraged to provide a default local policy and) s +5 547 M +( make its parameters known to administrators and users. At the) s +5 536 M +( discretion of the implementors, this default policy may be along the) s +5 525 M +( lines of 'anything goes' where there are no restrictions placed upon) s +5 514 M +( users, or it may be along the lines of 'excessively restrictive' in) s +5 503 M +( which case the administrators will have to actively make changes to) s +5 492 M +( this policy to meet their needs. Alternatively, it may be some) s +5 481 M +( attempt at providing something practical and immediately useful to) s +5 470 M +( the administrators of the system so they don't have to put in much) s +5 459 M +( effort to get SSH working. Whatever choice is made MUST be applied) s +5 448 M +( and enforced as required above.) s +5 426 M +(9.3.4 Public key authentication) s +5 404 M +( The use of public-key authentication assumes that the client host has) s +5 393 M +( not been compromised. It also assumes that the private-key of the) s +5 382 M +( server host has not been compromised.) s +5 360 M +( This risk can be mitigated by the use of passphrases on private keys;) s +5 349 M +( however, this is not an enforceable policy. The use of smartcards,) s +5 338 M +( or other technology to make passphrases an enforceable policy is) s +5 327 M +( suggested.) s +5 305 M +( The server could require both password and public-key authentication,) s +5 294 M +( however, this requires the client to expose its password to the) s +5 283 M +( server \(see section on password authentication below.\)) s +5 261 M +(9.3.5 Password authentication) s +5 239 M +( The password mechanism as specified in the authentication protocol) s +5 228 M +( assumes that the server has not been compromised. If the server has) s +5 217 M +( been compromised, using password authentication will reveal a valid) s +5 206 M +( username / password combination to the attacker, which may lead to) s +5 195 M +( further compromises.) s +5 173 M +( This vulnerability can be mitigated by using an alternative form of) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 22]) s +_R +S +PStoPSsaved restore +%%Page: (22,23) 12 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 23 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( authentication. For example, public-key authentication makes no) s +5 679 M +( assumptions about security on the server.) s +5 657 M +(9.3.6 Host based authentication) s +5 635 M +( Host based authentication assumes that the client has not been) s +5 624 M +( compromised. There are no mitigating strategies, other than to use) s +5 613 M +( host based authentication in combination with another authentication) s +5 602 M +( method.) s +5 580 M +(9.4 Connection protocol) s +5 558 M +(9.4.1 End point security) s +5 536 M +( End point security is assumed by the connection protocol. If the) s +5 525 M +( server has been compromised, any terminal sessions, port forwarding,) s +5 514 M +( or systems accessed on the host are compromised. There are no) s +5 503 M +( mitigating factors for this.) s +5 481 M +( If the client end point has been compromised, and the server fails to) s +5 470 M +( stop the attacker at the authentication protocol, all services) s +5 459 M +( exposed \(either as subsystems or through forwarding\) will be) s +5 448 M +( vulnerable to attack. Implementors SHOULD provide mechanisms for) s +5 437 M +( administrators to control which services are exposed to limit the) s +5 426 M +( vulnerability of other services.) s +5 404 M +( These controls might include controlling which machines and ports can) s +5 393 M +( be target in 'port-forwarding' operations, which users are allowed to) s +5 382 M +( use interactive shell facilities, or which users are allowed to use) s +5 371 M +( exposed subsystems.) s +5 349 M +(9.4.2 Proxy forwarding) s +5 327 M +( The SSH connection protocol allows for proxy forwarding of other) s +5 316 M +( protocols such as SNMP, POP3, and HTTP. This may be a concern for) s +5 305 M +( network administrators who wish to control the access of certain) s +5 294 M +( applications by users located outside of their physical location.) s +5 283 M +( Essentially, the forwarding of these protocols may violate site) s +5 272 M +( specific security policies as they may be undetectably tunneled) s +5 261 M +( through a firewall. Implementors SHOULD provide an administrative) s +5 250 M +( mechanism to control the proxy forwarding functionality so that site) s +5 239 M +( specific security policies may be upheld.) s +5 217 M +( In addition, a reverse proxy forwarding functionality is available,) s +5 206 M +( which again can be used to bypass firewall controls.) s +5 184 M +( As indicated above, end-point security is assumed during proxy) s +5 173 M +( forwarding operations. Failure of end-point security will compromise) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 23]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 24 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( all data passed over proxy forwarding.) s +5 668 M +(9.4.3 X11 forwarding) s +5 646 M +( Another form of proxy forwarding provided by the ssh connection) s +5 635 M +( protocol is the forwarding of the X11 protocol. If end-point) s +5 624 M +( security has been compromised, X11 forwarding may allow attacks) s +5 613 M +( against the X11 server. Users and administrators should, as a matter) s +5 602 M +( of course, use appropriate X11 security mechanisms to prevent) s +5 591 M +( unauthorized use of the X11 server. Implementors, administrators and) s +5 580 M +( users who wish to further explore the security mechanisms of X11 are) s +5 569 M +( invited to read [SCHEIFLER] and analyze previously reported problems) s +5 558 M +( with the interactions between SSH forwarding and X11 in CERT) s +5 547 M +( vulnerabilities VU#363181 and VU#118892 [CERT].) s +5 525 M +( X11 display forwarding with SSH, by itself, is not sufficient to) s +5 514 M +( correct well known problems with X11 security [VENEMA]. However, X11) s +5 503 M +( display forwarding in SSHv2 \(or other, secure protocols\), combined) s +5 492 M +( with actual and pseudo-displays which accept connections only over) s +5 481 M +( local IPC mechanisms authorized by permissions or ACLs, does correct) s +5 470 M +( many X11 security problems as long as the "none" MAC is not used. It) s +5 459 M +( is RECOMMENDED that X11 display implementations default to allowing) s +5 448 M +( display opens only over local IPC. It is RECOMMENDED that SSHv2) s +5 437 M +( server implementations that support X11 forwarding default to) s +5 426 M +( allowing display opens only over local IPC. On single-user systems) s +5 415 M +( it might be reasonable to default to allowing local display opens) s +5 404 M +( over TCP/IP.) s +5 382 M +( Implementors of the X11 forwarding protocol SHOULD implement the) s +5 371 M +( magic cookie access checking spoofing mechanism as described in) s +5 360 M +( [ssh-connect] as an additional mechanism to prevent unauthorized use) s +5 349 M +( of the proxy.) s +5 327 M +(Normative References) s +5 305 M +( [SSH-ARCH]) s +5 294 M +( Ylonen, T., "SSH Protocol Architecture", I-D) s +5 283 M +( draft-ietf-architecture-15.txt, Oct 2003.) s +5 261 M +( [SSH-TRANS]) s +5 250 M +( Ylonen, T., "SSH Transport Layer Protocol", I-D) s +5 239 M +( draft-ietf-transport-17.txt, Oct 2003.) s +5 217 M +( [SSH-USERAUTH]) s +5 206 M +( Ylonen, T., "SSH Authentication Protocol", I-D) s +5 195 M +( draft-ietf-userauth-18.txt, Oct 2003.) s +5 173 M +( [SSH-CONNECT]) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 24]) s +_R +S +PStoPSsaved restore +%%Page: (24,25) 13 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 25 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( Ylonen, T., "SSH Connection Protocol", I-D) s +5 679 M +( draft-ietf-connect-18.txt, Oct 2003.) s +5 657 M +( [SSH-NUMBERS]) s +5 646 M +( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s +5 635 M +( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s +5 624 M +( 2003.) s +5 602 M +( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s +5 591 M +( Requirement Levels", BCP 14, RFC 2119, March 1997.) s +5 569 M +(Informative References) s +5 547 M +( [FIPS-186]) s +5 536 M +( Federal Information Processing Standards Publication,) s +5 525 M +( "FIPS PUB 186, Digital Signature Standard", May 1994.) s +5 503 M +( [FIPS-197]) s +5 492 M +( National Institue of Standards and Technology, "FIPS 197,) s +5 481 M +( Specification for the Advanced Encryption Standard",) s +5 470 M +( November 2001.) s +5 448 M +( [ANSI T1.523-2001]) s +5 437 M +( American National Standards Insitute, Inc., "Telecom) s +5 426 M +( Glossary 2000", February 2001.) s +5 404 M +( [SCHEIFLER]) s +5 393 M +( Scheifler, R., "X Window System : The Complete Reference) s +5 382 M +( to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital) s +5 371 M +( Press ISBN 1555580882, Feburary 1992.) s +5 349 M +( [RFC0854] Postel, J. and J. Reynolds, "Telnet Protocol) s +5 338 M +( Specification", STD 8, RFC 854, May 1983.) s +5 316 M +( [RFC0894] Hornig, C., "Standard for the transmission of IP datagrams) s +5 305 M +( over Ethernet networks", STD 41, RFC 894, April 1984.) s +5 283 M +( [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",) s +5 272 M +( STD 13, RFC 1034, November 1987.) s +5 250 M +( [RFC1134] Perkins, D., "Point-to-Point Protocol: A proposal for) s +5 239 M +( multi-protocol transmission of datagrams over) s +5 228 M +( Point-to-Point links", RFC 1134, November 1989.) s +5 206 M +( [RFC1282] Kantor, B., "BSD Rlogin", RFC 1282, December 1991.) s +5 184 M +( [RFC1510] Kohl, J. and B. Neuman, "The Kerberos Network) s +5 173 M +( Authentication Service \(V5\)", RFC 1510, September 1993.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 25]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 26 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( [RFC1700] Reynolds, J. and J. Postel, "Assigned Numbers", RFC 1700,) s +5 679 M +( October 1994.) s +5 657 M +( [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness) s +5 646 M +( Recommendations for Security", RFC 1750, December 1994.) s +5 624 M +( [RFC3066] Alvestrand, H., "Tags for the Identification of) s +5 613 M +( Languages", BCP 47, RFC 3066, January 2001.) s +5 591 M +( [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC) s +5 580 M +( 1964, June 1996.) s +5 558 M +( [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism) s +5 547 M +( \(SPKM\)", RFC 2025, October 1996.) s +5 525 M +( [RFC2085] Oehler, M. and R. Glenn, "HMAC-MD5 IP Authentication with) s +5 514 M +( Replay Prevention", RFC 2085, February 1997.) s +5 492 M +( [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC:) s +5 481 M +( Keyed-Hashing for Message Authentication", RFC 2104,) s +5 470 M +( February 1997.) s +5 448 M +( [RFC2246] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A.) s +5 437 M +( and P. Kocher, "The TLS Protocol Version 1.0", RFC 2246,) s +5 426 M +( January 1999.) s +5 404 M +( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s +5 393 M +( 10646", RFC 2279, January 1998.) s +5 371 M +( [RFC2410] Glenn, R. and S. Kent, "The NULL Encryption Algorithm and) s +5 360 M +( Its Use With IPsec", RFC 2410, November 1998.) s +5 338 M +( [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an) s +5 327 M +( IANA Considerations Section in RFCs", BCP 26, RFC 2434,) s +5 316 M +( October 1998.) s +5 294 M +( [RFC2743] Linn, J., "Generic Security Service Application Program) s +5 283 M +( Interface Version 2, Update 1", RFC 2743, January 2000.) s +5 261 M +( [SCHNEIER]) s +5 250 M +( Schneier, B., "Applied Cryptography Second Edition:) s +5 239 M +( protocols algorithms and source in code in C", 1996.) s +5 217 M +( [KAUFMAN,PERLMAN,SPECINER]) s +5 206 M +( Kaufman, C., Perlman, R. and M. Speciner, "Network) s +5 195 M +( Security: PRIVATE Communication in a PUBLIC World", 1995.) s +5 173 M +( [CERT] CERT Coordination Center, The., "http://www.cert.org/nav/) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 26]) s +_R +S +PStoPSsaved restore +%%Page: (26,27) 14 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 27 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( index_red.html".) s +5 668 M +( [VENEMA] Venema, W., "Murphy's Law and Computer Security",) s +5 657 M +( Proceedings of 6th USENIX Security Symposium, San Jose CA) s +5 646 M +( http://www.usenix.org/publications/library/proceedings/) s +5 635 M +( sec96/venema.html, July 1996.) s +5 613 M +( [ROGAWAY] Rogaway, P., "Problems with Proposed IP Cryptography",) s +5 602 M +( Unpublished paper http://www.cs.ucdavis.edu/~rogaway/) s +5 591 M +( papers/draft-rogaway-ipsec-comments-00.txt, 1996.) s +5 569 M +( [DAI] Dai, W., "An attack against SSH2 protocol", Email to the) s +5 558 M +( SECSH Working Group [email protected] ftp://) s +5 547 M +( ftp.ietf.org/ietf-mail-archive/secsh/2002-02.mail, Feb) s +5 536 M +( 2002.) s +5 514 M +( [BELLARE,KOHNO,NAMPREMPRE]) s +5 503 M +( Bellaire, M., Kohno, T. and C. Namprempre, "Authenticated) s +5 492 M +( Encryption in SSH: Fixing the SSH Binary Packet Protocol",) s +5 481 M +( , Sept 2002.) s +5 448 M +(Authors' Addresses) s +5 426 M +( Tatu Ylonen) s +5 415 M +( SSH Communications Security Corp) s +5 404 M +( Fredrikinkatu 42) s +5 393 M +( HELSINKI FIN-00100) s +5 382 M +( Finland) s +5 360 M +( EMail: [email protected]) s +5 327 M +( Darren J. Moffat \(editor\)) s +5 316 M +( Sun Microsystems, Inc) s +5 305 M +( 17 Network Circle) s +5 294 M +( Menlo Park CA 94025) s +5 283 M +( USA) s +5 261 M +( EMail: [email protected]) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 27]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 28 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +(Intellectual Property Statement) s +5 668 M +( The IETF takes no position regarding the validity or scope of any) s +5 657 M +( intellectual property or other rights that might be claimed to) s +5 646 M +( pertain to the implementation or use of the technology described in) s +5 635 M +( this document or the extent to which any license under such rights) s +5 624 M +( might or might not be available; neither does it represent that it) s +5 613 M +( has made any effort to identify any such rights. Information on the) s +5 602 M +( IETF's procedures with respect to rights in standards-track and) s +5 591 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 580 M +( claims of rights made available for publication and any assurances of) s +5 569 M +( licenses to be made available, or the result of an attempt made to) s +5 558 M +( obtain a general license or permission for the use of such) s +5 547 M +( proprietary rights by implementors or users of this specification can) s +5 536 M +( be obtained from the IETF Secretariat.) s +5 514 M +( The IETF invites any interested party to bring to its attention any) s +5 503 M +( copyrights, patents or patent applications, or other proprietary) s +5 492 M +( rights which may cover technology that may be required to practice) s +5 481 M +( this standard. Please address the information to the IETF Executive) s +5 470 M +( Director.) s +5 448 M +( The IETF has been notified of intellectual property rights claimed in) s +5 437 M +( regard to some or all of the specification contained in this) s +5 426 M +( document. For more information consult the online list of claimed) s +5 415 M +( rights.) s +5 382 M +(Full Copyright Statement) s +5 360 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 338 M +( This document and translations of it may be copied and furnished to) s +5 327 M +( others, and derivative works that comment on or otherwise explain it) s +5 316 M +( or assist in its implementation may be prepared, copied, published) s +5 305 M +( and distributed, in whole or in part, without restriction of any) s +5 294 M +( kind, provided that the above copyright notice and this paragraph are) s +5 283 M +( included on all such copies and derivative works. However, this) s +5 272 M +( document itself may not be modified in any way, such as by removing) s +5 261 M +( the copyright notice or references to the Internet Society or other) s +5 250 M +( Internet organizations, except as needed for the purpose of) s +5 239 M +( developing Internet standards in which case the procedures for) s +5 228 M +( copyrights defined in the Internet Standards process must be) s +5 217 M +( followed, or as required to translate it into languages other than) s +5 206 M +( English.) s +5 184 M +( The limited permissions granted above are perpetual and will not be) s +5 173 M +( revoked by the Internet Society or its successors or assignees.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 28]) s +_R +S +PStoPSsaved restore +%%Page: (28,29) 15 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 29 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Protocol Architecture Oct 2003) s +5 690 M +( This document and the information contained herein is provided on an) s +5 679 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 668 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 657 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 646 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 635 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 602 M +(Acknowledgment) s +5 580 M +( Funding for the RFC Editor function is currently provided by the) s +5 569 M +( Internet Society.) s +5 129 M +(Ylonen & Moffat Expires March 31, 2004 [Page 29]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +showpage +PStoPSsaved restore +%%Trailer +%%Pages: 29 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt new file mode 100644 index 0000000000..18070e8485 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-architecture-15.txt @@ -0,0 +1,1624 @@ + + + +Network Working Group T. Ylonen +Internet-Draft SSH Communications Security Corp +Expires: March 31, 2004 D. Moffat, Ed. + Sun Microsystems, Inc + Oct 2003 + + + SSH Protocol Architecture + draft-ietf-secsh-architecture-15.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that other + groups may also distribute working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on March 31, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes the + architecture of the SSH protocol, as well as the notation and + terminology used in SSH protocol documents. It also discusses the SSH + algorithm naming system that allows local extensions. The SSH + protocol consists of three major components: The Transport Layer + Protocol provides server authentication, confidentiality, and + integrity with perfect forward secrecy. The User Authentication + Protocol authenticates the client to the server. The Connection + Protocol multiplexes the encrypted tunnel into several logical + channels. Details of these protocols are described in separate + + + +Ylonen & Moffat Expires March 31, 2004 [Page 1] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + documents. + +Table of Contents + + 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Specification of Requirements . . . . . . . . . . . . . . . 3 + 4. Architecture . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4.1 Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 4.2 Extensibility . . . . . . . . . . . . . . . . . . . . . . . 5 + 4.3 Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 5 + 4.4 Security Properties . . . . . . . . . . . . . . . . . . . . 6 + 4.5 Packet Size and Overhead . . . . . . . . . . . . . . . . . . 6 + 4.6 Localization and Character Set Support . . . . . . . . . . . 7 + 5. Data Type Representations Used in the SSH Protocols . . . . 8 + 6. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . 10 + 7. Message Numbers . . . . . . . . . . . . . . . . . . . . . . 11 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . 11 + 9. Security Considerations . . . . . . . . . . . . . . . . . . 12 + 9.1 Pseudo-Random Number Generation . . . . . . . . . . . . . . 12 + 9.2 Transport . . . . . . . . . . . . . . . . . . . . . . . . . 13 + 9.2.1 Confidentiality . . . . . . . . . . . . . . . . . . . . . . 13 + 9.2.2 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 16 + 9.2.3 Replay . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 + 9.2.4 Man-in-the-middle . . . . . . . . . . . . . . . . . . . . . 17 + 9.2.5 Denial-of-service . . . . . . . . . . . . . . . . . . . . . 19 + 9.2.6 Covert Channels . . . . . . . . . . . . . . . . . . . . . . 19 + 9.2.7 Forward Secrecy . . . . . . . . . . . . . . . . . . . . . . 20 + 9.3 Authentication Protocol . . . . . . . . . . . . . . . . . . 20 + 9.3.1 Weak Transport . . . . . . . . . . . . . . . . . . . . . . . 21 + 9.3.2 Debug messages . . . . . . . . . . . . . . . . . . . . . . . 21 + 9.3.3 Local security policy . . . . . . . . . . . . . . . . . . . 21 + 9.3.4 Public key authentication . . . . . . . . . . . . . . . . . 22 + 9.3.5 Password authentication . . . . . . . . . . . . . . . . . . 22 + 9.3.6 Host based authentication . . . . . . . . . . . . . . . . . 23 + 9.4 Connection protocol . . . . . . . . . . . . . . . . . . . . 23 + 9.4.1 End point security . . . . . . . . . . . . . . . . . . . . . 23 + 9.4.2 Proxy forwarding . . . . . . . . . . . . . . . . . . . . . . 23 + 9.4.3 X11 forwarding . . . . . . . . . . . . . . . . . . . . . . . 24 + Normative References . . . . . . . . . . . . . . . . . . . . 24 + Informative References . . . . . . . . . . . . . . . . . . . 25 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 27 + Intellectual Property and Copyright Statements . . . . . . . 28 + + + + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 2] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + +1. Contributors + + The major original contributors of this document were: Tatu Ylonen, + Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications + Security Corp), and Markku-Juhani O. Saarinen (University of + Jyvaskyla) + + The document editor is: [email protected]. Comments on this + internet draft should be sent to the IETF SECSH working group, + details at: http://ietf.org/html.charters/secsh-charter.html + +2. Introduction + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. It consists of three major + components: + o The Transport Layer Protocol [SSH-TRANS] provides server + authentication, confidentiality, and integrity. It may optionally + also provide compression. The transport layer will typically be + run over a TCP/IP connection, but might also be used on top of any + other reliable data stream. + o The User Authentication Protocol [SSH-USERAUTH] authenticates the + client-side user to the server. It runs over the transport layer + protocol. + o The Connection Protocol [SSH-CONNECT] multiplexes the encrypted + tunnel into several logical channels. It runs over the user + authentication protocol. + + The client sends a service request once a secure transport layer + connection has been established. A second service request is sent + after user authentication is complete. This allows new protocols to + be defined and coexist with the protocols listed above. + + The connection protocol provides channels that can be used for a wide + range of purposes. Standard methods are provided for setting up + secure interactive shell sessions and for forwarding ("tunneling") + arbitrary TCP/IP ports and X11 connections. + +3. Specification of Requirements + + All documents related to the SSH protocols shall use the keywords + "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" to describe + requirements. They are to be interpreted as described in [RFC2119]. + +4. Architecture + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 3] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + +4.1 Host Keys + + Each server host SHOULD have a host key. Hosts MAY have multiple + host keys using multiple different algorithms. Multiple hosts MAY + share the same host key. If a host has keys at all, it MUST have at + least one key using each REQUIRED public key algorithm (DSS + [FIPS-186]). + + The server host key is used during key exchange to verify that the + client is really talking to the correct server. For this to be + possible, the client must have a priori knowledge of the server's + public host key. + + Two different trust models can be used: + o The client has a local database that associates each host name (as + typed by the user) with the corresponding public host key. This + method requires no centrally administered infrastructure, and no + third-party coordination. The downside is that the database of + name-to-key associations may become burdensome to maintain. + o The host name-to-key association is certified by some trusted + certification authority. The client only knows the CA root key, + and can verify the validity of all host keys certified by accepted + CAs. + + The second alternative eases the maintenance problem, since + ideally only a single CA key needs to be securely stored on the + client. On the other hand, each host key must be appropriately + certified by a central authority before authorization is possible. + Also, a lot of trust is placed on the central infrastructure. + + The protocol provides the option that the server name - host key + association is not checked when connecting to the host for the first + time. This allows communication without prior communication of host + keys or certification. The connection still provides protection + against passive listening; however, it becomes vulnerable to active + man-in-the-middle attacks. Implementations SHOULD NOT normally allow + such connections by default, as they pose a potential security + problem. However, as there is no widely deployed key infrastructure + available on the Internet yet, this option makes the protocol much + more usable during the transition time until such an infrastructure + emerges, while still providing a much higher level of security than + that offered by older solutions (e.g. telnet [RFC-854] and rlogin + [RFC-1282]). + + Implementations SHOULD try to make the best effort to check host + keys. An example of a possible strategy is to only accept a host key + without checking the first time a host is connected, save the key in + a local database, and compare against that key on all future + + + +Ylonen & Moffat Expires March 31, 2004 [Page 4] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + connections to that host. + + Implementations MAY provide additional methods for verifying the + correctness of host keys, e.g. a hexadecimal fingerprint derived from + the SHA-1 hash of the public key. Such fingerprints can easily be + verified by using telephone or other external communication channels. + + All implementations SHOULD provide an option to not accept host keys + that cannot be verified. + + We believe that ease of use is critical to end-user acceptance of + security solutions, and no improvement in security is gained if the + new solutions are not used. Thus, providing the option not to check + the server host key is believed to improve the overall security of + the Internet, even though it reduces the security of the protocol in + configurations where it is allowed. + +4.2 Extensibility + + We believe that the protocol will evolve over time, and some + organizations will want to use their own encryption, authentication + and/or key exchange methods. Central registration of all extensions + is cumbersome, especially for experimental or classified features. + On the other hand, having no central registration leads to conflicts + in method identifiers, making interoperability difficult. + + We have chosen to identify algorithms, methods, formats, and + extension protocols with textual names that are of a specific format. + DNS names are used to create local namespaces where experimental or + classified extensions can be defined without fear of conflicts with + other implementations. + + One design goal has been to keep the base protocol as simple as + possible, and to require as few algorithms as possible. However, all + implementations MUST support a minimal set of algorithms to ensure + interoperability (this does not imply that the local policy on all + hosts would necessary allow these algorithms). The mandatory + algorithms are specified in the relevant protocol documents. + + Additional algorithms, methods, formats, and extension protocols can + be defined in separate drafts. See Section Algorithm Naming (Section + 6) for more information. + +4.3 Policy Issues + + The protocol allows full negotiation of encryption, integrity, key + exchange, compression, and public key algorithms and formats. + Encryption, integrity, public key, and compression algorithms can be + + + +Ylonen & Moffat Expires March 31, 2004 [Page 5] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + different for each direction. + + The following policy issues SHOULD be addressed in the configuration + mechanisms of each implementation: + o Encryption, integrity, and compression algorithms, separately for + each direction. The policy MUST specify which is the preferred + algorithm (e.g. the first algorithm listed in each category). + o Public key algorithms and key exchange method to be used for host + authentication. The existence of trusted host keys for different + public key algorithms also affects this choice. + o The authentication methods that are to be required by the server + for each user. The server's policy MAY require multiple + authentication for some or all users. The required algorithms MAY + depend on the location where the user is trying to log in from. + o The operations that the user is allowed to perform using the + connection protocol. Some issues are related to security; for + example, the policy SHOULD NOT allow the server to start sessions + or run commands on the client machine, and MUST NOT allow + connections to the authentication agent unless forwarding such + connections has been requested. Other issues, such as which TCP/ + IP ports can be forwarded and by whom, are clearly issues of local + policy. Many of these issues may involve traversing or bypassing + firewalls, and are interrelated with the local security policy. + +4.4 Security Properties + + The primary goal of the SSH protocol is improved security on the + Internet. It attempts to do this in a way that is easy to deploy, + even at the cost of absolute security. + o All encryption, integrity, and public key algorithms used are + well-known, well-established algorithms. + o All algorithms are used with cryptographically sound key sizes + that are believed to provide protection against even the strongest + cryptanalytic attacks for decades. + o All algorithms are negotiated, and in case some algorithm is + broken, it is easy to switch to some other algorithm without + modifying the base protocol. + + Specific concessions were made to make wide-spread fast deployment + easier. The particular case where this comes up is verifying that + the server host key really belongs to the desired host; the protocol + allows the verification to be left out (but this is NOT RECOMMENDED). + This is believed to significantly improve usability in the short + term, until widespread Internet public key infrastructures emerge. + +4.5 Packet Size and Overhead + + Some readers will worry about the increase in packet size due to new + + + +Ylonen & Moffat Expires March 31, 2004 [Page 6] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + headers, padding, and MAC. The minimum packet size is in the order + of 28 bytes (depending on negotiated algorithms). The increase is + negligible for large packets, but very significant for one-byte + packets (telnet-type sessions). There are, however, several factors + that make this a non-issue in almost all cases: + o The minimum size of a TCP/IP header is 32 bytes. Thus, the + increase is actually from 33 to 51 bytes (roughly). + o The minimum size of the data field of an Ethernet packet is 46 + bytes [RFC-894]. Thus, the increase is no more than 5 bytes. When + Ethernet headers are considered, the increase is less than 10 + percent. + o The total fraction of telnet-type data in the Internet is + negligible, even with increased packet sizes. + + The only environment where the packet size increase is likely to have + a significant effect is PPP [RFC-1134] over slow modem lines (PPP + compresses the TCP/IP headers, emphasizing the increase in packet + size). However, with modern modems, the time needed to transfer is in + the order of 2 milliseconds, which is a lot faster than people can + type. + + There are also issues related to the maximum packet size. To + minimize delays in screen updates, one does not want excessively + large packets for interactive sessions. The maximum packet size is + negotiated separately for each channel. + +4.6 Localization and Character Set Support + + For the most part, the SSH protocols do not directly pass text that + would be displayed to the user. However, there are some places where + such data might be passed. When applicable, the character set for the + data MUST be explicitly specified. In most places, ISO 10646 with + UTF-8 encoding is used [RFC-2279]. When applicable, a field is also + provided for a language tag [RFC-3066]. + + One big issue is the character set of the interactive session. There + is no clear solution, as different applications may display data in + different formats. Different types of terminal emulation may also be + employed in the client, and the character set to be used is + effectively determined by the terminal emulation. Thus, no place is + provided for directly specifying the character set or encoding for + terminal session data. However, the terminal emulation type (e.g. + "vt100") is transmitted to the remote site, and it implicitly + specifies the character set and encoding. Applications typically use + the terminal type to determine what character set they use, or the + character set is determined using some external means. The terminal + emulation may also allow configuring the default character set. In + any case, the character set for the terminal session is considered + + + +Ylonen & Moffat Expires March 31, 2004 [Page 7] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + primarily a client local issue. + + Internal names used to identify algorithms or protocols are normally + never displayed to users, and must be in US-ASCII. + + The client and server user names are inherently constrained by what + the server is prepared to accept. They might, however, occasionally + be displayed in logs, reports, etc. They MUST be encoded using ISO + 10646 UTF-8, but other encodings may be required in some cases. It + is up to the server to decide how to map user names to accepted user + names. Straight bit-wise binary comparison is RECOMMENDED. + + For localization purposes, the protocol attempts to minimize the + number of textual messages transmitted. When present, such messages + typically relate to errors, debugging information, or some externally + configured data. For data that is normally displayed, it SHOULD be + possible to fetch a localized message instead of the transmitted + message by using a numerical code. The remaining messages SHOULD be + configurable. + +5. Data Type Representations Used in the SSH Protocols + byte + + A byte represents an arbitrary 8-bit value (octet) [RFC-1700]. + Fixed length data is sometimes represented as an array of bytes, + written byte[n], where n is the number of bytes in the array. + + boolean + + A boolean value is stored as a single byte. The value 0 + represents FALSE, and the value 1 represents TRUE. All non-zero + values MUST be interpreted as TRUE; however, applications MUST NOT + store values other than 0 and 1. + + uint32 + + Represents a 32-bit unsigned integer. Stored as four bytes in the + order of decreasing significance (network byte order). For + example, the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 + aa. + + uint64 + + Represents a 64-bit unsigned integer. Stored as eight bytes in + the order of decreasing significance (network byte order). + + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 8] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + string + + Arbitrary length binary string. Strings are allowed to contain + arbitrary binary data, including null characters and 8-bit + characters. They are stored as a uint32 containing its length + (number of bytes that follow) and zero (= empty string) or more + bytes that are the value of the string. Terminating null + characters are not used. + + Strings are also used to store text. In that case, US-ASCII is + used for internal names, and ISO-10646 UTF-8 for text that might + be displayed to the user. The terminating null character SHOULD + NOT normally be stored in the string. + + For example, the US-ASCII string "testing" is represented as 00 00 + 00 07 t e s t i n g. The UTF8 mapping does not alter the encoding + of US-ASCII characters. + + mpint + + Represents multiple precision integers in two's complement format, + stored as a string, 8 bits per byte, MSB first. Negative numbers + have the value 1 as the most significant bit of the first byte of + the data partition. If the most significant bit would be set for a + positive number, the number MUST be preceded by a zero byte. + Unnecessary leading bytes with the value 0 or 255 MUST NOT be + included. The value zero MUST be stored as a string with zero + bytes of data. + + By convention, a number that is used in modular computations in + Z_n SHOULD be represented in the range 0 <= x < n. + + Examples: + value (hex) representation (hex) + --------------------------------------------------------------- + 0 00 00 00 00 + 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7 + 80 00 00 00 02 00 80 + -1234 00 00 00 02 ed cc + -deadbeef 00 00 00 05 ff 21 52 41 11 + + + + name-list + + A string containing a comma separated list of names. A name list + is represented as a uint32 containing its length (number of bytes + that follow) followed by a comma-separated list of zero or more + + + +Ylonen & Moffat Expires March 31, 2004 [Page 9] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + names. A name MUST be non-zero length, and it MUST NOT contain a + comma (','). Context may impose additional restrictions on the + names; for example, the names in a list may have to be valid + algorithm identifier (see Algorithm Naming below), or [RFC-3066] + language tags. The order of the names in a list may or may not be + significant, also depending on the context where the list is is + used. Terminating NUL characters are not used, neither for the + individual names, nor for the list as a whole. + + Examples: + value representation (hex) + --------------------------------------- + (), the empty list 00 00 00 00 + ("zlib") 00 00 00 04 7a 6c 69 62 + ("zlib", "none") 00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65 + + + + +6. Algorithm Naming + + The SSH protocols refer to particular hash, encryption, integrity, + compression, and key exchange algorithms or protocols by names. + There are some standard algorithms that all implementations MUST + support. There are also algorithms that are defined in the protocol + specification but are OPTIONAL. Furthermore, it is expected that + some organizations will want to use their own algorithms. + + In this protocol, all algorithm identifiers MUST be printable + US-ASCII non-empty strings no longer than 64 characters. Names MUST + be case-sensitive. + + There are two formats for algorithm names: + o Names that do not contain an at-sign (@) are reserved to be + assigned by IETF consensus (RFCs). Examples include `3des-cbc', + `sha-1', `hmac-sha1', and `zlib' (the quotes are not part of the + name). Names of this format MUST NOT be used without first + registering them. Registered names MUST NOT contain an at-sign + (@) or a comma (,). + o Anyone can define additional algorithms by using names in the + format name@domainname, e.g. "[email protected]". The + format of the part preceding the at sign is not specified; it MUST + consist of US-ASCII characters except at-sign and comma. The part + following the at-sign MUST be a valid fully qualified internet + domain name [RFC-1034] controlled by the person or organization + defining the name. It is up to each domain how it manages its + local namespace. + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 10] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + +7. Message Numbers + + SSH packets have message numbers in the range 1 to 255. These numbers + have been allocated as follows: + + + Transport layer protocol: + + 1 to 19 Transport layer generic (e.g. disconnect, ignore, debug, + etc.) + 20 to 29 Algorithm negotiation + 30 to 49 Key exchange method specific (numbers can be reused for + different authentication methods) + + User authentication protocol: + + 50 to 59 User authentication generic + 60 to 79 User authentication method specific (numbers can be + reused for different authentication methods) + + Connection protocol: + + 80 to 89 Connection protocol generic + 90 to 127 Channel related messages + + Reserved for client protocols: + + 128 to 191 Reserved + + Local extensions: + + 192 to 255 Local extensions + + + +8. IANA Considerations + + The initial state of the IANA registry is detailed in [SSH-NUMBERS]. + + Allocation of the following types of names in the SSH protocols is + assigned by IETF consensus: + o SSH encryption algorithm names, + o SSH MAC algorithm names, + o SSH public key algorithm names (public key algorithm also implies + encoding and signature/encryption capability), + o SSH key exchange method names, and + o SSH protocol (service) names. + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 11] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + These names MUST be printable US-ASCII strings, and MUST NOT contain + the characters at-sign ('@'), comma (','), or whitespace or control + characters (ASCII codes 32 or less). Names are case-sensitive, and + MUST NOT be longer than 64 characters. + + Names with the at-sign ('@') in them are allocated by the owner of + DNS name after the at-sign (hierarchical allocation in [RFC-2343]), + otherwise the same restrictions as above. + + Each category of names listed above has a separate namespace. + However, using the same name in multiple categories SHOULD be avoided + to minimize confusion. + + Message numbers (see Section Message Numbers (Section 7)) in the + range of 0..191 are allocated via IETF consensus; message numbers in + the 192..255 range (the "Local extensions" set) are reserved for + private use. + +9. Security Considerations + + In order to make the entire body of Security Considerations more + accessible, Security Considerations for the transport, + authentication, and connection documents have been gathered here. + + The transport protocol [1] provides a confidential channel over an + insecure network. It performs server host authentication, key + exchange, encryption, and integrity protection. It also derives a + unique session id that may be used by higher-level protocols. + + The authentication protocol [2] provides a suite of mechanisms which + can be used to authenticate the client user to the server. + Individual mechanisms specified in the in authentication protocol use + the session id provided by the transport protocol and/or depend on + the security and integrity guarantees of the transport protocol. + + The connection protocol [3] specifies a mechanism to multiplex + multiple streams [channels] of data over the confidential and + authenticated transport. It also specifies channels for accessing an + interactive shell, for 'proxy-forwarding' various external protocols + over the secure transport (including arbitrary TCP/IP protocols), and + for accessing secure 'subsystems' on the server host. + +9.1 Pseudo-Random Number Generation + + This protocol binds each session key to the session by including + random, session specific data in the hash used to produce session + keys. Special care should be taken to ensure that all of the random + numbers are of good quality. If the random data here (e.g., DH + + + +Ylonen & Moffat Expires March 31, 2004 [Page 12] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + parameters) are pseudo-random then the pseudo-random number generator + should be cryptographically secure (i.e., its next output not easily + guessed even when knowing all previous outputs) and, furthermore, + proper entropy needs to be added to the pseudo-random number + generator. RFC 1750 [1750] offers suggestions for sources of random + numbers and entropy. Implementors should note the importance of + entropy and the well-meant, anecdotal warning about the difficulty in + properly implementing pseudo-random number generating functions. + + The amount of entropy available to a given client or server may + sometimes be less than what is required. In this case one must + either resort to pseudo-random number generation regardless of + insufficient entropy or refuse to run the protocol. The latter is + preferable. + +9.2 Transport + +9.2.1 Confidentiality + + It is beyond the scope of this document and the Secure Shell Working + Group to analyze or recommend specific ciphers other than the ones + which have been established and accepted within the industry. At the + time of this writing, ciphers commonly in use include 3DES, ARCFOUR, + twofish, serpent and blowfish. AES has been accepted by The + published as a US Federal Information Processing Standards [FIPS-197] + and the cryptographic community as being acceptable for this purpose + as well has accepted AES. As always, implementors and users should + check current literature to ensure that no recent vulnerabilities + have been found in ciphers used within products. Implementors should + also check to see which ciphers are considered to be relatively + stronger than others and should recommend their use to users over + relatively weaker ciphers. It would be considered good form for an + implementation to politely and unobtrusively notify a user that a + stronger cipher is available and should be used when a weaker one is + actively chosen. + + The "none" cipher is provided for debugging and SHOULD NOT be used + except for that purpose. It's cryptographic properties are + sufficiently described in RFC 2410, which will show that its use does + not meet the intent of this protocol. + + The relative merits of these and other ciphers may also be found in + current literature. Two references that may provide information on + the subject are [SCHNEIER] and [KAUFMAN,PERLMAN,SPECINER]. Both of + these describe the CBC mode of operation of certain ciphers and the + weakness of this scheme. Essentially, this mode is theoretically + vulnerable to chosen cipher-text attacks because of the high + predictability of the start of packet sequence. However, this attack + + + +Ylonen & Moffat Expires March 31, 2004 [Page 13] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + is still deemed difficult and not considered fully practicable + especially if relatively longer block sizes are used. + + Additionally, another CBC mode attack may be mitigated through the + insertion of packets containing SSH_MSG_IGNORE. Without this + technique, a specific attack may be successful. For this attack + (commonly known as the Rogaway attack + [ROGAWAY],[DAI],[BELLARE,KOHNO,NAMPREMPRE]) to work, the attacker + would need to know the IV of the next block that is going to be + encrypted. In CBC mode that is the output of the encryption of the + previous block. If the attacker does not have any way to see the + packet yet (i.e it is in the internal buffers of the ssh + implementation or even in the kernel) then this attack will not work. + If the last packet has been sent out to the network (i.e the attacker + has access to it) then he can use the attack. + + In the optimal case an implementor would need to add an extra packet + only if the packet has been sent out onto the network and there are + no other packets waiting for transmission. Implementors may wish to + check to see if there are any unsent packets awaiting transmission, + but unfortunately it is not normally easy to obtain this information + from the kernel or buffers. If there are not, then a packet + containing SSH_MSG_IGNORE SHOULD be sent. If a new packet is added + to the stream every time the attacker knows the IV that is supposed + to be used for the next packet, then the attacker will not be able to + guess the correct IV, thus the attack will never be successfull. + + As an example, consider the following case: + + + Client Server + ------ ------ + TCP(seq=x, len=500) -> + contains Record 1 + + [500 ms passes, no ACK] + + TCP(seq=x, len=1000) -> + contains Records 1,2 + + ACK + + + 1. The Nagle algorithm + TCP retransmits mean that the two records + get coalesced into a single TCP segment + 2. Record 2 is *not* at the beginning of the TCP segment and never + will be, since it gets ACKed. + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 14] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + 3. Yet, the attack is possible because Record 1 has already been + seen. + + As this example indicates, it's totally unsafe to use the existence + of unflushed data in the TCP buffers proper as a guide to whether you + need an empty packet, since when you do the second write(), the + buffers will contain the un-ACKed Record 1. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 15] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + On the other hand, it's perfectly safe to have the following + situation: + + + Client Server + ------ ------ + TCP(seq=x, len=500) -> + contains SSH_MSG_IGNORE + + TCP(seq=y, len=500) -> + contains Data + + Provided that the IV for second SSH Record is fixed after the data for + the Data packet is determined -i.e. you do: + read from user + encrypt null packet + encrypt data packet + + +9.2.2 Data Integrity + + This protocol does allow the Data Integrity mechanism to be disabled. + Implementors SHOULD be wary of exposing this feature for any purpose + other than debugging. Users and administrators SHOULD be explicitly + warned anytime the "none" MAC is enabled. + + So long as the "none" MAC is not used, this protocol provides data + integrity. + + Because MACs use a 32 bit sequence number, they might start to leak + information after 2**32 packets have been sent. However, following + the rekeying recommendations should prevent this attack. The + transport protocol [1] recommends rekeying after one gigabyte of + data, and the smallest possible packet is 16 bytes. Therefore, + rekeying SHOULD happen after 2**28 packets at the very most. + +9.2.3 Replay + + The use of a MAC other than 'none' provides integrity and + authentication. In addition, the transport protocol provides a + unique session identifier (bound in part to pseudo-random data that + is part of the algorithm and key exchange process) that can be used + by higher level protocols to bind data to a given session and prevent + replay of data from prior sessions. For example, the authentication + protocol uses this to prevent replay of signatures from previous + sessions. Because public key authentication exchanges are + cryptographically bound to the session (i.e., to the initial key + exchange) they cannot be successfully replayed in other sessions. + + + +Ylonen & Moffat Expires March 31, 2004 [Page 16] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + Note that the session ID can be made public without harming the + security of the protocol. + + If two session happen to have the same session ID [hash of key + exchanges] then packets from one can be replayed against the other. + It must be stressed that the chances of such an occurrence are, + needless to say, minimal when using modern cryptographic methods. + This is all the more so true when specifying larger hash function + outputs and DH parameters. + + Replay detection using monotonically increasing sequence numbers as + input to the MAC, or HMAC in some cases, is described in [RFC2085] /> + [RFC2246], [RFC2743], [RFC1964], [RFC2025], and [RFC1510]. The + underlying construct is discussed in [RFC2104]. Essentially a + different sequence number in each packet ensures that at least this + one input to the MAC function will be unique and will provide a + nonrecurring MAC output that is not predictable to an attacker. If + the session stays active long enough, however, this sequence number + will wrap. This event may provide an attacker an opportunity to + replay a previously recorded packet with an identical sequence number + but only if the peers have not rekeyed since the transmission of the + first packet with that sequence number. If the peers have rekeyed, + then the replay will be detected as the MAC check will fail. For + this reason, it must be emphasized that peers MUST rekey before a + wrap of the sequence numbers. Naturally, if an attacker does attempt + to replay a captured packet before the peers have rekeyed, then the + receiver of the duplicate packet will not be able to validate the MAC + and it will be discarded. The reason that the MAC will fail is + because the receiver will formulate a MAC based upon the packet + contents, the shared secret, and the expected sequence number. Since + the replayed packet will not be using that expected sequence number + (the sequence number of the replayed packet will have already been + passed by the receiver) then the calculated MAC will not match the + MAC received with the packet. + +9.2.4 Man-in-the-middle + + This protocol makes no assumptions nor provisions for an + infrastructure or means for distributing the public keys of hosts. It + is expected that this protocol will sometimes be used without first + verifying the association between the server host key and the server + host name. Such usage is vulnerable to man-in-the-middle attacks. + This section describes this and encourages administrators and users + to understand the importance of verifying this association before any + session is initiated. + + There are three cases of man-in-the-middle attacks to consider. The + first is where an attacker places a device between the client and the + + + +Ylonen & Moffat Expires March 31, 2004 [Page 17] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + server before the session is initiated. In this case, the attack + device is trying to mimic the legitimate server and will offer its + public key to the client when the client initiates a session. If it + were to offer the public key of the server, then it would not be able + to decrypt or sign the transmissions between the legitimate server + and the client unless it also had access to the private-key of the + host. The attack device will also, simultaneously to this, initiate + a session to the legitimate server masquerading itself as the client. + If the public key of the server had been securely distributed to the + client prior to that session initiation, the key offered to the + client by the attack device will not match the key stored on the + client. In that case, the user SHOULD be given a warning that the + offered host key does not match the host key cached on the client. + As described in Section 3.1 of [ARCH], the user may be free to accept + the new key and continue the session. It is RECOMMENDED that the + warning provide sufficient information to the user of the client + device so they may make an informed decision. If the user chooses to + continue the session with the stored public-key of the server (not + the public-key offered at the start of the session), then the session + specific data between the attacker and server will be different + between the client-to-attacker session and the attacker-to-server + sessions due to the randomness discussed above. From this, the + attacker will not be able to make this attack work since the attacker + will not be able to correctly sign packets containing this session + specific data from the server since he does not have the private key + of that server. + + The second case that should be considered is similar to the first + case in that it also happens at the time of connection but this case + points out the need for the secure distribution of server public + keys. If the server public keys are not securely distributed then + the client cannot know if it is talking to the intended server. An + attacker may use social engineering techniques to pass off server + keys to unsuspecting users and may then place a man-in-the-middle + attack device between the legitimate server and the clients. If this + is allowed to happen then the clients will form client-to-attacker + sessions and the attacker will form attacker-to-server sessions and + will be able to monitor and manipulate all of the traffic between the + clients and the legitimate servers. Server administrators are + encouraged to make host key fingerprints available for checking by + some means whose security does not rely on the integrity of the + actual host keys. Possible mechanisms are discussed in Section 3.1 + of [SSH-ARCH] and may also include secured Web pages, physical pieces + of paper, etc. Implementors SHOULD provide recommendations on how + best to do this with their implementation. Because the protocol is + extensible, future extensions to the protocol may provide better + mechanisms for dealing with the need to know the server's host key + before connecting. For example, making the host key fingerprint + + + +Ylonen & Moffat Expires March 31, 2004 [Page 18] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + available through a secure DNS lookup, or using kerberos over gssapi + during key exchange to authenticate the server are possibilities. + + In the third man-in-the-middle case, attackers may attempt to + manipulate packets in transit between peers after the session has + been established. As described in the Replay part of this section, a + successful attack of this nature is very improbable. As in the + Replay section, this reasoning does assume that the MAC is secure and + that it is infeasible to construct inputs to a MAC algorithm to give + a known output. This is discussed in much greater detail in Section + 6 of RFC 2104. If the MAC algorithm has a vulnerability or is weak + enough, then the attacker may be able to specify certain inputs to + yield a known MAC. With that they may be able to alter the contents + of a packet in transit. Alternatively the attacker may be able to + exploit the algorithm vulnerability or weakness to find the shared + secret by reviewing the MACs from captured packets. In either of + those cases, an attacker could construct a packet or packets that + could be inserted into an SSH stream. To prevent that, implementors + are encouraged to utilize commonly accepted MAC algorithms and + administrators are encouraged to watch current literature and + discussions of cryptography to ensure that they are not using a MAC + algorithm that has a recently found vulnerability or weakness. + + In summary, the use of this protocol without a reliable association + of the binding between a host and its host keys is inherently + insecure and is NOT RECOMMENDED. It may however be necessary in + non-security critical environments, and will still provide protection + against passive attacks. Implementors of protocols and applications + running on top of this protocol should keep this possibility in mind. + +9.2.5 Denial-of-service + + This protocol is designed to be used over a reliable transport. If + transmission errors or message manipulation occur, the connection is + closed. The connection SHOULD be re-established if this occurs. + Denial of service attacks of this type ("wire cutter") are almost + impossible to avoid. + + In addition, this protocol is vulnerable to Denial of Service attacks + because an attacker can force the server to go through the CPU and + memory intensive tasks of connection setup and key exchange without + authenticating. Implementors SHOULD provide features that make this + more difficult. For example, only allowing connections from a subset + of IPs known to have valid users. + +9.2.6 Covert Channels + + The protocol was not designed to eliminate covert channels. For + + + +Ylonen & Moffat Expires March 31, 2004 [Page 19] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + example, the padding, SSH_MSG_IGNORE messages, and several other + places in the protocol can be used to pass covert information, and + the recipient has no reliable way to verify whether such information + is being sent. + +9.2.7 Forward Secrecy + + It should be noted that the Diffie-Hellman key exchanges may provide + perfect forward secrecy (PFS). PFS is essentially defined as the + cryptographic property of a key-establishment protocol in which the + compromise of a session key or long-term private key after a given + session does not cause the compromise of any earlier session. [ANSI + T1.523-2001] SSHv2 sessions resulting from a key exchange using + diffie-hellman-group1-sha1 are secure even if private keying/ + authentication material is later revealed, but not if the session + keys are revealed. So, given this definition of PFS, SSHv2 does have + PFS. It is hoped that all other key exchange mechanisms proposed and + used in the future will also provide PFS. This property is not + commuted to any of the applications or protocols using SSH as a + transport however. The transport layer of SSH provides + confidentiality for password authentication and other methods that + rely on secret data. + + Of course, if the DH private parameters for the client and server are + revealed then the session key is revealed, but these items can be + thrown away after the key exchange completes. It's worth pointing + out that these items should not be allowed to end up on swap space + and that they should be erased from memory as soon as the key + exchange completes. + +9.3 Authentication Protocol + + The purpose of this protocol is to perform client user + authentication. It assumes that this run over a secure transport + layer protocol, which has already authenticated the server machine, + established an encrypted communications channel, and computed a + unique session identifier for this session. + + Several authentication methods with different security + characteristics are allowed. It is up to the server's local policy + to decide which methods (or combinations of methods) it is willing to + accept for each user. Authentication is no stronger than the weakest + combination allowed. + + The server may go into a "sleep" period after repeated unsuccessful + authentication attempts to make key search more difficult for + attackers. Care should be taken so that this doesn't become a + self-denial of service vector. + + + +Ylonen & Moffat Expires March 31, 2004 [Page 20] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + +9.3.1 Weak Transport + + If the transport layer does not provide confidentiality, + authentication methods that rely on secret data SHOULD be disabled. + If it does not provide strong integrity protection, requests to + change authentication data (e.g. a password change) SHOULD be + disabled to prevent an attacker from modifying the ciphertext + without being noticed, or rendering the new authentication data + unusable (denial of service). + + The assumption as stated above that the Authentication Protocol only + run over a secure transport that has previously authenticated the + server is very important to note. People deploying SSH are reminded + of the consequences of man-in-the-middle attacks if the client does + not have a very strong a priori association of the server with the + host key of that server. Specifically for the case of the + Authentication Protocol the client may form a session to a + man-in-the-middle attack device and divulge user credentials such as + their username and password. Even in the cases of authentication + where no user credentials are divulged, an attacker may still gain + information they shouldn't have by capturing key-strokes in much the + same way that a honeypot works. + +9.3.2 Debug messages + + Special care should be taken when designing debug messages. These + messages may reveal surprising amounts of information about the host + if not properly designed. Debug messages can be disabled (during + user authentication phase) if high security is required. + Administrators of host machines should make all attempts to + compartmentalize all event notification messages and protect them + from unwarranted observation. Developers should be aware of the + sensitive nature of some of the normal event messages and debug + messages and may want to provide guidance to administrators on ways + to keep this information away from unauthorized people. Developers + should consider minimizing the amount of sensitive information + obtainable by users during the authentication phase in accordance + with the local policies. For this reason, it is RECOMMENDED that + debug messages be initially disabled at the time of deployment and + require an active decision by an administrator to allow them to be + enabled. It is also RECOMMENDED that a message expressing this + concern be presented to the administrator of a system when the action + is taken to enable debugging messages. + +9.3.3 Local security policy + + Implementer MUST ensure that the credentials provided validate the + professed user and also MUST ensure that the local policy of the + + + +Ylonen & Moffat Expires March 31, 2004 [Page 21] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + server permits the user the access requested. In particular, because + of the flexible nature of the SSH connection protocol, it may not be + possible to determine the local security policy, if any, that should + apply at the time of authentication because the kind of service being + requested is not clear at that instant. For example, local policy + might allow a user to access files on the server, but not start an + interactive shell. However, during the authentication protocol, it is + not known whether the user will be accessing files or attempting to + use an interactive shell, or even both. In any event, where local + security policy for the server host exists, it MUST be applied and + enforced correctly. + + Implementors are encouraged to provide a default local policy and + make its parameters known to administrators and users. At the + discretion of the implementors, this default policy may be along the + lines of 'anything goes' where there are no restrictions placed upon + users, or it may be along the lines of 'excessively restrictive' in + which case the administrators will have to actively make changes to + this policy to meet their needs. Alternatively, it may be some + attempt at providing something practical and immediately useful to + the administrators of the system so they don't have to put in much + effort to get SSH working. Whatever choice is made MUST be applied + and enforced as required above. + +9.3.4 Public key authentication + + The use of public-key authentication assumes that the client host has + not been compromised. It also assumes that the private-key of the + server host has not been compromised. + + This risk can be mitigated by the use of passphrases on private keys; + however, this is not an enforceable policy. The use of smartcards, + or other technology to make passphrases an enforceable policy is + suggested. + + The server could require both password and public-key authentication, + however, this requires the client to expose its password to the + server (see section on password authentication below.) + +9.3.5 Password authentication + + The password mechanism as specified in the authentication protocol + assumes that the server has not been compromised. If the server has + been compromised, using password authentication will reveal a valid + username / password combination to the attacker, which may lead to + further compromises. + + This vulnerability can be mitigated by using an alternative form of + + + +Ylonen & Moffat Expires March 31, 2004 [Page 22] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + authentication. For example, public-key authentication makes no + assumptions about security on the server. + +9.3.6 Host based authentication + + Host based authentication assumes that the client has not been + compromised. There are no mitigating strategies, other than to use + host based authentication in combination with another authentication + method. + +9.4 Connection protocol + +9.4.1 End point security + + End point security is assumed by the connection protocol. If the + server has been compromised, any terminal sessions, port forwarding, + or systems accessed on the host are compromised. There are no + mitigating factors for this. + + If the client end point has been compromised, and the server fails to + stop the attacker at the authentication protocol, all services + exposed (either as subsystems or through forwarding) will be + vulnerable to attack. Implementors SHOULD provide mechanisms for + administrators to control which services are exposed to limit the + vulnerability of other services. + + These controls might include controlling which machines and ports can + be target in 'port-forwarding' operations, which users are allowed to + use interactive shell facilities, or which users are allowed to use + exposed subsystems. + +9.4.2 Proxy forwarding + + The SSH connection protocol allows for proxy forwarding of other + protocols such as SNMP, POP3, and HTTP. This may be a concern for + network administrators who wish to control the access of certain + applications by users located outside of their physical location. + Essentially, the forwarding of these protocols may violate site + specific security policies as they may be undetectably tunneled + through a firewall. Implementors SHOULD provide an administrative + mechanism to control the proxy forwarding functionality so that site + specific security policies may be upheld. + + In addition, a reverse proxy forwarding functionality is available, + which again can be used to bypass firewall controls. + + As indicated above, end-point security is assumed during proxy + forwarding operations. Failure of end-point security will compromise + + + +Ylonen & Moffat Expires March 31, 2004 [Page 23] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + all data passed over proxy forwarding. + +9.4.3 X11 forwarding + + Another form of proxy forwarding provided by the ssh connection + protocol is the forwarding of the X11 protocol. If end-point + security has been compromised, X11 forwarding may allow attacks + against the X11 server. Users and administrators should, as a matter + of course, use appropriate X11 security mechanisms to prevent + unauthorized use of the X11 server. Implementors, administrators and + users who wish to further explore the security mechanisms of X11 are + invited to read [SCHEIFLER] and analyze previously reported problems + with the interactions between SSH forwarding and X11 in CERT + vulnerabilities VU#363181 and VU#118892 [CERT]. + + X11 display forwarding with SSH, by itself, is not sufficient to + correct well known problems with X11 security [VENEMA]. However, X11 + display forwarding in SSHv2 (or other, secure protocols), combined + with actual and pseudo-displays which accept connections only over + local IPC mechanisms authorized by permissions or ACLs, does correct + many X11 security problems as long as the "none" MAC is not used. It + is RECOMMENDED that X11 display implementations default to allowing + display opens only over local IPC. It is RECOMMENDED that SSHv2 + server implementations that support X11 forwarding default to + allowing display opens only over local IPC. On single-user systems + it might be reasonable to default to allowing local display opens + over TCP/IP. + + Implementors of the X11 forwarding protocol SHOULD implement the + magic cookie access checking spoofing mechanism as described in + [ssh-connect] as an additional mechanism to prevent unauthorized use + of the proxy. + +Normative References + + [SSH-ARCH] + Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-15.txt, Oct 2003. + + [SSH-TRANS] + Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-17.txt, Oct 2003. + + [SSH-USERAUTH] + Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-18.txt, Oct 2003. + + [SSH-CONNECT] + + + +Ylonen & Moffat Expires March 31, 2004 [Page 24] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + Ylonen, T., "SSH Connection Protocol", I-D + draft-ietf-connect-18.txt, Oct 2003. + + [SSH-NUMBERS] + Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct + 2003. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +Informative References + + [FIPS-186] + Federal Information Processing Standards Publication, + "FIPS PUB 186, Digital Signature Standard", May 1994. + + [FIPS-197] + National Institue of Standards and Technology, "FIPS 197, + Specification for the Advanced Encryption Standard", + November 2001. + + [ANSI T1.523-2001] + American National Standards Insitute, Inc., "Telecom + Glossary 2000", February 2001. + + [SCHEIFLER] + Scheifler, R., "X Window System : The Complete Reference + to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital + Press ISBN 1555580882, Feburary 1992. + + [RFC0854] Postel, J. and J. Reynolds, "Telnet Protocol + Specification", STD 8, RFC 854, May 1983. + + [RFC0894] Hornig, C., "Standard for the transmission of IP datagrams + over Ethernet networks", STD 41, RFC 894, April 1984. + + [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", + STD 13, RFC 1034, November 1987. + + [RFC1134] Perkins, D., "Point-to-Point Protocol: A proposal for + multi-protocol transmission of datagrams over + Point-to-Point links", RFC 1134, November 1989. + + [RFC1282] Kantor, B., "BSD Rlogin", RFC 1282, December 1991. + + [RFC1510] Kohl, J. and B. Neuman, "The Kerberos Network + Authentication Service (V5)", RFC 1510, September 1993. + + + +Ylonen & Moffat Expires March 31, 2004 [Page 25] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + [RFC1700] Reynolds, J. and J. Postel, "Assigned Numbers", RFC 1700, + October 1994. + + [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness + Recommendations for Security", RFC 1750, December 1994. + + [RFC3066] Alvestrand, H., "Tags for the Identification of + Languages", BCP 47, RFC 3066, January 2001. + + [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC + 1964, June 1996. + + [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism + (SPKM)", RFC 2025, October 1996. + + [RFC2085] Oehler, M. and R. Glenn, "HMAC-MD5 IP Authentication with + Replay Prevention", RFC 2085, February 1997. + + [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: + Keyed-Hashing for Message Authentication", RFC 2104, + February 1997. + + [RFC2246] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. + and P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, + January 1999. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + [RFC2410] Glenn, R. and S. Kent, "The NULL Encryption Algorithm and + Its Use With IPsec", RFC 2410, November 1998. + + [RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 2434, + October 1998. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [SCHNEIER] + Schneier, B., "Applied Cryptography Second Edition: + protocols algorithms and source in code in C", 1996. + + [KAUFMAN,PERLMAN,SPECINER] + Kaufman, C., Perlman, R. and M. Speciner, "Network + Security: PRIVATE Communication in a PUBLIC World", 1995. + + [CERT] CERT Coordination Center, The., "http://www.cert.org/nav/ + + + +Ylonen & Moffat Expires March 31, 2004 [Page 26] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + index_red.html". + + [VENEMA] Venema, W., "Murphy's Law and Computer Security", + Proceedings of 6th USENIX Security Symposium, San Jose CA + http://www.usenix.org/publications/library/proceedings/ + sec96/venema.html, July 1996. + + [ROGAWAY] Rogaway, P., "Problems with Proposed IP Cryptography", + Unpublished paper http://www.cs.ucdavis.edu/~rogaway/ + papers/draft-rogaway-ipsec-comments-00.txt, 1996. + + [DAI] Dai, W., "An attack against SSH2 protocol", Email to the + SECSH Working Group [email protected] ftp:// + ftp.ietf.org/ietf-mail-archive/secsh/2002-02.mail, Feb + 2002. + + [BELLARE,KOHNO,NAMPREMPRE] + Bellaire, M., Kohno, T. and C. Namprempre, "Authenticated + Encryption in SSH: Fixing the SSH Binary Packet Protocol", + , Sept 2002. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Darren J. Moffat (editor) + Sun Microsystems, Inc + 17 Network Circle + Menlo Park CA 94025 + USA + + EMail: [email protected] + + + + + + + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 27] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + + +Ylonen & Moffat Expires March 31, 2004 [Page 28] + +Internet-Draft SSH Protocol Architecture Oct 2003 + + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat Expires March 31, 2004 [Page 29]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps new file mode 100644 index 0000000000..7a386724c2 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.2.ps @@ -0,0 +1,2557 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Fri Oct 31 13:33:02 2003 +%%Orientation: Portrait +%%Pages: 11 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Network Working Group T. Ylonen) s +5 690 M +(Internet-Draft SSH Communications Security Corp) s +5 679 M +(Expires: March 31, 2004 D. Moffat, Editor, Ed.) s +5 668 M +( Sun Microsystems, Inc) s +5 657 M +( Oct 2003) s +5 624 M +( SSH Connection Protocol) s +5 613 M +( draft-ietf-secsh-connect-18.txt) s +5 591 M +(Status of this Memo) s +5 569 M +( This document is an Internet-Draft and is in full conformance with) s +5 558 M +( all provisions of Section 10 of RFC2026.) s +5 536 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 525 M +( Task Force \(IETF\), its areas, and its working groups. Note that other) s +5 514 M +( groups may also distribute working documents as Internet-Drafts.) s +5 492 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 481 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 470 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 459 M +( material or to cite them other than as "work in progress.") s +5 437 M +( The list of current Internet-Drafts can be accessed at http://) s +5 426 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 404 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 393 M +( http://www.ietf.org/shadow.html.) s +5 371 M +( This Internet-Draft will expire on March 31, 2004.) s +5 349 M +(Copyright Notice) s +5 327 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 305 M +(Abstract) s +5 283 M +( SSH is a protocol for secure remote login and other secure network) s +5 272 M +( services over an insecure network.) s +5 250 M +( This document describes the SSH Connection Protocol. It provides) s +5 239 M +( interactive login sessions, remote execution of commands, forwarded) s +5 228 M +( TCP/IP connections, and forwarded X11 connections. All of these) s +5 217 M +( channels are multiplexed into a single encrypted tunnel.) s +5 195 M +( The SSH Connection Protocol has been designed to run on top of the) s +5 184 M +( SSH transport layer and user authentication protocols.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(Table of Contents) s +5 668 M +( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 657 M +( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 646 M +( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s +5 635 M +( 4. Global Requests . . . . . . . . . . . . . . . . . . . . . . 3) s +5 624 M +( 5. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . 4) s +5 613 M +( 5.1 Opening a Channel . . . . . . . . . . . . . . . . . . . . . 4) s +5 602 M +( 5.2 Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 5) s +5 591 M +( 5.3 Closing a Channel . . . . . . . . . . . . . . . . . . . . . 6) s +5 580 M +( 5.4 Channel-Specific Requests . . . . . . . . . . . . . . . . . 7) s +5 569 M +( 6. Interactive Sessions . . . . . . . . . . . . . . . . . . . . 8) s +5 558 M +( 6.1 Opening a Session . . . . . . . . . . . . . . . . . . . . . 8) s +5 547 M +( 6.2 Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 8) s +5 536 M +( 6.3 X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 9) s +5 525 M +( 6.3.1 Requesting X11 Forwarding . . . . . . . . . . . . . . . . . 9) s +5 514 M +( 6.3.2 X11 Channels . . . . . . . . . . . . . . . . . . . . . . . . 10) s +5 503 M +( 6.4 Environment Variable Passing . . . . . . . . . . . . . . . . 10) s +5 492 M +( 6.5 Starting a Shell or a Command . . . . . . . . . . . . . . . 10) s +5 481 M +( 6.6 Session Data Transfer . . . . . . . . . . . . . . . . . . . 11) s +5 470 M +( 6.7 Window Dimension Change Message . . . . . . . . . . . . . . 12) s +5 459 M +( 6.8 Local Flow Control . . . . . . . . . . . . . . . . . . . . . 12) s +5 448 M +( 6.9 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 12) s +5 437 M +( 6.10 Returning Exit Status . . . . . . . . . . . . . . . . . . . 13) s +5 426 M +( 7. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . 14) s +5 415 M +( 7.1 Requesting Port Forwarding . . . . . . . . . . . . . . . . . 14) s +5 404 M +( 7.2 TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 15) s +5 393 M +( 8. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . 16) s +5 382 M +( 9. Summary of Message Numbers . . . . . . . . . . . . . . . . . 18) s +5 371 M +( 10. Security Considerations . . . . . . . . . . . . . . . . . . 18) s +5 360 M +( 11. iana cONSiderations . . . . . . . . . . . . . . . . . . . . 19) s +5 349 M +( 12. Intellectual Property . . . . . . . . . . . . . . . . . . . 19) s +5 338 M +( Normative References . . . . . . . . . . . . . . . . . . . . 19) s +5 327 M +( Informative References . . . . . . . . . . . . . . . . . . . 20) s +5 316 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20) s +5 305 M +( Intellectual Property and Copyright Statements . . . . . . . 21) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(1. Contributors) s +5 668 M +( The major original contributors of this document were: Tatu Ylonen,) s +5 657 M +( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s +5 646 M +( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s +5 635 M +( Jyvaskyla\)) s +5 613 M +( The document editor is: [email protected]. Comments on this) s +5 602 M +( internet draft should be sent to the IETF SECSH working group,) s +5 591 M +( details at: http://ietf.org/html.charters/secsh-charter.html) s +5 569 M +(2. Introduction) s +5 547 M +( The SSH Connection Protocol has been designed to run on top of the) s +5 536 M +( SSH transport layer and user authentication protocols. It provides) s +5 525 M +( interactive login sessions, remote execution of commands, forwarded) s +5 514 M +( TCP/IP connections, and forwarded X11 connections. The service name) s +5 503 M +( for this protocol is "ssh-connection".) s +5 481 M +( This document should be read only after reading the SSH architecture) s +5 470 M +( document [SSH-ARCH]. This document freely uses terminology and) s +5 459 M +( notation from the architecture document without reference or further) s +5 448 M +( explanation.) s +5 426 M +(3. Conventions Used in This Document) s +5 404 M +( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s +5 393 M +( and "MAY" that appear in this document are to be interpreted as) s +5 382 M +( described in [RFC2119].) s +5 360 M +( The used data types and terminology are specified in the architecture) s +5 349 M +( document [SSH-ARCH].) s +5 327 M +( The architecture document also discusses the algorithm naming) s +5 316 M +( conventions that MUST be used with the SSH protocols.) s +5 294 M +(4. Global Requests) s +5 272 M +( There are several kinds of requests that affect the state of the) s +5 261 M +( remote end "globally", independent of any channels. An example is a) s +5 250 M +( request to start TCP/IP forwarding for a specific port. All such) s +5 239 M +( requests use the following format.) s +5 217 M +( byte SSH_MSG_GLOBAL_REQUEST) s +5 206 M +( string request name \(restricted to US-ASCII\)) s +5 195 M +( boolean want reply) s +5 184 M +( ... request-specific data follows) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( Request names follow the DNS extensibility naming convention outlined) s +5 679 M +( in [SSH-ARCH].) s +5 657 M +( The recipient will respond to this message with) s +5 646 M +( SSH_MSG_REQUEST_SUCCESS or SSH_MSG_REQUEST_FAILURE if `want reply' is) s +5 635 M +( TRUE.) s +5 613 M +( byte SSH_MSG_REQUEST_SUCCESS) s +5 602 M +( ..... response specific data) s +5 580 M +( Usually the response specific data is non-existent.) s +5 558 M +( If the recipient does not recognize or support the request, it simply) s +5 547 M +( responds with SSH_MSG_REQUEST_FAILURE.) s +5 525 M +( byte SSH_MSG_REQUEST_FAILURE) s +5 492 M +(5. Channel Mechanism) s +5 470 M +( All terminal sessions, forwarded connections, etc. are channels.) s +5 459 M +( Either side may open a channel. Multiple channels are multiplexed) s +5 448 M +( into a single connection.) s +5 426 M +( Channels are identified by numbers at each end. The number referring) s +5 415 M +( to a channel may be different on each side. Requests to open a) s +5 404 M +( channel contain the sender's channel number. Any other) s +5 393 M +( channel-related messages contain the recipient's channel number for) s +5 382 M +( the channel.) s +5 360 M +( Channels are flow-controlled. No data may be sent to a channel until) s +5 349 M +( a message is received to indicate that window space is available.) s +5 327 M +(5.1 Opening a Channel) s +5 305 M +( When either side wishes to open a new channel, it allocates a local) s +5 294 M +( number for the channel. It then sends the following message to the) s +5 283 M +( other side, and includes the local channel number and initial window) s +5 272 M +( size in the message.) s +5 250 M +( byte SSH_MSG_CHANNEL_OPEN) s +5 239 M +( string channel type \(restricted to US-ASCII\)) s +5 228 M +( uint32 sender channel) s +5 217 M +( uint32 initial window size) s +5 206 M +( uint32 maximum packet size) s +5 195 M +( ... channel type specific data follows) s +5 173 M +( The channel type is a name as described in the SSH architecture) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( document, with similar extension mechanisms. `sender channel' is a) s +5 679 M +( local identifier for the channel used by the sender of this message.) s +5 668 M +( `initial window size' specifies how many bytes of channel data can be) s +5 657 M +( sent to the sender of this message without adjusting the window.) s +5 646 M +( `Maximum packet size' specifies the maximum size of an individual) s +5 635 M +( data packet that can be sent to the sender \(for example, one might) s +5 624 M +( want to use smaller packets for interactive connections to get better) s +5 613 M +( interactive response on slow links\).) s +5 591 M +( The remote side then decides whether it can open the channel, and) s +5 580 M +( responds with either) s +5 558 M +( byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION) s +5 547 M +( uint32 recipient channel) s +5 536 M +( uint32 sender channel) s +5 525 M +( uint32 initial window size) s +5 514 M +( uint32 maximum packet size) s +5 503 M +( ... channel type specific data follows) s +5 481 M +( where `recipient channel' is the channel number given in the original) s +5 470 M +( open request, and `sender channel' is the channel number allocated by) s +5 459 M +( the other side, or) s +5 437 M +( byte SSH_MSG_CHANNEL_OPEN_FAILURE) s +5 426 M +( uint32 recipient channel) s +5 415 M +( uint32 reason code) s +5 404 M +( string additional textual information \(ISO-10646 UTF-8 [RFC2279]\)) s +5 393 M +( string language tag \(as defined in [RFC3066]\)) s +5 371 M +( If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support) s +5 360 M +( the specified channel type, it simply responds with) s +5 349 M +( SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional) s +5 338 M +( information to the user. If this is done, the client software should) s +5 327 M +( take the precautions discussed in [SSH-ARCH].) s +5 305 M +( The following reason codes are defined:) s +5 283 M +( #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1) s +5 272 M +( #define SSH_OPEN_CONNECT_FAILED 2) s +5 261 M +( #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3) s +5 250 M +( #define SSH_OPEN_RESOURCE_SHORTAGE 4) s +5 217 M +(5.2 Data Transfer) s +5 195 M +( The window size specifies how many bytes the other party can send) s +5 184 M +( before it must wait for the window to be adjusted. Both parties use) s +5 173 M +( the following message to adjust the window.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( byte SSH_MSG_CHANNEL_WINDOW_ADJUST) s +5 679 M +( uint32 recipient channel) s +5 668 M +( uint32 bytes to add) s +5 646 M +( After receiving this message, the recipient MAY send the given number) s +5 635 M +( of bytes more than it was previously allowed to send; the window size) s +5 624 M +( is incremented.) s +5 602 M +( Data transfer is done with messages of the following type.) s +5 580 M +( byte SSH_MSG_CHANNEL_DATA) s +5 569 M +( uint32 recipient channel) s +5 558 M +( string data) s +5 536 M +( The maximum amount of data allowed is the current window size. The) s +5 525 M +( window size is decremented by the amount of data sent. Both parties) s +5 514 M +( MAY ignore all extra data sent after the allowed window is empty.) s +5 492 M +( Additionally, some channels can transfer several types of data. An) s +5 481 M +( example of this is stderr data from interactive sessions. Such data) s +5 470 M +( can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a) s +5 459 M +( separate integer specifies the type of the data. The available types) s +5 448 M +( and their interpretation depend on the type of the channel.) s +5 426 M +( byte SSH_MSG_CHANNEL_EXTENDED_DATA) s +5 415 M +( uint32 recipient_channel) s +5 404 M +( uint32 data_type_code) s +5 393 M +( string data) s +5 371 M +( Data sent with these messages consumes the same window as ordinary) s +5 360 M +( data.) s +5 338 M +( Currently, only the following type is defined.) s +5 316 M +( #define SSH_EXTENDED_DATA_STDERR 1) s +5 283 M +(5.3 Closing a Channel) s +5 261 M +( When a party will no longer send more data to a channel, it SHOULD) s +5 250 M +( send SSH_MSG_CHANNEL_EOF.) s +5 228 M +( byte SSH_MSG_CHANNEL_EOF) s +5 217 M +( uint32 recipient_channel) s +5 195 M +( No explicit response is sent to this message; however, the) s +5 184 M +( application may send EOF to whatever is at the other end of the) s +5 173 M +( channel. Note that the channel remains open after this message, and) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( more data may still be sent in the other direction. This message) s +5 679 M +( does not consume window space and can be sent even if no window space) s +5 668 M +( is available.) s +5 646 M +( When either party wishes to terminate the channel, it sends) s +5 635 M +( SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST) s +5 624 M +( send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this) s +5 613 M +( message for the channel. The channel is considered closed for a) s +5 602 M +( party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and) s +5 591 M +( the party may then reuse the channel number. A party MAY send) s +5 580 M +( SSH_MSG_CHANNEL_CLOSE without having sent or received) s +5 569 M +( SSH_MSG_CHANNEL_EOF.) s +5 547 M +( byte SSH_MSG_CHANNEL_CLOSE) s +5 536 M +( uint32 recipient_channel) s +5 514 M +( This message does not consume window space and can be sent even if no) s +5 503 M +( window space is available.) s +5 481 M +( It is recommended that any data sent before this message is delivered) s +5 470 M +( to the actual destination, if possible.) s +5 448 M +(5.4 Channel-Specific Requests) s +5 426 M +( Many channel types have extensions that are specific to that) s +5 415 M +( particular channel type. An example is requesting a pty \(pseudo) s +5 404 M +( terminal\) for an interactive session.) s +5 382 M +( All channel-specific requests use the following format.) s +5 360 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 349 M +( uint32 recipient channel) s +5 338 M +( string request type \(restricted to US-ASCII\)) s +5 327 M +( boolean want reply) s +5 316 M +( ... type-specific data) s +5 294 M +( If want reply is FALSE, no response will be sent to the request.) s +5 283 M +( Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS) s +5 272 M +( or SSH_MSG_CHANNEL_FAILURE, or request-specific continuation) s +5 261 M +( messages. If the request is not recognized or is not supported for) s +5 250 M +( the channel, SSH_MSG_CHANNEL_FAILURE is returned.) s +5 228 M +( This message does not consume window space and can be sent even if no) s +5 217 M +( window space is available. Request types are local to each channel) s +5 206 M +( type.) s +5 184 M +( The client is allowed to send further messages without waiting for) s +5 173 M +( the response to the request.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( request type names follow the DNS extensibility naming convention) s +5 679 M +( outlined in [SSH-ARCH]) s +5 657 M +( byte SSH_MSG_CHANNEL_SUCCESS) s +5 646 M +( uint32 recipient_channel) s +5 613 M +( byte SSH_MSG_CHANNEL_FAILURE) s +5 602 M +( uint32 recipient_channel) s +5 580 M +( These messages do not consume window space and can be sent even if no) s +5 569 M +( window space is available.) s +5 547 M +(6. Interactive Sessions) s +5 525 M +( A session is a remote execution of a program. The program may be a) s +5 514 M +( shell, an application, a system command, or some built-in subsystem.) s +5 503 M +( It may or may not have a tty, and may or may not involve X11) s +5 492 M +( forwarding. Multiple sessions can be active simultaneously.) s +5 470 M +(6.1 Opening a Session) s +5 448 M +( A session is started by sending the following message.) s +5 426 M +( byte SSH_MSG_CHANNEL_OPEN) s +5 415 M +( string "session") s +5 404 M +( uint32 sender channel) s +5 393 M +( uint32 initial window size) s +5 382 M +( uint32 maximum packet size) s +5 360 M +( Client implementations SHOULD reject any session channel open) s +5 349 M +( requests to make it more difficult for a corrupt server to attack the) s +5 338 M +( client.) s +5 316 M +(6.2 Requesting a Pseudo-Terminal) s +5 294 M +( A pseudo-terminal can be allocated for the session by sending the) s +5 283 M +( following message.) s +5 261 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 250 M +( uint32 recipient_channel) s +5 239 M +( string "pty-req") s +5 228 M +( boolean want_reply) s +5 217 M +( string TERM environment variable value \(e.g., vt100\)) s +5 206 M +( uint32 terminal width, characters \(e.g., 80\)) s +5 195 M +( uint32 terminal height, rows \(e.g., 24\)) s +5 184 M +( uint32 terminal width, pixels \(e.g., 640\)) s +5 173 M +( uint32 terminal height, pixels \(e.g., 480\)) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( string encoded terminal modes) s +5 668 M +( The encoding of terminal modes is described in Section Encoding of) s +5 657 M +( Terminal Modes \(Section 8\). Zero dimension parameters MUST be) s +5 646 M +( ignored. The character/row dimensions override the pixel dimensions) s +5 635 M +( \(when nonzero\). Pixel dimensions refer to the drawable area of the) s +5 624 M +( window.) s +5 602 M +( The dimension parameters are only informational.) s +5 580 M +( The client SHOULD ignore pty requests.) s +5 558 M +(6.3 X11 Forwarding) s +5 536 M +(6.3.1 Requesting X11 Forwarding) s +5 514 M +( X11 forwarding may be requested for a session by sending) s +5 492 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 481 M +( uint32 recipient channel) s +5 470 M +( string "x11-req") s +5 459 M +( boolean want reply) s +5 448 M +( boolean single connection) s +5 437 M +( string x11 authentication protocol) s +5 426 M +( string x11 authentication cookie) s +5 415 M +( uint32 x11 screen number) s +5 393 M +( It is recommended that the authentication cookie that is sent be a) s +5 382 M +( fake, random cookie, and that the cookie is checked and replaced by) s +5 371 M +( the real cookie when a connection request is received.) s +5 349 M +( X11 connection forwarding should stop when the session channel is) s +5 338 M +( closed; however, already opened forwardings should not be) s +5 327 M +( automatically closed when the session channel is closed.) s +5 305 M +( If `single connection' is TRUE, only a single connection should be) s +5 294 M +( forwarded. No more connections will be forwarded after the first, or) s +5 283 M +( after the session channel has been closed.) s +5 261 M +( The "x11 authentication protocol" is the name of the X11) s +5 250 M +( authentication method used, e.g. "MIT-MAGIC-COOKIE-1".) s +5 228 M +( The x11 authentication cookie MUST be hexadecimal encoded.) s +5 206 M +( X Protocol is documented in [SCHEIFLER].) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(6.3.2 X11 Channels) s +5 668 M +( X11 channels are opened with a channel open request. The resulting) s +5 657 M +( channels are independent of the session, and closing the session) s +5 646 M +( channel does not close the forwarded X11 channels.) s +5 624 M +( byte SSH_MSG_CHANNEL_OPEN) s +5 613 M +( string "x11") s +5 602 M +( uint32 sender channel) s +5 591 M +( uint32 initial window size) s +5 580 M +( uint32 maximum packet size) s +5 569 M +( string originator address \(e.g. "192.168.7.38"\)) s +5 558 M +( uint32 originator port) s +5 536 M +( The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION) s +5 525 M +( or SSH_MSG_CHANNEL_OPEN_FAILURE.) s +5 503 M +( Implementations MUST reject any X11 channel open requests if they) s +5 492 M +( have not requested X11 forwarding.) s +5 470 M +(6.4 Environment Variable Passing) s +5 448 M +( Environment variables may be passed to the shell/command to be) s +5 437 M +( started later. Uncontrolled setting of environment variables in a) s +5 426 M +( privileged process can be a security hazard. It is recommended that) s +5 415 M +( implementations either maintain a list of allowable variable names or) s +5 404 M +( only set environment variables after the server process has dropped) s +5 393 M +( sufficient privileges.) s +5 371 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 360 M +( uint32 recipient channel) s +5 349 M +( string "env") s +5 338 M +( boolean want reply) s +5 327 M +( string variable name) s +5 316 M +( string variable value) s +5 283 M +(6.5 Starting a Shell or a Command) s +5 261 M +( Once the session has been set up, a program is started at the remote) s +5 250 M +( end. The program can be a shell, an application program or a) s +5 239 M +( subsystem with a host-independent name. Only one of these requests) s +5 228 M +( can succeed per channel.) s +5 206 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 195 M +( uint32 recipient channel) s +5 184 M +( string "shell") s +5 173 M +( boolean want reply) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( This message will request the user's default shell \(typically defined) s +5 679 M +( in /etc/passwd in UNIX systems\) to be started at the other end.) s +5 657 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 646 M +( uint32 recipient channel) s +5 635 M +( string "exec") s +5 624 M +( boolean want reply) s +5 613 M +( string command) s +5 591 M +( This message will request the server to start the execution of the) s +5 580 M +( given command. The command string may contain a path. Normal) s +5 569 M +( precautions MUST be taken to prevent the execution of unauthorized) s +5 558 M +( commands.) s +5 536 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 525 M +( uint32 recipient channel) s +5 514 M +( string "subsystem") s +5 503 M +( boolean want reply) s +5 492 M +( string subsystem name) s +5 470 M +( This last form executes a predefined subsystem. It is expected that) s +5 459 M +( these will include a general file transfer mechanism, and possibly) s +5 448 M +( other features. Implementations may also allow configuring more such) s +5 437 M +( mechanisms. As the user's shell is usually used to execute the) s +5 426 M +( subsystem, it is advisable for the subsystem protocol to have a) s +5 415 M +( "magic cookie" at the beginning of the protocol transaction to) s +5 404 M +( distinguish it from arbitrary output generated by shell) s +5 393 M +( initialization scripts etc. This spurious output from the shell may) s +5 382 M +( be filtered out either at the server or at the client.) s +5 360 M +( The server SHOULD not halt the execution of the protocol stack when) s +5 349 M +( starting a shell or a program. All input and output from these SHOULD) s +5 338 M +( be redirected to the channel or to the encrypted tunnel.) s +5 316 M +( It is RECOMMENDED to request and check the reply for these messages.) s +5 305 M +( The client SHOULD ignore these messages.) s +5 283 M +( Subsystem names follow the DNS extensibility naming convention) s +5 272 M +( outlined in [SSH-ARCH].) s +5 250 M +(6.6 Session Data Transfer) s +5 228 M +( Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and) s +5 217 M +( SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The) s +5 206 M +( extended data type SSH_EXTENDED_DATA_STDERR has been defined for) s +5 195 M +( stderr data.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(6.7 Window Dimension Change Message) s +5 668 M +( When the window \(terminal\) size changes on the client side, it MAY) s +5 657 M +( send a message to the other side to inform it of the new dimensions.) s +5 635 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 624 M +( uint32 recipient_channel) s +5 613 M +( string "window-change") s +5 602 M +( boolean FALSE) s +5 591 M +( uint32 terminal width, columns) s +5 580 M +( uint32 terminal height, rows) s +5 569 M +( uint32 terminal width, pixels) s +5 558 M +( uint32 terminal height, pixels) s +5 536 M +( No response SHOULD be sent to this message.) s +5 514 M +(6.8 Local Flow Control) s +5 492 M +( On many systems, it is possible to determine if a pseudo-terminal is) s +5 481 M +( using control-S/control-Q flow control. When flow control is) s +5 470 M +( allowed, it is often desirable to do the flow control at the client) s +5 459 M +( end to speed up responses to user requests. This is facilitated by) s +5 448 M +( the following notification. Initially, the server is responsible for) s +5 437 M +( flow control. \(Here, again, client means the side originating the) s +5 426 M +( session, and server means the other side.\)) s +5 404 M +( The message below is used by the server to inform the client when it) s +5 393 M +( can or cannot perform flow control \(control-S/control-Q processing\).) s +5 382 M +( If `client can do' is TRUE, the client is allowed to do flow control) s +5 371 M +( using control-S and control-Q. The client MAY ignore this message.) s +5 349 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 338 M +( uint32 recipient channel) s +5 327 M +( string "xon-xoff") s +5 316 M +( boolean FALSE) s +5 305 M +( boolean client can do) s +5 283 M +( No response is sent to this message.) s +5 261 M +(6.9 Signals) s +5 239 M +( A signal can be delivered to the remote process/service using the) s +5 228 M +( following message. Some systems may not implement signals, in which) s +5 217 M +( case they SHOULD ignore this message.) s +5 195 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 184 M +( uint32 recipient channel) s +5 173 M +( string "signal") s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( boolean FALSE) s +5 679 M +( string signal name without the "SIG" prefix.) s +5 657 M +( Signal names will be encoded as discussed in the "exit-signal") s +5 646 M +( SSH_MSG_CHANNEL_REQUEST.) s +5 624 M +(6.10 Returning Exit Status) s +5 602 M +( When the command running at the other end terminates, the following) s +5 591 M +( message can be sent to return the exit status of the command.) s +5 580 M +( Returning the status is RECOMMENDED. No acknowledgment is sent for) s +5 569 M +( this message. The channel needs to be closed with) s +5 558 M +( SSH_MSG_CHANNEL_CLOSE after this message.) s +5 536 M +( The client MAY ignore these messages.) s +5 514 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 503 M +( uint32 recipient_channel) s +5 492 M +( string "exit-status") s +5 481 M +( boolean FALSE) s +5 470 M +( uint32 exit_status) s +5 448 M +( The remote command may also terminate violently due to a signal.) s +5 437 M +( Such a condition can be indicated by the following message. A zero) s +5 426 M +( exit_status usually means that the command terminated successfully.) s +5 404 M +( byte SSH_MSG_CHANNEL_REQUEST) s +5 393 M +( uint32 recipient channel) s +5 382 M +( string "exit-signal") s +5 371 M +( boolean FALSE) s +5 360 M +( string signal name without the "SIG" prefix.) s +5 349 M +( boolean core dumped) s +5 338 M +( string error message \(ISO-10646 UTF-8\)) s +5 327 M +( string language tag \(as defined in [RFC3066]\)) s +5 305 M +( The signal name is one of the following \(these are from [POSIX]\)) s +5 283 M +( ABRT) s +5 272 M +( ALRM) s +5 261 M +( FPE) s +5 250 M +( HUP) s +5 239 M +( ILL) s +5 228 M +( INT) s +5 217 M +( KILL) s +5 206 M +( PIPE) s +5 195 M +( QUIT) s +5 184 M +( SEGV) s +5 173 M +( TERM) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( USR1) s +5 679 M +( USR2) s +5 657 M +( Additional signal names MAY be sent in the format "sig-name@xyz",) s +5 646 M +( where `sig-name' and `xyz' may be anything a particular implementor) s +5 635 M +( wants \(except the `@' sign\). However, it is suggested that if a) s +5 624 M +( `configure' script is used, the non-standard signal names it finds be) s +5 613 M +( encoded as "[email protected]", where `SIG' is the signal name) s +5 602 M +( without the "SIG" prefix, and `xyz' be the host type, as determined) s +5 591 M +( by `config.guess'.) s +5 569 M +( The `error message' contains an additional explanation of the error) s +5 558 M +( message. The message may consist of multiple lines. The client) s +5 547 M +( software MAY display this message to the user. If this is done, the) s +5 536 M +( client software should take the precautions discussed in [SSH-ARCH].) s +5 514 M +(7. TCP/IP Port Forwarding) s +5 492 M +(7.1 Requesting Port Forwarding) s +5 470 M +( A party need not explicitly request forwardings from its own end to) s +5 459 M +( the other direction. However, if it wishes that connections to a) s +5 448 M +( port on the other side be forwarded to the local side, it must) s +5 437 M +( explicitly request this.) s +5 404 M +( byte SSH_MSG_GLOBAL_REQUEST) s +5 393 M +( string "tcpip-forward") s +5 382 M +( boolean want reply) s +5 371 M +( string address to bind \(e.g. "0.0.0.0"\)) s +5 360 M +( uint32 port number to bind) s +5 338 M +( `Address to bind' and `port number to bind' specify the IP address) s +5 327 M +( and port to which the socket to be listened is bound. The address) s +5 316 M +( should be "0.0.0.0" if connections are allowed from anywhere. \(Note) s +5 305 M +( that the client can still filter connections based on information) s +5 294 M +( passed in the open request.\)) s +5 272 M +( Implementations should only allow forwarding privileged ports if the) s +5 261 M +( user has been authenticated as a privileged user.) s +5 239 M +( Client implementations SHOULD reject these messages; they are) s +5 228 M +( normally only sent by the client.) s +5 195 M +( If a client passes 0 as port number to bind and has want reply TRUE) s +5 184 M +( then the server allocates the next available unprivileged port number) s +5 173 M +( and replies with the following message, otherwise there is no) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( response specific data.) s +5 657 M +( byte SSH_MSG_GLOBAL_REQUEST_SUCCESS) s +5 646 M +( uint32 port that was bound on the server) s +5 624 M +( A port forwarding can be cancelled with the following message. Note) s +5 613 M +( that channel open requests may be received until a reply to this) s +5 602 M +( message is received.) s +5 580 M +( byte SSH_MSG_GLOBAL_REQUEST) s +5 569 M +( string "cancel-tcpip-forward") s +5 558 M +( boolean want reply) s +5 547 M +( string address_to_bind \(e.g. "127.0.0.1"\)) s +5 536 M +( uint32 port number to bind) s +5 514 M +( Client implementations SHOULD reject these messages; they are) s +5 503 M +( normally only sent by the client.) s +5 481 M +(7.2 TCP/IP Forwarding Channels) s +5 459 M +( When a connection comes to a port for which remote forwarding has) s +5 448 M +( been requested, a channel is opened to forward the port to the other) s +5 437 M +( side.) s +5 415 M +( byte SSH_MSG_CHANNEL_OPEN) s +5 404 M +( string "forwarded-tcpip") s +5 393 M +( uint32 sender channel) s +5 382 M +( uint32 initial window size) s +5 371 M +( uint32 maximum packet size) s +5 360 M +( string address that was connected) s +5 349 M +( uint32 port that was connected) s +5 338 M +( string originator IP address) s +5 327 M +( uint32 originator port) s +5 305 M +( Implementations MUST reject these messages unless they have) s +5 294 M +( previously requested a remote TCP/IP port forwarding with the given) s +5 283 M +( port number.) s +5 261 M +( When a connection comes to a locally forwarded TCP/IP port, the) s +5 250 M +( following packet is sent to the other side. Note that these messages) s +5 239 M +( MAY be sent also for ports for which no forwarding has been) s +5 228 M +( explicitly requested. The receiving side must decide whether to) s +5 217 M +( allow the forwarding.) s +5 195 M +( byte SSH_MSG_CHANNEL_OPEN) s +5 184 M +( string "direct-tcpip") s +5 173 M +( uint32 sender channel) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( uint32 initial window size) s +5 679 M +( uint32 maximum packet size) s +5 668 M +( string host to connect) s +5 657 M +( uint32 port to connect) s +5 646 M +( string originator IP address) s +5 635 M +( uint32 originator port) s +5 613 M +( `Host to connect' and `port to connect' specify the TCP/IP host and) s +5 602 M +( port where the recipient should connect the channel. `Host to) s +5 591 M +( connect' may be either a domain name or a numeric IP address.) s +5 569 M +( `Originator IP address' is the numeric IP address of the machine) s +5 558 M +( where the connection request comes from, and `originator port' is the) s +5 547 M +( port on the originator host from where the connection came from.) s +5 525 M +( Forwarded TCP/IP channels are independent of any sessions, and) s +5 514 M +( closing a session channel does not in any way imply that forwarded) s +5 503 M +( connections should be closed.) s +5 481 M +( Client implementations SHOULD reject direct TCP/IP open requests for) s +5 470 M +( security reasons.) s +5 448 M +(8. Encoding of Terminal Modes) s +5 426 M +( Terminal modes \(as passed in a pty request\) are encoded into a byte) s +5 415 M +( stream. It is intended that the coding be portable across different) s +5 404 M +( environments.) s +5 382 M +( The tty mode description is a stream of bytes. The stream consists) s +5 371 M +( of opcode-argument pairs. It is terminated by opcode TTY_OP_END \(0\).) s +5 360 M +( Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255) s +5 349 M +( are not yet defined, and cause parsing to stop \(they should only be) s +5 338 M +( used after any other data\).) s +5 316 M +( The client SHOULD put in the stream any modes it knows about, and the) s +5 305 M +( server MAY ignore any modes it does not know about. This allows some) s +5 294 M +( degree of machine-independence, at least between systems that use a) s +5 283 M +( POSIX-like tty interface. The protocol can support other systems as) s +5 272 M +( well, but the client may need to fill reasonable values for a number) s +5 261 M +( of parameters so the server pty gets set to a reasonable mode \(the) s +5 250 M +( server leaves all unspecified mode bits in their default values, and) s +5 239 M +( only some combinations make sense\).) s +5 217 M +( The following opcodes have been defined. The naming of opcodes) s +5 206 M +( mostly follows the POSIX terminal mode flags.) s +5 184 M +( 0 TTY_OP_END Indicates end of options.) s +5 173 M +( 1 VINTR Interrupt character; 255 if none. Similarly for the) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16]) s +_R +S +PStoPSsaved restore +%%Page: (16,17) 9 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 17 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( other characters. Not all of these characters are) s +5 679 M +( supported on all systems.) s +5 668 M +( 2 VQUIT The quit character \(sends SIGQUIT signal on POSIX) s +5 657 M +( systems\).) s +5 646 M +( 3 VERASE Erase the character to left of the cursor.) s +5 635 M +( 4 VKILL Kill the current input line.) s +5 624 M +( 5 VEOF End-of-file character \(sends EOF from the terminal\).) s +5 613 M +( 6 VEOL End-of-line character in addition to carriage return) s +5 602 M +( and/or linefeed.) s +5 591 M +( 7 VEOL2 Additional end-of-line character.) s +5 580 M +( 8 VSTART Continues paused output \(normally control-Q\).) s +5 569 M +( 9 VSTOP Pauses output \(normally control-S\).) s +5 558 M +( 10 VSUSP Suspends the current program.) s +5 547 M +( 11 VDSUSP Another suspend character.) s +5 536 M +( 12 VREPRINT Reprints the current input line.) s +5 525 M +( 13 VWERASE Erases a word left of cursor.) s +5 514 M +( 14 VLNEXT Enter the next character typed literally, even if it) s +5 503 M +( is a special character) s +5 492 M +( 15 VFLUSH Character to flush output.) s +5 481 M +( 16 VSWTCH Switch to a different shell layer.) s +5 470 M +( 17 VSTATUS Prints system status line \(load, command, pid etc\).) s +5 459 M +( 18 VDISCARD Toggles the flushing of terminal output.) s +5 448 M +( 30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if) s +5 437 M +( this flag is FALSE set, and 1 if it is TRUE.) s +5 426 M +( 31 PARMRK Mark parity and framing errors.) s +5 415 M +( 32 INPCK Enable checking of parity errors.) s +5 404 M +( 33 ISTRIP Strip 8th bit off characters.) s +5 393 M +( 34 INLCR Map NL into CR on input.) s +5 382 M +( 35 IGNCR Ignore CR on input.) s +5 371 M +( 36 ICRNL Map CR to NL on input.) s +5 360 M +( 37 IUCLC Translate uppercase characters to lowercase.) s +5 349 M +( 38 IXON Enable output flow control.) s +5 338 M +( 39 IXANY Any char will restart after stop.) s +5 327 M +( 40 IXOFF Enable input flow control.) s +5 316 M +( 41 IMAXBEL Ring bell on input queue full.) s +5 305 M +( 50 ISIG Enable signals INTR, QUIT, [D]SUSP.) s +5 294 M +( 51 ICANON Canonicalize input lines.) s +5 283 M +( 52 XCASE Enable input and output of uppercase characters by) s +5 272 M +( preceding their lowercase equivalents with `\\'.) s +5 261 M +( 53 ECHO Enable echoing.) s +5 250 M +( 54 ECHOE Visually erase chars.) s +5 239 M +( 55 ECHOK Kill character discards current line.) s +5 228 M +( 56 ECHONL Echo NL even if ECHO is off.) s +5 217 M +( 57 NOFLSH Don't flush after interrupt.) s +5 206 M +( 58 TOSTOP Stop background jobs from output.) s +5 195 M +( 59 IEXTEN Enable extensions.) s +5 184 M +( 60 ECHOCTL Echo control characters as ^\(Char\).) s +5 173 M +( 61 ECHOKE Visual erase for line kill.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 18 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( 62 PENDIN Retype pending input.) s +5 679 M +( 70 OPOST Enable output processing.) s +5 668 M +( 71 OLCUC Convert lowercase to uppercase.) s +5 657 M +( 72 ONLCR Map NL to CR-NL.) s +5 646 M +( 73 OCRNL Translate carriage return to newline \(output\).) s +5 635 M +( 74 ONOCR Translate newline to carriage return-newline) s +5 624 M +( \(output\).) s +5 613 M +( 75 ONLRET Newline performs a carriage return \(output\).) s +5 602 M +( 90 CS7 7 bit mode.) s +5 591 M +( 91 CS8 8 bit mode.) s +5 580 M +( 92 PARENB Parity enable.) s +5 569 M +( 93 PARODD Odd parity, else even.) s +5 547 M +( 128 TTY_OP_ISPEED Specifies the input baud rate in bits per second.) s +5 536 M +( 129 TTY_OP_OSPEED Specifies the output baud rate in bits per second.) s +5 503 M +(9. Summary of Message Numbers) s +5 481 M +( #define SSH_MSG_GLOBAL_REQUEST 80) s +5 470 M +( #define SSH_MSG_REQUEST_SUCCESS 81) s +5 459 M +( #define SSH_MSG_REQUEST_FAILURE 82) s +5 448 M +( #define SSH_MSG_CHANNEL_OPEN 90) s +5 437 M +( #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91) s +5 426 M +( #define SSH_MSG_CHANNEL_OPEN_FAILURE 92) s +5 415 M +( #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93) s +5 404 M +( #define SSH_MSG_CHANNEL_DATA 94) s +5 393 M +( #define SSH_MSG_CHANNEL_EXTENDED_DATA 95) s +5 382 M +( #define SSH_MSG_CHANNEL_EOF 96) s +5 371 M +( #define SSH_MSG_CHANNEL_CLOSE 97) s +5 360 M +( #define SSH_MSG_CHANNEL_REQUEST 98) s +5 349 M +( #define SSH_MSG_CHANNEL_SUCCESS 99) s +5 338 M +( #define SSH_MSG_CHANNEL_FAILURE 100) s +5 305 M +(10. Security Considerations) s +5 283 M +( This protocol is assumed to run on top of a secure, authenticated) s +5 272 M +( transport. User authentication and protection against network-level) s +5 261 M +( attacks are assumed to be provided by the underlying protocols.) s +5 239 M +( It is RECOMMENDED that implementations disable all the potentially) s +5 228 M +( dangerous features \(e.g. agent forwarding, X11 forwarding, and TCP/IP) s +5 217 M +( forwarding\) if the host key has changed.) s +5 195 M +( Full security considerations for this protocol are provided in) s +5 184 M +( Section 8 of [SSH-ARCH]) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18]) s +_R +S +PStoPSsaved restore +%%Page: (18,19) 10 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 19 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(11. iana cONSiderations) s +5 668 M +( This document is part of a set, the IANA considerations for the SSH) s +5 657 M +( protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH],) s +5 646 M +( [SSH-CONNECT] are detailed in [SSH-NUMBERS].) s +5 624 M +(12. Intellectual Property) s +5 602 M +( The IETF takes no position regarding the validity or scope of any) s +5 591 M +( intellectual property or other rights that might be claimed to) s +5 580 M +( pertain to the implementation or use of the technology described in) s +5 569 M +( this document or the extent to which any license under such rights) s +5 558 M +( might or might not be available; neither does it represent that it) s +5 547 M +( has made any effort to identify any such rights. Information on the) s +5 536 M +( IETF's procedures with respect to rights in standards-track and) s +5 525 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 514 M +( claims of rights made available for publication and any assurances of) s +5 503 M +( licenses to be made available, or the result of an attempt made to) s +5 492 M +( obtain a general license or permission for the use of such) s +5 481 M +( proprietary rights by implementers or users of this specification can) s +5 470 M +( be obtained from the IETF Secretariat.) s +5 448 M +( The IETF has been notified of intellectual property rights claimed in) s +5 437 M +( regard to some or all of the specification contained in this) s +5 426 M +( document. For more information consult the online list of claimed) s +5 415 M +( rights.) s +5 393 M +(Normative References) s +5 371 M +( [SSH-ARCH]) s +5 360 M +( Ylonen, T., "SSH Protocol Architecture", I-D) s +5 349 M +( draft-ietf-architecture-15.txt, Oct 2003.) s +5 327 M +( [SSH-TRANS]) s +5 316 M +( Ylonen, T., "SSH Transport Layer Protocol", I-D) s +5 305 M +( draft-ietf-transport-17.txt, Oct 2003.) s +5 283 M +( [SSH-USERAUTH]) s +5 272 M +( Ylonen, T., "SSH Authentication Protocol", I-D) s +5 261 M +( draft-ietf-userauth-18.txt, Oct 2003.) s +5 239 M +( [SSH-CONNECT]) s +5 228 M +( Ylonen, T., "SSH Connection Protocol", I-D) s +5 217 M +( draft-ietf-connect-18.txt, Oct 2003.) s +5 195 M +( [SSH-NUMBERS]) s +5 184 M +( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s +5 173 M +( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 20 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( 2003.) s +5 668 M +( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s +5 657 M +( Requirement Levels", BCP 14, RFC 2119, March 1997.) s +5 635 M +(Informative References) s +5 613 M +( [RFC3066] Alvestrand, H., "Tags for the Identification of) s +5 602 M +( Languages", BCP 47, RFC 3066, January 2001.) s +5 580 M +( [RFC1884] Hinden, R. and S. Deering, "IP Version 6 Addressing) s +5 569 M +( Architecture", RFC 1884, December 1995.) s +5 547 M +( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s +5 536 M +( 10646", RFC 2279, January 1998.) s +5 514 M +( [SCHEIFLER]) s +5 503 M +( Scheifler, R., "X Window System : The Complete Reference) s +5 492 M +( to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital) s +5 481 M +( Press ISBN 1555580882, Feburary 1992.) s +5 459 M +( [POSIX] ISO/IEC, 9945-1., "Information technology -- Portable) s +5 448 M +( Operating System Interface \(POSIX\)-Part 1: System) s +5 437 M +( Application Program Interface \(API\) C Language", ANSI/IEE) s +5 426 M +( Std 1003.1, July 1996.) s +5 393 M +(Authors' Addresses) s +5 371 M +( Tatu Ylonen) s +5 360 M +( SSH Communications Security Corp) s +5 349 M +( Fredrikinkatu 42) s +5 338 M +( HELSINKI FIN-00100) s +5 327 M +( Finland) s +5 305 M +( EMail: [email protected]) s +5 272 M +( Darren J. Moffat \(editor\)) s +5 261 M +( Sun Microsystems, Inc) s +5 250 M +( 17 Network Circle) s +5 239 M +( Menlo Park CA 94025) s +5 228 M +( USA) s +5 206 M +( EMail: [email protected]) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20]) s +_R +S +PStoPSsaved restore +%%Page: (20,21) 11 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 21 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +(Intellectual Property Statement) s +5 668 M +( The IETF takes no position regarding the validity or scope of any) s +5 657 M +( intellectual property or other rights that might be claimed to) s +5 646 M +( pertain to the implementation or use of the technology described in) s +5 635 M +( this document or the extent to which any license under such rights) s +5 624 M +( might or might not be available; neither does it represent that it) s +5 613 M +( has made any effort to identify any such rights. Information on the) s +5 602 M +( IETF's procedures with respect to rights in standards-track and) s +5 591 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 580 M +( claims of rights made available for publication and any assurances of) s +5 569 M +( licenses to be made available, or the result of an attempt made to) s +5 558 M +( obtain a general license or permission for the use of such) s +5 547 M +( proprietary rights by implementors or users of this specification can) s +5 536 M +( be obtained from the IETF Secretariat.) s +5 514 M +( The IETF invites any interested party to bring to its attention any) s +5 503 M +( copyrights, patents or patent applications, or other proprietary) s +5 492 M +( rights which may cover technology that may be required to practice) s +5 481 M +( this standard. Please address the information to the IETF Executive) s +5 470 M +( Director.) s +5 448 M +( The IETF has been notified of intellectual property rights claimed in) s +5 437 M +( regard to some or all of the specification contained in this) s +5 426 M +( document. For more information consult the online list of claimed) s +5 415 M +( rights.) s +5 382 M +(Full Copyright Statement) s +5 360 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 338 M +( This document and translations of it may be copied and furnished to) s +5 327 M +( others, and derivative works that comment on or otherwise explain it) s +5 316 M +( or assist in its implementation may be prepared, copied, published) s +5 305 M +( and distributed, in whole or in part, without restriction of any) s +5 294 M +( kind, provided that the above copyright notice and this paragraph are) s +5 283 M +( included on all such copies and derivative works. However, this) s +5 272 M +( document itself may not be modified in any way, such as by removing) s +5 261 M +( the copyright notice or references to the Internet Society or other) s +5 250 M +( Internet organizations, except as needed for the purpose of) s +5 239 M +( developing Internet standards in which case the procedures for) s +5 228 M +( copyrights defined in the Internet Standards process must be) s +5 217 M +( followed, or as required to translate it into languages other than) s +5 206 M +( English.) s +5 184 M +( The limited permissions granted above are perpetual and will not be) s +5 173 M +( revoked by the Internet Society or its successors or assignees.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 22 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Connection Protocol Oct 2003) s +5 690 M +( This document and the information contained herein is provided on an) s +5 679 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 668 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 657 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 646 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 635 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 602 M +(Acknowledgment) s +5 580 M +( Funding for the RFC Editor function is currently provided by the) s +5 569 M +( Internet Society.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]) s +_R +S +PStoPSsaved restore +%%Trailer +%%Pages: 22 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt new file mode 100644 index 0000000000..1cb8ad6409 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-connect-18.txt @@ -0,0 +1,1232 @@ + + + +Network Working Group T. Ylonen +Internet-Draft SSH Communications Security Corp +Expires: March 31, 2004 D. Moffat, Editor, Ed. + Sun Microsystems, Inc + Oct 2003 + + + SSH Connection Protocol + draft-ietf-secsh-connect-18.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that other + groups may also distribute working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on March 31, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. + + This document describes the SSH Connection Protocol. It provides + interactive login sessions, remote execution of commands, forwarded + TCP/IP connections, and forwarded X11 connections. All of these + channels are multiplexed into a single encrypted tunnel. + + The SSH Connection Protocol has been designed to run on top of the + SSH transport layer and user authentication protocols. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +Table of Contents + + 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Conventions Used in This Document . . . . . . . . . . . . . 3 + 4. Global Requests . . . . . . . . . . . . . . . . . . . . . . 3 + 5. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . 4 + 5.1 Opening a Channel . . . . . . . . . . . . . . . . . . . . . 4 + 5.2 Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 5 + 5.3 Closing a Channel . . . . . . . . . . . . . . . . . . . . . 6 + 5.4 Channel-Specific Requests . . . . . . . . . . . . . . . . . 7 + 6. Interactive Sessions . . . . . . . . . . . . . . . . . . . . 8 + 6.1 Opening a Session . . . . . . . . . . . . . . . . . . . . . 8 + 6.2 Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 8 + 6.3 X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 9 + 6.3.1 Requesting X11 Forwarding . . . . . . . . . . . . . . . . . 9 + 6.3.2 X11 Channels . . . . . . . . . . . . . . . . . . . . . . . . 10 + 6.4 Environment Variable Passing . . . . . . . . . . . . . . . . 10 + 6.5 Starting a Shell or a Command . . . . . . . . . . . . . . . 10 + 6.6 Session Data Transfer . . . . . . . . . . . . . . . . . . . 11 + 6.7 Window Dimension Change Message . . . . . . . . . . . . . . 12 + 6.8 Local Flow Control . . . . . . . . . . . . . . . . . . . . . 12 + 6.9 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 6.10 Returning Exit Status . . . . . . . . . . . . . . . . . . . 13 + 7. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . 14 + 7.1 Requesting Port Forwarding . . . . . . . . . . . . . . . . . 14 + 7.2 TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 15 + 8. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . 16 + 9. Summary of Message Numbers . . . . . . . . . . . . . . . . . 18 + 10. Security Considerations . . . . . . . . . . . . . . . . . . 18 + 11. iana cONSiderations . . . . . . . . . . . . . . . . . . . . 19 + 12. Intellectual Property . . . . . . . . . . . . . . . . . . . 19 + Normative References . . . . . . . . . . . . . . . . . . . . 19 + Informative References . . . . . . . . . . . . . . . . . . . 20 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 20 + Intellectual Property and Copyright Statements . . . . . . . 21 + + + + + + + + + + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +1. Contributors + + The major original contributors of this document were: Tatu Ylonen, + Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications + Security Corp), and Markku-Juhani O. Saarinen (University of + Jyvaskyla) + + The document editor is: [email protected]. Comments on this + internet draft should be sent to the IETF SECSH working group, + details at: http://ietf.org/html.charters/secsh-charter.html + +2. Introduction + + The SSH Connection Protocol has been designed to run on top of the + SSH transport layer and user authentication protocols. It provides + interactive login sessions, remote execution of commands, forwarded + TCP/IP connections, and forwarded X11 connections. The service name + for this protocol is "ssh-connection". + + This document should be read only after reading the SSH architecture + document [SSH-ARCH]. This document freely uses terminology and + notation from the architecture document without reference or further + explanation. + +3. Conventions Used in This Document + + The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", + and "MAY" that appear in this document are to be interpreted as + described in [RFC2119]. + + The used data types and terminology are specified in the architecture + document [SSH-ARCH]. + + The architecture document also discusses the algorithm naming + conventions that MUST be used with the SSH protocols. + +4. Global Requests + + There are several kinds of requests that affect the state of the + remote end "globally", independent of any channels. An example is a + request to start TCP/IP forwarding for a specific port. All such + requests use the following format. + + byte SSH_MSG_GLOBAL_REQUEST + string request name (restricted to US-ASCII) + boolean want reply + ... request-specific data follows + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + Request names follow the DNS extensibility naming convention outlined + in [SSH-ARCH]. + + The recipient will respond to this message with + SSH_MSG_REQUEST_SUCCESS or SSH_MSG_REQUEST_FAILURE if `want reply' is + TRUE. + + byte SSH_MSG_REQUEST_SUCCESS + ..... response specific data + + Usually the response specific data is non-existent. + + If the recipient does not recognize or support the request, it simply + responds with SSH_MSG_REQUEST_FAILURE. + + byte SSH_MSG_REQUEST_FAILURE + + +5. Channel Mechanism + + All terminal sessions, forwarded connections, etc. are channels. + Either side may open a channel. Multiple channels are multiplexed + into a single connection. + + Channels are identified by numbers at each end. The number referring + to a channel may be different on each side. Requests to open a + channel contain the sender's channel number. Any other + channel-related messages contain the recipient's channel number for + the channel. + + Channels are flow-controlled. No data may be sent to a channel until + a message is received to indicate that window space is available. + +5.1 Opening a Channel + + When either side wishes to open a new channel, it allocates a local + number for the channel. It then sends the following message to the + other side, and includes the local channel number and initial window + size in the message. + + byte SSH_MSG_CHANNEL_OPEN + string channel type (restricted to US-ASCII) + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + ... channel type specific data follows + + The channel type is a name as described in the SSH architecture + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + document, with similar extension mechanisms. `sender channel' is a + local identifier for the channel used by the sender of this message. + `initial window size' specifies how many bytes of channel data can be + sent to the sender of this message without adjusting the window. + `Maximum packet size' specifies the maximum size of an individual + data packet that can be sent to the sender (for example, one might + want to use smaller packets for interactive connections to get better + interactive response on slow links). + + The remote side then decides whether it can open the channel, and + responds with either + + byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION + uint32 recipient channel + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + ... channel type specific data follows + + where `recipient channel' is the channel number given in the original + open request, and `sender channel' is the channel number allocated by + the other side, or + + byte SSH_MSG_CHANNEL_OPEN_FAILURE + uint32 recipient channel + uint32 reason code + string additional textual information (ISO-10646 UTF-8 [RFC2279]) + string language tag (as defined in [RFC3066]) + + If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support + the specified channel type, it simply responds with + SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional + information to the user. If this is done, the client software should + take the precautions discussed in [SSH-ARCH]. + + The following reason codes are defined: + + #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 + #define SSH_OPEN_CONNECT_FAILED 2 + #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3 + #define SSH_OPEN_RESOURCE_SHORTAGE 4 + + +5.2 Data Transfer + + The window size specifies how many bytes the other party can send + before it must wait for the window to be adjusted. Both parties use + the following message to adjust the window. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + byte SSH_MSG_CHANNEL_WINDOW_ADJUST + uint32 recipient channel + uint32 bytes to add + + After receiving this message, the recipient MAY send the given number + of bytes more than it was previously allowed to send; the window size + is incremented. + + Data transfer is done with messages of the following type. + + byte SSH_MSG_CHANNEL_DATA + uint32 recipient channel + string data + + The maximum amount of data allowed is the current window size. The + window size is decremented by the amount of data sent. Both parties + MAY ignore all extra data sent after the allowed window is empty. + + Additionally, some channels can transfer several types of data. An + example of this is stderr data from interactive sessions. Such data + can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a + separate integer specifies the type of the data. The available types + and their interpretation depend on the type of the channel. + + byte SSH_MSG_CHANNEL_EXTENDED_DATA + uint32 recipient_channel + uint32 data_type_code + string data + + Data sent with these messages consumes the same window as ordinary + data. + + Currently, only the following type is defined. + + #define SSH_EXTENDED_DATA_STDERR 1 + + +5.3 Closing a Channel + + When a party will no longer send more data to a channel, it SHOULD + send SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_EOF + uint32 recipient_channel + + No explicit response is sent to this message; however, the + application may send EOF to whatever is at the other end of the + channel. Note that the channel remains open after this message, and + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + more data may still be sent in the other direction. This message + does not consume window space and can be sent even if no window space + is available. + + When either party wishes to terminate the channel, it sends + SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST + send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this + message for the channel. The channel is considered closed for a + party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and + the party may then reuse the channel number. A party MAY send + SSH_MSG_CHANNEL_CLOSE without having sent or received + SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_CLOSE + uint32 recipient_channel + + This message does not consume window space and can be sent even if no + window space is available. + + It is recommended that any data sent before this message is delivered + to the actual destination, if possible. + +5.4 Channel-Specific Requests + + Many channel types have extensions that are specific to that + particular channel type. An example is requesting a pty (pseudo + terminal) for an interactive session. + + All channel-specific requests use the following format. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string request type (restricted to US-ASCII) + boolean want reply + ... type-specific data + + If want reply is FALSE, no response will be sent to the request. + Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS + or SSH_MSG_CHANNEL_FAILURE, or request-specific continuation + messages. If the request is not recognized or is not supported for + the channel, SSH_MSG_CHANNEL_FAILURE is returned. + + This message does not consume window space and can be sent even if no + window space is available. Request types are local to each channel + type. + + The client is allowed to send further messages without waiting for + the response to the request. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + request type names follow the DNS extensibility naming convention + outlined in [SSH-ARCH] + + byte SSH_MSG_CHANNEL_SUCCESS + uint32 recipient_channel + + + byte SSH_MSG_CHANNEL_FAILURE + uint32 recipient_channel + + These messages do not consume window space and can be sent even if no + window space is available. + +6. Interactive Sessions + + A session is a remote execution of a program. The program may be a + shell, an application, a system command, or some built-in subsystem. + It may or may not have a tty, and may or may not involve X11 + forwarding. Multiple sessions can be active simultaneously. + +6.1 Opening a Session + + A session is started by sending the following message. + + byte SSH_MSG_CHANNEL_OPEN + string "session" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + + Client implementations SHOULD reject any session channel open + requests to make it more difficult for a corrupt server to attack the + client. + +6.2 Requesting a Pseudo-Terminal + + A pseudo-terminal can be allocated for the session by sending the + following message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "pty-req" + boolean want_reply + string TERM environment variable value (e.g., vt100) + uint32 terminal width, characters (e.g., 80) + uint32 terminal height, rows (e.g., 24) + uint32 terminal width, pixels (e.g., 640) + uint32 terminal height, pixels (e.g., 480) + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + string encoded terminal modes + + The encoding of terminal modes is described in Section Encoding of + Terminal Modes (Section 8). Zero dimension parameters MUST be + ignored. The character/row dimensions override the pixel dimensions + (when nonzero). Pixel dimensions refer to the drawable area of the + window. + + The dimension parameters are only informational. + + The client SHOULD ignore pty requests. + +6.3 X11 Forwarding + +6.3.1 Requesting X11 Forwarding + + X11 forwarding may be requested for a session by sending + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "x11-req" + boolean want reply + boolean single connection + string x11 authentication protocol + string x11 authentication cookie + uint32 x11 screen number + + It is recommended that the authentication cookie that is sent be a + fake, random cookie, and that the cookie is checked and replaced by + the real cookie when a connection request is received. + + X11 connection forwarding should stop when the session channel is + closed; however, already opened forwardings should not be + automatically closed when the session channel is closed. + + If `single connection' is TRUE, only a single connection should be + forwarded. No more connections will be forwarded after the first, or + after the session channel has been closed. + + The "x11 authentication protocol" is the name of the X11 + authentication method used, e.g. "MIT-MAGIC-COOKIE-1". + + The x11 authentication cookie MUST be hexadecimal encoded. + + X Protocol is documented in [SCHEIFLER]. + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +6.3.2 X11 Channels + + X11 channels are opened with a channel open request. The resulting + channels are independent of the session, and closing the session + channel does not close the forwarded X11 channels. + + byte SSH_MSG_CHANNEL_OPEN + string "x11" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + string originator address (e.g. "192.168.7.38") + uint32 originator port + + The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION + or SSH_MSG_CHANNEL_OPEN_FAILURE. + + Implementations MUST reject any X11 channel open requests if they + have not requested X11 forwarding. + +6.4 Environment Variable Passing + + Environment variables may be passed to the shell/command to be + started later. Uncontrolled setting of environment variables in a + privileged process can be a security hazard. It is recommended that + implementations either maintain a list of allowable variable names or + only set environment variables after the server process has dropped + sufficient privileges. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "env" + boolean want reply + string variable name + string variable value + + +6.5 Starting a Shell or a Command + + Once the session has been set up, a program is started at the remote + end. The program can be a shell, an application program or a + subsystem with a host-independent name. Only one of these requests + can succeed per channel. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "shell" + boolean want reply + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + This message will request the user's default shell (typically defined + in /etc/passwd in UNIX systems) to be started at the other end. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "exec" + boolean want reply + string command + + This message will request the server to start the execution of the + given command. The command string may contain a path. Normal + precautions MUST be taken to prevent the execution of unauthorized + commands. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "subsystem" + boolean want reply + string subsystem name + + This last form executes a predefined subsystem. It is expected that + these will include a general file transfer mechanism, and possibly + other features. Implementations may also allow configuring more such + mechanisms. As the user's shell is usually used to execute the + subsystem, it is advisable for the subsystem protocol to have a + "magic cookie" at the beginning of the protocol transaction to + distinguish it from arbitrary output generated by shell + initialization scripts etc. This spurious output from the shell may + be filtered out either at the server or at the client. + + The server SHOULD not halt the execution of the protocol stack when + starting a shell or a program. All input and output from these SHOULD + be redirected to the channel or to the encrypted tunnel. + + It is RECOMMENDED to request and check the reply for these messages. + The client SHOULD ignore these messages. + + Subsystem names follow the DNS extensibility naming convention + outlined in [SSH-ARCH]. + +6.6 Session Data Transfer + + Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and + SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The + extended data type SSH_EXTENDED_DATA_STDERR has been defined for + stderr data. + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +6.7 Window Dimension Change Message + + When the window (terminal) size changes on the client side, it MAY + send a message to the other side to inform it of the new dimensions. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "window-change" + boolean FALSE + uint32 terminal width, columns + uint32 terminal height, rows + uint32 terminal width, pixels + uint32 terminal height, pixels + + No response SHOULD be sent to this message. + +6.8 Local Flow Control + + On many systems, it is possible to determine if a pseudo-terminal is + using control-S/control-Q flow control. When flow control is + allowed, it is often desirable to do the flow control at the client + end to speed up responses to user requests. This is facilitated by + the following notification. Initially, the server is responsible for + flow control. (Here, again, client means the side originating the + session, and server means the other side.) + + The message below is used by the server to inform the client when it + can or cannot perform flow control (control-S/control-Q processing). + If `client can do' is TRUE, the client is allowed to do flow control + using control-S and control-Q. The client MAY ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "xon-xoff" + boolean FALSE + boolean client can do + + No response is sent to this message. + +6.9 Signals + + A signal can be delivered to the remote process/service using the + following message. Some systems may not implement signals, in which + case they SHOULD ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "signal" + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + boolean FALSE + string signal name without the "SIG" prefix. + + Signal names will be encoded as discussed in the "exit-signal" + SSH_MSG_CHANNEL_REQUEST. + +6.10 Returning Exit Status + + When the command running at the other end terminates, the following + message can be sent to return the exit status of the command. + Returning the status is RECOMMENDED. No acknowledgment is sent for + this message. The channel needs to be closed with + SSH_MSG_CHANNEL_CLOSE after this message. + + The client MAY ignore these messages. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient_channel + string "exit-status" + boolean FALSE + uint32 exit_status + + The remote command may also terminate violently due to a signal. + Such a condition can be indicated by the following message. A zero + exit_status usually means that the command terminated successfully. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "exit-signal" + boolean FALSE + string signal name without the "SIG" prefix. + boolean core dumped + string error message (ISO-10646 UTF-8) + string language tag (as defined in [RFC3066]) + + The signal name is one of the following (these are from [POSIX]) + + ABRT + ALRM + FPE + HUP + ILL + INT + KILL + PIPE + QUIT + SEGV + TERM + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + USR1 + USR2 + + Additional signal names MAY be sent in the format "sig-name@xyz", + where `sig-name' and `xyz' may be anything a particular implementor + wants (except the `@' sign). However, it is suggested that if a + `configure' script is used, the non-standard signal names it finds be + encoded as "[email protected]", where `SIG' is the signal name + without the "SIG" prefix, and `xyz' be the host type, as determined + by `config.guess'. + + The `error message' contains an additional explanation of the error + message. The message may consist of multiple lines. The client + software MAY display this message to the user. If this is done, the + client software should take the precautions discussed in [SSH-ARCH]. + +7. TCP/IP Port Forwarding + +7.1 Requesting Port Forwarding + + A party need not explicitly request forwardings from its own end to + the other direction. However, if it wishes that connections to a + port on the other side be forwarded to the local side, it must + explicitly request this. + + + byte SSH_MSG_GLOBAL_REQUEST + string "tcpip-forward" + boolean want reply + string address to bind (e.g. "0.0.0.0") + uint32 port number to bind + + `Address to bind' and `port number to bind' specify the IP address + and port to which the socket to be listened is bound. The address + should be "0.0.0.0" if connections are allowed from anywhere. (Note + that the client can still filter connections based on information + passed in the open request.) + + Implementations should only allow forwarding privileged ports if the + user has been authenticated as a privileged user. + + Client implementations SHOULD reject these messages; they are + normally only sent by the client. + + + If a client passes 0 as port number to bind and has want reply TRUE + then the server allocates the next available unprivileged port number + and replies with the following message, otherwise there is no + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + response specific data. + + + byte SSH_MSG_GLOBAL_REQUEST_SUCCESS + uint32 port that was bound on the server + + A port forwarding can be cancelled with the following message. Note + that channel open requests may be received until a reply to this + message is received. + + byte SSH_MSG_GLOBAL_REQUEST + string "cancel-tcpip-forward" + boolean want reply + string address_to_bind (e.g. "127.0.0.1") + uint32 port number to bind + + Client implementations SHOULD reject these messages; they are + normally only sent by the client. + +7.2 TCP/IP Forwarding Channels + + When a connection comes to a port for which remote forwarding has + been requested, a channel is opened to forward the port to the other + side. + + byte SSH_MSG_CHANNEL_OPEN + string "forwarded-tcpip" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + string address that was connected + uint32 port that was connected + string originator IP address + uint32 originator port + + Implementations MUST reject these messages unless they have + previously requested a remote TCP/IP port forwarding with the given + port number. + + When a connection comes to a locally forwarded TCP/IP port, the + following packet is sent to the other side. Note that these messages + MAY be sent also for ports for which no forwarding has been + explicitly requested. The receiving side must decide whether to + allow the forwarding. + + byte SSH_MSG_CHANNEL_OPEN + string "direct-tcpip" + uint32 sender channel + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + uint32 initial window size + uint32 maximum packet size + string host to connect + uint32 port to connect + string originator IP address + uint32 originator port + + `Host to connect' and `port to connect' specify the TCP/IP host and + port where the recipient should connect the channel. `Host to + connect' may be either a domain name or a numeric IP address. + + `Originator IP address' is the numeric IP address of the machine + where the connection request comes from, and `originator port' is the + port on the originator host from where the connection came from. + + Forwarded TCP/IP channels are independent of any sessions, and + closing a session channel does not in any way imply that forwarded + connections should be closed. + + Client implementations SHOULD reject direct TCP/IP open requests for + security reasons. + +8. Encoding of Terminal Modes + + Terminal modes (as passed in a pty request) are encoded into a byte + stream. It is intended that the coding be portable across different + environments. + + The tty mode description is a stream of bytes. The stream consists + of opcode-argument pairs. It is terminated by opcode TTY_OP_END (0). + Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255 + are not yet defined, and cause parsing to stop (they should only be + used after any other data). + + The client SHOULD put in the stream any modes it knows about, and the + server MAY ignore any modes it does not know about. This allows some + degree of machine-independence, at least between systems that use a + POSIX-like tty interface. The protocol can support other systems as + well, but the client may need to fill reasonable values for a number + of parameters so the server pty gets set to a reasonable mode (the + server leaves all unspecified mode bits in their default values, and + only some combinations make sense). + + The following opcodes have been defined. The naming of opcodes + mostly follows the POSIX terminal mode flags. + + 0 TTY_OP_END Indicates end of options. + 1 VINTR Interrupt character; 255 if none. Similarly for the + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + other characters. Not all of these characters are + supported on all systems. + 2 VQUIT The quit character (sends SIGQUIT signal on POSIX + systems). + 3 VERASE Erase the character to left of the cursor. + 4 VKILL Kill the current input line. + 5 VEOF End-of-file character (sends EOF from the terminal). + 6 VEOL End-of-line character in addition to carriage return + and/or linefeed. + 7 VEOL2 Additional end-of-line character. + 8 VSTART Continues paused output (normally control-Q). + 9 VSTOP Pauses output (normally control-S). + 10 VSUSP Suspends the current program. + 11 VDSUSP Another suspend character. + 12 VREPRINT Reprints the current input line. + 13 VWERASE Erases a word left of cursor. + 14 VLNEXT Enter the next character typed literally, even if it + is a special character + 15 VFLUSH Character to flush output. + 16 VSWTCH Switch to a different shell layer. + 17 VSTATUS Prints system status line (load, command, pid etc). + 18 VDISCARD Toggles the flushing of terminal output. + 30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if + this flag is FALSE set, and 1 if it is TRUE. + 31 PARMRK Mark parity and framing errors. + 32 INPCK Enable checking of parity errors. + 33 ISTRIP Strip 8th bit off characters. + 34 INLCR Map NL into CR on input. + 35 IGNCR Ignore CR on input. + 36 ICRNL Map CR to NL on input. + 37 IUCLC Translate uppercase characters to lowercase. + 38 IXON Enable output flow control. + 39 IXANY Any char will restart after stop. + 40 IXOFF Enable input flow control. + 41 IMAXBEL Ring bell on input queue full. + 50 ISIG Enable signals INTR, QUIT, [D]SUSP. + 51 ICANON Canonicalize input lines. + 52 XCASE Enable input and output of uppercase characters by + preceding their lowercase equivalents with `\'. + 53 ECHO Enable echoing. + 54 ECHOE Visually erase chars. + 55 ECHOK Kill character discards current line. + 56 ECHONL Echo NL even if ECHO is off. + 57 NOFLSH Don't flush after interrupt. + 58 TOSTOP Stop background jobs from output. + 59 IEXTEN Enable extensions. + 60 ECHOCTL Echo control characters as ^(Char). + 61 ECHOKE Visual erase for line kill. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + 62 PENDIN Retype pending input. + 70 OPOST Enable output processing. + 71 OLCUC Convert lowercase to uppercase. + 72 ONLCR Map NL to CR-NL. + 73 OCRNL Translate carriage return to newline (output). + 74 ONOCR Translate newline to carriage return-newline + (output). + 75 ONLRET Newline performs a carriage return (output). + 90 CS7 7 bit mode. + 91 CS8 8 bit mode. + 92 PARENB Parity enable. + 93 PARODD Odd parity, else even. + + 128 TTY_OP_ISPEED Specifies the input baud rate in bits per second. + 129 TTY_OP_OSPEED Specifies the output baud rate in bits per second. + + +9. Summary of Message Numbers + + #define SSH_MSG_GLOBAL_REQUEST 80 + #define SSH_MSG_REQUEST_SUCCESS 81 + #define SSH_MSG_REQUEST_FAILURE 82 + #define SSH_MSG_CHANNEL_OPEN 90 + #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 + #define SSH_MSG_CHANNEL_OPEN_FAILURE 92 + #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 + #define SSH_MSG_CHANNEL_DATA 94 + #define SSH_MSG_CHANNEL_EXTENDED_DATA 95 + #define SSH_MSG_CHANNEL_EOF 96 + #define SSH_MSG_CHANNEL_CLOSE 97 + #define SSH_MSG_CHANNEL_REQUEST 98 + #define SSH_MSG_CHANNEL_SUCCESS 99 + #define SSH_MSG_CHANNEL_FAILURE 100 + + +10. Security Considerations + + This protocol is assumed to run on top of a secure, authenticated + transport. User authentication and protection against network-level + attacks are assumed to be provided by the underlying protocols. + + It is RECOMMENDED that implementations disable all the potentially + dangerous features (e.g. agent forwarding, X11 forwarding, and TCP/IP + forwarding) if the host key has changed. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +11. iana cONSiderations + + This document is part of a set, the IANA considerations for the SSH + protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH], + [SSH-CONNECT] are detailed in [SSH-NUMBERS]. + +12. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementers or users of this specification can + be obtained from the IETF Secretariat. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + +Normative References + + [SSH-ARCH] + Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-15.txt, Oct 2003. + + [SSH-TRANS] + Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-17.txt, Oct 2003. + + [SSH-USERAUTH] + Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-18.txt, Oct 2003. + + [SSH-CONNECT] + Ylonen, T., "SSH Connection Protocol", I-D + draft-ietf-connect-18.txt, Oct 2003. + + [SSH-NUMBERS] + Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + 2003. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +Informative References + + [RFC3066] Alvestrand, H., "Tags for the Identification of + Languages", BCP 47, RFC 3066, January 2001. + + [RFC1884] Hinden, R. and S. Deering, "IP Version 6 Addressing + Architecture", RFC 1884, December 1995. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + [SCHEIFLER] + Scheifler, R., "X Window System : The Complete Reference + to Xlib, X Protocol, Icccm, Xlfd, 3rd edition.", Digital + Press ISBN 1555580882, Feburary 1992. + + [POSIX] ISO/IEC, 9945-1., "Information technology -- Portable + Operating System Interface (POSIX)-Part 1: System + Application Program Interface (API) C Language", ANSI/IEE + Std 1003.1, July 1996. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Darren J. Moffat (editor) + Sun Microsystems, Inc + 17 Network Circle + Menlo Park CA 94025 + USA + + EMail: [email protected] + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20] + +Internet-Draft SSH Connection Protocol Oct 2003 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21] + +Internet-Draft SSH Connection Protocol Oct 2003 + + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps new file mode 100644 index 0000000000..06c91bf8cd --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.2.ps @@ -0,0 +1,2853 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Wed Nov 12 12:26:07 2003 +%%Orientation: Portrait +%%Pages: 15 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Network Working Group T. Ylonen) s +5 690 M +(Internet-Draft S. Lehtinen) s +5 679 M +(Expires: April 1, 2002 SSH Communications Security Corp) s +5 668 M +( October 2001) s +5 635 M +( SSH File Transfer Protocol) s +5 624 M +( draft-ietf-secsh-filexfer-02.txt) s +5 602 M +(Status of this Memo) s +5 580 M +( This document is an Internet-Draft and is in full conformance with) s +5 569 M +( all provisions of Section 10 of RFC2026.) s +5 547 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 536 M +( Task Force \(IETF\), its areas, and its working groups. Note that) s +5 525 M +( other groups may also distribute working documents as Internet-) s +5 514 M +( Drafts.) s +5 492 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 481 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 470 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 459 M +( material or to cite them other than as "work in progress.") s +5 437 M +( The list of current Internet-Drafts can be accessed at http://) s +5 426 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 404 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 393 M +( http://www.ietf.org/shadow.html.) s +5 371 M +( This Internet-Draft will expire on April 1, 2002.) s +5 349 M +(Copyright Notice) s +5 327 M +( Copyright \(C\) The Internet Society \(2001\). All Rights Reserved.) s +5 305 M +(Abstract) s +5 283 M +( The SSH File Transfer Protocol provides secure file transfer) s +5 272 M +( functionality over any reliable data stream. It is the standard file) s +5 261 M +( transfer protocol for use with the SSH2 protocol. This document) s +5 250 M +( describes the file transfer protocol and its interface to the SSH2) s +5 239 M +( protocol suite.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(Table of Contents) s +5 668 M +( 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 657 M +( 2. Use with the SSH Connection Protocol . . . . . . . . . . . . 4) s +5 646 M +( 3. General Packet Format . . . . . . . . . . . . . . . . . . . 5) s +5 635 M +( 4. Protocol Initialization . . . . . . . . . . . . . . . . . . 7) s +5 624 M +( 5. File Attributes . . . . . . . . . . . . . . . . . . . . . . 8) s +5 613 M +( 6. Requests From the Client to the Server . . . . . . . . . . . 10) s +5 602 M +( 6.1 Request Synchronization and Reordering . . . . . . . . . . . 10) s +5 591 M +( 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . . 11) s +5 580 M +( 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . . 11) s +5 569 M +( 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . . 13) s +5 558 M +( 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . . 14) s +5 547 M +( 6.6 Creating and Deleting Directories . . . . . . . . . . . . . 15) s +5 536 M +( 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . . 15) s +5 525 M +( 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . . 16) s +5 514 M +( 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . . 17) s +5 503 M +( 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . . 18) s +5 492 M +( 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . . 18) s +5 481 M +( 7. Responses from the Server to the Client . . . . . . . . . . 20) s +5 470 M +( 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . . 24) s +5 459 M +( 9. Security Considerations . . . . . . . . . . . . . . . . . . 25) s +5 448 M +( 10. Changes from previous protocol versions . . . . . . . . . . 26) s +5 437 M +( 10.1 Changes between versions 3 and 2 . . . . . . . . . . . . . . 26) s +5 426 M +( 10.2 Changes between versions 2 and 1 . . . . . . . . . . . . . . 26) s +5 415 M +( 10.3 Changes between versions 1 and 0 . . . . . . . . . . . . . . 26) s +5 404 M +( 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . 27) s +5 393 M +( References . . . . . . . . . . . . . . . . . . . . . . . . . 28) s +5 382 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 28) s +5 371 M +( Full Copyright Statement . . . . . . . . . . . . . . . . . . 29) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(1. Introduction) s +5 668 M +( This protocol provides secure file transfer \(and more generally file) s +5 657 M +( system access\) functionality over a reliable data stream, such as a) s +5 646 M +( channel in the SSH2 protocol [3].) s +5 624 M +( This protocol is designed so that it could be used to implement a) s +5 613 M +( secure remote file system service, as well as a secure file transfer) s +5 602 M +( service.) s +5 580 M +( This protocol assumes that it runs over a secure channel, and that) s +5 569 M +( the server has already authenticated the user at the client end, and) s +5 558 M +( that the identity of the client user is externally available to the) s +5 547 M +( server implementation.) s +5 525 M +( In general, this protocol follows a simple request-response model.) s +5 514 M +( Each request and response contains a sequence number and multiple) s +5 503 M +( requests may be pending simultaneously. There are a relatively large) s +5 492 M +( number of different request messages, but a small number of possible) s +5 481 M +( response messages. Each request has one or more response messages) s +5 470 M +( that may be returned in result \(e.g., a read either returns data or) s +5 459 M +( reports error status\).) s +5 437 M +( The packet format descriptions in this specification follow the) s +5 426 M +( notation presented in the secsh architecture draft.[3].) s +5 404 M +( Even though this protocol is described in the context of the SSH2) s +5 393 M +( protocol, this protocol is general and independent of the rest of the) s +5 382 M +( SSH2 protocol suite. It could be used in a number of different) s +5 371 M +( applications, such as secure file transfer over TLS RFC 2246 [1] and) s +5 360 M +( transfer of management information in VPN applications.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(2. Use with the SSH Connection Protocol) s +5 668 M +( When used with the SSH2 Protocol suite, this protocol is intended to) s +5 657 M +( be used from the SSH Connection Protocol [5] as a subsystem, as) s +5 646 M +( described in section ``Starting a Shell or a Command''. The) s +5 635 M +( subsystem name used with this protocol is "sftp".) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(3. General Packet Format) s +5 668 M +( All packets transmitted over the secure connection are of the) s +5 657 M +( following format:) s +5 635 M +( uint32 length) s +5 624 M +( byte type) s +5 613 M +( byte[length - 1] data payload) s +5 591 M +( That is, they are just data preceded by 32-bit length and 8-bit type) s +5 580 M +( fields. The `length' is the length of the data area, and does not) s +5 569 M +( include the `length' field itself. The format and interpretation of) s +5 558 M +( the data area depends on the packet type.) s +5 536 M +( All packet descriptions below only specify the packet type and the) s +5 525 M +( data that goes into the data field. Thus, they should be prefixed by) s +5 514 M +( the `length' and `type' fields.) s +5 492 M +( The maximum size of a packet is in practice determined by the client) s +5 481 M +( \(the maximum size of read or write requests that it sends, plus a few) s +5 470 M +( bytes of packet overhead\). All servers SHOULD support packets of at) s +5 459 M +( least 34000 bytes \(where the packet size refers to the full length,) s +5 448 M +( including the header above\). This should allow for reads and writes) s +5 437 M +( of at most 32768 bytes.) s +5 415 M +( There is no limit on the number of outstanding \(non-acknowledged\)) s +5 404 M +( requests that the client may send to the server. In practice this is) s +5 393 M +( limited by the buffering available on the data stream and the queuing) s +5 382 M +( performed by the server. If the server's queues are full, it should) s +5 371 M +( not read any more data from the stream, and flow control will prevent) s +5 360 M +( the client from sending more requests. Note, however, that while) s +5 349 M +( there is no restriction on the protocol level, the client's API may) s +5 338 M +( provide a limit in order to prevent infinite queuing of outgoing) s +5 327 M +( requests at the client.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( The following values are defined for packet types.) s +5 668 M +( #define SSH_FXP_INIT 1) s +5 657 M +( #define SSH_FXP_VERSION 2) s +5 646 M +( #define SSH_FXP_OPEN 3) s +5 635 M +( #define SSH_FXP_CLOSE 4) s +5 624 M +( #define SSH_FXP_READ 5) s +5 613 M +( #define SSH_FXP_WRITE 6) s +5 602 M +( #define SSH_FXP_LSTAT 7) s +5 591 M +( #define SSH_FXP_FSTAT 8) s +5 580 M +( #define SSH_FXP_SETSTAT 9) s +5 569 M +( #define SSH_FXP_FSETSTAT 10) s +5 558 M +( #define SSH_FXP_OPENDIR 11) s +5 547 M +( #define SSH_FXP_READDIR 12) s +5 536 M +( #define SSH_FXP_REMOVE 13) s +5 525 M +( #define SSH_FXP_MKDIR 14) s +5 514 M +( #define SSH_FXP_RMDIR 15) s +5 503 M +( #define SSH_FXP_REALPATH 16) s +5 492 M +( #define SSH_FXP_STAT 17) s +5 481 M +( #define SSH_FXP_RENAME 18) s +5 470 M +( #define SSH_FXP_READLINK 19) s +5 459 M +( #define SSH_FXP_SYMLINK 20) s +5 448 M +( #define SSH_FXP_STATUS 101) s +5 437 M +( #define SSH_FXP_HANDLE 102) s +5 426 M +( #define SSH_FXP_DATA 103) s +5 415 M +( #define SSH_FXP_NAME 104) s +5 404 M +( #define SSH_FXP_ATTRS 105) s +5 393 M +( #define SSH_FXP_EXTENDED 200) s +5 382 M +( #define SSH_FXP_EXTENDED_REPLY 201) s +5 360 M +( Additional packet types should only be defined if the protocol) s +5 349 M +( version number \(see Section ``Protocol Initialization''\) is) s +5 338 M +( incremented, and their use MUST be negotiated using the version) s +5 327 M +( number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY) s +5 316 M +( packets can be used to implement vendor-specific extensions. See) s +5 305 M +( Section ``Vendor-Specific-Extensions'' for more details.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(4. Protocol Initialization) s +5 668 M +( When the file transfer protocol starts, it first sends a SSH_FXP_INIT) s +5 657 M +( \(including its version number\) packet to the server. The server) s +5 646 M +( responds with a SSH_FXP_VERSION packet, supplying the lowest of its) s +5 635 M +( own and the client's version number. Both parties should from then) s +5 624 M +( on adhere to particular version of the protocol.) s +5 602 M +( The SSH_FXP_INIT packet \(from client to server\) has the following) s +5 591 M +( data:) s +5 569 M +( uint32 version) s +5 558 M +( <extension data>) s +5 536 M +( The SSH_FXP_VERSION packet \(from server to client\) has the following) s +5 525 M +( data:) s +5 503 M +( uint32 version) s +5 492 M +( <extension data>) s +5 470 M +( The version number of the protocol specified in this document is 3.) s +5 459 M +( The version number should be incremented for each incompatible) s +5 448 M +( revision of this protocol.) s +5 426 M +( The extension data in the above packets may be empty, or may be a) s +5 415 M +( sequence of) s +5 393 M +( string extension_name) s +5 382 M +( string extension_data) s +5 360 M +( pairs \(both strings MUST always be present if one is, but the) s +5 349 M +( `extension_data' string may be of zero length\). If present, these) s +5 338 M +( strings indicate extensions to the baseline protocol. The) s +5 327 M +( `extension_name' field\(s\) identify the name of the extension. The) s +5 316 M +( name should be of the form "name@domain", where the domain is the DNS) s +5 305 M +( domain name of the organization defining the extension. Additional) s +5 294 M +( names that are not of this format may be defined later by the IETF.) s +5 283 M +( Implementations MUST silently ignore any extensions whose name they) s +5 272 M +( do not recognize.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(5. File Attributes) s +5 668 M +( A new compound data type is defined for encoding file attributes. It) s +5 657 M +( is basically just a combination of elementary types, but is defined) s +5 646 M +( once because of the non-trivial description of the fields and to) s +5 635 M +( ensure maintainability.) s +5 613 M +( The same encoding is used both when returning file attributes from) s +5 602 M +( the server and when sending file attributes to the server. When) s +5 591 M +( sending it to the server, the flags field specifies which attributes) s +5 580 M +( are included, and the server will use default values for the) s +5 569 M +( remaining attributes \(or will not modify the values of remaining) s +5 558 M +( attributes\). When receiving attributes from the server, the flags) s +5 547 M +( specify which attributes are included in the returned data. The) s +5 536 M +( server normally returns all attributes it knows about.) s +5 514 M +( uint32 flags) s +5 503 M +( uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE) s +5 492 M +( uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID) s +5 481 M +( uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID) s +5 470 M +( uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS) s +5 459 M +( uint32 atime present only if flag SSH_FILEXFER_ACMODTIME) s +5 448 M +( uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME) s +5 437 M +( uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED) s +5 426 M +( string extended_type) s +5 415 M +( string extended_data) s +5 404 M +( ... more extended data \(extended_type - extended_data pairs\),) s +5 393 M +( so that number of pairs equals extended_count) s +5 371 M +( The `flags' specify which of the fields are present. Those fields) s +5 360 M +( for which the corresponding flag is not set are not present \(not) s +5 349 M +( included in the packet\). New flags can only be added by incrementing) s +5 338 M +( the protocol version number \(or by using the extension mechanism) s +5 327 M +( described below\).) s +5 305 M +( The `size' field specifies the size of the file in bytes.) s +5 283 M +( The `uid' and `gid' fields contain numeric Unix-like user and group) s +5 272 M +( identifiers, respectively.) s +5 250 M +( The `permissions' field contains a bit mask of file permissions as) s +5 239 M +( defined by posix [1].) s +5 217 M +( The `atime' and `mtime' contain the access and modification times of) s +5 206 M +( the files, respectively. They are represented as seconds from Jan 1,) s +5 195 M +( 1970 in UTC.) s +5 173 M +( The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( mechanism for vendor-specific extensions. If the flag is specified,) s +5 679 M +( then the `extended_count' field is present. It specifies the number) s +5 668 M +( of extended_type-extended_data pairs that follow. Each of these) s +5 657 M +( pairs specifies an extended attribute. For each of the attributes,) s +5 646 M +( the extended_type field should be a string of the format) s +5 635 M +( "name@domain", where "domain" is a valid, registered domain name and) s +5 624 M +( "name" identifies the method. The IETF may later standardize certain) s +5 613 M +( names that deviate from this format \(e.g., that do not contain the) s +5 602 M +( "@" sign\). The interpretation of `extended_data' depends on the) s +5 591 M +( type. Implementations SHOULD ignore extended data fields that they) s +5 580 M +( do not understand.) s +5 558 M +( Additional fields can be added to the attributes by either defining) s +5 547 M +( additional bits to the flags field to indicate their presence, or by) s +5 536 M +( defining extended attributes for them. The extended attributes) s +5 525 M +( mechanism is recommended for most purposes; additional flags bits) s +5 514 M +( should only be defined by an IETF standards action that also) s +5 503 M +( increments the protocol version number. The use of such new fields) s +5 492 M +( MUST be negotiated by the version number in the protocol exchange.) s +5 481 M +( It is a protocol error if a packet with unsupported protocol bits is) s +5 470 M +( received.) s +5 448 M +( The flags bits are defined to have the following values:) s +5 426 M +( #define SSH_FILEXFER_ATTR_SIZE 0x00000001) s +5 415 M +( #define SSH_FILEXFER_ATTR_UIDGID 0x00000002) s +5 404 M +( #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004) s +5 393 M +( #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008) s +5 382 M +( #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(6. Requests From the Client to the Server) s +5 668 M +( Requests from the client to the server represent the various file) s +5 657 M +( system operations. Each request begins with an `id' field, which is) s +5 646 M +( a 32-bit identifier identifying the request \(selected by the client\).) s +5 635 M +( The same identifier will be returned in the response to the request.) s +5 624 M +( One possible implementation of it is a monotonically increasing) s +5 613 M +( request sequence number \(modulo 2^32\).) s +5 591 M +( Many operations in the protocol operate on open files. The) s +5 580 M +( SSH_FXP_OPEN request can return a file handle \(which is an opaque) s +5 569 M +( variable-length string\) which may be used to access the file later) s +5 558 M +( \(e.g. in a read operation\). The client MUST NOT send requests the) s +5 547 M +( server with bogus or closed handles. However, the server MUST) s +5 536 M +( perform adequate checks on the handle in order to avoid security) s +5 525 M +( risks due to fabricated handles.) s +5 503 M +( This design allows either stateful and stateless server) s +5 492 M +( implementation, as well as an implementation which caches state) s +5 481 M +( between requests but may also flush it. The contents of the file) s +5 470 M +( handle string are entirely up to the server and its design. The) s +5 459 M +( client should not modify or attempt to interpret the file handle) s +5 448 M +( strings.) s +5 426 M +( The file handle strings MUST NOT be longer than 256 bytes.) s +5 404 M +(6.1 Request Synchronization and Reordering) s +5 382 M +( The protocol and implementations MUST process requests relating to) s +5 371 M +( the same file in the order in which they are received. In other) s +5 360 M +( words, if an application submits multiple requests to the server, the) s +5 349 M +( results in the responses will be the same as if it had sent the) s +5 338 M +( requests one at a time and waited for the response in each case. For) s +5 327 M +( example, the server may process non-overlapping read/write requests) s +5 316 M +( to the same file in parallel, but overlapping reads and writes cannot) s +5 305 M +( be reordered or parallelized. However, there are no ordering) s +5 294 M +( restrictions on the server for processing requests from two different) s +5 283 M +( file transfer connections. The server may interleave and parallelize) s +5 272 M +( them at will.) s +5 250 M +( There are no restrictions on the order in which responses to) s +5 239 M +( outstanding requests are delivered to the client, except that the) s +5 228 M +( server must ensure fairness in the sense that processing of no) s +5 217 M +( request will be indefinitely delayed even if the client is sending) s +5 206 M +( other requests so that there are multiple outstanding requests all) s +5 195 M +( the time.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(6.2 File Names) s +5 668 M +( This protocol represents file names as strings. File names are) s +5 657 M +( assumed to use the slash \('/'\) character as a directory separator.) s +5 635 M +( File names starting with a slash are "absolute", and are relative to) s +5 624 M +( the root of the file system. Names starting with any other character) s +5 613 M +( are relative to the user's default directory \(home directory\). Note) s +5 602 M +( that identifying the user is assumed to take place outside of this) s +5 591 M +( protocol.) s +5 569 M +( Servers SHOULD interpret a path name component ".." as referring to) s +5 558 M +( the parent directory, and "." as referring to the current directory.) s +5 547 M +( If the server implementation limits access to certain parts of the) s +5 536 M +( file system, it must be extra careful in parsing file names when) s +5 525 M +( enforcing such restrictions. There have been numerous reported) s +5 514 M +( security bugs where a ".." in a path name has allowed access outside) s +5 503 M +( the intended area.) s +5 481 M +( An empty path name is valid, and it refers to the user's default) s +5 470 M +( directory \(usually the user's home directory\).) s +5 448 M +( Otherwise, no syntax is defined for file names by this specification.) s +5 437 M +( Clients should not make any other assumptions; however, they can) s +5 426 M +( splice path name components returned by SSH_FXP_READDIR together) s +5 415 M +( using a slash \('/'\) as the separator, and that will work as expected.) s +5 393 M +( It is understood that the lack of well-defined semantics for file) s +5 382 M +( names may cause interoperability problems between clients and servers) s +5 371 M +( using radically different operating systems. However, this approach) s +5 360 M +( is known to work acceptably with most systems, and alternative) s +5 349 M +( approaches that e.g. treat file names as sequences of structured) s +5 338 M +( components are quite complicated.) s +5 316 M +(6.3 Opening, Creating, and Closing Files) s +5 294 M +( Files are opened and created using the SSH_FXP_OPEN message, whose) s +5 283 M +( data part is as follows:) s +5 261 M +( uint32 id) s +5 250 M +( string filename) s +5 239 M +( uint32 pflags) s +5 228 M +( ATTRS attrs) s +5 206 M +( The `id' field is the request identifier as for all requests.) s +5 184 M +( The `filename' field specifies the file name. See Section ``File) s +5 173 M +( Names'' for more information.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( The `pflags' field is a bitmask. The following bits have been) s +5 679 M +( defined.) s +5 657 M +( #define SSH_FXF_READ 0x00000001) s +5 646 M +( #define SSH_FXF_WRITE 0x00000002) s +5 635 M +( #define SSH_FXF_APPEND 0x00000004) s +5 624 M +( #define SSH_FXF_CREAT 0x00000008) s +5 613 M +( #define SSH_FXF_TRUNC 0x00000010) s +5 602 M +( #define SSH_FXF_EXCL 0x00000020) s +5 580 M +( These have the following meanings:) s +5 558 M +( SSH_FXF_READ) s +5 547 M +( Open the file for reading.) s +5 525 M +( SSH_FXF_WRITE) s +5 514 M +( Open the file for writing. If both this and SSH_FXF_READ are) s +5 503 M +( specified, the file is opened for both reading and writing.) s +5 481 M +( SSH_FXF_APPEND) s +5 470 M +( Force all writes to append data at the end of the file.) s +5 448 M +( SSH_FXF_CREAT) s +5 437 M +( If this flag is specified, then a new file will be created if one) s +5 426 M +( does not already exist \(if O_TRUNC is specified, the new file will) s +5 415 M +( be truncated to zero length if it previously exists\).) s +5 393 M +( SSH_FXF_TRUNC) s +5 382 M +( Forces an existing file with the same name to be truncated to zero) s +5 371 M +( length when creating a file by specifying SSH_FXF_CREAT.) s +5 360 M +( SSH_FXF_CREAT MUST also be specified if this flag is used.) s +5 338 M +( SSH_FXF_EXCL) s +5 327 M +( Causes the request to fail if the named file already exists.) s +5 316 M +( SSH_FXF_CREAT MUST also be specified if this flag is used.) s +5 294 M +( The `attrs' field specifies the initial attributes for the file.) s +5 283 M +( Default values will be used for those attributes that are not) s +5 272 M +( specified. See Section ``File Attributes'' for more information.) s +5 250 M +( Regardless the server operating system, the file will always be) s +5 239 M +( opened in "binary" mode \(i.e., no translations between different) s +5 228 M +( character sets and newline encodings\).) s +5 206 M +( The response to this message will be either SSH_FXP_HANDLE \(if the) s +5 195 M +( operation is successful\) or SSH_FXP_STATUS \(if the operation fails\).) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( A file is closed by using the SSH_FXP_CLOSE request. Its data field) s +5 679 M +( has the following format:) s +5 657 M +( uint32 id) s +5 646 M +( string handle) s +5 624 M +( where `id' is the request identifier, and `handle' is a handle) s +5 613 M +( previously returned in the response to SSH_FXP_OPEN or) s +5 602 M +( SSH_FXP_OPENDIR. The handle becomes invalid immediately after this) s +5 591 M +( request has been sent.) s +5 569 M +( The response to this request will be a SSH_FXP_STATUS message. One) s +5 558 M +( should note that on some server platforms even a close can fail.) s +5 547 M +( This can happen e.g. if the server operating system caches writes,) s +5 536 M +( and an error occurs while flushing cached writes during the close.) s +5 514 M +(6.4 Reading and Writing) s +5 492 M +( Once a file has been opened, it can be read using the SSH_FXP_READ) s +5 481 M +( message, which has the following format:) s +5 459 M +( uint32 id) s +5 448 M +( string handle) s +5 437 M +( uint64 offset) s +5 426 M +( uint32 len) s +5 404 M +( where `id' is the request identifier, `handle' is an open file handle) s +5 393 M +( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) relative) s +5 382 M +( to the beginning of the file from where to start reading, and `len') s +5 371 M +( is the maximum number of bytes to read.) s +5 349 M +( In response to this request, the server will read as many bytes as it) s +5 338 M +( can from the file \(up to `len'\), and return them in a SSH_FXP_DATA) s +5 327 M +( message. If an error occurs or EOF is encountered before reading any) s +5 316 M +( data, the server will respond with SSH_FXP_STATUS. For normal disk) s +5 305 M +( files, it is guaranteed that this will read the specified number of) s +5 294 M +( bytes, or up to end of file. For e.g. device files this may return) s +5 283 M +( fewer bytes than requested.) s +5 261 M +( Writing to a file is achieved using the SSH_FXP_WRITE message, which) s +5 250 M +( has the following format:) s +5 228 M +( uint32 id) s +5 217 M +( string handle) s +5 206 M +( uint64 offset) s +5 195 M +( string data) s +5 173 M +( where `id' is a request identifier, `handle' is a file handle) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) from the) s +5 679 M +( beginning of the file where to start writing, and `data' is the data) s +5 668 M +( to be written.) s +5 646 M +( The write will extend the file if writing beyond the end of the file.) s +5 635 M +( It is legal to write way beyond the end of the file; the semantics) s +5 624 M +( are to write zeroes from the end of the file to the specified offset) s +5 613 M +( and then the data. On most operating systems, such writes do not) s +5 602 M +( allocate disk space but instead leave "holes" in the file.) s +5 580 M +( The server responds to a write request with a SSH_FXP_STATUS message.) s +5 558 M +(6.5 Removing and Renaming Files) s +5 536 M +( Files can be removed using the SSH_FXP_REMOVE message. It has the) s +5 525 M +( following format:) s +5 503 M +( uint32 id) s +5 492 M +( string filename) s +5 470 M +( where `id' is the request identifier and `filename' is the name of) s +5 459 M +( the file to be removed. See Section ``File Names'' for more) s +5 448 M +( information. This request cannot be used to remove directories.) s +5 426 M +( The server will respond to this request with a SSH_FXP_STATUS) s +5 415 M +( message.) s +5 393 M +( Files \(and directories\) can be renamed using the SSH_FXP_RENAME) s +5 382 M +( message. Its data is as follows:) s +5 360 M +( uint32 id) s +5 349 M +( string oldpath) s +5 338 M +( string newpath) s +5 316 M +( where `id' is the request identifier, `oldpath' is the name of an) s +5 305 M +( existing file or directory, and `newpath' is the new name for the) s +5 294 M +( file or directory. It is an error if there already exists a file) s +5 283 M +( with the name specified by newpath. The server may also fail rename) s +5 272 M +( requests in other situations, for example if `oldpath' and `newpath') s +5 261 M +( point to different file systems on the server.) s +5 239 M +( The server will respond to this request with a SSH_FXP_STATUS) s +5 228 M +( message.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(6.6 Creating and Deleting Directories) s +5 668 M +( New directories can be created using the SSH_FXP_MKDIR request. It) s +5 657 M +( has the following format:) s +5 635 M +( uint32 id) s +5 624 M +( string path) s +5 613 M +( ATTRS attrs) s +5 591 M +( where `id' is the request identifier, `path' and `attrs' specifies) s +5 580 M +( the modifications to be made to its attributes. See Section ``File) s +5 569 M +( Names'' for more information on file names. Attributes are discussed) s +5 558 M +( in more detail in Section ``File Attributes''. specifies the) s +5 547 M +( directory to be created. An error will be returned if a file or) s +5 536 M +( directory with the specified path already exists. The server will) s +5 525 M +( respond to this request with a SSH_FXP_STATUS message.) s +5 503 M +( Directories can be removed using the SSH_FXP_RMDIR request, which) s +5 492 M +( has the following format:) s +5 470 M +( uint32 id) s +5 459 M +( string path) s +5 437 M +( where `id' is the request identifier, and `path' specifies the) s +5 426 M +( directory to be removed. See Section ``File Names'' for more) s +5 415 M +( information on file names. An error will be returned if no directory) s +5 404 M +( with the specified path exists, or if the specified directory is not) s +5 393 M +( empty, or if the path specified a file system object other than a) s +5 382 M +( directory. The server responds to this request with a SSH_FXP_STATUS) s +5 371 M +( message.) s +5 349 M +(6.7 Scanning Directories) s +5 327 M +( The files in a directory can be listed using the SSH_FXP_OPENDIR and) s +5 316 M +( SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one) s +5 305 M +( or more file names with full file attributes for each file. The) s +5 294 M +( client should call SSH_FXP_READDIR repeatedly until it has found the) s +5 283 M +( file it is looking for or until the server responds with a) s +5 272 M +( SSH_FXP_STATUS message indicating an error \(normally SSH_FX_EOF if) s +5 261 M +( there are no more files in the directory\). The client should then) s +5 250 M +( close the handle using the SSH_FXP_CLOSE request.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( The SSH_FXP_OPENDIR opens a directory for reading. It has the) s +5 679 M +( following format:) s +5 657 M +( uint32 id) s +5 646 M +( string path) s +5 624 M +( where `id' is the request identifier and `path' is the path name of) s +5 613 M +( the directory to be listed \(without any trailing slash\). See Section) s +5 602 M +( ``File Names'' for more information on file names. This will return) s +5 591 M +( an error if the path does not specify a directory or if the directory) s +5 580 M +( is not readable. The server will respond to this request with either) s +5 569 M +( a SSH_FXP_HANDLE or a SSH_FXP_STATUS message.) s +5 547 M +( Once the directory has been successfully opened, files \(and) s +5 536 M +( directories\) contained in it can be listed using SSH_FXP_READDIR) s +5 525 M +( requests. These are of the format) s +5 503 M +( uint32 id) s +5 492 M +( string handle) s +5 470 M +( where `id' is the request identifier, and `handle' is a handle) s +5 459 M +( returned by SSH_FXP_OPENDIR. \(It is a protocol error to attempt to) s +5 448 M +( use an ordinary file handle returned by SSH_FXP_OPEN.\)) s +5 426 M +( The server responds to this request with either a SSH_FXP_NAME or a) s +5 415 M +( SSH_FXP_STATUS message. One or more names may be returned at a time.) s +5 404 M +( Full status information is returned for each name in order to speed) s +5 393 M +( up typical directory listings.) s +5 371 M +( When the client no longer wishes to read more names from the) s +5 360 M +( directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle) s +5 349 M +( should be closed regardless of whether an error has occurred or not.) s +5 327 M +(6.8 Retrieving File Attributes) s +5 305 M +( Very often, file attributes are automatically returned by) s +5 294 M +( SSH_FXP_READDIR. However, sometimes there is need to specifically) s +5 283 M +( retrieve the attributes for a named file. This can be done using the) s +5 272 M +( SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests.) s +5 250 M +( SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT) s +5 239 M +( follows symbolic links on the server, whereas SSH_FXP_LSTAT does not) s +5 228 M +( follow symbolic links. Both have the same format:) s +5 206 M +( uint32 id) s +5 195 M +( string path) s +5 173 M +( where `id' is the request identifier, and `path' specifies the file) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 16]) s +_R +S +PStoPSsaved restore +%%Page: (16,17) 9 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 17 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( system object for which status is to be returned. The server) s +5 679 M +( responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS.) s +5 657 M +( SSH_FXP_FSTAT differs from the others in that it returns status) s +5 646 M +( information for an open file \(identified by the file handle\). Its) s +5 635 M +( format is as follows:) s +5 613 M +( uint32 id) s +5 602 M +( string handle) s +5 580 M +( where `id' is the request identifier and `handle' is a file handle) s +5 569 M +( returned by SSH_FXP_OPEN. The server responds to this request with) s +5 558 M +( SSH_FXP_ATTRS or SSH_FXP_STATUS.) s +5 536 M +(6.9 Setting File Attributes) s +5 514 M +( File attributes may be modified using the SSH_FXP_SETSTAT and) s +5 503 M +( SSH_FXP_FSETSTAT requests. These requests are used for operations) s +5 492 M +( such as changing the ownership, permissions or access times, as well) s +5 481 M +( as for truncating a file.) s +5 459 M +( The SSH_FXP_SETSTAT request is of the following format:) s +5 437 M +( uint32 id) s +5 426 M +( string path) s +5 415 M +( ATTRS attrs) s +5 393 M +( where `id' is the request identifier, `path' specifies the file) s +5 382 M +( system object \(e.g. file or directory\) whose attributes are to be) s +5 371 M +( modified, and `attrs' specifies the modifications to be made to its) s +5 360 M +( attributes. Attributes are discussed in more detail in Section) s +5 349 M +( ``File Attributes''.) s +5 327 M +( An error will be returned if the specified file system object does) s +5 316 M +( not exist or the user does not have sufficient rights to modify the) s +5 305 M +( specified attributes. The server responds to this request with a) s +5 294 M +( SSH_FXP_STATUS message.) s +5 272 M +( The SSH_FXP_FSETSTAT request modifies the attributes of a file which) s +5 261 M +( is already open. It has the following format:) s +5 239 M +( uint32 id) s +5 228 M +( string handle) s +5 217 M +( ATTRS attrs) s +5 195 M +( where `id' is the request identifier, `handle' \(MUST be returned by) s +5 184 M +( SSH_FXP_OPEN\) identifies the file whose attributes are to be) s +5 173 M +( modified, and `attrs' specifies the modifications to be made to its) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 17]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 18 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( attributes. Attributes are discussed in more detail in Section) s +5 679 M +( ``File Attributes''. The server will respond to this request with) s +5 668 M +( SSH_FXP_STATUS.) s +5 646 M +(6.10 Dealing with Symbolic links) s +5 624 M +( The SSH_FXP_READLINK request may be used to read the target of a) s +5 613 M +( symbolic link. It would have a data part as follows:) s +5 591 M +( uint32 id) s +5 580 M +( string path) s +5 558 M +( where `id' is the request identifier and `path' specifies the path) s +5 547 M +( name of the symlink to be read.) s +5 525 M +( The server will respond with a SSH_FXP_NAME packet containing only) s +5 514 M +( one name and a dummy attributes value. The name in the returned) s +5 503 M +( packet contains the target of the link. If an error occurs, the) s +5 492 M +( server may respond with SSH_FXP_STATUS.) s +5 470 M +( The SSH_FXP_SYMLINK request will create a symbolic link on the) s +5 459 M +( server. It is of the following format) s +5 437 M +( uint32 id) s +5 426 M +( string linkpath) s +5 415 M +( string targetpath) s +5 393 M +( where `id' is the request identifier, `linkpath' specifies the path) s +5 382 M +( name of the symlink to be created and `targetpath' specifies the) s +5 371 M +( target of the symlink. The server shall respond with a) s +5 360 M +( SSH_FXP_STATUS indicating either success \(SSH_FX_OK\) or an error) s +5 349 M +( condition.) s +5 327 M +(6.11 Canonicalizing the Server-Side Path Name) s +5 305 M +( The SSH_FXP_REALPATH request can be used to have the server) s +5 294 M +( canonicalize any given path name to an absolute path. This is useful) s +5 283 M +( for converting path names containing ".." components or relative) s +5 272 M +( pathnames without a leading slash into absolute paths. The format of) s +5 261 M +( the request is as follows:) s +5 239 M +( uint32 id) s +5 228 M +( string path) s +5 206 M +( where `id' is the request identifier and `path' specifies the path) s +5 195 M +( name to be canonicalized. The server will respond with a) s +5 184 M +( SSH_FXP_NAME packet containing only one name and a dummy attributes) s +5 173 M +( value. The name is the returned packet will be in canonical form.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 18]) s +_R +S +PStoPSsaved restore +%%Page: (18,19) 10 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 19 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( If an error occurs, the server may also respond with SSH_FXP_STATUS.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 19]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 20 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(7. Responses from the Server to the Client) s +5 668 M +( The server responds to the client using one of a few response) s +5 657 M +( packets. All requests can return a SSH_FXP_STATUS response upon) s +5 646 M +( failure. When the operation is successful, any of the responses may) s +5 635 M +( be returned \(depending on the operation\). If no data needs to be) s +5 624 M +( returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK) s +5 613 M +( status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used) s +5 602 M +( to return a file handle \(for SSH_FXP_OPEN and SSH_FXP_OPENDIR) s +5 591 M +( requests\), SSH_FXP_DATA is used to return data from SSH_FXP_READ,) s +5 580 M +( SSH_FXP_NAME is used to return one or more file names from a) s +5 569 M +( SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is) s +5 558 M +( used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and) s +5 547 M +( SSH_FXP_FSTAT requests.) s +5 525 M +( Exactly one response will be returned for each request. Each) s +5 514 M +( response packet contains a request identifier which can be used to) s +5 503 M +( match each response with the corresponding request. Note that it is) s +5 492 M +( legal to have several requests outstanding simultaneously, and the) s +5 481 M +( server is allowed to send responses to them in a different order from) s +5 470 M +( the order in which the requests were sent \(the result of their) s +5 459 M +( execution, however, is guaranteed to be as if they had been processed) s +5 448 M +( one at a time in the order in which the requests were sent\).) s +5 426 M +( Response packets are of the same general format as request packets.) s +5 415 M +( Each response packet begins with the request identifier.) s +5 393 M +( The format of the data portion of the SSH_FXP_STATUS response is as) s +5 382 M +( follows:) s +5 360 M +( uint32 id) s +5 349 M +( uint32 error/status code) s +5 338 M +( string error message \(ISO-10646 UTF-8 [RFC-2279]\)) s +5 327 M +( string language tag \(as defined in [RFC-1766]\)) s +5 305 M +( where `id' is the request identifier, and `error/status code') s +5 294 M +( indicates the result of the requested operation. The value SSH_FX_OK) s +5 283 M +( indicates success, and all other values indicate failure.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 20]) s +_R +S +PStoPSsaved restore +%%Page: (20,21) 11 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 21 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( Currently, the following values are defined \(other values may be) s +5 679 M +( defined by future versions of this protocol\):) s +5 657 M +( #define SSH_FX_OK 0) s +5 646 M +( #define SSH_FX_EOF 1) s +5 635 M +( #define SSH_FX_NO_SUCH_FILE 2) s +5 624 M +( #define SSH_FX_PERMISSION_DENIED 3) s +5 613 M +( #define SSH_FX_FAILURE 4) s +5 602 M +( #define SSH_FX_BAD_MESSAGE 5) s +5 591 M +( #define SSH_FX_NO_CONNECTION 6) s +5 580 M +( #define SSH_FX_CONNECTION_LOST 7) s +5 569 M +( #define SSH_FX_OP_UNSUPPORTED 8) s +5 547 M +( SSH_FX_OK) s +5 536 M +( Indicates successful completion of the operation.) s +5 514 M +( SSH_FX_EOF) s +5 503 M +( indicates end-of-file condition; for SSH_FX_READ it means that no) s +5 492 M +( more data is available in the file, and for SSH_FX_READDIR it) s +5 481 M +( indicates that no more files are contained in the directory.) s +5 459 M +( SSH_FX_NO_SUCH_FILE) s +5 448 M +( is returned when a reference is made to a file which should exist) s +5 437 M +( but doesn't.) s +5 415 M +( SSH_FX_PERMISSION_DENIED) s +5 404 M +( is returned when the authenticated user does not have sufficient) s +5 393 M +( permissions to perform the operation.) s +5 371 M +( SSH_FX_FAILURE) s +5 360 M +( is a generic catch-all error message; it should be returned if an) s +5 349 M +( error occurs for which there is no more specific error code) s +5 338 M +( defined.) s +5 316 M +( SSH_FX_BAD_MESSAGE) s +5 305 M +( may be returned if a badly formatted packet or protocol) s +5 294 M +( incompatibility is detected.) s +5 272 M +( SSH_FX_NO_CONNECTION) s +5 261 M +( is a pseudo-error which indicates that the client has no) s +5 250 M +( connection to the server \(it can only be generated locally by the) s +5 239 M +( client, and MUST NOT be returned by servers\).) s +5 217 M +( SSH_FX_CONNECTION_LOST) s +5 206 M +( is a pseudo-error which indicates that the connection to the) s +5 195 M +( server has been lost \(it can only be generated locally by the) s +5 184 M +( client, and MUST NOT be returned by servers\).) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 21]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 22 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( SSH_FX_OP_UNSUPPORTED) s +5 679 M +( indicates that an attempt was made to perform an operation which) s +5 668 M +( is not supported for the server \(it may be generated locally by) s +5 657 M +( the client if e.g. the version number exchange indicates that a) s +5 646 M +( required feature is not supported by the server, or it may be) s +5 635 M +( returned by the server if the server does not implement an) s +5 624 M +( operation\).) s +5 602 M +( The SSH_FXP_HANDLE response has the following format:) s +5 580 M +( uint32 id) s +5 569 M +( string handle) s +5 547 M +( where `id' is the request identifier, and `handle' is an arbitrary) s +5 536 M +( string that identifies an open file or directory on the server. The) s +5 525 M +( handle is opaque to the client; the client MUST NOT attempt to) s +5 514 M +( interpret or modify it in any way. The length of the handle string) s +5 503 M +( MUST NOT exceed 256 data bytes.) s +5 481 M +( The SSH_FXP_DATA response has the following format:) s +5 459 M +( uint32 id) s +5 448 M +( string data) s +5 426 M +( where `id' is the request identifier, and `data' is an arbitrary byte) s +5 415 M +( string containing the requested data. The data string may be at most) s +5 404 M +( the number of bytes requested in a SSH_FXP_READ request, but may also) s +5 393 M +( be shorter if end of file is reached or if the read is from something) s +5 382 M +( other than a regular file.) s +5 360 M +( The SSH_FXP_NAME response has the following format:) s +5 338 M +( uint32 id) s +5 327 M +( uint32 count) s +5 316 M +( repeats count times:) s +5 305 M +( string filename) s +5 294 M +( string longname) s +5 283 M +( ATTRS attrs) s +5 261 M +( where `id' is the request identifier, `count' is the number of names) s +5 250 M +( returned in this response, and the remaining fields repeat `count') s +5 239 M +( times \(so that all three fields are first included for the first) s +5 228 M +( file, then for the second file, etc\). In the repeated part,) s +5 217 M +( `filename' is a file name being returned \(for SSH_FXP_READDIR, it) s +5 206 M +( will be a relative name within the directory, without any path) s +5 195 M +( components; for SSH_FXP_REALPATH it will be an absolute path name\),) s +5 184 M +( `longname' is an expanded format for the file name, similar to what) s +5 173 M +( is returned by "ls -l" on Unix systems, and `attrs' is the attributes) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 22]) s +_R +S +PStoPSsaved restore +%%Page: (22,23) 12 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 23 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +( of the file as described in Section ``File Attributes''.) s +5 668 M +( The format of the `longname' field is unspecified by this protocol.) s +5 657 M +( It MUST be suitable for use in the output of a directory listing) s +5 646 M +( command \(in fact, the recommended operation for a directory listing) s +5 635 M +( command is to simply display this data\). However, clients SHOULD NOT) s +5 624 M +( attempt to parse the longname field for file attributes; they SHOULD) s +5 613 M +( use the attrs field instead.) s +5 591 M +( The recommended format for the longname field is as follows:) s +5 569 M +( -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer) s +5 558 M +( 1234567890 123 12345678 12345678 12345678 123456789012) s +5 536 M +( Here, the first line is sample output, and the second field indicates) s +5 525 M +( widths of the various fields. Fields are separated by spaces. The) s +5 514 M +( first field lists file permissions for user, group, and others; the) s +5 503 M +( second field is link count; the third field is the name of the user) s +5 492 M +( who owns the file; the fourth field is the name of the group that) s +5 481 M +( owns the file; the fifth field is the size of the file in bytes; the) s +5 470 M +( sixth field \(which actually may contain spaces, but is fixed to 12) s +5 459 M +( characters\) is the file modification time, and the seventh field is) s +5 448 M +( the file name. Each field is specified to be a minimum of certain) s +5 437 M +( number of character positions \(indicated by the second line above\),) s +5 426 M +( but may also be longer if the data does not fit in the specified) s +5 415 M +( length.) s +5 393 M +( The SSH_FXP_ATTRS response has the following format:) s +5 371 M +( uint32 id) s +5 360 M +( ATTRS attrs) s +5 338 M +( where `id' is the request identifier, and `attrs' is the returned) s +5 327 M +( file attributes as described in Section ``File Attributes''.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 23]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 24 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(8. Vendor-Specific Extensions) s +5 668 M +( The SSH_FXP_EXTENDED request provides a generic extension mechanism) s +5 657 M +( for adding vendor-specific commands. The request has the following) s +5 646 M +( format:) s +5 624 M +( uint32 id) s +5 613 M +( string extended-request) s +5 602 M +( ... any request-specific data ...) s +5 580 M +( where `id' is the request identifier, and `extended-request' is a) s +5 569 M +( string of the format "name@domain", where domain is an internet) s +5 558 M +( domain name of the vendor defining the request. The rest of the) s +5 547 M +( request is completely vendor-specific, and servers should only) s +5 536 M +( attempt to interpret it if they recognize the `extended-request') s +5 525 M +( name.) s +5 503 M +( The server may respond to such requests using any of the response) s +5 492 M +( packets defined in Section ``Responses from the Server to the) s +5 481 M +( Client''. Additionally, the server may also respond with a) s +5 470 M +( SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does) s +5 459 M +( not recognize the `extended-request' name, then the server MUST) s +5 448 M +( respond with SSH_FXP_STATUS with error/status set to) s +5 437 M +( SSH_FX_OP_UNSUPPORTED.) s +5 415 M +( The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary) s +5 404 M +( extension-specific data from the server to the client. It is of the) s +5 393 M +( following format:) s +5 371 M +( uint32 id) s +5 360 M +( ... any request-specific data ...) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 24]) s +_R +S +PStoPSsaved restore +%%Page: (24,25) 13 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 25 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(9. Security Considerations) s +5 668 M +( This protocol assumes that it is run over a secure channel and that) s +5 657 M +( the endpoints of the channel have been authenticated. Thus, this) s +5 646 M +( protocol assumes that it is externally protected from network-level) s +5 635 M +( attacks.) s +5 613 M +( This protocol provides file system access to arbitrary files on the) s +5 602 M +( server \(only constrained by the server implementation\). It is the) s +5 591 M +( responsibility of the server implementation to enforce any access) s +5 580 M +( controls that may be required to limit the access allowed for any) s +5 569 M +( particular user \(the user being authenticated externally to this) s +5 558 M +( protocol, typically using the SSH User Authentication Protocol [6].) s +5 536 M +( Care must be taken in the server implementation to check the validity) s +5 525 M +( of received file handle strings. The server should not rely on them) s +5 514 M +( directly; it MUST check the validity of each handle before relying on) s +5 503 M +( it.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 25]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 26 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(10. Changes from previous protocol versions) s +5 668 M +( The SSH File Transfer Protocol has changed over time, before it's) s +5 657 M +( standardization. The following is a description of the incompatible) s +5 646 M +( changes between different versions.) s +5 624 M +(10.1 Changes between versions 3 and 2) s +5 602 M +( o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.) s +5 580 M +( o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were) s +5 569 M +( added.) s +5 547 M +( o The SSH_FXP_STATUS message was changed to include fields `error) s +5 536 M +( message' and `language tag'.) s +5 503 M +(10.2 Changes between versions 2 and 1) s +5 481 M +( o The SSH_FXP_RENAME message was added.) s +5 448 M +(10.3 Changes between versions 1 and 0) s +5 426 M +( o Implementation changes, no actual protocol changes.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 26]) s +_R +S +PStoPSsaved restore +%%Page: (26,27) 14 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 27 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(11. Trademark Issues) s +5 668 M +( "ssh" is a registered trademark of SSH Communications Security Corp) s +5 657 M +( in the United States and/or other countries.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 27]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 28 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(References) s +5 668 M +( [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and) s +5 657 M +( P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January) s +5 646 M +( 1999.) s +5 624 M +( [2] Institute of Electrical and Electronics Engineers, "Information) s +5 613 M +( Technology - Portable Operating System Interface \(POSIX\) - Part) s +5 602 M +( 1: System Application Program Interface \(API\) [C Language]",) s +5 591 M +( IEEE Standard 1003.2, 1996.) s +5 569 M +( [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 558 M +( Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh-) s +5 547 M +( architecture-09 \(work in progress\), July 2001.) s +5 525 M +( [4] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 514 M +( Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh-) s +5 503 M +( architecture-09 \(work in progress\), July 2001.) s +5 481 M +( [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 470 M +( Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-11) s +5 459 M +( \(work in progress\), July 2001.) s +5 437 M +( [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 426 M +( Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh-) s +5 415 M +( userauth-11 \(work in progress\), July 2001.) s +5 382 M +(Authors' Addresses) s +5 360 M +( Tatu Ylonen) s +5 349 M +( SSH Communications Security Corp) s +5 338 M +( Fredrikinkatu 42) s +5 327 M +( HELSINKI FIN-00100) s +5 316 M +( Finland) s +5 294 M +( EMail: [email protected]) s +5 261 M +( Sami Lehtinen) s +5 250 M +( SSH Communications Security Corp) s +5 239 M +( Fredrikinkatu 42) s +5 228 M +( HELSINKI FIN-00100) s +5 217 M +( Finland) s +5 195 M +( EMail: [email protected]) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 28]) s +_R +S +PStoPSsaved restore +%%Page: (28,29) 15 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 29 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2001) s +5 690 M +(Full Copyright Statement) s +5 668 M +( Copyright \(C\) The Internet Society \(2001\). All Rights Reserved.) s +5 646 M +( This document and translations of it may be copied and furnished to) s +5 635 M +( others, and derivative works that comment on or otherwise explain it) s +5 624 M +( or assist in its implementation may be prepared, copied, published) s +5 613 M +( and distributed, in whole or in part, without restriction of any) s +5 602 M +( kind, provided that the above copyright notice and this paragraph are) s +5 591 M +( included on all such copies and derivative works. However, this) s +5 580 M +( document itself may not be modified in any way, such as by removing) s +5 569 M +( the copyright notice or references to the Internet Society or other) s +5 558 M +( Internet organizations, except as needed for the purpose of) s +5 547 M +( developing Internet standards in which case the procedures for) s +5 536 M +( copyrights defined in the Internet Standards process must be) s +5 525 M +( followed, or as required to translate it into languages other than) s +5 514 M +( English.) s +5 492 M +( The limited permissions granted above are perpetual and will not be) s +5 481 M +( revoked by the Internet Society or its successors or assigns.) s +5 459 M +( This document and the information contained herein is provided on an) s +5 448 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 437 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 426 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 415 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 404 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 382 M +(Acknowledgement) s +5 360 M +( Funding for the RFC Editor function is currently provided by the) s +5 349 M +( Internet Society.) s +5 129 M +(Ylonen & Lehtinen Expires April 1, 2002 [Page 29]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 30 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +_R +S +PStoPSsaved restore +%%Trailer +%%Pages: 30 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt new file mode 100644 index 0000000000..c4ec8c1125 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-02.txt @@ -0,0 +1,1627 @@ + + + +Network Working Group T. Ylonen +Internet-Draft S. Lehtinen +Expires: April 1, 2002 SSH Communications Security Corp + October 2001 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-02.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 1, 2002. + +Copyright Notice + + Copyright (C) The Internet Society (2001). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 1] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . . 5 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . . 7 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . . 8 + 6. Requests From the Client to the Server . . . . . . . . . . . 10 + 6.1 Request Synchronization and Reordering . . . . . . . . . . . 10 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . . 11 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . . 13 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . . 14 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . . 15 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . . 15 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . . 16 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . . 17 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . . 18 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . . 18 + 7. Responses from the Server to the Client . . . . . . . . . . 20 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . . 24 + 9. Security Considerations . . . . . . . . . . . . . . . . . . 25 + 10. Changes from previous protocol versions . . . . . . . . . . 26 + 10.1 Changes between versions 3 and 2 . . . . . . . . . . . . . . 26 + 10.2 Changes between versions 2 and 1 . . . . . . . . . . . . . . 26 + 10.3 Changes between versions 1 and 0 . . . . . . . . . . . . . . 26 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . . 27 + References . . . . . . . . . . . . . . . . . . . . . . . . . 28 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 28 + Full Copyright Statement . . . . . . . . . . . . . . . . . . 29 + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 2] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [3]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft.[3]. + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 3] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [5] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 4] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 5] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The following values are defined for packet types. + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 6] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +4. Protocol Initialization + + When the file transfer protocol starts, it first sends a SSH_FXP_INIT + (including its version number) packet to the server. The server + responds with a SSH_FXP_VERSION packet, supplying the lowest of its + own and the client's version number. Both parties should from then + on adhere to particular version of the protocol. + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + <extension data> + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + <extension data> + + The version number of the protocol specified in this document is 3. + The version number should be incremented for each incompatible + revision of this protocol. + + The extension data in the above packets may be empty, or may be a + sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 7] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. It + is basically just a combination of elementary types, but is defined + once because of the non-trivial description of the fields and to + ensure maintainability. + + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ACMODTIME + uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The `size' field specifies the size of the file in bytes. + + The `uid' and `gid' fields contain numeric Unix-like user and group + identifiers, respectively. + + The `permissions' field contains a bit mask of file permissions as + defined by posix [1]. + + The `atime' and `mtime' contain the access and modification times of + the files, respectively. They are represented as seconds from Jan 1, + 1970 in UTC. + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 8] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + The flags bits are defined to have the following values: + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 + #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 9] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation of it is a monotonically increasing + request sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 10] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + uint32 id + string filename + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 11] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + Regardless the server operating system, the file will always be + opened in "binary" mode (i.e., no translations between different + character sets and newline encodings). + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 12] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the SSH_FXP_READ + message, which has the following format: + + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. For normal disk + files, it is guaranteed that this will read the specified number of + bytes, or up to end of file. For e.g. device files this may return + fewer bytes than requested. + + Writing to a file is achieved using the SSH_FXP_WRITE message, which + has the following format: + + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 13] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath + string newpath + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 14] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path + ATTRS attrs + + where `id' is the request identifier, `path' and `attrs' specifies + the modifications to be made to its attributes. See Section ``File + Names'' for more information on file names. Attributes are discussed + in more detail in Section ``File Attributes''. specifies the + directory to be created. An error will be returned if a file or + directory with the specified path already exists. The server will + respond to this request with a SSH_FXP_STATUS message. + + Directories can be removed using the SSH_FXP_RMDIR request, which + has the following format: + + uint32 id + string path + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. An error will be returned if no directory + with the specified path exists, or if the specified directory is not + empty, or if the path specified a file system object other than a + directory. The server responds to this request with a SSH_FXP_STATUS + message. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 15] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path + + where `id' is the request identifier, and `path' specifies the file + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 16] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + uint32 id + string path + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 17] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + uint32 id + string linkpath + string targetpath + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing only one name and a dummy attributes + value. The name is the returned packet will be in canonical form. + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 18] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + If an error occurs, the server may also respond with SSH_FXP_STATUS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 19] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 20] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which should exist + but doesn't. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 21] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + The SSH_FXP_NAME response has the following format: + + uint32 id + uint32 count + repeats count times: + string filename + string longname + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + `longname' is an expanded format for the file name, similar to what + is returned by "ls -l" on Unix systems, and `attrs' is the attributes + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 22] + +Internet-Draft SSH File Transfer Protocol October 2001 + + + of the file as described in Section ``File Attributes''. + + The format of the `longname' field is unspecified by this protocol. + It MUST be suitable for use in the output of a directory listing + command (in fact, the recommended operation for a directory listing + command is to simply display this data). However, clients SHOULD NOT + attempt to parse the longname field for file attributes; they SHOULD + use the attrs field instead. + + The recommended format for the longname field is as follows: + + -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer + 1234567890 123 12345678 12345678 12345678 123456789012 + + Here, the first line is sample output, and the second field indicates + widths of the various fields. Fields are separated by spaces. The + first field lists file permissions for user, group, and others; the + second field is link count; the third field is the name of the user + who owns the file; the fourth field is the name of the group that + owns the file; the fifth field is the size of the file in bytes; the + sixth field (which actually may contain spaces, but is fixed to 12 + characters) is the file modification time, and the seventh field is + the file name. Each field is specified to be a minimum of certain + number of character positions (indicated by the second line above), + but may also be longer if the data does not fit in the specified + length. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 23] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 24] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [6]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 25] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.2 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.3 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 26] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 27] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [3] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- + architecture-09 (work in progress), July 2001. + + [4] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- + architecture-09 (work in progress), July 2001. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-11 + (work in progress), July 2001. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- + userauth-11 (work in progress), July 2001. + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 28] + +Internet-Draft SSH File Transfer Protocol October 2001 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Ylonen & Lehtinen Expires April 1, 2002 [Page 29] + + + diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps new file mode 100644 index 0000000000..6a40cd6067 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.2.ps @@ -0,0 +1,3511 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Wed Nov 12 12:18:50 2003 +%%Orientation: Portrait +%%Pages: 18 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Secure Shell Working Group J. Galbraith) s +5 690 M +(Internet-Draft VanDyke Software) s +5 679 M +(Expires: April 16, 2003 T. Ylonen) s +5 668 M +( S. Lehtinen) s +5 657 M +( SSH Communications Security Corp) s +5 646 M +( October 16, 2002) s +5 613 M +( SSH File Transfer Protocol) s +5 602 M +( draft-ietf-secsh-filexfer-03.txt) s +5 580 M +(Status of this Memo) s +5 558 M +( This document is an Internet-Draft and is in full conformance with) s +5 547 M +( all provisions of Section 10 of RFC2026.) s +5 525 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 514 M +( Task Force \(IETF\), its areas, and its working groups. Note that) s +5 503 M +( other groups may also distribute working documents as Internet-) s +5 492 M +( Drafts.) s +5 470 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 459 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 448 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 437 M +( material or to cite them other than as "work in progress.") s +5 415 M +( The list of current Internet-Drafts can be accessed at http://) s +5 404 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 382 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 371 M +( http://www.ietf.org/shadow.html.) s +5 349 M +( This Internet-Draft will expire on April 16, 2003.) s +5 327 M +(Copyright Notice) s +5 305 M +( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s +5 283 M +(Abstract) s +5 261 M +( The SSH File Transfer Protocol provides secure file transfer) s +5 250 M +( functionality over any reliable data stream. It is the standard file) s +5 239 M +( transfer protocol for use with the SSH2 protocol. This document) s +5 228 M +( describes the file transfer protocol and its interface to the SSH2) s +5 217 M +( protocol suite.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(Table of Contents) s +5 668 M +( 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 657 M +( 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4) s +5 646 M +( 3. General Packet Format . . . . . . . . . . . . . . . . . . 5) s +5 635 M +( 4. Protocol Initialization . . . . . . . . . . . . . . . . . 7) s +5 624 M +( 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 7) s +5 613 M +( 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 7) s +5 602 M +( 4.3 Determining Server Newline Convention . . . . . . . . . . 8) s +5 591 M +( 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 9) s +5 580 M +( 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 9) s +5 569 M +( 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 10) s +5 558 M +( 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 10) s +5 547 M +( 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 10) s +5 536 M +( 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 11) s +5 525 M +( 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 11) s +5 514 M +( 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 11) s +5 503 M +( 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 12) s +5 492 M +( 6. Requests From the Client to the Server . . . . . . . . . . 13) s +5 481 M +( 6.1 Request Synchronization and Reordering . . . . . . . . . . 13) s +5 470 M +( 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 14) s +5 459 M +( 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 14) s +5 448 M +( 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 17) s +5 437 M +( 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 18) s +5 426 M +( 6.6 Creating and Deleting Directories . . . . . . . . . . . . 19) s +5 415 M +( 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 19) s +5 404 M +( 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 20) s +5 393 M +( 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 21) s +5 382 M +( 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 22) s +5 371 M +( 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 23) s +5 360 M +( 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 23) s +5 349 M +( 7. Responses from the Server to the Client . . . . . . . . . 24) s +5 338 M +( 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 28) s +5 327 M +( 9. Security Considerations . . . . . . . . . . . . . . . . . 29) s +5 316 M +( 10. Changes from previous protocol versions . . . . . . . . . 30) s +5 305 M +( 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 30) s +5 294 M +( 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 31) s +5 283 M +( 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 31) s +5 272 M +( 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 31) s +5 261 M +( 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 32) s +5 250 M +( References . . . . . . . . . . . . . . . . . . . . . . . . 33) s +5 239 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . 33) s +5 228 M +( Full Copyright Statement . . . . . . . . . . . . . . . . . 35) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(1. Introduction) s +5 668 M +( This protocol provides secure file transfer \(and more generally file) s +5 657 M +( system access\) functionality over a reliable data stream, such as a) s +5 646 M +( channel in the SSH2 protocol [5].) s +5 624 M +( This protocol is designed so that it could be used to implement a) s +5 613 M +( secure remote file system service, as well as a secure file transfer) s +5 602 M +( service.) s +5 580 M +( This protocol assumes that it runs over a secure channel, and that) s +5 569 M +( the server has already authenticated the user at the client end, and) s +5 558 M +( that the identity of the client user is externally available to the) s +5 547 M +( server implementation.) s +5 525 M +( In general, this protocol follows a simple request-response model.) s +5 514 M +( Each request and response contains a sequence number and multiple) s +5 503 M +( requests may be pending simultaneously. There are a relatively large) s +5 492 M +( number of different request messages, but a small number of possible) s +5 481 M +( response messages. Each request has one or more response messages) s +5 470 M +( that may be returned in result \(e.g., a read either returns data or) s +5 459 M +( reports error status\).) s +5 437 M +( The packet format descriptions in this specification follow the) s +5 426 M +( notation presented in the secsh architecture draft. [5]) s +5 404 M +( Even though this protocol is described in the context of the SSH2) s +5 393 M +( protocol, this protocol is general and independent of the rest of the) s +5 382 M +( SSH2 protocol suite. It could be used in a number of different) s +5 371 M +( applications, such as secure file transfer over TLS RFC 2246 [1] and) s +5 360 M +( transfer of management information in VPN applications.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(2. Use with the SSH Connection Protocol) s +5 668 M +( When used with the SSH2 Protocol suite, this protocol is intended to) s +5 657 M +( be used from the SSH Connection Protocol [7] as a subsystem, as) s +5 646 M +( described in section ``Starting a Shell or a Command''. The) s +5 635 M +( subsystem name used with this protocol is "sftp".) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(3. General Packet Format) s +5 668 M +( All packets transmitted over the secure connection are of the) s +5 657 M +( following format:) s +5 635 M +( uint32 length) s +5 624 M +( byte type) s +5 613 M +( byte[length - 1] data payload) s +5 591 M +( That is, they are just data preceded by 32-bit length and 8-bit type) s +5 580 M +( fields. The `length' is the length of the data area, and does not) s +5 569 M +( include the `length' field itself. The format and interpretation of) s +5 558 M +( the data area depends on the packet type.) s +5 536 M +( All packet descriptions below only specify the packet type and the) s +5 525 M +( data that goes into the data field. Thus, they should be prefixed by) s +5 514 M +( the `length' and `type' fields.) s +5 492 M +( The maximum size of a packet is in practice determined by the client) s +5 481 M +( \(the maximum size of read or write requests that it sends, plus a few) s +5 470 M +( bytes of packet overhead\). All servers SHOULD support packets of at) s +5 459 M +( least 34000 bytes \(where the packet size refers to the full length,) s +5 448 M +( including the header above\). This should allow for reads and writes) s +5 437 M +( of at most 32768 bytes.) s +5 415 M +( There is no limit on the number of outstanding \(non-acknowledged\)) s +5 404 M +( requests that the client may send to the server. In practice this is) s +5 393 M +( limited by the buffering available on the data stream and the queuing) s +5 382 M +( performed by the server. If the server's queues are full, it should) s +5 371 M +( not read any more data from the stream, and flow control will prevent) s +5 360 M +( the client from sending more requests. Note, however, that while) s +5 349 M +( there is no restriction on the protocol level, the client's API may) s +5 338 M +( provide a limit in order to prevent infinite queuing of outgoing) s +5 327 M +( requests at the client.) s +5 305 M +( The following values are defined for packet types.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( #define SSH_FXP_INIT 1) s +5 679 M +( #define SSH_FXP_VERSION 2) s +5 668 M +( #define SSH_FXP_OPEN 3) s +5 657 M +( #define SSH_FXP_CLOSE 4) s +5 646 M +( #define SSH_FXP_READ 5) s +5 635 M +( #define SSH_FXP_WRITE 6) s +5 624 M +( #define SSH_FXP_LSTAT 7) s +5 613 M +( #define SSH_FXP_FSTAT 8) s +5 602 M +( #define SSH_FXP_SETSTAT 9) s +5 591 M +( #define SSH_FXP_FSETSTAT 10) s +5 580 M +( #define SSH_FXP_OPENDIR 11) s +5 569 M +( #define SSH_FXP_READDIR 12) s +5 558 M +( #define SSH_FXP_REMOVE 13) s +5 547 M +( #define SSH_FXP_MKDIR 14) s +5 536 M +( #define SSH_FXP_RMDIR 15) s +5 525 M +( #define SSH_FXP_REALPATH 16) s +5 514 M +( #define SSH_FXP_STAT 17) s +5 503 M +( #define SSH_FXP_RENAME 18) s +5 492 M +( #define SSH_FXP_READLINK 19) s +5 481 M +( #define SSH_FXP_SYMLINK 20) s +5 459 M +( #define SSH_FXP_STATUS 101) s +5 448 M +( #define SSH_FXP_HANDLE 102) s +5 437 M +( #define SSH_FXP_DATA 103) s +5 426 M +( #define SSH_FXP_NAME 104) s +5 415 M +( #define SSH_FXP_ATTRS 105) s +5 393 M +( #define SSH_FXP_EXTENDED 200) s +5 382 M +( #define SSH_FXP_EXTENDED_REPLY 201) s +5 360 M +( RESERVED_FOR_EXTENSIONS 210-255) s +5 338 M +( Additional packet types should only be defined if the protocol) s +5 327 M +( version number \(see Section ``Protocol Initialization''\) is) s +5 316 M +( incremented, and their use MUST be negotiated using the version) s +5 305 M +( number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY) s +5 294 M +( packets can be used to implement vendor-specific extensions. See) s +5 283 M +( Section ``Vendor-Specific-Extensions'' for more details.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(4. Protocol Initialization) s +5 668 M +( When the file transfer protocol starts, the client first sends a) s +5 657 M +( SSH_FXP_INIT \(including its version number\) packet to the server.) s +5 646 M +( The server responds with a SSH_FXP_VERSION packet, supplying the) s +5 635 M +( lowest of its own and the client's version number. Both parties) s +5 624 M +( should from then on adhere to particular version of the protocol.) s +5 602 M +( The version number of the protocol specified in this document is 4.) s +5 591 M +( The version number should be incremented for each incompatible) s +5 580 M +( revision of this protocol.) s +5 558 M +(4.1 Client Initialization) s +5 536 M +( The SSH_FXP_INIT packet \(from client to server\) has the following) s +5 525 M +( data:) s +5 503 M +( uint32 version) s +5 481 M +( Version 3 of this protocol allowed clients to include extensions in) s +5 470 M +( the SSH_FXP_INIT packet; however, this can cause interoperability) s +5 459 M +( problems with version 1 and version 2 servers because the client must) s +5 448 M +( send this packet before knowing the servers version.) s +5 426 M +( In this version of the protocol, clients MUST use the) s +5 415 M +( SSH_FXP_EXTENDED packet to send extensions to the server after) s +5 404 M +( version exchange has completed. Clients MUST NOT include extensions) s +5 393 M +( in the version packet. This will prevent interoperability problems) s +5 382 M +( with older servers) s +5 360 M +(4.2 Server Initialization) s +5 338 M +( The SSH_FXP_VERSION packet \(from server to client\) has the following) s +5 327 M +( data:) s +5 305 M +( uint32 version) s +5 294 M +( <extension data>) s +5 272 M +( 'version' is the lower of the protocol version supported by the) s +5 261 M +( server and the version number received from the client.) s +5 239 M +( The extension data may be empty, or may be a sequence of) s +5 217 M +( string extension_name) s +5 206 M +( string extension_data) s +5 184 M +( pairs \(both strings MUST always be present if one is, but the) s +5 173 M +( `extension_data' string may be of zero length\). If present, these) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( strings indicate extensions to the baseline protocol. The) s +5 679 M +( `extension_name' field\(s\) identify the name of the extension. The) s +5 668 M +( name should be of the form "name@domain", where the domain is the DNS) s +5 657 M +( domain name of the organization defining the extension. Additional) s +5 646 M +( names that are not of this format may be defined later by the IETF.) s +5 635 M +( Implementations MUST silently ignore any extensions whose name they) s +5 624 M +( do not recognize.) s +5 602 M +(4.3 Determining Server Newline Convention) s +5 580 M +( In order to correctly process text files in a cross platform) s +5 569 M +( compatible way, the newline convention must be converted from that of) s +5 558 M +( the server to that of the client, or, during an upload, from that of) s +5 547 M +( the client to that of the server.) s +5 525 M +( Versions 3 and prior of this protocol made no provisions for) s +5 514 M +( processing text files. Many clients implemented some sort of) s +5 503 M +( conversion algorithm, but without either a 'canonical' on the wire) s +5 492 M +( format or knowledge of the servers newline convention, correct) s +5 481 M +( conversion was not always possible.) s +5 459 M +( Starting with Version 4, the SSH_FXF_TEXT file open flag \(Section) s +5 448 M +( 6.3\) makes it possible to request that the server translate a file to) s +5 437 M +( a 'canonical' on the wire format. This format uses \\r\\n as the line) s +5 426 M +( separator.) s +5 404 M +( Servers for systems using multiple newline characters \(for example,) s +5 393 M +( Mac OS X or VMS\) or systems using counted records, MUST translate to) s +5 382 M +( the canonical form.) s +5 360 M +( However, to ease the burden of implementation on servers that use a) s +5 349 M +( single, simple separator sequence, the following extension allows the) s +5 338 M +( canonical format to be changed.) s +5 316 M +( string "newline") s +5 305 M +( string new-canonical-separator \(usually "\\r" or "\\n" or "\\r\\n"\)) s +5 283 M +( All clients MUST support this extension.) s +5 261 M +( When processing text files, clients SHOULD NOT translate any) s +5 250 M +( character or sequence that is not an exact match of the servers) s +5 239 M +( newline separator.) s +5 217 M +( In particular, if the newline sequence being used is the canonical) s +5 206 M +( "\\r\\n" sequence, a lone \\r or a lone \\n SHOULD be written through) s +5 195 M +( without change.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(5. File Attributes) s +5 668 M +( A new compound data type is defined for encoding file attributes.) s +5 657 M +( The same encoding is used both when returning file attributes from) s +5 646 M +( the server and when sending file attributes to the server. When) s +5 635 M +( sending it to the server, the flags field specifies which attributes) s +5 624 M +( are included, and the server will use default values for the) s +5 613 M +( remaining attributes \(or will not modify the values of remaining) s +5 602 M +( attributes\). When receiving attributes from the server, the flags) s +5 591 M +( specify which attributes are included in the returned data. The) s +5 580 M +( server normally returns all attributes it knows about.) s +5 558 M +( uint32 flags) s +5 547 M +( byte type always present) s +5 536 M +( uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE) s +5 525 M +( string owner present only if flag SSH_FILEXFER_ATTR_OWNERGROUP) s +5 514 M +( string group present only if flag SSH_FILEXFER_ATTR_OWNERGROUP) s +5 503 M +( uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS) s +5 492 M +( uint32 atime present only if flag SSH_FILEXFER_ATTR_ACCESSTIME) s +5 481 M +( uint32 createtime present only if flag SSH_FILEXFER_ATTR_CREATETIME) s +5 470 M +( uint32 mtime present only if flag SSH_FILEXFER_ATTR_MODIFYTIME) s +5 459 M +( string acl present only if flag SSH_FILEXFER_ATTR_ACL) s +5 448 M +( uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED) s +5 437 M +( string extended_type) s +5 426 M +( string extended_data) s +5 415 M +( ... more extended data \(extended_type - extended_data pairs\),) s +5 404 M +( so that number of pairs equals extended_count) s +5 371 M +(5.1 Flags) s +5 349 M +( The `flags' specify which of the fields are present. Those fields) s +5 338 M +( for which the corresponding flag is not set are not present \(not) s +5 327 M +( included in the packet\). New flags can only be added by incrementing) s +5 316 M +( the protocol version number \(or by using the extension mechanism) s +5 305 M +( described below\).) s +5 283 M +( The flags bits are defined to have the following values:) s +5 261 M +( #define SSH_FILEXFER_ATTR_SIZE 0x00000001) s +5 250 M +( #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004) s +5 239 M +( #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008) s +5 228 M +( #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010) s +5 217 M +( #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020) s +5 206 M +( #define SSH_FILEXFER_ATTR_ACL 0x00000040) s +5 195 M +( #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080) s +5 184 M +( #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( In previous versions of this protocol flags value 0x00000002 was) s +5 679 M +( SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP) s +5 668 M +( was given a new value in order to ease implementation burden.) s +5 657 M +( 0x00000002 MUST NOT appear in the mask. Some future version of this) s +5 646 M +( protocol may reuse flag 0x00000002.) s +5 624 M +(5.2 Type) s +5 602 M +( The type field is always present. The following types are defined:) s +5 580 M +( #define SSH_FILEXFER_TYPE_REGULAR 1) s +5 569 M +( #define SSH_FILEXFER_TYPE_DIRECTORY 2) s +5 558 M +( #define SSH_FILEXFER_TYPE_SYMLINK 3) s +5 547 M +( #define SSH_FILEXFER_TYPE_SPECIAL 4) s +5 536 M +( #define SSH_FILEXFER_TYPE_UNKNOWN 5) s +5 514 M +( On a POSIX system, these values would be derived from the permission) s +5 503 M +( field.) s +5 481 M +(5.3 Size) s +5 459 M +( The `size' field specifies the size of the file on disk, in bytes.) s +5 448 M +( If it is present during file creation, it should be considered a hint) s +5 437 M +( as to the files eventual size.) s +5 415 M +( Files opened with the SSH_FXF_TEXT flag may have a size that is) s +5 404 M +( greater or less than the value of the size field.) s +5 382 M +(5.4 Owner and Group) s +5 360 M +( The `owner' and `group' fields are represented as UTF-8 strings; this) s +5 349 M +( is the form used by NFS v4. See NFS version 4 Protocol. [3] The) s +5 338 M +( following text is selected quotations from section 5.6.) s +5 316 M +( To avoid a representation that is tied to a particular underlying) s +5 305 M +( implementation at the client or server, the use of UTF-8 strings has) s +5 294 M +( been chosen. The string should be of the form user@dns_domain".) s +5 283 M +( This will allow for a client and server that do not use the same) s +5 272 M +( local representation the ability to translate to a common syntax that) s +5 261 M +( can be interpreted by both. In the case where there is no) s +5 250 M +( translation available to the client or server, the attribute value) s +5 239 M +( must be constructed without the "@". Therefore, the absence of the @) s +5 228 M +( from the owner or owner_group attribute signifies that no translation) s +5 217 M +( was available and the receiver of the attribute should not place any) s +5 206 M +( special meaning with the attribute value. Even though the attribute) s +5 195 M +( value can not be translated, it may still be useful. In the case of) s +5 184 M +( a client, the attribute string may be used for local display of) s +5 173 M +( ownership.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(5.5 Permissions) s +5 668 M +( The `permissions' field contains a bit mask of file permissions as) s +5 657 M +( defined by POSIX [1].) s +5 635 M +(5.6 Times) s +5 613 M +( The 'atime', 'createtime', and 'mtime' contain the access, creation,) s +5 602 M +( and modification times of the files, respectively. They are) s +5 591 M +( represented as seconds from Jan 1, 1970 in UTC.) s +5 569 M +(5.7 ACL) s +5 547 M +( The 'ACL' field contains an ACL similar to that defined in section) s +5 536 M +( 5.9 of NFS version 4 Protocol [3].) s +5 514 M +( uint32 ace-count) s +5 492 M +( repeated ace-count time:) s +5 481 M +( uint32 ace-type) s +5 470 M +( uint32 ace-flag) s +5 459 M +( uint32 ace-mask) s +5 448 M +( string who [UTF-8]) s +5 426 M +( ace-type is one of the following four values \(taken from NFS Version) s +5 415 M +( 4 Protocol [3]:) s +5 393 M +( const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000;) s +5 382 M +( const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001;) s +5 371 M +( const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002;) s +5 360 M +( const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003;) s +5 338 M +( ace-flag is a combination of the following flag values. See NFS) s +5 327 M +( Version 4 Protocol [3] section 5.9.2:) s +5 305 M +( const ACE4_FILE_INHERIT_ACE = 0x00000001;) s +5 294 M +( const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002;) s +5 283 M +( const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004;) s +5 272 M +( const ACE4_INHERIT_ONLY_ACE = 0x00000008;) s +5 261 M +( const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010;) s +5 250 M +( const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020;) s +5 239 M +( const ACE4_IDENTIFIER_GROUP = 0x00000040;) s +5 217 M +( ace-mask is any combination of the following flags \(taken from NFS) s +5 206 M +( Version 4 Protocol [3] section 5.9.3:) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( const ACE4_READ_DATA = 0x00000001;) s +5 679 M +( const ACE4_LIST_DIRECTORY = 0x00000001;) s +5 668 M +( const ACE4_WRITE_DATA = 0x00000002;) s +5 657 M +( const ACE4_ADD_FILE = 0x00000002;) s +5 646 M +( const ACE4_APPEND_DATA = 0x00000004;) s +5 635 M +( const ACE4_ADD_SUBDIRECTORY = 0x00000004;) s +5 624 M +( const ACE4_READ_NAMED_ATTRS = 0x00000008;) s +5 613 M +( const ACE4_WRITE_NAMED_ATTRS = 0x00000010;) s +5 602 M +( const ACE4_EXECUTE = 0x00000020;) s +5 591 M +( const ACE4_DELETE_CHILD = 0x00000040;) s +5 580 M +( const ACE4_READ_ATTRIBUTES = 0x00000080;) s +5 569 M +( const ACE4_WRITE_ATTRIBUTES = 0x00000100;) s +5 558 M +( const ACE4_DELETE = 0x00010000;) s +5 547 M +( const ACE4_READ_ACL = 0x00020000;) s +5 536 M +( const ACE4_WRITE_ACL = 0x00040000;) s +5 525 M +( const ACE4_WRITE_OWNER = 0x00080000;) s +5 514 M +( const ACE4_SYNCHRONIZE = 0x00100000;) s +5 492 M +( who is a UTF-8 string of the form described in 'Owner and Group') s +5 481 M +( \(Section 5.4\)) s +5 459 M +(5.8 Extended attributes) s +5 437 M +( The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension) s +5 426 M +( mechanism for vendor-specific extensions. If the flag is specified,) s +5 415 M +( then the `extended_count' field is present. It specifies the number) s +5 404 M +( of extended_type-extended_data pairs that follow. Each of these) s +5 393 M +( pairs specifies an extended attribute. For each of the attributes,) s +5 382 M +( the extended_type field should be a string of the format) s +5 371 M +( "name@domain", where "domain" is a valid, registered domain name and) s +5 360 M +( "name" identifies the method. The IETF may later standardize certain) s +5 349 M +( names that deviate from this format \(e.g., that do not contain the) s +5 338 M +( "@" sign\). The interpretation of `extended_data' depends on the) s +5 327 M +( type. Implementations SHOULD ignore extended data fields that they) s +5 316 M +( do not understand.) s +5 294 M +( Additional fields can be added to the attributes by either defining) s +5 283 M +( additional bits to the flags field to indicate their presence, or by) s +5 272 M +( defining extended attributes for them. The extended attributes) s +5 261 M +( mechanism is recommended for most purposes; additional flags bits) s +5 250 M +( should only be defined by an IETF standards action that also) s +5 239 M +( increments the protocol version number. The use of such new fields) s +5 228 M +( MUST be negotiated by the version number in the protocol exchange.) s +5 217 M +( It is a protocol error if a packet with unsupported protocol bits is) s +5 206 M +( received.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(6. Requests From the Client to the Server) s +5 668 M +( Requests from the client to the server represent the various file) s +5 657 M +( system operations. Each request begins with an `id' field, which is) s +5 646 M +( a 32-bit identifier identifying the request \(selected by the client\).) s +5 635 M +( The same identifier will be returned in the response to the request.) s +5 624 M +( One possible implementation is a monotonically increasing request) s +5 613 M +( sequence number \(modulo 2^32\).) s +5 591 M +( Many operations in the protocol operate on open files. The) s +5 580 M +( SSH_FXP_OPEN request can return a file handle \(which is an opaque) s +5 569 M +( variable-length string\) which may be used to access the file later) s +5 558 M +( \(e.g. in a read operation\). The client MUST NOT send requests the) s +5 547 M +( server with bogus or closed handles. However, the server MUST) s +5 536 M +( perform adequate checks on the handle in order to avoid security) s +5 525 M +( risks due to fabricated handles.) s +5 503 M +( This design allows either stateful and stateless server) s +5 492 M +( implementation, as well as an implementation which caches state) s +5 481 M +( between requests but may also flush it. The contents of the file) s +5 470 M +( handle string are entirely up to the server and its design. The) s +5 459 M +( client should not modify or attempt to interpret the file handle) s +5 448 M +( strings.) s +5 426 M +( The file handle strings MUST NOT be longer than 256 bytes.) s +5 404 M +(6.1 Request Synchronization and Reordering) s +5 382 M +( The protocol and implementations MUST process requests relating to) s +5 371 M +( the same file in the order in which they are received. In other) s +5 360 M +( words, if an application submits multiple requests to the server, the) s +5 349 M +( results in the responses will be the same as if it had sent the) s +5 338 M +( requests one at a time and waited for the response in each case. For) s +5 327 M +( example, the server may process non-overlapping read/write requests) s +5 316 M +( to the same file in parallel, but overlapping reads and writes cannot) s +5 305 M +( be reordered or parallelized. However, there are no ordering) s +5 294 M +( restrictions on the server for processing requests from two different) s +5 283 M +( file transfer connections. The server may interleave and parallelize) s +5 272 M +( them at will.) s +5 250 M +( There are no restrictions on the order in which responses to) s +5 239 M +( outstanding requests are delivered to the client, except that the) s +5 228 M +( server must ensure fairness in the sense that processing of no) s +5 217 M +( request will be indefinitely delayed even if the client is sending) s +5 206 M +( other requests so that there are multiple outstanding requests all) s +5 195 M +( the time.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(6.2 File Names) s +5 668 M +( This protocol represents file names as strings. File names are) s +5 657 M +( assumed to use the slash \('/'\) character as a directory separator.) s +5 635 M +( File names starting with a slash are "absolute", and are relative to) s +5 624 M +( the root of the file system. Names starting with any other character) s +5 613 M +( are relative to the user's default directory \(home directory\). Note) s +5 602 M +( that identifying the user is assumed to take place outside of this) s +5 591 M +( protocol.) s +5 569 M +( Servers SHOULD interpret a path name component ".." as referring to) s +5 558 M +( the parent directory, and "." as referring to the current directory.) s +5 547 M +( If the server implementation limits access to certain parts of the) s +5 536 M +( file system, it must be extra careful in parsing file names when) s +5 525 M +( enforcing such restrictions. There have been numerous reported) s +5 514 M +( security bugs where a ".." in a path name has allowed access outside) s +5 503 M +( the intended area.) s +5 481 M +( An empty path name is valid, and it refers to the user's default) s +5 470 M +( directory \(usually the user's home directory\).) s +5 448 M +( Otherwise, no syntax is defined for file names by this specification.) s +5 437 M +( Clients should not make any other assumptions; however, they can) s +5 426 M +( splice path name components returned by SSH_FXP_READDIR together) s +5 415 M +( using a slash \('/'\) as the separator, and that will work as expected.) s +5 393 M +( In order to comply with IETF Policy on Character Sets and Languages) s +5 382 M +( [2], all filenames are to be encoded in UTF-8. The shortest valid) s +5 371 M +( UTF-8 encoding of the UNICODE data MUST be used. The server is) s +5 360 M +( responsible for converting the UNICODE data to whatever canonical) s +5 349 M +( form it requires.) s +5 327 M +( For example, if the server requires that precomposed characters) s +5 316 M +( always be used, the server MUST NOT assume the filename as sent by) s +5 305 M +( the client has this attribute, but must do this normalization itself.) s +5 283 M +( It is understood that the lack of well-defined semantics for file) s +5 272 M +( names may cause interoperability problems between clients and servers) s +5 261 M +( using radically different operating systems. However, this approach) s +5 250 M +( is known to work acceptably with most systems, and alternative) s +5 239 M +( approaches that e.g. treat file names as sequences of structured) s +5 228 M +( components are quite complicated.) s +5 206 M +(6.3 Opening, Creating, and Closing Files) s +5 184 M +( Files are opened and created using the SSH_FXP_OPEN message, whose) s +5 173 M +( data part is as follows:) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( uint32 id) s +5 679 M +( string filename [UTF-8]) s +5 668 M +( uint32 pflags) s +5 657 M +( ATTRS attrs) s +5 635 M +( The `id' field is the request identifier as for all requests.) s +5 613 M +( The `filename' field specifies the file name. See Section ``File) s +5 602 M +( Names'' for more information.) s +5 580 M +( The `pflags' field is a bitmask. The following bits have been) s +5 569 M +( defined.) s +5 547 M +( #define SSH_FXF_READ 0x00000001) s +5 536 M +( #define SSH_FXF_WRITE 0x00000002) s +5 525 M +( #define SSH_FXF_APPEND 0x00000004) s +5 514 M +( #define SSH_FXF_CREAT 0x00000008) s +5 503 M +( #define SSH_FXF_TRUNC 0x00000010) s +5 492 M +( #define SSH_FXF_EXCL 0x00000020) s +5 481 M +( #define SSH_FXF_TEXT 0x00000040) s +5 459 M +( These have the following meanings:) s +5 437 M +( SSH_FXF_READ) s +5 426 M +( Open the file for reading.) s +5 404 M +( SSH_FXF_WRITE) s +5 393 M +( Open the file for writing. If both this and SSH_FXF_READ are) s +5 382 M +( specified, the file is opened for both reading and writing.) s +5 360 M +( SSH_FXF_APPEND) s +5 349 M +( Force all writes to append data at the end of the file. The) s +5 338 M +( offset parameter to write will be ignored.) s +5 316 M +( SSH_FXF_CREAT) s +5 305 M +( If this flag is specified, then a new file will be created if one) s +5 294 M +( does not already exist \(if O_TRUNC is specified, the new file will) s +5 283 M +( be truncated to zero length if it previously exists\).) s +5 261 M +( SSH_FXF_TRUNC) s +5 250 M +( Forces an existing file with the same name to be truncated to zero) s +5 239 M +( length when creating a file by specifying SSH_FXF_CREAT.) s +5 228 M +( SSH_FXF_CREAT MUST also be specified if this flag is used.) s +5 206 M +( SSH_FXF_EXCL) s +5 195 M +( Causes the request to fail if the named file already exists.) s +5 184 M +( SSH_FXF_CREAT MUST also be specified if this flag is used.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( SSH_FXF_TEXT) s +5 679 M +( Indicates that the server should treat the file as text and) s +5 668 M +( convert it to the canonical newline convention in use. \(See) s +5 657 M +( Determining Server Newline Convention. \(Section 4.3\)) s +5 635 M +( When a file is opened with the FXF_TEXT flag, the offset field in) s +5 624 M +( both the read and write function are ignored.) s +5 602 M +( Servers MUST correctly process multiple parallel reads and writes) s +5 591 M +( correctly in this mode. Naturally, it is permissible for them to) s +5 580 M +( do this by serializing the requests. It would not be possible for) s +5 569 M +( a client to reliably detect a server that does not implement) s +5 558 M +( parallel writes in time to prevent damage.) s +5 536 M +( Clients SHOULD use the SSH_FXF_APPEND flag to append data to a) s +5 525 M +( text file rather then using write with a calculated offset.) s +5 503 M +( To support seeks on text file the following SSH_FXP_EXTENDED) s +5 492 M +( packet is defined.) s +5 448 M +( string "text-seek") s +5 437 M +( string file-handle) s +5 426 M +( uint64 line-number) s +5 404 M +( line-number is the index of the line number to seek to, where byte) s +5 393 M +( 0 in the file is line number 0, and the byte directly following) s +5 382 M +( the first newline sequence in the file is line number 1 and so on.) s +5 360 M +( The response to a "text-seek" request is an SSH_FXP_STATUS) s +5 349 M +( message.) s +5 327 M +( An attempt to seek past the end-of-file should result in a) s +5 316 M +( SSH_FX_EOF status.) s +5 294 M +( Servers SHOULD support at least one "text-seek" in order to) s +5 283 M +( support resume. However, a client MUST be prepared to receive) s +5 272 M +( SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation.) s +5 261 M +( The client can then try a fall-back strategy, if it has one.) s +5 239 M +( Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned) s +5 228 M +( for read or write operations that are not sequential.) s +5 206 M +( The `attrs' field specifies the initial attributes for the file.) s +5 195 M +( Default values will be used for those attributes that are not) s +5 184 M +( specified. See Section ``File Attributes'' for more information.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 16]) s +_R +S +PStoPSsaved restore +%%Page: (16,17) 9 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 17 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( The response to this message will be either SSH_FXP_HANDLE \(if the) s +5 679 M +( operation is successful\) or SSH_FXP_STATUS \(if the operation fails\).) s +5 657 M +( A file is closed by using the SSH_FXP_CLOSE request. Its data field) s +5 646 M +( has the following format:) s +5 624 M +( uint32 id) s +5 613 M +( string handle) s +5 591 M +( where `id' is the request identifier, and `handle' is a handle) s +5 580 M +( previously returned in the response to SSH_FXP_OPEN or) s +5 569 M +( SSH_FXP_OPENDIR. The handle becomes invalid immediately after this) s +5 558 M +( request has been sent.) s +5 536 M +( The response to this request will be a SSH_FXP_STATUS message. One) s +5 525 M +( should note that on some server platforms even a close can fail.) s +5 514 M +( This can happen e.g. if the server operating system caches writes,) s +5 503 M +( and an error occurs while flushing cached writes during the close.) s +5 481 M +(6.4 Reading and Writing) s +5 459 M +( Once a file has been opened, it can be read using the SSH_FXP_READ) s +5 448 M +( message, which has the following format:) s +5 426 M +( uint32 id) s +5 415 M +( string handle) s +5 404 M +( uint64 offset) s +5 393 M +( uint32 len) s +5 371 M +( where `id' is the request identifier, `handle' is an open file handle) s +5 360 M +( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) relative) s +5 349 M +( to the beginning of the file from where to start reading, and `len') s +5 338 M +( is the maximum number of bytes to read.) s +5 316 M +( In response to this request, the server will read as many bytes as it) s +5 305 M +( can from the file \(up to `len'\), and return them in a SSH_FXP_DATA) s +5 294 M +( message. If an error occurs or EOF is encountered before reading any) s +5 283 M +( data, the server will respond with SSH_FXP_STATUS. For normal disk) s +5 272 M +( files, it is guaranteed that this will read the specified number of) s +5 261 M +( bytes, or up to end of file. For e.g. device files this may return) s +5 250 M +( fewer bytes than requested.) s +5 228 M +( Writing to a file is achieved using the SSH_FXP_WRITE message, which) s +5 217 M +( has the following format:) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 17]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 18 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( uint32 id) s +5 679 M +( string handle) s +5 668 M +( uint64 offset) s +5 657 M +( string data) s +5 635 M +( where `id' is a request identifier, `handle' is a file handle) s +5 624 M +( returned by SSH_FXP_OPEN, `offset' is the offset \(in bytes\) from the) s +5 613 M +( beginning of the file where to start writing, and `data' is the data) s +5 602 M +( to be written.) s +5 580 M +( The write will extend the file if writing beyond the end of the file.) s +5 569 M +( It is legal to write way beyond the end of the file; the semantics) s +5 558 M +( are to write zeroes from the end of the file to the specified offset) s +5 547 M +( and then the data. On most operating systems, such writes do not) s +5 536 M +( allocate disk space but instead leave "holes" in the file.) s +5 514 M +( The server responds to a write request with a SSH_FXP_STATUS message.) s +5 492 M +(6.5 Removing and Renaming Files) s +5 470 M +( Files can be removed using the SSH_FXP_REMOVE message. It has the) s +5 459 M +( following format:) s +5 437 M +( uint32 id) s +5 426 M +( string filename [UTF-8]) s +5 404 M +( where `id' is the request identifier and `filename' is the name of) s +5 393 M +( the file to be removed. See Section ``File Names'' for more) s +5 382 M +( information. This request cannot be used to remove directories.) s +5 360 M +( The server will respond to this request with a SSH_FXP_STATUS) s +5 349 M +( message.) s +5 327 M +( Files \(and directories\) can be renamed using the SSH_FXP_RENAME) s +5 316 M +( message. Its data is as follows:) s +5 294 M +( uint32 id) s +5 283 M +( string oldpath [UTF-8]) s +5 272 M +( string newpath [UTF-8]) s +5 250 M +( where `id' is the request identifier, `oldpath' is the name of an) s +5 239 M +( existing file or directory, and `newpath' is the new name for the) s +5 228 M +( file or directory. It is an error if there already exists a file) s +5 217 M +( with the name specified by newpath. The server may also fail rename) s +5 206 M +( requests in other situations, for example if `oldpath' and `newpath') s +5 195 M +( point to different file systems on the server.) s +5 173 M +( The server will respond to this request with a SSH_FXP_STATUS) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 18]) s +_R +S +PStoPSsaved restore +%%Page: (18,19) 10 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 19 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( message.) s +5 668 M +(6.6 Creating and Deleting Directories) s +5 646 M +( New directories can be created using the SSH_FXP_MKDIR request. It) s +5 635 M +( has the following format:) s +5 613 M +( uint32 id) s +5 602 M +( string path [UTF-8]) s +5 591 M +( ATTRS attrs) s +5 569 M +( where `id' is the request identifier.) s +5 547 M +( `path' specifies the directory to be created. See Section ``File) s +5 536 M +( Names'' for more information on file names.) s +5 514 M +( `attrs' specifies the attributes that should be applied to it upon) s +5 503 M +( creation. Attributes are discussed in more detail in Section ``File) s +5 492 M +( Attributes''.) s +5 470 M +( The server will respond to this request with a SSH_FXP_STATUS) s +5 459 M +( message. If a file or directory with the specified path already) s +5 448 M +( exists, an error will be returned.) s +5 426 M +( Directories can be removed using the SSH_FXP_RMDIR request, which has) s +5 415 M +( the following format:) s +5 393 M +( uint32 id) s +5 382 M +( string path [UTF-8]) s +5 360 M +( where `id' is the request identifier, and `path' specifies the) s +5 349 M +( directory to be removed. See Section ``File Names'' for more) s +5 338 M +( information on file names.) s +5 316 M +( The server responds to this request with a SSH_FXP_STATUS message.) s +5 305 M +( Errors may be returned from this operation for various reasons,) s +5 294 M +( including, but not limited to, the path does not exist, the path does) s +5 283 M +( not refer to a directory object, the directory is not empty, or the) s +5 272 M +( user has insufficient access or permission to perform the requested) s +5 261 M +( operation.) s +5 239 M +(6.7 Scanning Directories) s +5 217 M +( The files in a directory can be listed using the SSH_FXP_OPENDIR and) s +5 206 M +( SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one) s +5 195 M +( or more file names with full file attributes for each file. The) s +5 184 M +( client should call SSH_FXP_READDIR repeatedly until it has found the) s +5 173 M +( file it is looking for or until the server responds with a) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 19]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 20 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( SSH_FXP_STATUS message indicating an error \(normally SSH_FX_EOF if) s +5 679 M +( there are no more files in the directory\). The client should then) s +5 668 M +( close the handle using the SSH_FXP_CLOSE request.) s +5 646 M +( The SSH_FXP_OPENDIR opens a directory for reading. It has the) s +5 635 M +( following format:) s +5 613 M +( uint32 id) s +5 602 M +( string path [UTF-8]) s +5 580 M +( where `id' is the request identifier and `path' is the path name of) s +5 569 M +( the directory to be listed \(without any trailing slash\). See Section) s +5 558 M +( ``File Names'' for more information on file names. This will return) s +5 547 M +( an error if the path does not specify a directory or if the directory) s +5 536 M +( is not readable. The server will respond to this request with either) s +5 525 M +( a SSH_FXP_HANDLE or a SSH_FXP_STATUS message.) s +5 503 M +( Once the directory has been successfully opened, files \(and) s +5 492 M +( directories\) contained in it can be listed using SSH_FXP_READDIR) s +5 481 M +( requests. These are of the format) s +5 459 M +( uint32 id) s +5 448 M +( string handle) s +5 426 M +( where `id' is the request identifier, and `handle' is a handle) s +5 415 M +( returned by SSH_FXP_OPENDIR. \(It is a protocol error to attempt to) s +5 404 M +( use an ordinary file handle returned by SSH_FXP_OPEN.\)) s +5 382 M +( The server responds to this request with either a SSH_FXP_NAME or a) s +5 371 M +( SSH_FXP_STATUS message. One or more names may be returned at a time.) s +5 360 M +( Full status information is returned for each name in order to speed) s +5 349 M +( up typical directory listings.) s +5 327 M +( If there are no more names available to be read, the server MUST) s +5 316 M +( respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF.) s +5 294 M +( When the client no longer wishes to read more names from the) s +5 283 M +( directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle) s +5 272 M +( should be closed regardless of whether an error has occurred or not.) s +5 250 M +(6.8 Retrieving File Attributes) s +5 228 M +( Very often, file attributes are automatically returned by) s +5 217 M +( SSH_FXP_READDIR. However, sometimes there is need to specifically) s +5 206 M +( retrieve the attributes for a named file. This can be done using the) s +5 195 M +( SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests.) s +5 173 M +( SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 20]) s +_R +S +PStoPSsaved restore +%%Page: (20,21) 11 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 21 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( follows symbolic links on the server, whereas SSH_FXP_LSTAT does not) s +5 679 M +( follow symbolic links. Both have the same format:) s +5 657 M +( uint32 id) s +5 646 M +( string path [UTF-8]) s +5 635 M +( uint32 flags) s +5 613 M +( where `id' is the request identifier, and `path' specifies the file) s +5 602 M +( system object for which status is to be returned. The server) s +5 591 M +( responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS.) s +5 569 M +( The flags field specify the attribute flags in which the client has) s +5 558 M +( particular interest. This is a hint to the server. For example,) s +5 547 M +( because retrieving owner / group and acl information can be an) s +5 536 M +( expensive operation under some operating systems, the server may) s +5 525 M +( choose not to retrieve this information unless the client expresses a) s +5 514 M +( specific interest in it.) s +5 492 M +( The client has no guarantee the server will provide all the fields) s +5 481 M +( that it has expressed an interest in.) s +5 459 M +( SSH_FXP_FSTAT differs from the others in that it returns status) s +5 448 M +( information for an open file \(identified by the file handle\). Its) s +5 437 M +( format is as follows:) s +5 415 M +( uint32 id) s +5 404 M +( string handle) s +5 393 M +( uint32 flags) s +5 371 M +( where `id' is the request identifier and `handle' is a file handle) s +5 360 M +( returned by SSH_FXP_OPEN. The server responds to this request with) s +5 349 M +( SSH_FXP_ATTRS or SSH_FXP_STATUS.) s +5 327 M +(6.9 Setting File Attributes) s +5 305 M +( File attributes may be modified using the SSH_FXP_SETSTAT and) s +5 294 M +( SSH_FXP_FSETSTAT requests. These requests are used for operations) s +5 283 M +( such as changing the ownership, permissions or access times, as well) s +5 272 M +( as for truncating a file.) s +5 250 M +( The SSH_FXP_SETSTAT request is of the following format:) s +5 228 M +( uint32 id) s +5 217 M +( string path [UTF-8]) s +5 206 M +( ATTRS attrs) s +5 184 M +( where `id' is the request identifier, `path' specifies the file) s +5 173 M +( system object \(e.g. file or directory\) whose attributes are to be) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 21]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 22 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( modified, and `attrs' specifies the modifications to be made to its) s +5 679 M +( attributes. Attributes are discussed in more detail in Section) s +5 668 M +( ``File Attributes''.) s +5 646 M +( An error will be returned if the specified file system object does) s +5 635 M +( not exist or the user does not have sufficient rights to modify the) s +5 624 M +( specified attributes. The server responds to this request with a) s +5 613 M +( SSH_FXP_STATUS message.) s +5 591 M +( The SSH_FXP_FSETSTAT request modifies the attributes of a file which) s +5 580 M +( is already open. It has the following format:) s +5 558 M +( uint32 id) s +5 547 M +( string handle) s +5 536 M +( ATTRS attrs) s +5 514 M +( where `id' is the request identifier, `handle' \(MUST be returned by) s +5 503 M +( SSH_FXP_OPEN\) identifies the file whose attributes are to be) s +5 492 M +( modified, and `attrs' specifies the modifications to be made to its) s +5 481 M +( attributes. Attributes are discussed in more detail in Section) s +5 470 M +( ``File Attributes''. The server will respond to this request with) s +5 459 M +( SSH_FXP_STATUS.) s +5 437 M +(6.10 Dealing with Symbolic links) s +5 415 M +( The SSH_FXP_READLINK request may be used to read the target of a) s +5 404 M +( symbolic link. It would have a data part as follows:) s +5 382 M +( uint32 id) s +5 371 M +( string path [UTF-8]) s +5 349 M +( where `id' is the request identifier and `path' specifies the path) s +5 338 M +( name of the symlink to be read.) s +5 316 M +( The server will respond with a SSH_FXP_NAME packet containing only) s +5 305 M +( one name and a dummy attributes value. The name in the returned) s +5 294 M +( packet contains the target of the link. If an error occurs, the) s +5 283 M +( server may respond with SSH_FXP_STATUS.) s +5 261 M +( The SSH_FXP_SYMLINK request will create a symbolic link on the) s +5 250 M +( server. It is of the following format) s +5 228 M +( uint32 id) s +5 217 M +( string linkpath [UTF-8]) s +5 206 M +( string targetpath [UTF-8]) s +5 184 M +( where `id' is the request identifier, `linkpath' specifies the path) s +5 173 M +( name of the symlink to be created and `targetpath' specifies the) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 22]) s +_R +S +PStoPSsaved restore +%%Page: (22,23) 12 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 23 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( target of the symlink. The server shall respond with a) s +5 679 M +( SSH_FXP_STATUS indicating either success \(SSH_FX_OK\) or an error) s +5 668 M +( condition.) s +5 646 M +(6.11 Canonicalizing the Server-Side Path Name) s +5 624 M +( The SSH_FXP_REALPATH request can be used to have the server) s +5 613 M +( canonicalize any given path name to an absolute path. This is useful) s +5 602 M +( for converting path names containing ".." components or relative) s +5 591 M +( pathnames without a leading slash into absolute paths. The format of) s +5 580 M +( the request is as follows:) s +5 558 M +( uint32 id) s +5 547 M +( string path [UTF-8]) s +5 525 M +( where `id' is the request identifier and `path' specifies the path) s +5 514 M +( name to be canonicalized. The server will respond with a) s +5 503 M +( SSH_FXP_NAME packet containing the name in canonical form and a dummy) s +5 492 M +( attributes value. If an error occurs, the server may also respond) s +5 481 M +( with SSH_FXP_STATUS.) s +5 459 M +(6.11.1 Best practice for dealing with paths) s +5 437 M +( The client SHOULD treat the results of SSH_FXP_REALPATH as a) s +5 426 M +( canonical absolute path, even if the path does not appear to be) s +5 415 M +( absolute. A client that use REALPATH\("."\) and treats the result as) s +5 404 M +( absolute, even if there is no leading slash, will continue to) s +5 393 M +( function correctly, even when talking to a Windows NT or VMS style) s +5 382 M +( system, where absolute paths may not begin with a slash.) s +5 360 M +( For example, if the client wishes to change directory up, and the) s +5 349 M +( server has returned "c:/x/y/z" from REALPATH, the client SHOULD use) s +5 338 M +( "c:/x/y/z/..".) s +5 316 M +( As a second example, if the client wishes to open the file "x.txt" in) s +5 305 M +( the current directory, and server has returned "dka100:/x/y/z" as the) s +5 294 M +( canonical path of the directory, the client SHOULD open "dka100:/x/y/) s +5 283 M +( z/x.txt") s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 23]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 24 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(7. Responses from the Server to the Client) s +5 668 M +( The server responds to the client using one of a few response) s +5 657 M +( packets. All requests can return a SSH_FXP_STATUS response upon) s +5 646 M +( failure. When the operation is successful, any of the responses may) s +5 635 M +( be returned \(depending on the operation\). If no data needs to be) s +5 624 M +( returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK) s +5 613 M +( status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used) s +5 602 M +( to return a file handle \(for SSH_FXP_OPEN and SSH_FXP_OPENDIR) s +5 591 M +( requests\), SSH_FXP_DATA is used to return data from SSH_FXP_READ,) s +5 580 M +( SSH_FXP_NAME is used to return one or more file names from a) s +5 569 M +( SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is) s +5 558 M +( used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and) s +5 547 M +( SSH_FXP_FSTAT requests.) s +5 525 M +( Exactly one response will be returned for each request. Each) s +5 514 M +( response packet contains a request identifier which can be used to) s +5 503 M +( match each response with the corresponding request. Note that it is) s +5 492 M +( legal to have several requests outstanding simultaneously, and the) s +5 481 M +( server is allowed to send responses to them in a different order from) s +5 470 M +( the order in which the requests were sent \(the result of their) s +5 459 M +( execution, however, is guaranteed to be as if they had been processed) s +5 448 M +( one at a time in the order in which the requests were sent\).) s +5 426 M +( Response packets are of the same general format as request packets.) s +5 415 M +( Each response packet begins with the request identifier.) s +5 393 M +( The format of the data portion of the SSH_FXP_STATUS response is as) s +5 382 M +( follows:) s +5 360 M +( uint32 id) s +5 349 M +( uint32 error/status code) s +5 338 M +( string error message \(ISO-10646 UTF-8 [RFC-2279]\)) s +5 327 M +( string language tag \(as defined in [RFC-1766]\)) s +5 305 M +( where `id' is the request identifier, and `error/status code') s +5 294 M +( indicates the result of the requested operation. The value SSH_FX_OK) s +5 283 M +( indicates success, and all other values indicate failure.) s +5 261 M +( Currently, the following values are defined \(other values may be) s +5 250 M +( defined by future versions of this protocol\):) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 24]) s +_R +S +PStoPSsaved restore +%%Page: (24,25) 13 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 25 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( #define SSH_FX_OK 0) s +5 679 M +( #define SSH_FX_EOF 1) s +5 668 M +( #define SSH_FX_NO_SUCH_FILE 2) s +5 657 M +( #define SSH_FX_PERMISSION_DENIED 3) s +5 646 M +( #define SSH_FX_FAILURE 4) s +5 635 M +( #define SSH_FX_BAD_MESSAGE 5) s +5 624 M +( #define SSH_FX_NO_CONNECTION 6) s +5 613 M +( #define SSH_FX_CONNECTION_LOST 7) s +5 602 M +( #define SSH_FX_OP_UNSUPPORTED 8) s +5 591 M +( #define SSH_FX_INVALID_HANDLE 9) s +5 580 M +( #define SSH_FX_NO_SUCH_PATH 10) s +5 569 M +( #define SSH_FX_FILE_ALREADY_EXISTS 11) s +5 558 M +( #define SSH_FX_WRITE_PROTECT 12) s +5 536 M +( SSH_FX_OK) s +5 525 M +( Indicates successful completion of the operation.) s +5 503 M +( SSH_FX_EOF) s +5 492 M +( indicates end-of-file condition; for SSH_FX_READ it means that no) s +5 481 M +( more data is available in the file, and for SSH_FX_READDIR it) s +5 470 M +( indicates that no more files are contained in the directory.) s +5 448 M +( SSH_FX_NO_SUCH_FILE) s +5 437 M +( is returned when a reference is made to a file which does not) s +5 426 M +( exist.) s +5 404 M +( SSH_FX_PERMISSION_DENIED) s +5 393 M +( is returned when the authenticated user does not have sufficient) s +5 382 M +( permissions to perform the operation.) s +5 360 M +( SSH_FX_FAILURE) s +5 349 M +( is a generic catch-all error message; it should be returned if an) s +5 338 M +( error occurs for which there is no more specific error code) s +5 327 M +( defined.) s +5 305 M +( SSH_FX_BAD_MESSAGE) s +5 294 M +( may be returned if a badly formatted packet or protocol) s +5 283 M +( incompatibility is detected.) s +5 261 M +( SSH_FX_NO_CONNECTION) s +5 250 M +( is a pseudo-error which indicates that the client has no) s +5 239 M +( connection to the server \(it can only be generated locally by the) s +5 228 M +( client, and MUST NOT be returned by servers\).) s +5 206 M +( SSH_FX_CONNECTION_LOST) s +5 195 M +( is a pseudo-error which indicates that the connection to the) s +5 184 M +( server has been lost \(it can only be generated locally by the) s +5 173 M +( client, and MUST NOT be returned by servers\).) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 25]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 26 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( SSH_FX_OP_UNSUPPORTED) s +5 679 M +( indicates that an attempt was made to perform an operation which) s +5 668 M +( is not supported for the server \(it may be generated locally by) s +5 657 M +( the client if e.g. the version number exchange indicates that a) s +5 646 M +( required feature is not supported by the server, or it may be) s +5 635 M +( returned by the server if the server does not implement an) s +5 624 M +( operation\).) s +5 602 M +( SSH_FX_INVALID_HANDLE) s +5 591 M +( The handle value was invalid.) s +5 569 M +( SSH_FX_NO_SUCH_PATH) s +5 558 M +( The file path does not exist or is invalid.) s +5 536 M +( SSH_FX_FILE_ALREADY_EXISTS) s +5 525 M +( The file already exists.) s +5 503 M +( SSH_FX_WRITE_PROTECT) s +5 492 M +( The file is on read only media, or the media is write protected.) s +5 470 M +( The SSH_FXP_HANDLE response has the following format:) s +5 448 M +( uint32 id) s +5 437 M +( string handle) s +5 415 M +( where `id' is the request identifier, and `handle' is an arbitrary) s +5 404 M +( string that identifies an open file or directory on the server. The) s +5 393 M +( handle is opaque to the client; the client MUST NOT attempt to) s +5 382 M +( interpret or modify it in any way. The length of the handle string) s +5 371 M +( MUST NOT exceed 256 data bytes.) s +5 349 M +( The SSH_FXP_DATA response has the following format:) s +5 327 M +( uint32 id) s +5 316 M +( string data) s +5 294 M +( where `id' is the request identifier, and `data' is an arbitrary byte) s +5 283 M +( string containing the requested data. The data string may be at most) s +5 272 M +( the number of bytes requested in a SSH_FXP_READ request, but may also) s +5 261 M +( be shorter if end of file is reached or if the read is from something) s +5 250 M +( other than a regular file.) s +5 228 M +( The SSH_FXP_NAME response has the following format:) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 26]) s +_R +S +PStoPSsaved restore +%%Page: (26,27) 14 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 27 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( uint32 id) s +5 679 M +( uint32 count) s +5 668 M +( repeats count times:) s +5 657 M +( string filename [UTF-8]) s +5 646 M +( ATTRS attrs) s +5 624 M +( where `id' is the request identifier, `count' is the number of names) s +5 613 M +( returned in this response, and the remaining fields repeat `count') s +5 602 M +( times \(so that all three fields are first included for the first) s +5 591 M +( file, then for the second file, etc\). In the repeated part,) s +5 580 M +( `filename' is a file name being returned \(for SSH_FXP_READDIR, it) s +5 569 M +( will be a relative name within the directory, without any path) s +5 558 M +( components; for SSH_FXP_REALPATH it will be an absolute path name\),) s +5 547 M +( and `attrs' is the attributes of the file as described in Section) s +5 536 M +( ``File Attributes''.) s +5 514 M +( The SSH_FXP_ATTRS response has the following format:) s +5 492 M +( uint32 id) s +5 481 M +( ATTRS attrs) s +5 459 M +( where `id' is the request identifier, and `attrs' is the returned) s +5 448 M +( file attributes as described in Section ``File Attributes''.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 27]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 28 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(8. Vendor-Specific Extensions) s +5 668 M +( The SSH_FXP_EXTENDED request provides a generic extension mechanism) s +5 657 M +( for adding vendor-specific commands. The request has the following) s +5 646 M +( format:) s +5 624 M +( uint32 id) s +5 613 M +( string extended-request) s +5 602 M +( ... any request-specific data ...) s +5 580 M +( where `id' is the request identifier, and `extended-request' is a) s +5 569 M +( string of the format "name@domain", where domain is an internet) s +5 558 M +( domain name of the vendor defining the request. The rest of the) s +5 547 M +( request is completely vendor-specific, and servers should only) s +5 536 M +( attempt to interpret it if they recognize the `extended-request') s +5 525 M +( name.) s +5 503 M +( The server may respond to such requests using any of the response) s +5 492 M +( packets defined in Section ``Responses from the Server to the) s +5 481 M +( Client''. Additionally, the server may also respond with a) s +5 470 M +( SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does) s +5 459 M +( not recognize the `extended-request' name, then the server MUST) s +5 448 M +( respond with SSH_FXP_STATUS with error/status set to) s +5 437 M +( SSH_FX_OP_UNSUPPORTED.) s +5 415 M +( The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary) s +5 404 M +( extension-specific data from the server to the client. It is of the) s +5 393 M +( following format:) s +5 371 M +( uint32 id) s +5 360 M +( ... any request-specific data ...) s +5 338 M +( There is a range of packet types reserved for use by extensions. In) s +5 327 M +( order to avoid collision, extensions that turn on the use of) s +5 316 M +( additional packet types should determine those numbers dynamically.) s +5 294 M +( The suggested way of doing this is have an extension request from the) s +5 283 M +( client to the server that enables the extension; the extension) s +5 272 M +( response from the server to the client would specify the actual type) s +5 261 M +( values to use, in additional to any other data.) s +5 239 M +( Extension authors should be mindful of the limited range of packet) s +5 228 M +( types available \(there are only 45 values available\) and avoid) s +5 217 M +( requiring a new packet type where possible.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 28]) s +_R +S +PStoPSsaved restore +%%Page: (28,29) 15 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 29 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(9. Security Considerations) s +5 668 M +( This protocol assumes that it is run over a secure channel and that) s +5 657 M +( the endpoints of the channel have been authenticated. Thus, this) s +5 646 M +( protocol assumes that it is externally protected from network-level) s +5 635 M +( attacks.) s +5 613 M +( This protocol provides file system access to arbitrary files on the) s +5 602 M +( server \(only constrained by the server implementation\). It is the) s +5 591 M +( responsibility of the server implementation to enforce any access) s +5 580 M +( controls that may be required to limit the access allowed for any) s +5 569 M +( particular user \(the user being authenticated externally to this) s +5 558 M +( protocol, typically using the SSH User Authentication Protocol [8].) s +5 536 M +( Care must be taken in the server implementation to check the validity) s +5 525 M +( of received file handle strings. The server should not rely on them) s +5 514 M +( directly; it MUST check the validity of each handle before relying on) s +5 503 M +( it.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 29]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 30 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(10. Changes from previous protocol versions) s +5 668 M +( The SSH File Transfer Protocol has changed over time, before it's) s +5 657 M +( standardization. The following is a description of the incompatible) s +5 646 M +( changes between different versions.) s +5 624 M +(10.1 Changes between versions 4 and 3) s +5 602 M +( Many of the changes between version 4 and version 3 are to the) s +5 591 M +( attribute structure to make it more flexible for non-unix platforms.) s +5 569 M +( o Make all filenames UTF-8.) s +5 547 M +( o Added 'newline' extension.) s +5 525 M +( o Made file attribute owner and group strings so they can actually) s +5 514 M +( be used on disparate systems.) s +5 492 M +( o Added createtime field, and added separate flags for atime,) s +5 481 M +( createtime, and mtime so they can be set separately.) s +5 459 M +( o Split the file type out of the permissions field and into it's own) s +5 448 M +( field \(which is always present.\)) s +5 426 M +( o Added acl attribute.) s +5 404 M +( o Added SSH_FXF_TEXT file open flag.) s +5 382 M +( o Added flags field to the get stat commands so that the client can) s +5 371 M +( specifically request information the server might not normally) s +5 360 M +( included for performance reasons.) s +5 338 M +( o Removed the long filename from the names structure-- it can now be) s +5 327 M +( built from information available in the attrs structure.) s +5 305 M +( o Added reserved range of packet numbers for extensions.) s +5 283 M +( o Added several additional error codes.) s +5 261 M +( o Change the way version negotiate works slightly. Previously, if) s +5 250 M +( the client version were higher than the server version, the server) s +5 239 M +( was supposed to 'echo back' the clients version. The server now) s +5 228 M +( sends it's own version and the lower of the two is considered to) s +5 217 M +( be the one in use.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 30]) s +_R +S +PStoPSsaved restore +%%Page: (30,31) 16 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 31 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(10.2 Changes between versions 3 and 2) s +5 668 M +( o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.) s +5 646 M +( o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were) s +5 635 M +( added.) s +5 613 M +( o The SSH_FXP_STATUS message was changed to include fields `error) s +5 602 M +( message' and `language tag'.) s +5 569 M +(10.3 Changes between versions 2 and 1) s +5 547 M +( o The SSH_FXP_RENAME message was added.) s +5 514 M +(10.4 Changes between versions 1 and 0) s +5 492 M +( o Implementation changes, no actual protocol changes.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 31]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 32 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(11. Trademark Issues) s +5 668 M +( "ssh" is a registered trademark of SSH Communications Security Corp) s +5 657 M +( in the United States and/or other countries.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 32]) s +_R +S +PStoPSsaved restore +%%Page: (32,33) 17 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 33 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(References) s +5 668 M +( [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and) s +5 657 M +( P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January) s +5 646 M +( 1999.) s +5 624 M +( [2] Alvestrand, H., "IETF Policy on Character Sets and Languages",) s +5 613 M +( BCP 18, RFC 2277, January 1998.) s +5 591 M +( [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame,) s +5 580 M +( C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC) s +5 569 M +( 3010, December 2000.) s +5 547 M +( [4] Institute of Electrical and Electronics Engineers, "Information) s +5 536 M +( Technology - Portable Operating System Interface \(POSIX\) - Part) s +5 525 M +( 1: System Application Program Interface \(API\) [C Language]",) s +5 514 M +( IEEE Standard 1003.2, 1996.) s +5 492 M +( [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 481 M +( Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh-) s +5 470 M +( architecture-13 \(work in progress\), September 2002.) s +5 448 M +( [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 437 M +( Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh-) s +5 426 M +( transport-15 \(work in progress\), September 2002.) s +5 404 M +( [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 393 M +( Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16) s +5 382 M +( \(work in progress\), September 2002.) s +5 360 M +( [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S.) s +5 349 M +( Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh-) s +5 338 M +( userauth-16 \(work in progress\), September 2002.) s +5 305 M +(Authors' Addresses) s +5 283 M +( Joseph Galbraith) s +5 272 M +( VanDyke Software) s +5 261 M +( 4848 Tramway Ridge Blvd) s +5 250 M +( Suite 101) s +5 239 M +( Albuquerque, NM 87111) s +5 228 M +( US) s +5 206 M +( Phone: +1 505 332 5700) s +5 195 M +( EMail: [email protected]) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 33]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 34 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +( Tatu Ylonen) s +5 679 M +( SSH Communications Security Corp) s +5 668 M +( Fredrikinkatu 42) s +5 657 M +( HELSINKI FIN-00100) s +5 646 M +( Finland) s +5 624 M +( EMail: [email protected]) s +5 591 M +( Sami Lehtinen) s +5 580 M +( SSH Communications Security Corp) s +5 569 M +( Fredrikinkatu 42) s +5 558 M +( HELSINKI FIN-00100) s +5 547 M +( Finland) s +5 525 M +( EMail: [email protected]) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 34]) s +_R +S +PStoPSsaved restore +%%Page: (34,35) 18 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 35 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH File Transfer Protocol October 2002) s +5 690 M +(Full Copyright Statement) s +5 668 M +( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s +5 646 M +( This document and translations of it may be copied and furnished to) s +5 635 M +( others, and derivative works that comment on or otherwise explain it) s +5 624 M +( or assist in its implementation may be prepared, copied, published) s +5 613 M +( and distributed, in whole or in part, without restriction of any) s +5 602 M +( kind, provided that the above copyright notice and this paragraph are) s +5 591 M +( included on all such copies and derivative works. However, this) s +5 580 M +( document itself may not be modified in any way, such as by removing) s +5 569 M +( the copyright notice or references to the Internet Society or other) s +5 558 M +( Internet organizations, except as needed for the purpose of) s +5 547 M +( developing Internet standards in which case the procedures for) s +5 536 M +( copyrights defined in the Internet Standards process must be) s +5 525 M +( followed, or as required to translate it into languages other than) s +5 514 M +( English.) s +5 492 M +( The limited permissions granted above are perpetual and will not be) s +5 481 M +( revoked by the Internet Society or its successors or assigns.) s +5 459 M +( This document and the information contained herein is provided on an) s +5 448 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 437 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 426 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 415 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 404 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 382 M +(Acknowledgement) s +5 360 M +( Funding for the RFC Editor function is currently provided by the) s +5 349 M +( Internet Society.) s +5 129 M +(Galbraith, et al. Expires April 16, 2003 [Page 35]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 36 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +_R +S +PStoPSsaved restore +%%Trailer +%%Pages: 36 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt new file mode 100644 index 0000000000..83960ae976 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-03.txt @@ -0,0 +1,1962 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: April 16, 2003 T. Ylonen + S. Lehtinen + SSH Communications Security Corp + October 16, 2002 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-03.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on April 16, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 1] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . 7 + 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 7 + 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 7 + 4.3 Determining Server Newline Convention . . . . . . . . . . 8 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 9 + 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 10 + 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 12 + 6. Requests From the Client to the Server . . . . . . . . . . 13 + 6.1 Request Synchronization and Reordering . . . . . . . . . . 13 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 14 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 14 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 17 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 18 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . 19 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 19 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 20 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 21 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 22 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 23 + 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 23 + 7. Responses from the Server to the Client . . . . . . . . . 24 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 28 + 9. Security Considerations . . . . . . . . . . . . . . . . . 29 + 10. Changes from previous protocol versions . . . . . . . . . 30 + 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 30 + 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 31 + 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 31 + 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 31 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 32 + References . . . . . . . . . . . . . . . . . . . . . . . . 33 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . 33 + Full Copyright Statement . . . . . . . . . . . . . . . . . 35 + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 2] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [5]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft. [5] + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 3] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [7] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 4] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + The following values are defined for packet types. + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 5] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + RESERVED_FOR_EXTENSIONS 210-255 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 6] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +4. Protocol Initialization + + When the file transfer protocol starts, the client first sends a + SSH_FXP_INIT (including its version number) packet to the server. + The server responds with a SSH_FXP_VERSION packet, supplying the + lowest of its own and the client's version number. Both parties + should from then on adhere to particular version of the protocol. + + The version number of the protocol specified in this document is 4. + The version number should be incremented for each incompatible + revision of this protocol. + +4.1 Client Initialization + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + + Version 3 of this protocol allowed clients to include extensions in + the SSH_FXP_INIT packet; however, this can cause interoperability + problems with version 1 and version 2 servers because the client must + send this packet before knowing the servers version. + + In this version of the protocol, clients MUST use the + SSH_FXP_EXTENDED packet to send extensions to the server after + version exchange has completed. Clients MUST NOT include extensions + in the version packet. This will prevent interoperability problems + with older servers + +4.2 Server Initialization + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + <extension data> + + 'version' is the lower of the protocol version supported by the + server and the version number received from the client. + + The extension data may be empty, or may be a sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + + + +Galbraith, et al. Expires April 16, 2003 [Page 7] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + +4.3 Determining Server Newline Convention + + In order to correctly process text files in a cross platform + compatible way, the newline convention must be converted from that of + the server to that of the client, or, during an upload, from that of + the client to that of the server. + + Versions 3 and prior of this protocol made no provisions for + processing text files. Many clients implemented some sort of + conversion algorithm, but without either a 'canonical' on the wire + format or knowledge of the servers newline convention, correct + conversion was not always possible. + + Starting with Version 4, the SSH_FXF_TEXT file open flag (Section + 6.3) makes it possible to request that the server translate a file to + a 'canonical' on the wire format. This format uses \r\n as the line + separator. + + Servers for systems using multiple newline characters (for example, + Mac OS X or VMS) or systems using counted records, MUST translate to + the canonical form. + + However, to ease the burden of implementation on servers that use a + single, simple separator sequence, the following extension allows the + canonical format to be changed. + + string "newline" + string new-canonical-separator (usually "\r" or "\n" or "\r\n") + + All clients MUST support this extension. + + When processing text files, clients SHOULD NOT translate any + character or sequence that is not an exact match of the servers + newline separator. + + In particular, if the newline sequence being used is the canonical + "\r\n" sequence, a lone \r or a lone \n SHOULD be written through + without change. + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 8] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + byte type always present + uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE + string owner present only if flag SSH_FILEXFER_ATTR_OWNERGROUP + string group present only if flag SSH_FILEXFER_ATTR_OWNERGROUP + uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS + uint32 atime present only if flag SSH_FILEXFER_ATTR_ACCESSTIME + uint32 createtime present only if flag SSH_FILEXFER_ATTR_CREATETIME + uint32 mtime present only if flag SSH_FILEXFER_ATTR_MODIFYTIME + string acl present only if flag SSH_FILEXFER_ATTR_ACL + uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + +5.1 Flags + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The flags bits are defined to have the following values: + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 + #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 + #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 + #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 + #define SSH_FILEXFER_ATTR_ACL 0x00000040 + #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + + + +Galbraith, et al. Expires April 16, 2003 [Page 9] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + In previous versions of this protocol flags value 0x00000002 was + SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP + was given a new value in order to ease implementation burden. + 0x00000002 MUST NOT appear in the mask. Some future version of this + protocol may reuse flag 0x00000002. + +5.2 Type + + The type field is always present. The following types are defined: + + #define SSH_FILEXFER_TYPE_REGULAR 1 + #define SSH_FILEXFER_TYPE_DIRECTORY 2 + #define SSH_FILEXFER_TYPE_SYMLINK 3 + #define SSH_FILEXFER_TYPE_SPECIAL 4 + #define SSH_FILEXFER_TYPE_UNKNOWN 5 + + On a POSIX system, these values would be derived from the permission + field. + +5.3 Size + + The `size' field specifies the size of the file on disk, in bytes. + If it is present during file creation, it should be considered a hint + as to the files eventual size. + + Files opened with the SSH_FXF_TEXT flag may have a size that is + greater or less than the value of the size field. + +5.4 Owner and Group + + The `owner' and `group' fields are represented as UTF-8 strings; this + is the form used by NFS v4. See NFS version 4 Protocol. [3] The + following text is selected quotations from section 5.6. + + To avoid a representation that is tied to a particular underlying + implementation at the client or server, the use of UTF-8 strings has + been chosen. The string should be of the form user@dns_domain". + This will allow for a client and server that do not use the same + local representation the ability to translate to a common syntax that + can be interpreted by both. In the case where there is no + translation available to the client or server, the attribute value + must be constructed without the "@". Therefore, the absence of the @ + from the owner or owner_group attribute signifies that no translation + was available and the receiver of the attribute should not place any + special meaning with the attribute value. Even though the attribute + value can not be translated, it may still be useful. In the case of + a client, the attribute string may be used for local display of + ownership. + + + +Galbraith, et al. Expires April 16, 2003 [Page 10] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +5.5 Permissions + + The `permissions' field contains a bit mask of file permissions as + defined by POSIX [1]. + +5.6 Times + + The 'atime', 'createtime', and 'mtime' contain the access, creation, + and modification times of the files, respectively. They are + represented as seconds from Jan 1, 1970 in UTC. + +5.7 ACL + + The 'ACL' field contains an ACL similar to that defined in section + 5.9 of NFS version 4 Protocol [3]. + + uint32 ace-count + + repeated ace-count time: + uint32 ace-type + uint32 ace-flag + uint32 ace-mask + string who [UTF-8] + + ace-type is one of the following four values (taken from NFS Version + 4 Protocol [3]: + + const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; + const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; + const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; + const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; + + ace-flag is a combination of the following flag values. See NFS + Version 4 Protocol [3] section 5.9.2: + + const ACE4_FILE_INHERIT_ACE = 0x00000001; + const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; + const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; + const ACE4_INHERIT_ONLY_ACE = 0x00000008; + const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; + const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; + const ACE4_IDENTIFIER_GROUP = 0x00000040; + + ace-mask is any combination of the following flags (taken from NFS + Version 4 Protocol [3] section 5.9.3: + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 11] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + const ACE4_READ_DATA = 0x00000001; + const ACE4_LIST_DIRECTORY = 0x00000001; + const ACE4_WRITE_DATA = 0x00000002; + const ACE4_ADD_FILE = 0x00000002; + const ACE4_APPEND_DATA = 0x00000004; + const ACE4_ADD_SUBDIRECTORY = 0x00000004; + const ACE4_READ_NAMED_ATTRS = 0x00000008; + const ACE4_WRITE_NAMED_ATTRS = 0x00000010; + const ACE4_EXECUTE = 0x00000020; + const ACE4_DELETE_CHILD = 0x00000040; + const ACE4_READ_ATTRIBUTES = 0x00000080; + const ACE4_WRITE_ATTRIBUTES = 0x00000100; + const ACE4_DELETE = 0x00010000; + const ACE4_READ_ACL = 0x00020000; + const ACE4_WRITE_ACL = 0x00040000; + const ACE4_WRITE_OWNER = 0x00080000; + const ACE4_SYNCHRONIZE = 0x00100000; + + who is a UTF-8 string of the form described in 'Owner and Group' + (Section 5.4) + +5.8 Extended attributes + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 12] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation is a monotonically increasing request + sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 13] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + In order to comply with IETF Policy on Character Sets and Languages + [2], all filenames are to be encoded in UTF-8. The shortest valid + UTF-8 encoding of the UNICODE data MUST be used. The server is + responsible for converting the UNICODE data to whatever canonical + form it requires. + + For example, if the server requires that precomposed characters + always be used, the server MUST NOT assume the filename as sent by + the client has this attribute, but must do this normalization itself. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + + +Galbraith, et al. Expires April 16, 2003 [Page 14] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + string filename [UTF-8] + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + #define SSH_FXF_TEXT 0x00000040 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. The + offset parameter to write will be ignored. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + + + +Galbraith, et al. Expires April 16, 2003 [Page 15] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FXF_TEXT + Indicates that the server should treat the file as text and + convert it to the canonical newline convention in use. (See + Determining Server Newline Convention. (Section 4.3) + + When a file is opened with the FXF_TEXT flag, the offset field in + both the read and write function are ignored. + + Servers MUST correctly process multiple parallel reads and writes + correctly in this mode. Naturally, it is permissible for them to + do this by serializing the requests. It would not be possible for + a client to reliably detect a server that does not implement + parallel writes in time to prevent damage. + + Clients SHOULD use the SSH_FXF_APPEND flag to append data to a + text file rather then using write with a calculated offset. + + To support seeks on text file the following SSH_FXP_EXTENDED + packet is defined. + + + + string "text-seek" + string file-handle + uint64 line-number + + line-number is the index of the line number to seek to, where byte + 0 in the file is line number 0, and the byte directly following + the first newline sequence in the file is line number 1 and so on. + + The response to a "text-seek" request is an SSH_FXP_STATUS + message. + + An attempt to seek past the end-of-file should result in a + SSH_FX_EOF status. + + Servers SHOULD support at least one "text-seek" in order to + support resume. However, a client MUST be prepared to receive + SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. + The client can then try a fall-back strategy, if it has one. + + Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned + for read or write operations that are not sequential. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + + + +Galbraith, et al. Expires April 16, 2003 [Page 16] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the SSH_FXP_READ + message, which has the following format: + + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. For normal disk + files, it is guaranteed that this will read the specified number of + bytes, or up to end of file. For e.g. device files this may return + fewer bytes than requested. + + Writing to a file is achieved using the SSH_FXP_WRITE message, which + has the following format: + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 17] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename [UTF-8] + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath [UTF-8] + string newpath [UTF-8] + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + + + +Galbraith, et al. Expires April 16, 2003 [Page 18] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + message. + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier. + + `path' specifies the directory to be created. See Section ``File + Names'' for more information on file names. + + `attrs' specifies the attributes that should be applied to it upon + creation. Attributes are discussed in more detail in Section ``File + Attributes''. + + The server will respond to this request with a SSH_FXP_STATUS + message. If a file or directory with the specified path already + exists, an error will be returned. + + Directories can be removed using the SSH_FXP_RMDIR request, which has + the following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. + + The server responds to this request with a SSH_FXP_STATUS message. + Errors may be returned from this operation for various reasons, + including, but not limited to, the path does not exist, the path does + not refer to a directory object, the directory is not empty, or the + user has insufficient access or permission to perform the requested + operation. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + + + +Galbraith, et al. Expires April 16, 2003 [Page 19] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + If there are no more names available to be read, the server MUST + respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + + + +Galbraith, et al. Expires April 16, 2003 [Page 20] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path [UTF-8] + uint32 flags + + where `id' is the request identifier, and `path' specifies the file + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + The flags field specify the attribute flags in which the client has + particular interest. This is a hint to the server. For example, + because retrieving owner / group and acl information can be an + expensive operation under some operating systems, the server may + choose not to retrieve this information unless the client expresses a + specific interest in it. + + The client has no guarantee the server will provide all the fields + that it has expressed an interest in. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + uint32 flags + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + + + +Galbraith, et al. Expires April 16, 2003 [Page 21] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + uint32 id + string linkpath [UTF-8] + string targetpath [UTF-8] + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + + + +Galbraith, et al. Expires April 16, 2003 [Page 22] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing the name in canonical form and a dummy + attributes value. If an error occurs, the server may also respond + with SSH_FXP_STATUS. + +6.11.1 Best practice for dealing with paths + + The client SHOULD treat the results of SSH_FXP_REALPATH as a + canonical absolute path, even if the path does not appear to be + absolute. A client that use REALPATH(".") and treats the result as + absolute, even if there is no leading slash, will continue to + function correctly, even when talking to a Windows NT or VMS style + system, where absolute paths may not begin with a slash. + + For example, if the client wishes to change directory up, and the + server has returned "c:/x/y/z" from REALPATH, the client SHOULD use + "c:/x/y/z/..". + + As a second example, if the client wishes to open the file "x.txt" in + the current directory, and server has returned "dka100:/x/y/z" as the + canonical path of the directory, the client SHOULD open "dka100:/x/y/ + z/x.txt" + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 23] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 24] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + #define SSH_FX_INVALID_HANDLE 9 + #define SSH_FX_NO_SUCH_PATH 10 + #define SSH_FX_FILE_ALREADY_EXISTS 11 + #define SSH_FX_WRITE_PROTECT 12 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which does not + exist. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + + +Galbraith, et al. Expires April 16, 2003 [Page 25] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + SSH_FX_INVALID_HANDLE + The handle value was invalid. + + SSH_FX_NO_SUCH_PATH + The file path does not exist or is invalid. + + SSH_FX_FILE_ALREADY_EXISTS + The file already exists. + + SSH_FX_WRITE_PROTECT + The file is on read only media, or the media is write protected. + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + The SSH_FXP_NAME response has the following format: + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 26] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + uint32 id + uint32 count + repeats count times: + string filename [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + and `attrs' is the attributes of the file as described in Section + ``File Attributes''. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 27] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + There is a range of packet types reserved for use by extensions. In + order to avoid collision, extensions that turn on the use of + additional packet types should determine those numbers dynamically. + + The suggested way of doing this is have an extension request from the + client to the server that enables the extension; the extension + response from the server to the client would specify the actual type + values to use, in additional to any other data. + + Extension authors should be mindful of the limited range of packet + types available (there are only 45 values available) and avoid + requiring a new packet type where possible. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 28] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [8]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 29] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 4 and 3 + + Many of the changes between version 4 and version 3 are to the + attribute structure to make it more flexible for non-unix platforms. + + o Make all filenames UTF-8. + + o Added 'newline' extension. + + o Made file attribute owner and group strings so they can actually + be used on disparate systems. + + o Added createtime field, and added separate flags for atime, + createtime, and mtime so they can be set separately. + + o Split the file type out of the permissions field and into it's own + field (which is always present.) + + o Added acl attribute. + + o Added SSH_FXF_TEXT file open flag. + + o Added flags field to the get stat commands so that the client can + specifically request information the server might not normally + included for performance reasons. + + o Removed the long filename from the names structure-- it can now be + built from information available in the attrs structure. + + o Added reserved range of packet numbers for extensions. + + o Added several additional error codes. + + o Change the way version negotiate works slightly. Previously, if + the client version were higher than the server version, the server + was supposed to 'echo back' the clients version. The server now + sends it's own version and the lower of the two is considered to + be the one in use. + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 30] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +10.2 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.3 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.4 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 31] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 32] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", + BCP 18, RFC 2277, January 1998. + + [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, + C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC + 3010, December 2000. + + [4] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", draft-ietf-secsh- + architecture-13 (work in progress), September 2002. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", draft-ietf-secsh- + transport-15 (work in progress), September 2002. + + [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 + (work in progress), September 2002. + + [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", draft-ietf-secsh- + userauth-16 (work in progress), September 2002. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: [email protected] + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 33] + +Internet-Draft SSH File Transfer Protocol October 2002 + + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 34] + +Internet-Draft SSH File Transfer Protocol October 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires April 16, 2003 [Page 35] + + diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt new file mode 100644 index 0000000000..9f51883cd2 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-filexfer-04.txt @@ -0,0 +1,2130 @@ + + + +Secure Shell Working Group J. Galbraith +Internet-Draft VanDyke Software +Expires: June 18, 2003 T. Ylonen + S. Lehtinen + SSH Communications Security Corp + December 18, 2002 + + + SSH File Transfer Protocol + draft-ietf-secsh-filexfer-04.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as + Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on June 18, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + The SSH File Transfer Protocol provides secure file transfer + functionality over any reliable data stream. It is the standard file + transfer protocol for use with the SSH2 protocol. This document + describes the file transfer protocol and its interface to the SSH2 + protocol suite. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 1] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Use with the SSH Connection Protocol . . . . . . . . . . . 4 + 3. General Packet Format . . . . . . . . . . . . . . . . . . 5 + 3.1 The use of stderr in the server . . . . . . . . . . . . . 6 + 4. Protocol Initialization . . . . . . . . . . . . . . . . . 8 + 4.1 Client Initialization . . . . . . . . . . . . . . . . . . 8 + 4.2 Server Initialization . . . . . . . . . . . . . . . . . . 8 + 4.3 Determining Server Newline Convention . . . . . . . . . . 9 + 5. File Attributes . . . . . . . . . . . . . . . . . . . . . 10 + 5.1 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.2 Type . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.3 Size . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 5.4 Owner and Group . . . . . . . . . . . . . . . . . . . . . 11 + 5.5 Permissions . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.6 Times . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.7 ACL . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 5.8 Extended attributes . . . . . . . . . . . . . . . . . . . 14 + 6. Requests From the Client to the Server . . . . . . . . . . 15 + 6.1 Request Synchronization and Reordering . . . . . . . . . . 15 + 6.2 File Names . . . . . . . . . . . . . . . . . . . . . . . . 16 + 6.3 Opening, Creating, and Closing Files . . . . . . . . . . . 16 + 6.4 Reading and Writing . . . . . . . . . . . . . . . . . . . 19 + 6.5 Removing and Renaming Files . . . . . . . . . . . . . . . 20 + 6.6 Creating and Deleting Directories . . . . . . . . . . . . 21 + 6.7 Scanning Directories . . . . . . . . . . . . . . . . . . . 21 + 6.8 Retrieving File Attributes . . . . . . . . . . . . . . . . 22 + 6.9 Setting File Attributes . . . . . . . . . . . . . . . . . 23 + 6.10 Dealing with Symbolic links . . . . . . . . . . . . . . . 24 + 6.11 Canonicalizing the Server-Side Path Name . . . . . . . . . 25 + 6.11.1 Best practice for dealing with paths . . . . . . . . . . . 25 + 7. Responses from the Server to the Client . . . . . . . . . 26 + 8. Vendor-Specific Extensions . . . . . . . . . . . . . . . . 30 + 9. Security Considerations . . . . . . . . . . . . . . . . . 31 + 10. Changes from previous protocol versions . . . . . . . . . 32 + 10.1 Changes between versions 4 and 3 . . . . . . . . . . . . . 32 + 10.2 Changes between versions 3 and 2 . . . . . . . . . . . . . 33 + 10.3 Changes between versions 2 and 1 . . . . . . . . . . . . . 33 + 10.4 Changes between versions 1 and 0 . . . . . . . . . . . . . 33 + 11. Trademark Issues . . . . . . . . . . . . . . . . . . . . . 34 + References . . . . . . . . . . . . . . . . . . . . . . . . 35 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . 35 + Intellectual Property and Copyright Statements . . . . . . 37 + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 2] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +1. Introduction + + This protocol provides secure file transfer (and more generally file + system access) functionality over a reliable data stream, such as a + channel in the SSH2 protocol [5]. + + This protocol is designed so that it could be used to implement a + secure remote file system service, as well as a secure file transfer + service. + + This protocol assumes that it runs over a secure channel, and that + the server has already authenticated the user at the client end, and + that the identity of the client user is externally available to the + server implementation. + + In general, this protocol follows a simple request-response model. + Each request and response contains a sequence number and multiple + requests may be pending simultaneously. There are a relatively large + number of different request messages, but a small number of possible + response messages. Each request has one or more response messages + that may be returned in result (e.g., a read either returns data or + reports error status). + + The packet format descriptions in this specification follow the + notation presented in the secsh architecture draft. [5] + + Even though this protocol is described in the context of the SSH2 + protocol, this protocol is general and independent of the rest of the + SSH2 protocol suite. It could be used in a number of different + applications, such as secure file transfer over TLS RFC 2246 [1] and + transfer of management information in VPN applications. + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 3] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +2. Use with the SSH Connection Protocol + + When used with the SSH2 Protocol suite, this protocol is intended to + be used from the SSH Connection Protocol [7] as a subsystem, as + described in section ``Starting a Shell or a Command''. The + subsystem name used with this protocol is "sftp". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 4] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +3. General Packet Format + + All packets transmitted over the secure connection are of the + following format: + + uint32 length + byte type + byte[length - 1] data payload + + That is, they are just data preceded by 32-bit length and 8-bit type + fields. The `length' is the length of the data area, and does not + include the `length' field itself. The format and interpretation of + the data area depends on the packet type. + + All packet descriptions below only specify the packet type and the + data that goes into the data field. Thus, they should be prefixed by + the `length' and `type' fields. + + The maximum size of a packet is in practice determined by the client + (the maximum size of read or write requests that it sends, plus a few + bytes of packet overhead). All servers SHOULD support packets of at + least 34000 bytes (where the packet size refers to the full length, + including the header above). This should allow for reads and writes + of at most 32768 bytes. + + There is no limit on the number of outstanding (non-acknowledged) + requests that the client may send to the server. In practice this is + limited by the buffering available on the data stream and the queuing + performed by the server. If the server's queues are full, it should + not read any more data from the stream, and flow control will prevent + the client from sending more requests. Note, however, that while + there is no restriction on the protocol level, the client's API may + provide a limit in order to prevent infinite queuing of outgoing + requests at the client. + + The following values are defined for packet types. + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 5] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FXP_INIT 1 + #define SSH_FXP_VERSION 2 + #define SSH_FXP_OPEN 3 + #define SSH_FXP_CLOSE 4 + #define SSH_FXP_READ 5 + #define SSH_FXP_WRITE 6 + #define SSH_FXP_LSTAT 7 + #define SSH_FXP_FSTAT 8 + #define SSH_FXP_SETSTAT 9 + #define SSH_FXP_FSETSTAT 10 + #define SSH_FXP_OPENDIR 11 + #define SSH_FXP_READDIR 12 + #define SSH_FXP_REMOVE 13 + #define SSH_FXP_MKDIR 14 + #define SSH_FXP_RMDIR 15 + #define SSH_FXP_REALPATH 16 + #define SSH_FXP_STAT 17 + #define SSH_FXP_RENAME 18 + #define SSH_FXP_READLINK 19 + #define SSH_FXP_SYMLINK 20 + + #define SSH_FXP_STATUS 101 + #define SSH_FXP_HANDLE 102 + #define SSH_FXP_DATA 103 + #define SSH_FXP_NAME 104 + #define SSH_FXP_ATTRS 105 + + #define SSH_FXP_EXTENDED 200 + #define SSH_FXP_EXTENDED_REPLY 201 + + RESERVED_FOR_EXTENSIONS 210-255 + + Additional packet types should only be defined if the protocol + version number (see Section ``Protocol Initialization'') is + incremented, and their use MUST be negotiated using the version + number. However, the SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY + packets can be used to implement vendor-specific extensions. See + Section ``Vendor-Specific-Extensions'' for more details. + +3.1 The use of stderr in the server + + Packets are sent and received on stdout and stdin. Data sent on + stderr by the server SHOULD be considered debug or supplemental error + information, and MAY be displayed to the user. + + For example, during initialization, there is no client request + active, so errors or warning information cannot be sent to the client + as part of the SFTP protocol at this early stage. However, the + + + +Galbraith, et al. Expires June 18, 2003 [Page 6] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + errors or warnings MAY be sent as stderr text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 7] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +4. Protocol Initialization + + When the file transfer protocol starts, the client first sends a + SSH_FXP_INIT (including its version number) packet to the server. + The server responds with a SSH_FXP_VERSION packet, supplying the + lowest of its own and the client's version number. Both parties + should from then on adhere to particular version of the protocol. + + The version number of the protocol specified in this document is 4. + The version number should be incremented for each incompatible + revision of this protocol. + +4.1 Client Initialization + + The SSH_FXP_INIT packet (from client to server) has the following + data: + + uint32 version + + Version 3 of this protocol allowed clients to include extensions in + the SSH_FXP_INIT packet; however, this can cause interoperability + problems with version 1 and version 2 servers because the client must + send this packet before knowing the servers version. + + In this version of the protocol, clients MUST use the + SSH_FXP_EXTENDED packet to send extensions to the server after + version exchange has completed. Clients MUST NOT include extensions + in the version packet. This will prevent interoperability problems + with older servers + +4.2 Server Initialization + + The SSH_FXP_VERSION packet (from server to client) has the following + data: + + uint32 version + <extension data> + + 'version' is the lower of the protocol version supported by the + server and the version number received from the client. + + The extension data may be empty, or may be a sequence of + + string extension_name + string extension_data + + pairs (both strings MUST always be present if one is, but the + `extension_data' string may be of zero length). If present, these + + + +Galbraith, et al. Expires June 18, 2003 [Page 8] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + strings indicate extensions to the baseline protocol. The + `extension_name' field(s) identify the name of the extension. The + name should be of the form "name@domain", where the domain is the DNS + domain name of the organization defining the extension. Additional + names that are not of this format may be defined later by the IETF. + Implementations MUST silently ignore any extensions whose name they + do not recognize. + +4.3 Determining Server Newline Convention + + In order to correctly process text files in a cross platform + compatible way, the newline convention must be converted from that of + the server to that of the client, or, during an upload, from that of + the client to that of the server. + + Versions 3 and prior of this protocol made no provisions for + processing text files. Many clients implemented some sort of + conversion algorithm, but without either a 'canonical' on the wire + format or knowledge of the servers newline convention, correct + conversion was not always possible. + + Starting with Version 4, the SSH_FXF_TEXT file open flag (Section + 6.3) makes it possible to request that the server translate a file to + a 'canonical' on the wire format. This format uses \r\n as the line + separator. + + Servers for systems using multiple newline characters (for example, + Mac OS X or VMS) or systems using counted records, MUST translate to + the canonical form. + + However, to ease the burden of implementation on servers that use a + single, simple separator sequence, the following extension allows the + canonical format to be changed. + + string "newline" + string new-canonical-separator (usually "\r" or "\n" or "\r\n") + + All clients MUST support this extension. + + When processing text files, clients SHOULD NOT translate any + character or sequence that is not an exact match of the servers + newline separator. + + In particular, if the newline sequence being used is the canonical + "\r\n" sequence, a lone \r or a lone \n SHOULD be written through + without change. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 9] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +5. File Attributes + + A new compound data type is defined for encoding file attributes. + The same encoding is used both when returning file attributes from + the server and when sending file attributes to the server. When + sending it to the server, the flags field specifies which attributes + are included, and the server will use default values for the + remaining attributes (or will not modify the values of remaining + attributes). When receiving attributes from the server, the flags + specify which attributes are included in the returned data. The + server normally returns all attributes it knows about. + + uint32 flags + byte type always present + uint64 size present only if flag SIZE + string owner present only if flag OWNERGROUP + string group present only if flag OWNERGROUP + uint32 permissions present only if flag PERMISSIONS + uint64 atime present only if flag ACCESSTIME + uint32 atime_nseconds present only if flag SUBSECOND_TIMES + uint64 createtime present only if flag CREATETIME + uint32 createtime_nseconds present only if flag SUBSECOND_TIMES + uint64 mtime present only if flag MODIFYTIME + uint32 mtime_nseconds present only if flag SUBSECOND_TIMES + string acl present only if flag ACL + uint32 extended_count present only if flag EXTENDED + string extended_type + string extended_data + ... more extended data (extended_type - extended_data pairs), + so that number of pairs equals extended_count + + +5.1 Flags + + The `flags' specify which of the fields are present. Those fields + for which the corresponding flag is not set are not present (not + included in the packet). New flags can only be added by incrementing + the protocol version number (or by using the extension mechanism + described below). + + The flags bits are defined to have the following values: + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 10] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FILEXFER_ATTR_SIZE 0x00000001 + #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000040 + #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 + #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 + #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 + #define SSH_FILEXFER_ATTR_ACL 0x00000040 + #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 + #define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100 + #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 + + In previous versions of this protocol flags value 0x00000002 was + SSH_FILEXFER_ATTR_UIDGID. This value is now unused, and OWNERGROUP + was given a new value in order to ease implementation burden. + 0x00000002 MUST NOT appear in the mask. Some future version of this + protocol may reuse flag 0x00000002. + +5.2 Type + + The type field is always present. The following types are defined: + + #define SSH_FILEXFER_TYPE_REGULAR 1 + #define SSH_FILEXFER_TYPE_DIRECTORY 2 + #define SSH_FILEXFER_TYPE_SYMLINK 3 + #define SSH_FILEXFER_TYPE_SPECIAL 4 + #define SSH_FILEXFER_TYPE_UNKNOWN 5 + + On a POSIX system, these values would be derived from the permission + field. + +5.3 Size + + The `size' field specifies the size of the file on disk, in bytes. + If it is present during file creation, it should be considered a hint + as to the files eventual size. + + Files opened with the SSH_FXF_TEXT flag may have a size that is + greater or less than the value of the size field. + +5.4 Owner and Group + + The `owner' and `group' fields are represented as UTF-8 strings; this + is the form used by NFS v4. See NFS version 4 Protocol. [3] The + following text is selected quotations from section 5.6. + + To avoid a representation that is tied to a particular underlying + implementation at the client or server, the use of UTF-8 strings has + been chosen. The string should be of the form user@dns_domain". + This will allow for a client and server that do not use the same + + + +Galbraith, et al. Expires June 18, 2003 [Page 11] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + local representation the ability to translate to a common syntax that + can be interpreted by both. In the case where there is no + translation available to the client or server, the attribute value + must be constructed without the "@". Therefore, the absence of the @ + from the owner or owner_group attribute signifies that no translation + was available and the receiver of the attribute should not place any + special meaning with the attribute value. Even though the attribute + value can not be translated, it may still be useful. In the case of + a client, the attribute string may be used for local display of + ownership. + +5.5 Permissions + + The `permissions' field contains a bit mask of file permissions as + defined by POSIX [1]. + +5.6 Times + + The 'atime', 'createtime', and 'mtime' contain the access, creation, + and modification times of the files, respectively. They are + represented as seconds from Jan 1, 1970 in UTC. + + A negative value indicates number of seconds before Jan 1, 1970. In + both cases, if the SSH_FILEXFER_ATTR_SUBSECOND_TIMES flag is set, the + nseconds field is to be added to the seconds field for the final time + representation. For example, if the time to be represented is + one-half second before 0 hour January 1, 1970, the seconds field + would have a value of negative one (-1) and the nseconds fields would + have a value of one-half second (500000000). Values greater than + 999,999,999 for nseconds are considered invalid. + +5.7 ACL + + The 'ACL' field contains an ACL similar to that defined in section + 5.9 of NFS version 4 Protocol [3]. + + uint32 ace-count + + repeated ace-count time: + uint32 ace-type + uint32 ace-flag + uint32 ace-mask + string who [UTF-8] + + ace-type is one of the following four values (taken from NFS Version + 4 Protocol [3]: + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 12] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; + const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; + const ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002; + const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; + + ace-flag is a combination of the following flag values. See NFS + Version 4 Protocol [3] section 5.9.2: + + const ACE4_FILE_INHERIT_ACE = 0x00000001; + const ACE4_DIRECTORY_INHERIT_ACE = 0x00000002; + const ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004; + const ACE4_INHERIT_ONLY_ACE = 0x00000008; + const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; + const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; + const ACE4_IDENTIFIER_GROUP = 0x00000040; + + ace-mask is any combination of the following flags (taken from NFS + Version 4 Protocol [3] section 5.9.3: + + const ACE4_READ_DATA = 0x00000001; + const ACE4_LIST_DIRECTORY = 0x00000001; + const ACE4_WRITE_DATA = 0x00000002; + const ACE4_ADD_FILE = 0x00000002; + const ACE4_APPEND_DATA = 0x00000004; + const ACE4_ADD_SUBDIRECTORY = 0x00000004; + const ACE4_READ_NAMED_ATTRS = 0x00000008; + const ACE4_WRITE_NAMED_ATTRS = 0x00000010; + const ACE4_EXECUTE = 0x00000020; + const ACE4_DELETE_CHILD = 0x00000040; + const ACE4_READ_ATTRIBUTES = 0x00000080; + const ACE4_WRITE_ATTRIBUTES = 0x00000100; + const ACE4_DELETE = 0x00010000; + const ACE4_READ_ACL = 0x00020000; + const ACE4_WRITE_ACL = 0x00040000; + const ACE4_WRITE_OWNER = 0x00080000; + const ACE4_SYNCHRONIZE = 0x00100000; + + who is a UTF-8 string of the form described in 'Owner and Group' + (Section 5.4) + + Also, as per '5.9.4 ACE who' [3] there are several identifiers that + need to be understood universally. Some of these identifiers cannot + be understood when an client access the server, but have meaning when + a local process accesses the file. The ability to display and modify + these permissions is permitted over SFTP. + + OWNER The owner of the file. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 13] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + GROUP The group associated with the file. + + EVERYONE The world. + + INTERACTIVE Accessed from an interactive terminal. + + NETWORK Accessed via the network. + + DIALUP Accessed as a dialup user to the server. + + BATCH Accessed from a batch job. + + ANONYMOUS Accessed without any authentication. + + AUTHENTICATED Any authenticated user (opposite of ANONYMOUS). + + SERVICE Access from a system service. + + To avoid conflict, these special identifiers are distinguish by an + appended "@" and should appear in the form "xxxx@" (note: no domain + name after the "@"). For example: ANONYMOUS@. + +5.8 Extended attributes + + The SSH_FILEXFER_ATTR_EXTENDED flag provides a general extension + mechanism for vendor-specific extensions. If the flag is specified, + then the `extended_count' field is present. It specifies the number + of extended_type-extended_data pairs that follow. Each of these + pairs specifies an extended attribute. For each of the attributes, + the extended_type field should be a string of the format + "name@domain", where "domain" is a valid, registered domain name and + "name" identifies the method. The IETF may later standardize certain + names that deviate from this format (e.g., that do not contain the + "@" sign). The interpretation of `extended_data' depends on the + type. Implementations SHOULD ignore extended data fields that they + do not understand. + + Additional fields can be added to the attributes by either defining + additional bits to the flags field to indicate their presence, or by + defining extended attributes for them. The extended attributes + mechanism is recommended for most purposes; additional flags bits + should only be defined by an IETF standards action that also + increments the protocol version number. The use of such new fields + MUST be negotiated by the version number in the protocol exchange. + It is a protocol error if a packet with unsupported protocol bits is + received. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 14] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +6. Requests From the Client to the Server + + Requests from the client to the server represent the various file + system operations. Each request begins with an `id' field, which is + a 32-bit identifier identifying the request (selected by the client). + The same identifier will be returned in the response to the request. + One possible implementation is a monotonically increasing request + sequence number (modulo 2^32). + + Many operations in the protocol operate on open files. The + SSH_FXP_OPEN request can return a file handle (which is an opaque + variable-length string) which may be used to access the file later + (e.g. in a read operation). The client MUST NOT send requests the + server with bogus or closed handles. However, the server MUST + perform adequate checks on the handle in order to avoid security + risks due to fabricated handles. + + This design allows either stateful and stateless server + implementation, as well as an implementation which caches state + between requests but may also flush it. The contents of the file + handle string are entirely up to the server and its design. The + client should not modify or attempt to interpret the file handle + strings. + + The file handle strings MUST NOT be longer than 256 bytes. + +6.1 Request Synchronization and Reordering + + The protocol and implementations MUST process requests relating to + the same file in the order in which they are received. In other + words, if an application submits multiple requests to the server, the + results in the responses will be the same as if it had sent the + requests one at a time and waited for the response in each case. For + example, the server may process non-overlapping read/write requests + to the same file in parallel, but overlapping reads and writes cannot + be reordered or parallelized. However, there are no ordering + restrictions on the server for processing requests from two different + file transfer connections. The server may interleave and parallelize + them at will. + + There are no restrictions on the order in which responses to + outstanding requests are delivered to the client, except that the + server must ensure fairness in the sense that processing of no + request will be indefinitely delayed even if the client is sending + other requests so that there are multiple outstanding requests all + the time. + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 15] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +6.2 File Names + + This protocol represents file names as strings. File names are + assumed to use the slash ('/') character as a directory separator. + + File names starting with a slash are "absolute", and are relative to + the root of the file system. Names starting with any other character + are relative to the user's default directory (home directory). Note + that identifying the user is assumed to take place outside of this + protocol. + + Servers SHOULD interpret a path name component ".." as referring to + the parent directory, and "." as referring to the current directory. + If the server implementation limits access to certain parts of the + file system, it must be extra careful in parsing file names when + enforcing such restrictions. There have been numerous reported + security bugs where a ".." in a path name has allowed access outside + the intended area. + + An empty path name is valid, and it refers to the user's default + directory (usually the user's home directory). + + Otherwise, no syntax is defined for file names by this specification. + Clients should not make any other assumptions; however, they can + splice path name components returned by SSH_FXP_READDIR together + using a slash ('/') as the separator, and that will work as expected. + + In order to comply with IETF Policy on Character Sets and Languages + [2], all filenames are to be encoded in UTF-8. The shortest valid + UTF-8 encoding of the UNICODE data MUST be used. The server is + responsible for converting the UNICODE data to whatever canonical + form it requires. + + For example, if the server requires that precomposed characters + always be used, the server MUST NOT assume the filename as sent by + the client has this attribute, but must do this normalization itself. + + It is understood that the lack of well-defined semantics for file + names may cause interoperability problems between clients and servers + using radically different operating systems. However, this approach + is known to work acceptably with most systems, and alternative + approaches that e.g. treat file names as sequences of structured + components are quite complicated. + +6.3 Opening, Creating, and Closing Files + + Files are opened and created using the SSH_FXP_OPEN message, whose + data part is as follows: + + + +Galbraith, et al. Expires June 18, 2003 [Page 16] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string filename [UTF-8] + uint32 pflags + ATTRS attrs + + The `id' field is the request identifier as for all requests. + + The `filename' field specifies the file name. See Section ``File + Names'' for more information. + + The `pflags' field is a bitmask. The following bits have been + defined. + + #define SSH_FXF_READ 0x00000001 + #define SSH_FXF_WRITE 0x00000002 + #define SSH_FXF_APPEND 0x00000004 + #define SSH_FXF_CREAT 0x00000008 + #define SSH_FXF_TRUNC 0x00000010 + #define SSH_FXF_EXCL 0x00000020 + #define SSH_FXF_TEXT 0x00000040 + + These have the following meanings: + + SSH_FXF_READ + Open the file for reading. + + SSH_FXF_WRITE + Open the file for writing. If both this and SSH_FXF_READ are + specified, the file is opened for both reading and writing. + + SSH_FXF_APPEND + Force all writes to append data at the end of the file. The + offset parameter to write will be ignored. + + SSH_FXF_CREAT + If this flag is specified, then a new file will be created if one + does not already exist (if O_TRUNC is specified, the new file will + be truncated to zero length if it previously exists). + + SSH_FXF_TRUNC + Forces an existing file with the same name to be truncated to zero + length when creating a file by specifying SSH_FXF_CREAT. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + SSH_FXF_EXCL + Causes the request to fail if the named file already exists. + SSH_FXF_CREAT MUST also be specified if this flag is used. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 17] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + SSH_FXF_TEXT + Indicates that the server should treat the file as text and + convert it to the canonical newline convention in use. (See + Determining Server Newline Convention. (Section 4.3) + + When a file is opened with the FXF_TEXT flag, the offset field in + both the read and write function are ignored. + + Servers MUST correctly process multiple parallel reads and writes + correctly in this mode. Naturally, it is permissible for them to + do this by serializing the requests. It would not be possible for + a client to reliably detect a server that does not implement + parallel writes in time to prevent damage. + + Clients SHOULD use the SSH_FXF_APPEND flag to append data to a + text file rather then using write with a calculated offset. + + To support seeks on text file the following SSH_FXP_EXTENDED + packet is defined. + + + + string "text-seek" + string file-handle + uint64 line-number + + line-number is the index of the line number to seek to, where byte + 0 in the file is line number 0, and the byte directly following + the first newline sequence in the file is line number 1 and so on. + + The response to a "text-seek" request is an SSH_FXP_STATUS + message. + + An attempt to seek past the end-of-file should result in a + SSH_FX_EOF status. + + Servers SHOULD support at least one "text-seek" in order to + support resume. However, a client MUST be prepared to receive + SSH_FX_OP_UNSUPPORTED when attempting a "text-seek" operation. + The client can then try a fall-back strategy, if it has one. + + Clients MUST be prepared to handle SSH_FX_OP_UNSUPPORTED returned + for read or write operations that are not sequential. + + The `attrs' field specifies the initial attributes for the file. + Default values will be used for those attributes that are not + specified. See Section ``File Attributes'' for more information. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 18] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + The response to this message will be either SSH_FXP_HANDLE (if the + operation is successful) or SSH_FXP_STATUS (if the operation fails). + + A file is closed by using the SSH_FXP_CLOSE request. Its data field + has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + previously returned in the response to SSH_FXP_OPEN or + SSH_FXP_OPENDIR. The handle becomes invalid immediately after this + request has been sent. + + The response to this request will be a SSH_FXP_STATUS message. One + should note that on some server platforms even a close can fail. + This can happen e.g. if the server operating system caches writes, + and an error occurs while flushing cached writes during the close. + +6.4 Reading and Writing + + Once a file has been opened, it can be read using the following + message: + + byte SSH_FXP_READ + uint32 id + string handle + uint64 offset + uint32 len + + where `id' is the request identifier, `handle' is an open file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) relative + to the beginning of the file from where to start reading, and `len' + is the maximum number of bytes to read. + + In response to this request, the server will read as many bytes as it + can from the file (up to `len'), and return them in a SSH_FXP_DATA + message. If an error occurs or EOF is encountered before reading any + data, the server will respond with SSH_FXP_STATUS. + + For normal disk files, it is normally guaranteed that this will read + the specified number of bytes, or up to end of file. However, if the + read length is very long, the server may truncate it if it doesn't + support packets of that length. See General Packet Format (Section + 3). + + For e.g. device files this may return fewer bytes than requested. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 19] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + Writing to a file is achieved using the following message: + + byte SSH_FXP_WRITE + uint32 id + string handle + uint64 offset + string data + + where `id' is a request identifier, `handle' is a file handle + returned by SSH_FXP_OPEN, `offset' is the offset (in bytes) from the + beginning of the file where to start writing, and `data' is the data + to be written. + + The write will extend the file if writing beyond the end of the file. + It is legal to write way beyond the end of the file; the semantics + are to write zeroes from the end of the file to the specified offset + and then the data. On most operating systems, such writes do not + allocate disk space but instead leave "holes" in the file. + + The server responds to a write request with a SSH_FXP_STATUS message. + +6.5 Removing and Renaming Files + + Files can be removed using the SSH_FXP_REMOVE message. It has the + following format: + + uint32 id + string filename [UTF-8] + + where `id' is the request identifier and `filename' is the name of + the file to be removed. See Section ``File Names'' for more + information. This request cannot be used to remove directories. + + The server will respond to this request with a SSH_FXP_STATUS + message. + + Files (and directories) can be renamed using the SSH_FXP_RENAME + message. Its data is as follows: + + uint32 id + string oldpath [UTF-8] + string newpath [UTF-8] + + where `id' is the request identifier, `oldpath' is the name of an + existing file or directory, and `newpath' is the new name for the + file or directory. It is an error if there already exists a file + with the name specified by newpath. The server may also fail rename + requests in other situations, for example if `oldpath' and `newpath' + + + +Galbraith, et al. Expires June 18, 2003 [Page 20] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + point to different file systems on the server. + + The server will respond to this request with a SSH_FXP_STATUS + message. + +6.6 Creating and Deleting Directories + + New directories can be created using the SSH_FXP_MKDIR request. It + has the following format: + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier. + + `path' specifies the directory to be created. See Section ``File + Names'' for more information on file names. + + `attrs' specifies the attributes that should be applied to it upon + creation. Attributes are discussed in more detail in Section ``File + Attributes''. + + The server will respond to this request with a SSH_FXP_STATUS + message. If a file or directory with the specified path already + exists, an error will be returned. + + Directories can be removed using the SSH_FXP_RMDIR request, which has + the following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier, and `path' specifies the + directory to be removed. See Section ``File Names'' for more + information on file names. + + The server responds to this request with a SSH_FXP_STATUS message. + Errors may be returned from this operation for various reasons, + including, but not limited to, the path does not exist, the path does + not refer to a directory object, the directory is not empty, or the + user has insufficient access or permission to perform the requested + operation. + +6.7 Scanning Directories + + The files in a directory can be listed using the SSH_FXP_OPENDIR and + SSH_FXP_READDIR requests. Each SSH_FXP_READDIR request returns one + + + +Galbraith, et al. Expires June 18, 2003 [Page 21] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + or more file names with full file attributes for each file. The + client should call SSH_FXP_READDIR repeatedly until it has found the + file it is looking for or until the server responds with a + SSH_FXP_STATUS message indicating an error (normally SSH_FX_EOF if + there are no more files in the directory). The client should then + close the handle using the SSH_FXP_CLOSE request. + + The SSH_FXP_OPENDIR opens a directory for reading. It has the + following format: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' is the path name of + the directory to be listed (without any trailing slash). See Section + ``File Names'' for more information on file names. This will return + an error if the path does not specify a directory or if the directory + is not readable. The server will respond to this request with either + a SSH_FXP_HANDLE or a SSH_FXP_STATUS message. + + Once the directory has been successfully opened, files (and + directories) contained in it can be listed using SSH_FXP_READDIR + requests. These are of the format + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is a handle + returned by SSH_FXP_OPENDIR. (It is a protocol error to attempt to + use an ordinary file handle returned by SSH_FXP_OPEN.) + + The server responds to this request with either a SSH_FXP_NAME or a + SSH_FXP_STATUS message. One or more names may be returned at a time. + Full status information is returned for each name in order to speed + up typical directory listings. + + If there are no more names available to be read, the server MUST + respond with a SSH_FXP_STATUS message with error code of SSH_FX_EOF. + + When the client no longer wishes to read more names from the + directory, it SHOULD call SSH_FXP_CLOSE for the handle. The handle + should be closed regardless of whether an error has occurred or not. + +6.8 Retrieving File Attributes + + Very often, file attributes are automatically returned by + SSH_FXP_READDIR. However, sometimes there is need to specifically + retrieve the attributes for a named file. This can be done using the + + + +Galbraith, et al. Expires June 18, 2003 [Page 22] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + SSH_FXP_STAT, SSH_FXP_LSTAT and SSH_FXP_FSTAT requests. + + SSH_FXP_STAT and SSH_FXP_LSTAT only differ in that SSH_FXP_STAT + follows symbolic links on the server, whereas SSH_FXP_LSTAT does not + follow symbolic links. Both have the same format: + + uint32 id + string path [UTF-8] + uint32 flags + + where `id' is the request identifier, and `path' specifies the file + system object for which status is to be returned. The server + responds to this request with either SSH_FXP_ATTRS or SSH_FXP_STATUS. + + The flags field specify the attribute flags in which the client has + particular interest. This is a hint to the server. For example, + because retrieving owner / group and acl information can be an + expensive operation under some operating systems, the server may + choose not to retrieve this information unless the client expresses a + specific interest in it. + + The client has no guarantee the server will provide all the fields + that it has expressed an interest in. + + SSH_FXP_FSTAT differs from the others in that it returns status + information for an open file (identified by the file handle). Its + format is as follows: + + uint32 id + string handle + uint32 flags + + where `id' is the request identifier and `handle' is a file handle + returned by SSH_FXP_OPEN. The server responds to this request with + SSH_FXP_ATTRS or SSH_FXP_STATUS. + +6.9 Setting File Attributes + + File attributes may be modified using the SSH_FXP_SETSTAT and + SSH_FXP_FSETSTAT requests. These requests are used for operations + such as changing the ownership, permissions or access times, as well + as for truncating a file. + + The SSH_FXP_SETSTAT request is of the following format: + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 23] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string path [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `path' specifies the file + system object (e.g. file or directory) whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. + + An error will be returned if the specified file system object does + not exist or the user does not have sufficient rights to modify the + specified attributes. The server responds to this request with a + SSH_FXP_STATUS message. + + The SSH_FXP_FSETSTAT request modifies the attributes of a file which + is already open. It has the following format: + + uint32 id + string handle + ATTRS attrs + + where `id' is the request identifier, `handle' (MUST be returned by + SSH_FXP_OPEN) identifies the file whose attributes are to be + modified, and `attrs' specifies the modifications to be made to its + attributes. Attributes are discussed in more detail in Section + ``File Attributes''. The server will respond to this request with + SSH_FXP_STATUS. + +6.10 Dealing with Symbolic links + + The SSH_FXP_READLINK request may be used to read the target of a + symbolic link. It would have a data part as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name of the symlink to be read. + + The server will respond with a SSH_FXP_NAME packet containing only + one name and a dummy attributes value. The name in the returned + packet contains the target of the link. If an error occurs, the + server may respond with SSH_FXP_STATUS. + + The SSH_FXP_SYMLINK request will create a symbolic link on the + server. It is of the following format + + + + +Galbraith, et al. Expires June 18, 2003 [Page 24] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + uint32 id + string linkpath [UTF-8] + string targetpath [UTF-8] + + where `id' is the request identifier, `linkpath' specifies the path + name of the symlink to be created and `targetpath' specifies the + target of the symlink. The server shall respond with a + SSH_FXP_STATUS indicating either success (SSH_FX_OK) or an error + condition. + +6.11 Canonicalizing the Server-Side Path Name + + The SSH_FXP_REALPATH request can be used to have the server + canonicalize any given path name to an absolute path. This is useful + for converting path names containing ".." components or relative + pathnames without a leading slash into absolute paths. The format of + the request is as follows: + + uint32 id + string path [UTF-8] + + where `id' is the request identifier and `path' specifies the path + name to be canonicalized. The server will respond with a + SSH_FXP_NAME packet containing the name in canonical form and a dummy + attributes value. If an error occurs, the server may also respond + with SSH_FXP_STATUS. + +6.11.1 Best practice for dealing with paths + + The client SHOULD treat the results of SSH_FXP_REALPATH as a + canonical absolute path, even if the path does not appear to be + absolute. A client that use REALPATH(".") and treats the result as + absolute, even if there is no leading slash, will continue to + function correctly, even when talking to a Windows NT or VMS style + system, where absolute paths may not begin with a slash. + + For example, if the client wishes to change directory up, and the + server has returned "c:/x/y/z" from REALPATH, the client SHOULD use + "c:/x/y/z/..". + + As a second example, if the client wishes to open the file "x.txt" in + the current directory, and server has returned "dka100:/x/y/z" as the + canonical path of the directory, the client SHOULD open "dka100:/x/y/ + z/x.txt" + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 25] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +7. Responses from the Server to the Client + + The server responds to the client using one of a few response + packets. All requests can return a SSH_FXP_STATUS response upon + failure. When the operation is successful, any of the responses may + be returned (depending on the operation). If no data needs to be + returned to the client, the SSH_FXP_STATUS response with SSH_FX_OK + status is appropriate. Otherwise, the SSH_FXP_HANDLE message is used + to return a file handle (for SSH_FXP_OPEN and SSH_FXP_OPENDIR + requests), SSH_FXP_DATA is used to return data from SSH_FXP_READ, + SSH_FXP_NAME is used to return one or more file names from a + SSH_FXP_READDIR or SSH_FXP_REALPATH request, and SSH_FXP_ATTRS is + used to return file attributes from SSH_FXP_STAT, SSH_FXP_LSTAT, and + SSH_FXP_FSTAT requests. + + Exactly one response will be returned for each request. Each + response packet contains a request identifier which can be used to + match each response with the corresponding request. Note that it is + legal to have several requests outstanding simultaneously, and the + server is allowed to send responses to them in a different order from + the order in which the requests were sent (the result of their + execution, however, is guaranteed to be as if they had been processed + one at a time in the order in which the requests were sent). + + Response packets are of the same general format as request packets. + Each response packet begins with the request identifier. + + The format of the data portion of the SSH_FXP_STATUS response is as + follows: + + uint32 id + uint32 error/status code + string error message (ISO-10646 UTF-8 [RFC-2279]) + string language tag (as defined in [RFC-1766]) + + where `id' is the request identifier, and `error/status code' + indicates the result of the requested operation. The value SSH_FX_OK + indicates success, and all other values indicate failure. + + Currently, the following values are defined (other values may be + defined by future versions of this protocol): + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 26] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + #define SSH_FX_OK 0 + #define SSH_FX_EOF 1 + #define SSH_FX_NO_SUCH_FILE 2 + #define SSH_FX_PERMISSION_DENIED 3 + #define SSH_FX_FAILURE 4 + #define SSH_FX_BAD_MESSAGE 5 + #define SSH_FX_NO_CONNECTION 6 + #define SSH_FX_CONNECTION_LOST 7 + #define SSH_FX_OP_UNSUPPORTED 8 + #define SSH_FX_INVALID_HANDLE 9 + #define SSH_FX_NO_SUCH_PATH 10 + #define SSH_FX_FILE_ALREADY_EXISTS 11 + #define SSH_FX_WRITE_PROTECT 12 + #define SSH_FX_NO_MEDIA 13 + + SSH_FX_OK + Indicates successful completion of the operation. + + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which does not + exist. + + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + + + +Galbraith, et al. Expires June 18, 2003 [Page 27] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + client, and MUST NOT be returned by servers). + + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + + SSH_FX_INVALID_HANDLE + The handle value was invalid. + + SSH_FX_NO_SUCH_PATH + The file path does not exist or is invalid. + + SSH_FX_FILE_ALREADY_EXISTS + The file already exists. + + SSH_FX_WRITE_PROTECT + The file is on read only media, or the media is write protected. + + SSH_FX_NO_MEDIA + The requested operation can not be completed because there is no + media available in the drive. + + The SSH_FXP_HANDLE response has the following format: + + uint32 id + string handle + + where `id' is the request identifier, and `handle' is an arbitrary + string that identifies an open file or directory on the server. The + handle is opaque to the client; the client MUST NOT attempt to + interpret or modify it in any way. The length of the handle string + MUST NOT exceed 256 data bytes. + + The SSH_FXP_DATA response has the following format: + + uint32 id + string data + + where `id' is the request identifier, and `data' is an arbitrary byte + string containing the requested data. The data string may be at most + the number of bytes requested in a SSH_FXP_READ request, but may also + be shorter if end of file is reached or if the read is from something + other than a regular file. + + + + +Galbraith, et al. Expires June 18, 2003 [Page 28] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + The SSH_FXP_NAME response has the following format: + + uint32 id + uint32 count + repeats count times: + string filename [UTF-8] + ATTRS attrs + + where `id' is the request identifier, `count' is the number of names + returned in this response, and the remaining fields repeat `count' + times (so that all three fields are first included for the first + file, then for the second file, etc). In the repeated part, + `filename' is a file name being returned (for SSH_FXP_READDIR, it + will be a relative name within the directory, without any path + components; for SSH_FXP_REALPATH it will be an absolute path name), + and `attrs' is the attributes of the file as described in Section + ``File Attributes''. + + The SSH_FXP_ATTRS response has the following format: + + uint32 id + ATTRS attrs + + where `id' is the request identifier, and `attrs' is the returned + file attributes as described in Section ``File Attributes''. + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 29] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +8. Vendor-Specific Extensions + + The SSH_FXP_EXTENDED request provides a generic extension mechanism + for adding vendor-specific commands. The request has the following + format: + + uint32 id + string extended-request + ... any request-specific data ... + + where `id' is the request identifier, and `extended-request' is a + string of the format "name@domain", where domain is an internet + domain name of the vendor defining the request. The rest of the + request is completely vendor-specific, and servers should only + attempt to interpret it if they recognize the `extended-request' + name. + + The server may respond to such requests using any of the response + packets defined in Section ``Responses from the Server to the + Client''. Additionally, the server may also respond with a + SSH_FXP_EXTENDED_REPLY packet, as defined below. If the server does + not recognize the `extended-request' name, then the server MUST + respond with SSH_FXP_STATUS with error/status set to + SSH_FX_OP_UNSUPPORTED. + + The SSH_FXP_EXTENDED_REPLY packet can be used to carry arbitrary + extension-specific data from the server to the client. It is of the + following format: + + uint32 id + ... any request-specific data ... + + There is a range of packet types reserved for use by extensions. In + order to avoid collision, extensions that turn on the use of + additional packet types should determine those numbers dynamically. + + The suggested way of doing this is have an extension request from the + client to the server that enables the extension; the extension + response from the server to the client would specify the actual type + values to use, in additional to any other data. + + Extension authors should be mindful of the limited range of packet + types available (there are only 45 values available) and avoid + requiring a new packet type where possible. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 30] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +9. Security Considerations + + This protocol assumes that it is run over a secure channel and that + the endpoints of the channel have been authenticated. Thus, this + protocol assumes that it is externally protected from network-level + attacks. + + This protocol provides file system access to arbitrary files on the + server (only constrained by the server implementation). It is the + responsibility of the server implementation to enforce any access + controls that may be required to limit the access allowed for any + particular user (the user being authenticated externally to this + protocol, typically using the SSH User Authentication Protocol [8]. + + Care must be taken in the server implementation to check the validity + of received file handle strings. The server should not rely on them + directly; it MUST check the validity of each handle before relying on + it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 31] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +10. Changes from previous protocol versions + + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + +10.1 Changes between versions 4 and 3 + + Many of the changes between version 4 and version 3 are to the + attribute structure to make it more flexible for non-unix platforms. + + o Clarify the use of stderr by the server. + + o Clarify handling of very large read requests by the server. + + o Make all filenames UTF-8. + + o Added 'newline' extension. + + o Made time fields 64 bit, and optionally have nanosecond resultion. + + o Made file attribute owner and group strings so they can actually + be used on disparate systems. + + o Added createtime field, and added separate flags for atime, + createtime, and mtime so they can be set separately. + + o Split the file type out of the permissions field and into it's own + field (which is always present.) + + o Added acl attribute. + + o Added SSH_FXF_TEXT file open flag. + + o Added flags field to the get stat commands so that the client can + specifically request information the server might not normally + included for performance reasons. + + o Removed the long filename from the names structure-- it can now be + built from information available in the attrs structure. + + o Added reserved range of packet numbers for extensions. + + o Added several additional error codes. + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 32] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +10.2 Changes between versions 3 and 2 + + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were + added. + + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + + +10.3 Changes between versions 2 and 1 + + o The SSH_FXP_RENAME message was added. + + +10.4 Changes between versions 1 and 0 + + o Implementation changes, no actual protocol changes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 33] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +11. Trademark Issues + + "ssh" is a registered trademark of SSH Communications Security Corp + in the United States and/or other countries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 34] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +References + + [1] Dierks, T., Allen, C., Treese, W., Karlton, P., Freier, A. and + P. Kocher, "The TLS Protocol Version 1.0", RFC 2246, January + 1999. + + [2] Alvestrand, H., "IETF Policy on Character Sets and Languages", + BCP 18, RFC 2277, January 1998. + + [3] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, + C., Eisler, M. and D. Noveck, "NFS version 4 Protocol", RFC + 3010, December 2000. + + [4] Institute of Electrical and Electronics Engineers, "Information + Technology - Portable Operating System Interface (POSIX) - Part + 1: System Application Program Interface (API) [C Language]", + IEEE Standard 1003.2, 1996. + + [5] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Architecture", + draft-ietf-secsh-architecture-13 (work in progress), September + 2002. + + [6] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Protocol Transport Protocol", + draft-ietf-secsh-transport-15 (work in progress), September + 2002. + + [7] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Connection Protocol", draft-ietf-secsh-connect-16 + (work in progress), September 2002. + + [8] Rinne, T., Ylonen, T., Kivinen, T., Saarinen, M. and S. + Lehtinen, "SSH Authentication Protocol", + draft-ietf-secsh-userauth-16 (work in progress), September 2002. + + +Authors' Addresses + + Joseph Galbraith + VanDyke Software + 4848 Tramway Ridge Blvd + Suite 101 + Albuquerque, NM 87111 + US + + Phone: +1 505 332 5700 + EMail: [email protected] + + + +Galbraith, et al. Expires June 18, 2003 [Page 35] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Sami Lehtinen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 36] + +Internet-Draft SSH File Transfer Protocol December 2002 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + + + +Galbraith, et al. Expires June 18, 2003 [Page 37] + +Internet-Draft SSH File Transfer Protocol December 2002 + + + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Galbraith, et al. Expires June 18, 2003 [Page 38] + + diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps new file mode 100644 index 0000000000..d692285b4e --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.2.ps @@ -0,0 +1,3205 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Fri Oct 31 13:35:14 2003 +%%Orientation: Portrait +%%Pages: 15 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Network Working Group T. Ylonen) s +5 690 M +(Internet-Draft SSH Communications Security Corp) s +5 679 M +(Expires: March 31, 2004 D. Moffat, Editor, Ed.) s +5 668 M +( Sun Microsystems, Inc) s +5 657 M +( Oct 2003) s +5 624 M +( SSH Transport Layer Protocol) s +5 613 M +( draft-ietf-secsh-transport-17.txt) s +5 591 M +(Status of this Memo) s +5 569 M +( This document is an Internet-Draft and is in full conformance with) s +5 558 M +( all provisions of Section 10 of RFC2026.) s +5 536 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 525 M +( Task Force \(IETF\), its areas, and its working groups. Note that other) s +5 514 M +( groups may also distribute working documents as Internet-Drafts.) s +5 492 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 481 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 470 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 459 M +( material or to cite them other than as "work in progress.") s +5 437 M +( The list of current Internet-Drafts can be accessed at http://) s +5 426 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 404 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 393 M +( http://www.ietf.org/shadow.html.) s +5 371 M +( This Internet-Draft will expire on March 31, 2004.) s +5 349 M +(Copyright Notice) s +5 327 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 305 M +(Abstract) s +5 283 M +( SSH is a protocol for secure remote login and other secure network) s +5 272 M +( services over an insecure network.) s +5 250 M +( This document describes the SSH transport layer protocol which) s +5 239 M +( typically runs on top of TCP/IP. The protocol can be used as a basis) s +5 228 M +( for a number of secure network services. It provides strong) s +5 217 M +( encryption, server authentication, and integrity protection. It may) s +5 206 M +( also provide compression.) s +5 184 M +( Key exchange method, public key algorithm, symmetric encryption) s +5 173 M +( algorithm, message authentication algorithm, and hash algorithm are) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( all negotiated.) s +5 668 M +( This document also describes the Diffie-Hellman key exchange method) s +5 657 M +( and the minimal set of algorithms that are needed to implement the) s +5 646 M +( SSH transport layer protocol.) s +5 624 M +(Table of Contents) s +5 602 M +( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 591 M +( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 580 M +( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s +5 569 M +( 4. Connection Setup . . . . . . . . . . . . . . . . . . . . . . 3) s +5 558 M +( 4.1 Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . 4) s +5 547 M +( 4.2 Protocol Version Exchange . . . . . . . . . . . . . . . . . 4) s +5 536 M +( 4.3 Compatibility With Old SSH Versions . . . . . . . . . . . . 4) s +5 525 M +( 4.3.1 Old Client, New Server . . . . . . . . . . . . . . . . . . . 5) s +5 514 M +( 4.3.2 New Client, Old Server . . . . . . . . . . . . . . . . . . . 5) s +5 503 M +( 5. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . 5) s +5 492 M +( 5.1 Maximum Packet Length . . . . . . . . . . . . . . . . . . . 6) s +5 481 M +( 5.2 Compression . . . . . . . . . . . . . . . . . . . . . . . . 7) s +5 470 M +( 5.3 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . 7) s +5 459 M +( 5.4 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 9) s +5 448 M +( 5.5 Key Exchange Methods . . . . . . . . . . . . . . . . . . . . 10) s +5 437 M +( 5.6 Public Key Algorithms . . . . . . . . . . . . . . . . . . . 11) s +5 426 M +( 6. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . 13) s +5 415 M +( 6.1 Algorithm Negotiation . . . . . . . . . . . . . . . . . . . 13) s +5 404 M +( 6.2 Output from Key Exchange . . . . . . . . . . . . . . . . . . 16) s +5 393 M +( 6.3 Taking Keys Into Use . . . . . . . . . . . . . . . . . . . . 17) s +5 382 M +( 7. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . 18) s +5 371 M +( 7.1 diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . 19) s +5 360 M +( 8. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . 20) s +5 349 M +( 9. Service Request . . . . . . . . . . . . . . . . . . . . . . 21) s +5 338 M +( 10. Additional Messages . . . . . . . . . . . . . . . . . . . . 21) s +5 327 M +( 10.1 Disconnection Message . . . . . . . . . . . . . . . . . . . 22) s +5 316 M +( 10.2 Ignored Data Message . . . . . . . . . . . . . . . . . . . . 22) s +5 305 M +( 10.3 Debug Message . . . . . . . . . . . . . . . . . . . . . . . 23) s +5 294 M +( 10.4 Reserved Messages . . . . . . . . . . . . . . . . . . . . . 23) s +5 283 M +( 11. Summary of Message Numbers . . . . . . . . . . . . . . . . . 23) s +5 272 M +( 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . 24) s +5 261 M +( 13. Security Considerations . . . . . . . . . . . . . . . . . . 24) s +5 250 M +( 14. Intellectual Property . . . . . . . . . . . . . . . . . . . 24) s +5 239 M +( 15. Additional Information . . . . . . . . . . . . . . . . . . . 24) s +5 228 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 26) s +5 217 M +( Normative . . . . . . . . . . . . . . . . . . . . . . . . . 25) s +5 206 M +( Informative . . . . . . . . . . . . . . . . . . . . . . . . 25) s +5 195 M +( A. Contibutors . . . . . . . . . . . . . . . . . . . . . . . . 27) s +5 184 M +( Intellectual Property and Copyright Statements . . . . . . . 28) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(1. Contributors) s +5 668 M +( The major original contributors of this document were: Tatu Ylonen,) s +5 657 M +( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s +5 646 M +( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s +5 635 M +( Jyvaskyla\)) s +5 613 M +( The document editor is: [email protected]. Comments on this) s +5 602 M +( internet draft should be sent to the IETF SECSH working group,) s +5 591 M +( details at: http://ietf.org/html.charters/secsh-charter.html) s +5 569 M +(2. Introduction) s +5 547 M +( The SSH transport layer is a secure low level transport protocol. It) s +5 536 M +( provides strong encryption, cryptographic host authentication, and) s +5 525 M +( integrity protection.) s +5 503 M +( Authentication in this protocol level is host-based; this protocol) s +5 492 M +( does not perform user authentication. A higher level protocol for) s +5 481 M +( user authentication can be designed on top of this protocol.) s +5 459 M +( The protocol has been designed to be simple, flexible, to allow) s +5 448 M +( parameter negotiation, and to minimize the number of round-trips.) s +5 437 M +( Key exchange method, public key algorithm, symmetric encryption) s +5 426 M +( algorithm, message authentication algorithm, and hash algorithm are) s +5 415 M +( all negotiated. It is expected that in most environments, only 2) s +5 404 M +( round-trips will be needed for full key exchange, server) s +5 393 M +( authentication, service request, and acceptance notification of) s +5 382 M +( service request. The worst case is 3 round-trips.) s +5 360 M +(3. Conventions Used in This Document) s +5 338 M +( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s +5 327 M +( and "MAY" that appear in this document are to be interpreted as) s +5 316 M +( described in [RFC2119].) s +5 294 M +( The used data types and terminology are specified in the architecture) s +5 283 M +( document [SSH-ARCH].) s +5 261 M +( The architecture document also discusses the algorithm naming) s +5 250 M +( conventions that MUST be used with the SSH protocols.) s +5 228 M +(4. Connection Setup) s +5 206 M +( SSH works over any 8-bit clean, binary-transparent transport. The) s +5 195 M +( underlying transport SHOULD protect against transmission errors as) s +5 184 M +( such errors cause the SSH connection to terminate.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( The client initiates the connection.) s +5 668 M +(4.1 Use over TCP/IP) s +5 646 M +( When used over TCP/IP, the server normally listens for connections on) s +5 635 M +( port 22. This port number has been registered with the IANA, and has) s +5 624 M +( been officially assigned for SSH.) s +5 602 M +(4.2 Protocol Version Exchange) s +5 580 M +( When the connection has been established, both sides MUST send an) s +5 569 M +( identification string of the form "SSH-protoversion-softwareversion) s +5 558 M +( comments", followed by carriage return and newline characters \(ASCII) s +5 547 M +( 13 and 10, respectively\). Both sides MUST be able to process) s +5 536 M +( identification strings without carriage return character. No null) s +5 525 M +( character is sent. The maximum length of the string is 255) s +5 514 M +( characters, including the carriage return and newline.) s +5 492 M +( The part of the identification string preceding carriage return and) s +5 481 M +( newline is used in the Diffie-Hellman key exchange \(see Section) s +5 470 M +( Section 7\).) s +5 448 M +( The server MAY send other lines of data before sending the version) s +5 437 M +( string. Each line SHOULD be terminated by a carriage return and) s +5 426 M +( newline. Such lines MUST NOT begin with "SSH-", and SHOULD be) s +5 415 M +( encoded in ISO-10646 UTF-8 [RFC2279] \(language is not specified\).) s +5 404 M +( Clients MUST be able to process such lines; they MAY be silently) s +5 393 M +( ignored, or MAY be displayed to the client user; if they are) s +5 382 M +( displayed, control character filtering discussed in [SSH-ARCH] SHOULD) s +5 371 M +( be used. The primary use of this feature is to allow TCP-wrappers to) s +5 360 M +( display an error message before disconnecting.) s +5 338 M +( Version strings MUST consist of printable US-ASCII characters, not) s +5 327 M +( including whitespaces or a minus sign \(-\). The version string is) s +5 316 M +( primarily used to trigger compatibility extensions and to indicate) s +5 305 M +( the capabilities of an implementation. The comment string should) s +5 294 M +( contain additional information that might be useful in solving user) s +5 283 M +( problems.) s +5 261 M +( The protocol version described in this document is 2.0.) s +5 239 M +( Key exchange will begin immediately after sending this identifier.) s +5 228 M +( All packets following the identification string SHALL use the binary) s +5 217 M +( packet protocol, to be described below.) s +5 195 M +(4.3 Compatibility With Old SSH Versions) s +5 173 M +( During the transition period, it is important to be able to work in a) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( way that is compatible with the installed SSH clients and servers) s +5 679 M +( that use an older version of the protocol. Information in this) s +5 668 M +( section is only relevant for implementations supporting compatibility) s +5 657 M +( with SSH versions 1.x. There is no standards track or informational) s +5 646 M +( draft available that defines the SSH 1.x protocol. The only known) s +5 635 M +( documentation of the 1.x protocol is contained in README files that) s +5 624 M +( are shipped along with the source code.) s +5 602 M +(4.3.1 Old Client, New Server) s +5 580 M +( Server implementations MAY support a configurable "compatibility") s +5 569 M +( flag that enables compatibility with old versions. When this flag is) s +5 558 M +( on, the server SHOULD identify its protocol version as "1.99".) s +5 547 M +( Clients using protocol 2.0 MUST be able to identify this as identical) s +5 536 M +( to "2.0". In this mode the server SHOULD NOT send the carriage) s +5 525 M +( return character \(ASCII 13\) after the version identification string.) s +5 503 M +( In the compatibility mode the server SHOULD NOT send any further data) s +5 492 M +( after its initialization string until it has received an) s +5 481 M +( identification string from the client. The server can then determine) s +5 470 M +( whether the client is using an old protocol, and can revert to the) s +5 459 M +( old protocol if required. In the compatibility mode, the server MUST) s +5 448 M +( NOT send additional data before the version string.) s +5 426 M +( When compatibility with old clients is not needed, the server MAY) s +5 415 M +( send its initial key exchange data immediately after the) s +5 404 M +( identification string.) s +5 382 M +(4.3.2 New Client, Old Server) s +5 360 M +( Since the new client MAY immediately send additional data after its) s +5 349 M +( identification string \(before receiving server's identification\), the) s +5 338 M +( old protocol may already have been corrupted when the client learns) s +5 327 M +( that the server is old. When this happens, the client SHOULD close) s +5 316 M +( the connection to the server, and reconnect using the old protocol.) s +5 294 M +(5. Binary Packet Protocol) s +5 272 M +( Each packet is in the following format:) s +5 250 M +( uint32 packet_length) s +5 239 M +( byte padding_length) s +5 228 M +( byte[n1] payload; n1 = packet_length - padding_length - 1) s +5 217 M +( byte[n2] random padding; n2 = padding_length) s +5 206 M +( byte[m] mac \(message authentication code\); m = mac_length) s +5 184 M +( packet_length) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( The length of the packet \(bytes\), not including MAC or the) s +5 679 M +( packet_length field itself.) s +5 657 M +( padding_length) s +5 646 M +( Length of padding \(bytes\).) s +5 624 M +( payload) s +5 613 M +( The useful contents of the packet. If compression has been) s +5 602 M +( negotiated, this field is compressed. Initially, compression) s +5 591 M +( MUST be "none".) s +5 569 M +( random padding) s +5 558 M +( Arbitrary-length padding, such that the total length of) s +5 547 M +( \(packet_length || padding_length || payload || padding\) is a) s +5 536 M +( multiple of the cipher block size or 8, whichever is larger.) s +5 525 M +( There MUST be at least four bytes of padding. The padding) s +5 514 M +( SHOULD consist of random bytes. The maximum amount of padding) s +5 503 M +( is 255 bytes.) s +5 481 M +( mac) s +5 470 M +( Message authentication code. If message authentication has) s +5 459 M +( been negotiated, this field contains the MAC bytes. Initially,) s +5 448 M +( the MAC algorithm MUST be "none".) s +5 415 M +( Note that length of the concatenation of packet length, padding) s +5 404 M +( length, payload, and padding MUST be a multiple of the cipher block) s +5 393 M +( size or 8, whichever is larger. This constraint MUST be enforced) s +5 382 M +( even when using stream ciphers. Note that the packet length field is) s +5 371 M +( also encrypted, and processing it requires special care when sending) s +5 360 M +( or receiving packets.) s +5 338 M +( The minimum size of a packet is 16 \(or the cipher block size,) s +5 327 M +( whichever is larger\) bytes \(plus MAC\); implementations SHOULD decrypt) s +5 316 M +( the length after receiving the first 8 \(or cipher block size,) s +5 305 M +( whichever is larger\) bytes of a packet.) s +5 283 M +(5.1 Maximum Packet Length) s +5 261 M +( All implementations MUST be able to process packets with uncompressed) s +5 250 M +( payload length of 32768 bytes or less and total packet size of 35000) s +5 239 M +( bytes or less \(including length, padding length, payload, padding,) s +5 228 M +( and MAC.\). The maximum of 35000 bytes is an arbitrary chosen value) s +5 217 M +( larger than uncompressed size. Implementations SHOULD support longer) s +5 206 M +( packets, where they might be needed, e.g. if an implementation wants) s +5 195 M +( to send a very large number of certificates. Such packets MAY be) s +5 184 M +( sent if the version string indicates that the other party is able to) s +5 173 M +( process them. However, implementations SHOULD check that the packet) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( length is reasonable for the implementation to avoid) s +5 679 M +( denial-of-service and/or buffer overflow attacks.) s +5 657 M +(5.2 Compression) s +5 635 M +( If compression has been negotiated, the payload field \(and only it\)) s +5 624 M +( will be compressed using the negotiated algorithm. The length field) s +5 613 M +( and MAC will be computed from the compressed payload. Encryption will) s +5 602 M +( be done after compression.) s +5 580 M +( Compression MAY be stateful, depending on the method. Compression) s +5 569 M +( MUST be independent for each direction, and implementations MUST) s +5 558 M +( allow independently choosing the algorithm for each direction.) s +5 536 M +( The following compression methods are currently defined:) s +5 514 M +( none REQUIRED no compression) s +5 503 M +( zlib OPTIONAL ZLIB \(LZ77\) compression) s +5 481 M +( The "zlib" compression is described in [RFC1950] and in [RFC1951].) s +5 470 M +( The compression context is initialized after each key exchange, and) s +5 459 M +( is passed from one packet to the next with only a partial flush being) s +5 448 M +( performed at the end of each packet. A partial flush means that the) s +5 437 M +( current compressed block is ended and all data will be output. If the) s +5 426 M +( current block is not a stored block, one or more empty blocks are) s +5 415 M +( added after the current block to ensure that there are at least 8) s +5 404 M +( bits counting from the start of the end-of-block code of the current) s +5 393 M +( block to the end of the packet payload.) s +5 371 M +( Additional methods may be defined as specified in [SSH-ARCH].) s +5 349 M +(5.3 Encryption) s +5 327 M +( An encryption algorithm and a key will be negotiated during the key) s +5 316 M +( exchange. When encryption is in effect, the packet length, padding) s +5 305 M +( length, payload and padding fields of each packet MUST be encrypted) s +5 294 M +( with the given algorithm.) s +5 272 M +( The encrypted data in all packets sent in one direction SHOULD be) s +5 261 M +( considered a single data stream. For example, initialization vectors) s +5 250 M +( SHOULD be passed from the end of one packet to the beginning of the) s +5 239 M +( next packet. All ciphers SHOULD use keys with an effective key length) s +5 228 M +( of 128 bits or more.) s +5 206 M +( The ciphers in each direction MUST run independently of each other,) s +5 195 M +( and implementations MUST allow independently choosing the algorithm) s +5 184 M +( for each direction \(if multiple algorithms are allowed by local) s +5 173 M +( policy\).) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( The following ciphers are currently defined:) s +5 668 M +( 3des-cbc REQUIRED three-key 3DES in CBC mode) s +5 657 M +( blowfish-cbc OPTIONALi Blowfish in CBC mode) s +5 646 M +( twofish256-cbc OPTIONAL Twofish in CBC mode,) s +5 635 M +( with 256-bit key) s +5 624 M +( twofish-cbc OPTIONAL alias for "twofish256-cbc" \(this) s +5 613 M +( is being retained for) s +5 602 M +( historical reasons\)) s +5 591 M +( twofish192-cbc OPTIONAL Twofish with 192-bit key) s +5 580 M +( twofish128-cbc OPTIONAL Twofish with 128-bit key) s +5 569 M +( aes256-cbc OPTIONAL AES \(Rijndael\) in CBC mode,) s +5 558 M +( with 256-bit key) s +5 547 M +( aes192-cbc OPTIONAL AES with 192-bit key) s +5 536 M +( aes128-cbc RECOMMENDED AES with 128-bit key) s +5 525 M +( serpent256-cbc OPTIONAL Serpent in CBC mode, with) s +5 514 M +( 256-bit key) s +5 503 M +( serpent192-cbc OPTIONAL Serpent with 192-bit key) s +5 492 M +( serpent128-cbc OPTIONAL Serpent with 128-bit key) s +5 481 M +( arcfour OPTIONAL the ARCFOUR stream cipher) s +5 470 M +( idea-cbc OPTIONAL IDEA in CBC mode) s +5 459 M +( cast128-cbc OPTIONAL CAST-128 in CBC mode) s +5 448 M +( none OPTIONAL no encryption; NOT RECOMMENDED) s +5 426 M +( The "3des-cbc" cipher is three-key triple-DES) s +5 415 M +( \(encrypt-decrypt-encrypt\), where the first 8 bytes of the key are) s +5 404 M +( used for the first encryption, the next 8 bytes for the decryption,) s +5 393 M +( and the following 8 bytes for the final encryption. This requires 24) s +5 382 M +( bytes of key data \(of which 168 bits are actually used\). To) s +5 371 M +( implement CBC mode, outer chaining MUST be used \(i.e., there is only) s +5 360 M +( one initialization vector\). This is a block cipher with 8 byte) s +5 349 M +( blocks. This algorithm is defined in [FIPS-46-3]) s +5 327 M +( The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit keys) s +5 316 M +( [SCHNEIER]. This is a block cipher with 8 byte blocks.) s +5 294 M +( The "twofish-cbc" or "twofish256-cbc" cipher is Twofish in CBC mode,) s +5 283 M +( with 256 bit keys as described [TWOFISH]. This is a block cipher with) s +5 272 M +( 16 byte blocks.) s +5 250 M +( The "twofish192-cbc" cipher. Same as above but with 192-bit key.) s +5 228 M +( The "twofish128-cbc" cipher. Same as above but with 128-bit key.) s +5 206 M +( The "aes256-cbc" cipher is AES \(Advanced Encryption Standard\)) s +5 195 M +( [FIPS-197], formerly Rijndael, in CBC mode. This version uses 256-bit) s +5 184 M +( key.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( The "aes192-cbc" cipher. Same as above but with 192-bit key.) s +5 668 M +( The "aes128-cbc" cipher. Same as above but with 128-bit key.) s +5 646 M +( The "serpent256-cbc" cipher in CBC mode, with 256-bit key as) s +5 635 M +( described in the Serpent AES submission.) s +5 613 M +( The "serpent192-cbc" cipher. Same as above but with 192-bit key.) s +5 591 M +( The "serpent128-cbc" cipher. Same as above but with 128-bit key.) s +5 569 M +( The "arcfour" is the Arcfour stream cipher with 128 bit keys. The) s +5 558 M +( Arcfour cipher is believed to be compatible with the RC4 cipher) s +5 547 M +( [SCHNEIER]. RC4 is a registered trademark of RSA Data Security Inc.) s +5 536 M +( Arcfour \(and RC4\) has problems with weak keys, and should be used) s +5 525 M +( with caution.) s +5 503 M +( The "idea-cbc" cipher is the IDEA cipher in CBC mode [SCHNEIER].) s +5 481 M +( The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode) s +5 470 M +( [RFC2144].) s +5 448 M +( The "none" algorithm specifies that no encryption is to be done.) s +5 437 M +( Note that this method provides no confidentiality protection, and it) s +5 426 M +( is not recommended. Some functionality \(e.g. password) s +5 415 M +( authentication\) may be disabled for security reasons if this cipher) s +5 404 M +( is chosen.) s +5 382 M +( Additional methods may be defined as specified in [SSH-ARCH].) s +5 360 M +(5.4 Data Integrity) s +5 338 M +( Data integrity is protected by including with each packet a message) s +5 327 M +( authentication code \(MAC\) that is computed from a shared secret,) s +5 316 M +( packet sequence number, and the contents of the packet.) s +5 294 M +( The message authentication algorithm and key are negotiated during) s +5 283 M +( key exchange. Initially, no MAC will be in effect, and its length) s +5 272 M +( MUST be zero. After key exchange, the selected MAC will be computed) s +5 261 M +( before encryption from the concatenation of packet data:) s +5 239 M +( mac = MAC\(key, sequence_number || unencrypted_packet\)) s +5 217 M +( where unencrypted_packet is the entire packet without MAC \(the length) s +5 206 M +( fields, payload and padding\), and sequence_number is an implicit) s +5 195 M +( packet sequence number represented as uint32. The sequence number is) s +5 184 M +( initialized to zero for the first packet, and is incremented after) s +5 173 M +( every packet \(regardless of whether encryption or MAC is in use\). It) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( is never reset, even if keys/algorithms are renegotiated later. It) s +5 679 M +( wraps around to zero after every 2^32 packets. The packet sequence) s +5 668 M +( number itself is not included in the packet sent over the wire.) s +5 646 M +( The MAC algorithms for each direction MUST run independently, and) s +5 635 M +( implementations MUST allow choosing the algorithm independently for) s +5 624 M +( both directions.) s +5 602 M +( The MAC bytes resulting from the MAC algorithm MUST be transmitted) s +5 591 M +( without encryption as the last part of the packet. The number of MAC) s +5 580 M +( bytes depends on the algorithm chosen.) s +5 558 M +( The following MAC algorithms are currently defined:) s +5 536 M +( hmac-sha1 REQUIRED HMAC-SHA1 \(digest length = key) s +5 525 M +( length = 20\)) s +5 514 M +( hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 \(digest) s +5 503 M +( length = 12, key length = 20\)) s +5 492 M +( hmac-md5 OPTIONAL HMAC-MD5 \(digest length = key) s +5 481 M +( length = 16\)) s +5 470 M +( hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 \(digest) s +5 459 M +( length = 12, key length = 16\)) s +5 448 M +( none OPTIONAL no MAC; NOT RECOMMENDED) s +5 426 M +( Figure 1) s +5 404 M +( The "hmac-*" algorithms are described in [RFC2104] The "*-n" MACs use) s +5 393 M +( only the first n bits of the resulting value.) s +5 371 M +( The hash algorithms are described in [SCHNEIER].) s +5 349 M +( Additional methods may be defined as specified in [SSH-ARCH].) s +5 327 M +(5.5 Key Exchange Methods) s +5 305 M +( The key exchange method specifies how one-time session keys are) s +5 294 M +( generated for encryption and for authentication, and how the server) s +5 283 M +( authentication is done.) s +5 261 M +( Only one REQUIRED key exchange method has been defined:) s +5 239 M +( diffie-hellman-group1-sha1 REQUIRED) s +5 217 M +( This method is described later in this document.) s +5 195 M +( Additional methods may be defined as specified in [SSH-ARCH].) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(5.6 Public Key Algorithms) s +5 668 M +( This protocol has been designed to be able to operate with almost any) s +5 657 M +( public key format, encoding, and algorithm \(signature and/or) s +5 646 M +( encryption\).) s +5 624 M +( There are several aspects that define a public key type:) s +5 613 M +( o Key format: how is the key encoded and how are certificates) s +5 602 M +( represented. The key blobs in this protocol MAY contain) s +5 591 M +( certificates in addition to keys.) s +5 580 M +( o Signature and/or encryption algorithms. Some key types may not) s +5 569 M +( support both signing and encryption. Key usage may also be) s +5 558 M +( restricted by policy statements in e.g. certificates. In this) s +5 547 M +( case, different key types SHOULD be defined for the different) s +5 536 M +( policy alternatives.) s +5 525 M +( o Encoding of signatures and/or encrypted data. This includes but is) s +5 514 M +( not limited to padding, byte order, and data formats.) s +5 492 M +( The following public key and/or certificate formats are currently defined:) s +5 470 M +( ssh-dss REQUIRED sign Raw DSS Key) s +5 459 M +( ssh-rsa RECOMMENDED sign Raw RSA Key) s +5 448 M +( x509v3-sign-rsa OPTIONAL sign X.509 certificates \(RSA key\)) s +5 437 M +( x509v3-sign-dss OPTIONAL sign X.509 certificates \(DSS key\)) s +5 426 M +( spki-sign-rsa OPTIONAL sign SPKI certificates \(RSA key\)) s +5 415 M +( spki-sign-dss OPTIONAL sign SPKI certificates \(DSS key\)) s +5 404 M +( pgp-sign-rsa OPTIONAL sign OpenPGP certificates \(RSA key\)) s +5 393 M +( pgp-sign-dss OPTIONAL sign OpenPGP certificates \(DSS key\)) s +5 371 M +( Additional key types may be defined as specified in [SSH-ARCH].) s +5 349 M +( The key type MUST always be explicitly known \(from algorithm) s +5 338 M +( negotiation or some other source\). It is not normally included in) s +5 327 M +( the key blob.) s +5 305 M +( Certificates and public keys are encoded as follows:) s +5 283 M +( string certificate or public key format identifier) s +5 272 M +( byte[n] key/certificate data) s +5 250 M +( The certificate part may have be a zero length string, but a public) s +5 239 M +( key is required. This is the public key that will be used for) s +5 228 M +( authentication; the certificate sequence contained in the certificate) s +5 217 M +( blob can be used to provide authorization.) s +5 195 M +( Public key / certifcate formats that do not explicitly specify a) s +5 184 M +( signature format identifier MUST use the public key / certificate) s +5 173 M +( format identifier as the signature identifier.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( Signatures are encoded as follows:) s +5 679 M +( string signature format identifier \(as specified by the) s +5 668 M +( public key / cert format\)) s +5 657 M +( byte[n] signature blob in format specific encoding.) s +5 624 M +( The "ssh-dss" key format has the following specific encoding:) s +5 602 M +( string "ssh-dss") s +5 591 M +( mpint p) s +5 580 M +( mpint q) s +5 569 M +( mpint g) s +5 558 M +( mpint y) s +5 536 M +( Here the p, q, g, and y parameters form the signature key blob.) s +5 514 M +( Signing and verifying using this key format is done according to the) s +5 503 M +( Digital Signature Standard [FIPS-186] using the SHA-1 hash. A) s +5 492 M +( description can also be found in [SCHNEIER].) s +5 470 M +( The resulting signature is encoded as follows:) s +5 448 M +( string "ssh-dss") s +5 437 M +( string dss_signature_blob) s +5 415 M +( dss_signature_blob is encoded as a string containing r followed by s) s +5 404 M +( \(which are 160 bits long integers, without lengths or padding,) s +5 393 M +( unsigned and in network byte order\).) s +5 371 M +( The "ssh-rsa" key format has the following specific encoding:) s +5 349 M +( string "ssh-rsa") s +5 338 M +( mpint e) s +5 327 M +( mpint n) s +5 305 M +( Here the e and n parameters form the signature key blob.) s +5 283 M +( Signing and verifying using this key format is done according to) s +5 272 M +( [SCHNEIER] and [PKCS1] using the SHA-1 hash.) s +5 250 M +( The resulting signature is encoded as follows:) s +5 228 M +( string "ssh-rsa") s +5 217 M +( string rsa_signature_blob) s +5 195 M +( rsa_signature_blob is encoded as a string containing s \(which is an) s +5 184 M +( integer, without lengths or padding, unsigned and in network byte) s +5 173 M +( order\).) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( The "spki-sign-rsa" method indicates that the certificate blob) s +5 679 M +( contains a sequence of SPKI certificates. The format of SPKI) s +5 668 M +( certificates is described in [RFC2693]. This method indicates that) s +5 657 M +( the key \(or one of the keys in the certificate\) is an RSA-key.) s +5 635 M +( The "spki-sign-dss". As above, but indicates that the key \(or one of) s +5 624 M +( the keys in the certificate\) is a DSS-key.) s +5 602 M +( The "pgp-sign-rsa" method indicates the certificates, the public key,) s +5 591 M +( and the signature are in OpenPGP compatible binary format) s +5 580 M +( \([RFC2440]\). This method indicates that the key is an RSA-key.) s +5 558 M +( The "pgp-sign-dss". As above, but indicates that the key is a) s +5 547 M +( DSS-key.) s +5 525 M +(6. Key Exchange) s +5 503 M +( Key exchange begins by each side sending lists of supported) s +5 492 M +( algorithms. Each side has a preferred algorithm in each category, and) s +5 481 M +( it is assumed that most implementations at any given time will use) s +5 470 M +( the same preferred algorithm. Each side MAY guess which algorithm) s +5 459 M +( the other side is using, and MAY send an initial key exchange packet) s +5 448 M +( according to the algorithm if appropriate for the preferred method.) s +5 426 M +( Guess is considered wrong, if:) s +5 415 M +( o the kex algorithm and/or the host key algorithm is guessed wrong) s +5 404 M +( \(server and client have different preferred algorithm\), or) s +5 393 M +( o if any of the other algorithms cannot be agreed upon \(the) s +5 382 M +( procedure is defined below in Section Section 6.1\).) s +5 360 M +( Otherwise, the guess is considered to be right and the optimistically) s +5 349 M +( sent packet MUST be handled as the first key exchange packet.) s +5 327 M +( However, if the guess was wrong, and a packet was optimistically sent) s +5 316 M +( by one or both parties, such packets MUST be ignored \(even if the) s +5 305 M +( error in the guess would not affect the contents of the initial) s +5 294 M +( packet\(s\)\), and the appropriate side MUST send the correct initial) s +5 283 M +( packet.) s +5 261 M +( Server authentication in the key exchange MAY be implicit. After a) s +5 250 M +( key exchange with implicit server authentication, the client MUST) s +5 239 M +( wait for response to its service request message before sending any) s +5 228 M +( further data.) s +5 206 M +(6.1 Algorithm Negotiation) s +5 184 M +( Key exchange begins by each side sending the following packet:) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( byte SSH_MSG_KEXINIT) s +5 679 M +( byte[16] cookie \(random bytes\)) s +5 668 M +( string kex_algorithms) s +5 657 M +( string server_host_key_algorithms) s +5 646 M +( string encryption_algorithms_client_to_server) s +5 635 M +( string encryption_algorithms_server_to_client) s +5 624 M +( string mac_algorithms_client_to_server) s +5 613 M +( string mac_algorithms_server_to_client) s +5 602 M +( string compression_algorithms_client_to_server) s +5 591 M +( string compression_algorithms_server_to_client) s +5 580 M +( string languages_client_to_server) s +5 569 M +( string languages_server_to_client) s +5 558 M +( boolean first_kex_packet_follows) s +5 547 M +( uint32 0 \(reserved for future extension\)) s +5 525 M +( Each of the algorithm strings MUST be a comma-separated list of) s +5 514 M +( algorithm names \(see ''Algorithm Naming'' in [SSH-ARCH]\). Each) s +5 503 M +( supported \(allowed\) algorithm MUST be listed in order of preference.) s +5 481 M +( The first algorithm in each list MUST be the preferred \(guessed\)) s +5 470 M +( algorithm. Each string MUST contain at least one algorithm name.) s +5 437 M +( cookie) s +5 426 M +( The cookie MUST be a random value generated by the sender. Its) s +5 415 M +( purpose is to make it impossible for either side to fully) s +5 404 M +( determine the keys and the session identifier.) s +5 382 M +( kex_algorithms) s +5 371 M +( Key exchange algorithms were defined above. The first) s +5 360 M +( algorithm MUST be the preferred \(and guessed\) algorithm. If) s +5 349 M +( both sides make the same guess, that algorithm MUST be used.) s +5 338 M +( Otherwise, the following algorithm MUST be used to choose a key) s +5 327 M +( exchange method: iterate over client's kex algorithms, one at a) s +5 316 M +( time. Choose the first algorithm that satisfies the following) s +5 305 M +( conditions:) s +5 294 M +( + the server also supports the algorithm,) s +5 283 M +( + if the algorithm requires an encryption-capable host key,) s +5 272 M +( there is an encryption-capable algorithm on the server's) s +5 261 M +( server_host_key_algorithms that is also supported by the) s +5 250 M +( client, and) s +5 239 M +( + if the algorithm requires a signature-capable host key,) s +5 228 M +( there is a signature-capable algorithm on the server's) s +5 217 M +( server_host_key_algorithms that is also supported by the) s +5 206 M +( client.) s +5 195 M +( + If no algorithm satisfying all these conditions can be) s +5 184 M +( found, the connection fails, and both sides MUST disconnect.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( server_host_key_algorithms) s +5 679 M +( List of the algorithms supported for the server host key. The) s +5 668 M +( server lists the algorithms for which it has host keys; the) s +5 657 M +( client lists the algorithms that it is willing to accept.) s +5 646 M +( \(There MAY be multiple host keys for a host, possibly with) s +5 635 M +( different algorithms.\)) s +5 613 M +( Some host keys may not support both signatures and encryption) s +5 602 M +( \(this can be determined from the algorithm\), and thus not all) s +5 591 M +( host keys are valid for all key exchange methods.) s +5 569 M +( Algorithm selection depends on whether the chosen key exchange) s +5 558 M +( algorithm requires a signature or encryption capable host key.) s +5 547 M +( It MUST be possible to determine this from the public key) s +5 536 M +( algorithm name. The first algorithm on the client's list that) s +5 525 M +( satisfies the requirements and is also supported by the server) s +5 514 M +( MUST be chosen. If there is no such algorithm, both sides MUST) s +5 503 M +( disconnect.) s +5 481 M +( encryption_algorithms) s +5 470 M +( Lists the acceptable symmetric encryption algorithms in order) s +5 459 M +( of preference. The chosen encryption algorithm to each) s +5 448 M +( direction MUST be the first algorithm on the client's list) s +5 437 M +( that is also on the server's list. If there is no such) s +5 426 M +( algorithm, both sides MUST disconnect.) s +5 404 M +( Note that "none" must be explicitly listed if it is to be) s +5 393 M +( acceptable. The defined algorithm names are listed in Section) s +5 382 M +( Section 5.3.) s +5 360 M +( mac_algorithms) s +5 349 M +( Lists the acceptable MAC algorithms in order of preference.) s +5 338 M +( The chosen MAC algorithm MUST be the first algorithm on the) s +5 327 M +( client's list that is also on the server's list. If there is) s +5 316 M +( no such algorithm, both sides MUST disconnect.) s +5 294 M +( Note that "none" must be explicitly listed if it is to be) s +5 283 M +( acceptable. The MAC algorithm names are listed in Section) s +5 272 M +( Figure 1.) s +5 250 M +( compression_algorithms) s +5 239 M +( Lists the acceptable compression algorithms in order of) s +5 228 M +( preference. The chosen compression algorithm MUST be the first) s +5 217 M +( algorithm on the client's list that is also on the server's) s +5 206 M +( list. If there is no such algorithm, both sides MUST) s +5 195 M +( disconnect.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( Note that "none" must be explicitly listed if it is to be) s +5 679 M +( acceptable. The compression algorithm names are listed in) s +5 668 M +( Section Section 5.2.) s +5 646 M +( languages) s +5 635 M +( This is a comma-separated list of language tags in order of) s +5 624 M +( preference [RFC3066]. Both parties MAY ignore this list. If) s +5 613 M +( there are no language preferences, this list SHOULD be empty.) s +5 602 M +( Language tags SHOULD NOT be present unless they are known to be) s +5 591 M +( needed by the sending party.) s +5 569 M +( first_kex_packet_follows) s +5 558 M +( Indicates whether a guessed key exchange packet follows. If a) s +5 547 M +( guessed packet will be sent, this MUST be TRUE. If no guessed) s +5 536 M +( packet will be sent, this MUST be FALSE.) s +5 514 M +( After receiving the SSH_MSG_KEXINIT packet from the other side,) s +5 503 M +( each party will know whether their guess was right. If the) s +5 492 M +( other party's guess was wrong, and this field was TRUE, the) s +5 481 M +( next packet MUST be silently ignored, and both sides MUST then) s +5 470 M +( act as determined by the negotiated key exchange method. If) s +5 459 M +( the guess was right, key exchange MUST continue using the) s +5 448 M +( guessed packet.) s +5 426 M +( After the KEXINIT packet exchange, the key exchange algorithm is run.) s +5 415 M +( It may involve several packet exchanges, as specified by the key) s +5 404 M +( exchange method.) s +5 382 M +(6.2 Output from Key Exchange) s +5 360 M +( The key exchange produces two values: a shared secret K, and an) s +5 349 M +( exchange hash H. Encryption and authentication keys are derived from) s +5 338 M +( these. The exchange hash H from the first key exchange is) s +5 327 M +( additionally used as the session identifier, which is a unique) s +5 316 M +( identifier for this connection. It is used by authentication methods) s +5 305 M +( as a part of the data that is signed as a proof of possession of a) s +5 294 M +( private key. Once computed, the session identifier is not changed,) s +5 283 M +( even if keys are later re-exchanged.) s +5 250 M +( Each key exchange method specifies a hash function that is used in) s +5 239 M +( the key exchange. The same hash algorithm MUST be used in key) s +5 228 M +( derivation. Here, we'll call it HASH.) s +5 195 M +( Encryption keys MUST be computed as HASH of a known value and K as) s +5 184 M +( follows:) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16]) s +_R +S +PStoPSsaved restore +%%Page: (16,17) 9 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 17 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( o Initial IV client to server: HASH\(K || H || "A" || session_id\)) s +5 679 M +( \(Here K is encoded as mpint and "A" as byte and session_id as raw) s +5 668 M +( data."A" means the single character A, ASCII 65\).) s +5 657 M +( o Initial IV server to client: HASH\(K || H || "B" || session_id\)) s +5 646 M +( o Encryption key client to server: HASH\(K || H || "C" || session_id\)) s +5 635 M +( o Encryption key server to client: HASH\(K || H || "D" || session_id\)) s +5 624 M +( o Integrity key client to server: HASH\(K || H || "E" || session_id\)) s +5 613 M +( o Integrity key server to client: HASH\(K || H || "F" || session_id\)) s +5 591 M +( Key data MUST be taken from the beginning of the hash output. 128) s +5 580 M +( bits \(16 bytes\) MUST be used for algorithms with variable-length) s +5 569 M +( keys. The only variable key length algorithm defined in this document) s +5 558 M +( is arcfour\). For other algorithms, as many bytes as are needed are) s +5 547 M +( taken from the beginning of the hash value. If the key length needed) s +5 536 M +( is longer than the output of the HASH, the key is extended by) s +5 525 M +( computing HASH of the concatenation of K and H and the entire key so) s +5 514 M +( far, and appending the resulting bytes \(as many as HASH generates\) to) s +5 503 M +( the key. This process is repeated until enough key material is) s +5 492 M +( available; the key is taken from the beginning of this value. In) s +5 481 M +( other words:) s +5 459 M +( K1 = HASH\(K || H || X || session_id\) \(X is e.g. "A"\)) s +5 448 M +( K2 = HASH\(K || H || K1\)) s +5 437 M +( K3 = HASH\(K || H || K1 || K2\)) s +5 426 M +( ...) s +5 415 M +( key = K1 || K2 || K3 || ...) s +5 393 M +( This process will lose entropy if the amount of entropy in K is) s +5 382 M +( larger than the internal state size of HASH.) s +5 360 M +(6.3 Taking Keys Into Use) s +5 338 M +( Key exchange ends by each side sending an SSH_MSG_NEWKEYS message.) s +5 327 M +( This message is sent with the old keys and algorithms. All messages) s +5 316 M +( sent after this message MUST use the new keys and algorithms.) s +5 283 M +( When this message is received, the new keys and algorithms MUST be) s +5 272 M +( taken into use for receiving.) s +5 239 M +( This message is the only valid message after key exchange, in) s +5 228 M +( addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE) s +5 217 M +( messages. The purpose of this message is to ensure that a party is) s +5 206 M +( able to respond with a disconnect message that the other party can) s +5 195 M +( understand if something goes wrong with the key exchange.) s +5 184 M +( Implementations MUST NOT accept any other messages after key exchange) s +5 173 M +( before receiving SSH_MSG_NEWKEYS.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 18 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( byte SSH_MSG_NEWKEYS) s +5 657 M +(7. Diffie-Hellman Key Exchange) s +5 635 M +( The Diffie-Hellman key exchange provides a shared secret that can not) s +5 624 M +( be determined by either party alone. The key exchange is combined) s +5 613 M +( with a signature with the host key to provide host authentication.) s +5 580 M +( In the following description \(C is the client, S is the server; p is) s +5 569 M +( a large safe prime, g is a generator for a subgroup of GF\(p\), and q) s +5 558 M +( is the order of the subgroup; V_S is S's version string; V_C is C's) s +5 547 M +( version string; K_S is S's public host key; I_C is C's KEXINIT) s +5 536 M +( message and I_S S's KEXINIT message which have been exchanged before) s +5 525 M +( this part begins\):) s +5 492 M +( 1. C generates a random number x \(1 < x < q\) and computes e = g^x) s +5 481 M +( mod p. C sends "e" to S.) s +5 459 M +( 2. S generates a random number y \(0 < y < q\) and computes f = g^y) s +5 448 M +( mod p. S receives "e". It computes K = e^y mod p, H = hash\(V_C) s +5 437 M +( || V_S || I_C || I_S || K_S || e || f || K\) \(these elements are) s +5 426 M +( encoded according to their types; see below\), and signature s on) s +5 415 M +( H with its private host key. S sends "K_S || f || s" to C. The) s +5 404 M +( signing operation may involve a second hashing operation.) s +5 382 M +( 3. C verifies that K_S really is the host key for S \(e.g. using) s +5 371 M +( certificates or a local database\). C is also allowed to accept) s +5 360 M +( the key without verification; however, doing so will render the) s +5 349 M +( protocol insecure against active attacks \(but may be desirable) s +5 338 M +( for practical reasons in the short term in many environments\). C) s +5 327 M +( then computes K = f^x mod p, H = hash\(V_C || V_S || I_C || I_S ||) s +5 316 M +( K_S || e || f || K\), and verifies the signature s on H.) s +5 294 M +( Either side MUST NOT send or accept e or f values that are not in the) s +5 283 M +( range [1, p-1]. If this condition is violated, the key exchange) s +5 272 M +( fails.) s +5 239 M +( This is implemented with the following messages. The hash algorithm) s +5 228 M +( for computing the exchange hash is defined by the method name, and is) s +5 217 M +( called HASH. The public key algorithm for signing is negotiated with) s +5 206 M +( the KEXINIT messages.) s +5 184 M +( First, the client sends the following:) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18]) s +_R +S +PStoPSsaved restore +%%Page: (18,19) 10 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 19 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( byte SSH_MSG_KEXDH_INIT) s +5 679 M +( mpint e) s +5 646 M +( The server responds with the following:) s +5 624 M +( byte SSH_MSG_KEXDH_REPLY) s +5 613 M +( string server public host key and certificates \(K_S\)) s +5 602 M +( mpint f) s +5 591 M +( string signature of H) s +5 569 M +( The hash H is computed as the HASH hash of the concatenation of the) s +5 558 M +( following:) s +5 536 M +( string V_C, the client's version string \(CR and NL excluded\)) s +5 525 M +( string V_S, the server's version string \(CR and NL excluded\)) s +5 514 M +( string I_C, the payload of the client's SSH_MSG_KEXINIT) s +5 503 M +( string I_S, the payload of the server's SSH_MSG_KEXINIT) s +5 492 M +( string K_S, the host key) s +5 481 M +( mpint e, exchange value sent by the client) s +5 470 M +( mpint f, exchange value sent by the server) s +5 459 M +( mpint K, the shared secret) s +5 437 M +( This value is called the exchange hash, and it is used to) s +5 426 M +( authenticate the key exchange. The exchange hash SHOULD be kept) s +5 415 M +( secret.) s +5 382 M +( The signature algorithm MUST be applied over H, not the original) s +5 371 M +( data. Most signature algorithms include hashing and additional) s +5 360 M +( padding. For example, "ssh-dss" specifies SHA-1 hashing; in that) s +5 349 M +( case, the data is first hashed with HASH to compute H, and H is then) s +5 338 M +( hashed with SHA-1 as part of the signing operation.) s +5 316 M +(7.1 diffie-hellman-group1-sha1) s +5 294 M +( The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman key) s +5 283 M +( exchange with SHA-1 as HASH, and Oakley group 14 [RFC3526] \(2048-bit) s +5 272 M +( MODP Group\). It is included below in hexadecimal and decimal.) s +5 250 M +( The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor\( 2^894 Pi +) s +5 239 M +( 129093 \). Its hexadecimal value is:) s +5 217 M +( FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1) s +5 206 M +( 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD) s +5 195 M +( EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245) s +5 184 M +( E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED) s +5 173 M +( EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 20 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( FFFFFFFF FFFFFFFF.) s +5 668 M +( In decimal, this value is:) s +5 646 M +( 179769313486231590770839156793787453197860296048756011706444) s +5 635 M +( 423684197180216158519368947833795864925541502180565485980503) s +5 624 M +( 646440548199239100050792877003355816639229553136239076508735) s +5 613 M +( 759914822574862575007425302077447712589550957937778424442426) s +5 602 M +( 617334727629299387668709205606050270810842907692932019128194) s +5 591 M +( 467627007.) s +5 569 M +( The generator used with this prime is g = 2. The group order q is \(p) s +5 558 M +( - 1\) / 2.) s +5 536 M +(8. Key Re-Exchange) s +5 514 M +( Key re-exchange is started by sending an SSH_MSG_KEXINIT packet when) s +5 503 M +( not already doing a key exchange \(as described in Section Section) s +5 492 M +( 6.1\). When this message is received, a party MUST respond with its) s +5 481 M +( own SSH_MSG_KEXINIT message except when the received SSH_MSG_KEXINIT) s +5 470 M +( already was a reply. Either party MAY initiate the re-exchange, but) s +5 459 M +( roles MUST NOT be changed \(i.e., the server remains the server, and) s +5 448 M +( the client remains the client\).) s +5 415 M +( Key re-exchange is performed using whatever encryption was in effect) s +5 404 M +( when the exchange was started. Encryption, compression, and MAC) s +5 393 M +( methods are not changed before a new SSH_MSG_NEWKEYS is sent after) s +5 382 M +( the key exchange \(as in the initial key exchange\). Re-exchange is) s +5 371 M +( processed identically to the initial key exchange, except for the) s +5 360 M +( session identifier that will remain unchanged. It is permissible to) s +5 349 M +( change some or all of the algorithms during the re-exchange. Host) s +5 338 M +( keys can also change. All keys and initialization vectors are) s +5 327 M +( recomputed after the exchange. Compression and encryption contexts) s +5 316 M +( are reset.) s +5 283 M +( It is recommended that the keys are changed after each gigabyte of) s +5 272 M +( transmitted data or after each hour of connection time, whichever) s +5 261 M +( comes sooner. However, since the re-exchange is a public key) s +5 250 M +( operation, it requires a fair amount of processing power and should) s +5 239 M +( not be performed too often.) s +5 206 M +( More application data may be sent after the SSH_MSG_NEWKEYS packet) s +5 195 M +( has been sent; key exchange does not affect the protocols that lie) s +5 184 M +( above the SSH transport layer.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20]) s +_R +S +PStoPSsaved restore +%%Page: (20,21) 11 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 21 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(9. Service Request) s +5 668 M +( After the key exchange, the client requests a service. The service is) s +5 657 M +( identified by a name. The format of names and procedures for defining) s +5 646 M +( new names are defined in [SSH-ARCH].) s +5 613 M +( Currently, the following names have been reserved:) s +5 591 M +( ssh-userauth) s +5 580 M +( ssh-connection) s +5 558 M +( Similar local naming policy is applied to the service names, as is) s +5 547 M +( applied to the algorithm names; a local service should use the) s +5 536 M +( "servicename@domain" syntax.) s +5 514 M +( byte SSH_MSG_SERVICE_REQUEST) s +5 503 M +( string service name) s +5 481 M +( If the server rejects the service request, it SHOULD send an) s +5 470 M +( appropriate SSH_MSG_DISCONNECT message and MUST disconnect.) s +5 437 M +( When the service starts, it may have access to the session identifier) s +5 426 M +( generated during the key exchange.) s +5 393 M +( If the server supports the service \(and permits the client to use) s +5 382 M +( it\), it MUST respond with the following:) s +5 360 M +( byte SSH_MSG_SERVICE_ACCEPT) s +5 349 M +( string service name) s +5 327 M +( Message numbers used by services should be in the area reserved for) s +5 316 M +( them \(see Section 6 in [SSH-ARCH]\). The transport level will) s +5 305 M +( continue to process its own messages.) s +5 272 M +( Note that after a key exchange with implicit server authentication,) s +5 261 M +( the client MUST wait for response to its service request message) s +5 250 M +( before sending any further data.) s +5 228 M +(10. Additional Messages) s +5 206 M +( Either party may send any of the following messages at any time.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 22 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(10.1 Disconnection Message) s +5 668 M +( byte SSH_MSG_DISCONNECT) s +5 657 M +( uint32 reason code) s +5 646 M +( string description [RFC2279]) s +5 635 M +( string language tag [RFC3066]) s +5 613 M +( This message causes immediate termination of the connection. All) s +5 602 M +( implementations MUST be able to process this message; they SHOULD be) s +5 591 M +( able to send this message.) s +5 569 M +( The sender MUST NOT send or receive any data after this message, and) s +5 558 M +( the recipient MUST NOT accept any data after receiving this message.) s +5 547 M +( The description field gives a more specific explanation in a) s +5 536 M +( human-readable form. The error code gives the reason in a more) s +5 525 M +( machine-readable format \(suitable for localization\), and can have the) s +5 514 M +( following values:) s +5 492 M +( #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1) s +5 481 M +( #define SSH_DISCONNECT_PROTOCOL_ERROR 2) s +5 470 M +( #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3) s +5 459 M +( #define SSH_DISCONNECT_RESERVED 4) s +5 448 M +( #define SSH_DISCONNECT_MAC_ERROR 5) s +5 437 M +( #define SSH_DISCONNECT_COMPRESSION_ERROR 6) s +5 426 M +( #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7) s +5 415 M +( #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8) s +5 404 M +( #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9) s +5 393 M +( #define SSH_DISCONNECT_CONNECTION_LOST 10) s +5 382 M +( #define SSH_DISCONNECT_BY_APPLICATION 11) s +5 371 M +( #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12) s +5 360 M +( #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13) s +5 349 M +( #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14) s +5 338 M +( #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15) s +5 316 M +( If the description string is displayed, control character filtering) s +5 305 M +( discussed in [SSH-ARCH] should be used to avoid attacks by sending) s +5 294 M +( terminal control characters.) s +5 272 M +(10.2 Ignored Data Message) s +5 250 M +( byte SSH_MSG_IGNORE) s +5 239 M +( string data) s +5 217 M +( All implementations MUST understand \(and ignore\) this message at any) s +5 206 M +( time \(after receiving the protocol version\). No implementation is) s +5 195 M +( required to send them. This message can be used as an additional) s +5 184 M +( protection measure against advanced traffic analysis techniques.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22]) s +_R +S +PStoPSsaved restore +%%Page: (22,23) 12 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 23 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(10.3 Debug Message) s +5 668 M +( byte SSH_MSG_DEBUG) s +5 657 M +( boolean always_display) s +5 646 M +( string message [RFC2279]) s +5 635 M +( string language tag [RFC3066]) s +5 613 M +( All implementations MUST understand this message, but they are) s +5 602 M +( allowed to ignore it. This message is used to pass the other side) s +5 591 M +( information that may help debugging. If always_display is TRUE, the) s +5 580 M +( message SHOULD be displayed. Otherwise, it SHOULD NOT be displayed) s +5 569 M +( unless debugging information has been explicitly requested by the) s +5 558 M +( user.) s +5 525 M +( The message doesn't need to contain a newline. It is, however,) s +5 514 M +( allowed to consist of multiple lines separated by CRLF \(Carriage) s +5 503 M +( Return - Line Feed\) pairs.) s +5 470 M +( If the message string is displayed, terminal control character) s +5 459 M +( filtering discussed in [SSH-ARCH] should be used to avoid attacks by) s +5 448 M +( sending terminal control characters.) s +5 426 M +(10.4 Reserved Messages) s +5 404 M +( An implementation MUST respond to all unrecognized messages with an) s +5 393 M +( SSH_MSG_UNIMPLEMENTED message in the order in which the messages were) s +5 382 M +( received. Such messages MUST be otherwise ignored. Later protocol) s +5 371 M +( versions may define other meanings for these message types.) s +5 349 M +( byte SSH_MSG_UNIMPLEMENTED) s +5 338 M +( uint32 packet sequence number of rejected message) s +5 305 M +(11. Summary of Message Numbers) s +5 283 M +( The following message numbers have been defined in this protocol:) s +5 261 M +( #define SSH_MSG_DISCONNECT 1) s +5 250 M +( #define SSH_MSG_IGNORE 2) s +5 239 M +( #define SSH_MSG_UNIMPLEMENTED 3) s +5 228 M +( #define SSH_MSG_DEBUG 4) s +5 217 M +( #define SSH_MSG_SERVICE_REQUEST 5) s +5 206 M +( #define SSH_MSG_SERVICE_ACCEPT 6) s +5 184 M +( #define SSH_MSG_KEXINIT 20) s +5 173 M +( #define SSH_MSG_NEWKEYS 21) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 23]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 24 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( /* Numbers 30-49 used for kex packets.) s +5 679 M +( Different kex methods may reuse message numbers in) s +5 668 M +( this range. */) s +5 646 M +( #define SSH_MSG_KEXDH_INIT 30) s +5 635 M +( #define SSH_MSG_KEXDH_REPLY 31) s +5 602 M +(12. IANA Considerations) s +5 580 M +( This document is part of a set, the IANA considerations for the SSH) s +5 569 M +( protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH],) s +5 558 M +( [SSH-CONNECT] are detailed in [SSH-NUMBERS].) s +5 536 M +(13. Security Considerations) s +5 514 M +( This protocol provides a secure encrypted channel over an insecure) s +5 503 M +( network. It performs server host authentication, key exchange,) s +5 492 M +( encryption, and integrity protection. It also derives a unique) s +5 481 M +( session id that may be used by higher-level protocols.) s +5 459 M +( Full security considerations for this protocol are provided in) s +5 448 M +( Section 8 of [SSH-ARCH]) s +5 426 M +(14. Intellectual Property) s +5 404 M +( The IETF takes no position regarding the validity or scope of any) s +5 393 M +( intellectual property or other rights that might be claimed to) s +5 382 M +( pertain to the implementation or use of the technology described in) s +5 371 M +( this document or the extent to which any license under such rights) s +5 360 M +( might or might not be available; neither does it represent that it) s +5 349 M +( has made any effort to identify any such rights. Information on the) s +5 338 M +( IETF's procedures with respect to rights in standards-track and) s +5 327 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 316 M +( claims of rights made available for publication and any assurances of) s +5 305 M +( licenses to be made available, or the result of an attempt made to) s +5 294 M +( obtain a general license or permission for the use of such) s +5 283 M +( proprietary rights by implementers or users of this specification can) s +5 272 M +( be obtained from the IETF Secretariat.) s +5 250 M +( The IETF has been notified of intellectual property rights claimed in) s +5 239 M +( regard to some or all of the specification contained in this) s +5 228 M +( document. For more information consult the online list of claimed) s +5 217 M +( rights.) s +5 195 M +(15. Additional Information) s +5 173 M +( The current document editor is: [email protected]. Comments on) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 24]) s +_R +S +PStoPSsaved restore +%%Page: (24,25) 13 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 25 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( this internet draft should be sent to the IETF SECSH working group,) s +5 679 M +( details at: http://ietf.org/html.charters/secsh-charter.html) s +5 657 M +(Normative) s +5 635 M +( [SSH-ARCH]) s +5 624 M +( Ylonen, T., "SSH Protocol Architecture", I-D) s +5 613 M +( draft-ietf-architecture-15.txt, Oct 2003.) s +5 591 M +( [SSH-TRANS]) s +5 580 M +( Ylonen, T., "SSH Transport Layer Protocol", I-D) s +5 569 M +( draft-ietf-transport-17.txt, Oct 2003.) s +5 547 M +( [SSH-USERAUTH]) s +5 536 M +( Ylonen, T., "SSH Authentication Protocol", I-D) s +5 525 M +( draft-ietf-userauth-18.txt, Oct 2003.) s +5 503 M +( [SSH-CONNECT]) s +5 492 M +( Ylonen, T., "SSH Connection Protocol", I-D) s +5 481 M +( draft-ietf-connect-18.txt, Oct 2003.) s +5 459 M +( [SSH-NUMBERS]) s +5 448 M +( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s +5 437 M +( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s +5 426 M +( 2003.) s +5 404 M +( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s +5 393 M +( Requirement Levels", BCP 14, RFC 2119, March 1997.) s +5 371 M +(Informative) s +5 349 M +( [FIPS-186]) s +5 338 M +( Federal Information Processing Standards Publication,) s +5 327 M +( "FIPS PUB 186, Digital Signature Standard", May 1994.) s +5 305 M +( [FIPS-197]) s +5 294 M +( NIST, "FIPS PUB 197 Advanced Encryption Standard \(AES\)",) s +5 283 M +( November 2001.) s +5 261 M +( [FIPS-46-3]) s +5 250 M +( U.S. Dept. of Commerce, "FIPS PUB 46-3, Data Encryption) s +5 239 M +( Standard \(DES\)", October 1999.) s +5 217 M +( [RFC2459] Housley, R., Ford, W., Polk, T. and D. Solo, "Internet) s +5 206 M +( X.509 Public Key Infrastructure Certificate and CRL) s +5 195 M +( Profile", RFC 2459, January 1999.) s +5 173 M +( [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 25]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 26 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( STD 13, RFC 1034, November 1987.) s +5 668 M +( [RFC3066] Alvestrand, H., "Tags for the Identification of) s +5 657 M +( Languages", BCP 47, RFC 3066, January 2001.) s +5 635 M +( [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format) s +5 624 M +( Specification version 3.3", RFC 1950, May 1996.) s +5 602 M +( [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification) s +5 591 M +( version 1.3", RFC 1951, May 1996.) s +5 569 M +( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s +5 558 M +( 10646", RFC 2279, January 1998.) s +5 536 M +( [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC:) s +5 525 M +( Keyed-Hashing for Message Authentication", RFC 2104,) s +5 514 M +( February 1997.) s +5 492 M +( [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", RFC 2144,) s +5 481 M +( May 1997.) s +5 459 M +( [RFC2440] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer,) s +5 448 M +( "OpenPGP Message Format", RFC 2440, November 1998.) s +5 426 M +( [RFC2693] Ellison, C., Frantz, B., Lampson, B., Rivest, R., Thomas,) s +5 415 M +( B. and T. Ylonen, "SPKI Certificate Theory", RFC 2693,) s +5 404 M +( September 1999.) s +5 382 M +( [RFC3526] Kivinen, T. and M. Kojo, "More Modular Exponential \(MODP\)) s +5 371 M +( Diffie-Hellman groups for Internet Key Exchange \(IKE\)",) s +5 360 M +( RFC 3526, May 2003.) s +5 338 M +( [SCHNEIER]) s +5 327 M +( Schneier, B., "Applied Cryptography Second Edition:) s +5 316 M +( protocols algorithms and source in code in C", 1996.) s +5 294 M +( [TWOFISH] Schneier, B., "The Twofish Encryptions Algorithm: A) s +5 283 M +( 128-Bit Block Cipher, 1st Edition", March 1999.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 26]) s +_R +S +PStoPSsaved restore +%%Page: (26,27) 14 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 27 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(Authors' Addresses) s +5 668 M +( Tatu Ylonen) s +5 657 M +( SSH Communications Security Corp) s +5 646 M +( Fredrikinkatu 42) s +5 635 M +( HELSINKI FIN-00100) s +5 624 M +( Finland) s +5 602 M +( EMail: [email protected]) s +5 569 M +( Darren J. Moffat \(editor\)) s +5 558 M +( Sun Microsystems, Inc) s +5 547 M +( 17 Network Circle) s +5 536 M +( Menlo Park 95025) s +5 525 M +( USA) s +5 503 M +( EMail: [email protected]) s +5 481 M +(Appendix A. Contibutors) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 27]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 28 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +(Intellectual Property Statement) s +5 668 M +( The IETF takes no position regarding the validity or scope of any) s +5 657 M +( intellectual property or other rights that might be claimed to) s +5 646 M +( pertain to the implementation or use of the technology described in) s +5 635 M +( this document or the extent to which any license under such rights) s +5 624 M +( might or might not be available; neither does it represent that it) s +5 613 M +( has made any effort to identify any such rights. Information on the) s +5 602 M +( IETF's procedures with respect to rights in standards-track and) s +5 591 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 580 M +( claims of rights made available for publication and any assurances of) s +5 569 M +( licenses to be made available, or the result of an attempt made to) s +5 558 M +( obtain a general license or permission for the use of such) s +5 547 M +( proprietary rights by implementors or users of this specification can) s +5 536 M +( be obtained from the IETF Secretariat.) s +5 514 M +( The IETF invites any interested party to bring to its attention any) s +5 503 M +( copyrights, patents or patent applications, or other proprietary) s +5 492 M +( rights which may cover technology that may be required to practice) s +5 481 M +( this standard. Please address the information to the IETF Executive) s +5 470 M +( Director.) s +5 448 M +( The IETF has been notified of intellectual property rights claimed in) s +5 437 M +( regard to some or all of the specification contained in this) s +5 426 M +( document. For more information consult the online list of claimed) s +5 415 M +( rights.) s +5 382 M +(Full Copyright Statement) s +5 360 M +( Copyright \(C\) The Internet Society \(2003\). All Rights Reserved.) s +5 338 M +( This document and translations of it may be copied and furnished to) s +5 327 M +( others, and derivative works that comment on or otherwise explain it) s +5 316 M +( or assist in its implementation may be prepared, copied, published) s +5 305 M +( and distributed, in whole or in part, without restriction of any) s +5 294 M +( kind, provided that the above copyright notice and this paragraph are) s +5 283 M +( included on all such copies and derivative works. However, this) s +5 272 M +( document itself may not be modified in any way, such as by removing) s +5 261 M +( the copyright notice or references to the Internet Society or other) s +5 250 M +( Internet organizations, except as needed for the purpose of) s +5 239 M +( developing Internet standards in which case the procedures for) s +5 228 M +( copyrights defined in the Internet Standards process must be) s +5 217 M +( followed, or as required to translate it into languages other than) s +5 206 M +( English.) s +5 184 M +( The limited permissions granted above are perpetual and will not be) s +5 173 M +( revoked by the Internet Society or its successors or assignees.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 28]) s +_R +S +PStoPSsaved restore +%%Page: (28,29) 15 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 29 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Transport Layer Protocol Oct 2003) s +5 690 M +( This document and the information contained herein is provided on an) s +5 679 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 668 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 657 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 646 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 635 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 602 M +(Acknowledgment) s +5 580 M +( Funding for the RFC Editor function is currently provided by the) s +5 569 M +( Internet Society.) s +5 129 M +(Ylonen & Moffat, Editor Expires March 31, 2004 [Page 29]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +showpage +PStoPSsaved restore +%%Trailer +%%Pages: 29 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt new file mode 100644 index 0000000000..9073ea52b2 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-transport-17.txt @@ -0,0 +1,1624 @@ + + + +Network Working Group T. Ylonen +Internet-Draft SSH Communications Security Corp +Expires: March 31, 2004 D. Moffat, Editor, Ed. + Sun Microsystems, Inc + Oct 2003 + + + SSH Transport Layer Protocol + draft-ietf-secsh-transport-17.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that other + groups may also distribute working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on March 31, 2004. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. + + This document describes the SSH transport layer protocol which + typically runs on top of TCP/IP. The protocol can be used as a basis + for a number of secure network services. It provides strong + encryption, server authentication, and integrity protection. It may + also provide compression. + + Key exchange method, public key algorithm, symmetric encryption + algorithm, message authentication algorithm, and hash algorithm are + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 1] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + all negotiated. + + This document also describes the Diffie-Hellman key exchange method + and the minimal set of algorithms that are needed to implement the + SSH transport layer protocol. + +Table of Contents + + 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Conventions Used in This Document . . . . . . . . . . . . . 3 + 4. Connection Setup . . . . . . . . . . . . . . . . . . . . . . 3 + 4.1 Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . 4 + 4.2 Protocol Version Exchange . . . . . . . . . . . . . . . . . 4 + 4.3 Compatibility With Old SSH Versions . . . . . . . . . . . . 4 + 4.3.1 Old Client, New Server . . . . . . . . . . . . . . . . . . . 5 + 4.3.2 New Client, Old Server . . . . . . . . . . . . . . . . . . . 5 + 5. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . 5 + 5.1 Maximum Packet Length . . . . . . . . . . . . . . . . . . . 6 + 5.2 Compression . . . . . . . . . . . . . . . . . . . . . . . . 7 + 5.3 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 5.4 Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 9 + 5.5 Key Exchange Methods . . . . . . . . . . . . . . . . . . . . 10 + 5.6 Public Key Algorithms . . . . . . . . . . . . . . . . . . . 11 + 6. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . 13 + 6.1 Algorithm Negotiation . . . . . . . . . . . . . . . . . . . 13 + 6.2 Output from Key Exchange . . . . . . . . . . . . . . . . . . 16 + 6.3 Taking Keys Into Use . . . . . . . . . . . . . . . . . . . . 17 + 7. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . 18 + 7.1 diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . 19 + 8. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . 20 + 9. Service Request . . . . . . . . . . . . . . . . . . . . . . 21 + 10. Additional Messages . . . . . . . . . . . . . . . . . . . . 21 + 10.1 Disconnection Message . . . . . . . . . . . . . . . . . . . 22 + 10.2 Ignored Data Message . . . . . . . . . . . . . . . . . . . . 22 + 10.3 Debug Message . . . . . . . . . . . . . . . . . . . . . . . 23 + 10.4 Reserved Messages . . . . . . . . . . . . . . . . . . . . . 23 + 11. Summary of Message Numbers . . . . . . . . . . . . . . . . . 23 + 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . 24 + 13. Security Considerations . . . . . . . . . . . . . . . . . . 24 + 14. Intellectual Property . . . . . . . . . . . . . . . . . . . 24 + 15. Additional Information . . . . . . . . . . . . . . . . . . . 24 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 26 + Normative . . . . . . . . . . . . . . . . . . . . . . . . . 25 + Informative . . . . . . . . . . . . . . . . . . . . . . . . 25 + A. Contibutors . . . . . . . . . . . . . . . . . . . . . . . . 27 + Intellectual Property and Copyright Statements . . . . . . . 28 + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 2] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +1. Contributors + + The major original contributors of this document were: Tatu Ylonen, + Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications + Security Corp), and Markku-Juhani O. Saarinen (University of + Jyvaskyla) + + The document editor is: [email protected]. Comments on this + internet draft should be sent to the IETF SECSH working group, + details at: http://ietf.org/html.charters/secsh-charter.html + +2. Introduction + + The SSH transport layer is a secure low level transport protocol. It + provides strong encryption, cryptographic host authentication, and + integrity protection. + + Authentication in this protocol level is host-based; this protocol + does not perform user authentication. A higher level protocol for + user authentication can be designed on top of this protocol. + + The protocol has been designed to be simple, flexible, to allow + parameter negotiation, and to minimize the number of round-trips. + Key exchange method, public key algorithm, symmetric encryption + algorithm, message authentication algorithm, and hash algorithm are + all negotiated. It is expected that in most environments, only 2 + round-trips will be needed for full key exchange, server + authentication, service request, and acceptance notification of + service request. The worst case is 3 round-trips. + +3. Conventions Used in This Document + + The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", + and "MAY" that appear in this document are to be interpreted as + described in [RFC2119]. + + The used data types and terminology are specified in the architecture + document [SSH-ARCH]. + + The architecture document also discusses the algorithm naming + conventions that MUST be used with the SSH protocols. + +4. Connection Setup + + SSH works over any 8-bit clean, binary-transparent transport. The + underlying transport SHOULD protect against transmission errors as + such errors cause the SSH connection to terminate. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 3] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + The client initiates the connection. + +4.1 Use over TCP/IP + + When used over TCP/IP, the server normally listens for connections on + port 22. This port number has been registered with the IANA, and has + been officially assigned for SSH. + +4.2 Protocol Version Exchange + + When the connection has been established, both sides MUST send an + identification string of the form "SSH-protoversion-softwareversion + comments", followed by carriage return and newline characters (ASCII + 13 and 10, respectively). Both sides MUST be able to process + identification strings without carriage return character. No null + character is sent. The maximum length of the string is 255 + characters, including the carriage return and newline. + + The part of the identification string preceding carriage return and + newline is used in the Diffie-Hellman key exchange (see Section + Section 7). + + The server MAY send other lines of data before sending the version + string. Each line SHOULD be terminated by a carriage return and + newline. Such lines MUST NOT begin with "SSH-", and SHOULD be + encoded in ISO-10646 UTF-8 [RFC2279] (language is not specified). + Clients MUST be able to process such lines; they MAY be silently + ignored, or MAY be displayed to the client user; if they are + displayed, control character filtering discussed in [SSH-ARCH] SHOULD + be used. The primary use of this feature is to allow TCP-wrappers to + display an error message before disconnecting. + + Version strings MUST consist of printable US-ASCII characters, not + including whitespaces or a minus sign (-). The version string is + primarily used to trigger compatibility extensions and to indicate + the capabilities of an implementation. The comment string should + contain additional information that might be useful in solving user + problems. + + The protocol version described in this document is 2.0. + + Key exchange will begin immediately after sending this identifier. + All packets following the identification string SHALL use the binary + packet protocol, to be described below. + +4.3 Compatibility With Old SSH Versions + + During the transition period, it is important to be able to work in a + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 4] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + way that is compatible with the installed SSH clients and servers + that use an older version of the protocol. Information in this + section is only relevant for implementations supporting compatibility + with SSH versions 1.x. There is no standards track or informational + draft available that defines the SSH 1.x protocol. The only known + documentation of the 1.x protocol is contained in README files that + are shipped along with the source code. + +4.3.1 Old Client, New Server + + Server implementations MAY support a configurable "compatibility" + flag that enables compatibility with old versions. When this flag is + on, the server SHOULD identify its protocol version as "1.99". + Clients using protocol 2.0 MUST be able to identify this as identical + to "2.0". In this mode the server SHOULD NOT send the carriage + return character (ASCII 13) after the version identification string. + + In the compatibility mode the server SHOULD NOT send any further data + after its initialization string until it has received an + identification string from the client. The server can then determine + whether the client is using an old protocol, and can revert to the + old protocol if required. In the compatibility mode, the server MUST + NOT send additional data before the version string. + + When compatibility with old clients is not needed, the server MAY + send its initial key exchange data immediately after the + identification string. + +4.3.2 New Client, Old Server + + Since the new client MAY immediately send additional data after its + identification string (before receiving server's identification), the + old protocol may already have been corrupted when the client learns + that the server is old. When this happens, the client SHOULD close + the connection to the server, and reconnect using the old protocol. + +5. Binary Packet Protocol + + Each packet is in the following format: + + uint32 packet_length + byte padding_length + byte[n1] payload; n1 = packet_length - padding_length - 1 + byte[n2] random padding; n2 = padding_length + byte[m] mac (message authentication code); m = mac_length + + packet_length + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 5] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + The length of the packet (bytes), not including MAC or the + packet_length field itself. + + padding_length + Length of padding (bytes). + + payload + The useful contents of the packet. If compression has been + negotiated, this field is compressed. Initially, compression + MUST be "none". + + random padding + Arbitrary-length padding, such that the total length of + (packet_length || padding_length || payload || padding) is a + multiple of the cipher block size or 8, whichever is larger. + There MUST be at least four bytes of padding. The padding + SHOULD consist of random bytes. The maximum amount of padding + is 255 bytes. + + mac + Message authentication code. If message authentication has + been negotiated, this field contains the MAC bytes. Initially, + the MAC algorithm MUST be "none". + + + Note that length of the concatenation of packet length, padding + length, payload, and padding MUST be a multiple of the cipher block + size or 8, whichever is larger. This constraint MUST be enforced + even when using stream ciphers. Note that the packet length field is + also encrypted, and processing it requires special care when sending + or receiving packets. + + The minimum size of a packet is 16 (or the cipher block size, + whichever is larger) bytes (plus MAC); implementations SHOULD decrypt + the length after receiving the first 8 (or cipher block size, + whichever is larger) bytes of a packet. + +5.1 Maximum Packet Length + + All implementations MUST be able to process packets with uncompressed + payload length of 32768 bytes or less and total packet size of 35000 + bytes or less (including length, padding length, payload, padding, + and MAC.). The maximum of 35000 bytes is an arbitrary chosen value + larger than uncompressed size. Implementations SHOULD support longer + packets, where they might be needed, e.g. if an implementation wants + to send a very large number of certificates. Such packets MAY be + sent if the version string indicates that the other party is able to + process them. However, implementations SHOULD check that the packet + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 6] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + length is reasonable for the implementation to avoid + denial-of-service and/or buffer overflow attacks. + +5.2 Compression + + If compression has been negotiated, the payload field (and only it) + will be compressed using the negotiated algorithm. The length field + and MAC will be computed from the compressed payload. Encryption will + be done after compression. + + Compression MAY be stateful, depending on the method. Compression + MUST be independent for each direction, and implementations MUST + allow independently choosing the algorithm for each direction. + + The following compression methods are currently defined: + + none REQUIRED no compression + zlib OPTIONAL ZLIB (LZ77) compression + + The "zlib" compression is described in [RFC1950] and in [RFC1951]. + The compression context is initialized after each key exchange, and + is passed from one packet to the next with only a partial flush being + performed at the end of each packet. A partial flush means that the + current compressed block is ended and all data will be output. If the + current block is not a stored block, one or more empty blocks are + added after the current block to ensure that there are at least 8 + bits counting from the start of the end-of-block code of the current + block to the end of the packet payload. + + Additional methods may be defined as specified in [SSH-ARCH]. + +5.3 Encryption + + An encryption algorithm and a key will be negotiated during the key + exchange. When encryption is in effect, the packet length, padding + length, payload and padding fields of each packet MUST be encrypted + with the given algorithm. + + The encrypted data in all packets sent in one direction SHOULD be + considered a single data stream. For example, initialization vectors + SHOULD be passed from the end of one packet to the beginning of the + next packet. All ciphers SHOULD use keys with an effective key length + of 128 bits or more. + + The ciphers in each direction MUST run independently of each other, + and implementations MUST allow independently choosing the algorithm + for each direction (if multiple algorithms are allowed by local + policy). + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 7] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + The following ciphers are currently defined: + + 3des-cbc REQUIRED three-key 3DES in CBC mode + blowfish-cbc OPTIONALi Blowfish in CBC mode + twofish256-cbc OPTIONAL Twofish in CBC mode, + with 256-bit key + twofish-cbc OPTIONAL alias for "twofish256-cbc" (this + is being retained for + historical reasons) + twofish192-cbc OPTIONAL Twofish with 192-bit key + twofish128-cbc OPTIONAL Twofish with 128-bit key + aes256-cbc OPTIONAL AES (Rijndael) in CBC mode, + with 256-bit key + aes192-cbc OPTIONAL AES with 192-bit key + aes128-cbc RECOMMENDED AES with 128-bit key + serpent256-cbc OPTIONAL Serpent in CBC mode, with + 256-bit key + serpent192-cbc OPTIONAL Serpent with 192-bit key + serpent128-cbc OPTIONAL Serpent with 128-bit key + arcfour OPTIONAL the ARCFOUR stream cipher + idea-cbc OPTIONAL IDEA in CBC mode + cast128-cbc OPTIONAL CAST-128 in CBC mode + none OPTIONAL no encryption; NOT RECOMMENDED + + The "3des-cbc" cipher is three-key triple-DES + (encrypt-decrypt-encrypt), where the first 8 bytes of the key are + used for the first encryption, the next 8 bytes for the decryption, + and the following 8 bytes for the final encryption. This requires 24 + bytes of key data (of which 168 bits are actually used). To + implement CBC mode, outer chaining MUST be used (i.e., there is only + one initialization vector). This is a block cipher with 8 byte + blocks. This algorithm is defined in [FIPS-46-3] + + The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit keys + [SCHNEIER]. This is a block cipher with 8 byte blocks. + + The "twofish-cbc" or "twofish256-cbc" cipher is Twofish in CBC mode, + with 256 bit keys as described [TWOFISH]. This is a block cipher with + 16 byte blocks. + + The "twofish192-cbc" cipher. Same as above but with 192-bit key. + + The "twofish128-cbc" cipher. Same as above but with 128-bit key. + + The "aes256-cbc" cipher is AES (Advanced Encryption Standard) + [FIPS-197], formerly Rijndael, in CBC mode. This version uses 256-bit + key. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 8] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + The "aes192-cbc" cipher. Same as above but with 192-bit key. + + The "aes128-cbc" cipher. Same as above but with 128-bit key. + + The "serpent256-cbc" cipher in CBC mode, with 256-bit key as + described in the Serpent AES submission. + + The "serpent192-cbc" cipher. Same as above but with 192-bit key. + + The "serpent128-cbc" cipher. Same as above but with 128-bit key. + + The "arcfour" is the Arcfour stream cipher with 128 bit keys. The + Arcfour cipher is believed to be compatible with the RC4 cipher + [SCHNEIER]. RC4 is a registered trademark of RSA Data Security Inc. + Arcfour (and RC4) has problems with weak keys, and should be used + with caution. + + The "idea-cbc" cipher is the IDEA cipher in CBC mode [SCHNEIER]. + + The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode + [RFC2144]. + + The "none" algorithm specifies that no encryption is to be done. + Note that this method provides no confidentiality protection, and it + is not recommended. Some functionality (e.g. password + authentication) may be disabled for security reasons if this cipher + is chosen. + + Additional methods may be defined as specified in [SSH-ARCH]. + +5.4 Data Integrity + + Data integrity is protected by including with each packet a message + authentication code (MAC) that is computed from a shared secret, + packet sequence number, and the contents of the packet. + + The message authentication algorithm and key are negotiated during + key exchange. Initially, no MAC will be in effect, and its length + MUST be zero. After key exchange, the selected MAC will be computed + before encryption from the concatenation of packet data: + + mac = MAC(key, sequence_number || unencrypted_packet) + + where unencrypted_packet is the entire packet without MAC (the length + fields, payload and padding), and sequence_number is an implicit + packet sequence number represented as uint32. The sequence number is + initialized to zero for the first packet, and is incremented after + every packet (regardless of whether encryption or MAC is in use). It + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 9] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + is never reset, even if keys/algorithms are renegotiated later. It + wraps around to zero after every 2^32 packets. The packet sequence + number itself is not included in the packet sent over the wire. + + The MAC algorithms for each direction MUST run independently, and + implementations MUST allow choosing the algorithm independently for + both directions. + + The MAC bytes resulting from the MAC algorithm MUST be transmitted + without encryption as the last part of the packet. The number of MAC + bytes depends on the algorithm chosen. + + The following MAC algorithms are currently defined: + + hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key + length = 20) + hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest + length = 12, key length = 20) + hmac-md5 OPTIONAL HMAC-MD5 (digest length = key + length = 16) + hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest + length = 12, key length = 16) + none OPTIONAL no MAC; NOT RECOMMENDED + + Figure 1 + + The "hmac-*" algorithms are described in [RFC2104] The "*-n" MACs use + only the first n bits of the resulting value. + + The hash algorithms are described in [SCHNEIER]. + + Additional methods may be defined as specified in [SSH-ARCH]. + +5.5 Key Exchange Methods + + The key exchange method specifies how one-time session keys are + generated for encryption and for authentication, and how the server + authentication is done. + + Only one REQUIRED key exchange method has been defined: + + diffie-hellman-group1-sha1 REQUIRED + + This method is described later in this document. + + Additional methods may be defined as specified in [SSH-ARCH]. + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 10] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +5.6 Public Key Algorithms + + This protocol has been designed to be able to operate with almost any + public key format, encoding, and algorithm (signature and/or + encryption). + + There are several aspects that define a public key type: + o Key format: how is the key encoded and how are certificates + represented. The key blobs in this protocol MAY contain + certificates in addition to keys. + o Signature and/or encryption algorithms. Some key types may not + support both signing and encryption. Key usage may also be + restricted by policy statements in e.g. certificates. In this + case, different key types SHOULD be defined for the different + policy alternatives. + o Encoding of signatures and/or encrypted data. This includes but is + not limited to padding, byte order, and data formats. + + The following public key and/or certificate formats are currently defined: + + ssh-dss REQUIRED sign Raw DSS Key + ssh-rsa RECOMMENDED sign Raw RSA Key + x509v3-sign-rsa OPTIONAL sign X.509 certificates (RSA key) + x509v3-sign-dss OPTIONAL sign X.509 certificates (DSS key) + spki-sign-rsa OPTIONAL sign SPKI certificates (RSA key) + spki-sign-dss OPTIONAL sign SPKI certificates (DSS key) + pgp-sign-rsa OPTIONAL sign OpenPGP certificates (RSA key) + pgp-sign-dss OPTIONAL sign OpenPGP certificates (DSS key) + + Additional key types may be defined as specified in [SSH-ARCH]. + + The key type MUST always be explicitly known (from algorithm + negotiation or some other source). It is not normally included in + the key blob. + + Certificates and public keys are encoded as follows: + + string certificate or public key format identifier + byte[n] key/certificate data + + The certificate part may have be a zero length string, but a public + key is required. This is the public key that will be used for + authentication; the certificate sequence contained in the certificate + blob can be used to provide authorization. + + Public key / certifcate formats that do not explicitly specify a + signature format identifier MUST use the public key / certificate + format identifier as the signature identifier. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 11] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + Signatures are encoded as follows: + string signature format identifier (as specified by the + public key / cert format) + byte[n] signature blob in format specific encoding. + + + The "ssh-dss" key format has the following specific encoding: + + string "ssh-dss" + mpint p + mpint q + mpint g + mpint y + + Here the p, q, g, and y parameters form the signature key blob. + + Signing and verifying using this key format is done according to the + Digital Signature Standard [FIPS-186] using the SHA-1 hash. A + description can also be found in [SCHNEIER]. + + The resulting signature is encoded as follows: + + string "ssh-dss" + string dss_signature_blob + + dss_signature_blob is encoded as a string containing r followed by s + (which are 160 bits long integers, without lengths or padding, + unsigned and in network byte order). + + The "ssh-rsa" key format has the following specific encoding: + + string "ssh-rsa" + mpint e + mpint n + + Here the e and n parameters form the signature key blob. + + Signing and verifying using this key format is done according to + [SCHNEIER] and [PKCS1] using the SHA-1 hash. + + The resulting signature is encoded as follows: + + string "ssh-rsa" + string rsa_signature_blob + + rsa_signature_blob is encoded as a string containing s (which is an + integer, without lengths or padding, unsigned and in network byte + order). + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 12] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + The "spki-sign-rsa" method indicates that the certificate blob + contains a sequence of SPKI certificates. The format of SPKI + certificates is described in [RFC2693]. This method indicates that + the key (or one of the keys in the certificate) is an RSA-key. + + The "spki-sign-dss". As above, but indicates that the key (or one of + the keys in the certificate) is a DSS-key. + + The "pgp-sign-rsa" method indicates the certificates, the public key, + and the signature are in OpenPGP compatible binary format + ([RFC2440]). This method indicates that the key is an RSA-key. + + The "pgp-sign-dss". As above, but indicates that the key is a + DSS-key. + +6. Key Exchange + + Key exchange begins by each side sending lists of supported + algorithms. Each side has a preferred algorithm in each category, and + it is assumed that most implementations at any given time will use + the same preferred algorithm. Each side MAY guess which algorithm + the other side is using, and MAY send an initial key exchange packet + according to the algorithm if appropriate for the preferred method. + + Guess is considered wrong, if: + o the kex algorithm and/or the host key algorithm is guessed wrong + (server and client have different preferred algorithm), or + o if any of the other algorithms cannot be agreed upon (the + procedure is defined below in Section Section 6.1). + + Otherwise, the guess is considered to be right and the optimistically + sent packet MUST be handled as the first key exchange packet. + + However, if the guess was wrong, and a packet was optimistically sent + by one or both parties, such packets MUST be ignored (even if the + error in the guess would not affect the contents of the initial + packet(s)), and the appropriate side MUST send the correct initial + packet. + + Server authentication in the key exchange MAY be implicit. After a + key exchange with implicit server authentication, the client MUST + wait for response to its service request message before sending any + further data. + +6.1 Algorithm Negotiation + + Key exchange begins by each side sending the following packet: + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 13] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + byte SSH_MSG_KEXINIT + byte[16] cookie (random bytes) + string kex_algorithms + string server_host_key_algorithms + string encryption_algorithms_client_to_server + string encryption_algorithms_server_to_client + string mac_algorithms_client_to_server + string mac_algorithms_server_to_client + string compression_algorithms_client_to_server + string compression_algorithms_server_to_client + string languages_client_to_server + string languages_server_to_client + boolean first_kex_packet_follows + uint32 0 (reserved for future extension) + + Each of the algorithm strings MUST be a comma-separated list of + algorithm names (see ''Algorithm Naming'' in [SSH-ARCH]). Each + supported (allowed) algorithm MUST be listed in order of preference. + + The first algorithm in each list MUST be the preferred (guessed) + algorithm. Each string MUST contain at least one algorithm name. + + + cookie + The cookie MUST be a random value generated by the sender. Its + purpose is to make it impossible for either side to fully + determine the keys and the session identifier. + + kex_algorithms + Key exchange algorithms were defined above. The first + algorithm MUST be the preferred (and guessed) algorithm. If + both sides make the same guess, that algorithm MUST be used. + Otherwise, the following algorithm MUST be used to choose a key + exchange method: iterate over client's kex algorithms, one at a + time. Choose the first algorithm that satisfies the following + conditions: + + the server also supports the algorithm, + + if the algorithm requires an encryption-capable host key, + there is an encryption-capable algorithm on the server's + server_host_key_algorithms that is also supported by the + client, and + + if the algorithm requires a signature-capable host key, + there is a signature-capable algorithm on the server's + server_host_key_algorithms that is also supported by the + client. + + If no algorithm satisfying all these conditions can be + found, the connection fails, and both sides MUST disconnect. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 14] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + server_host_key_algorithms + List of the algorithms supported for the server host key. The + server lists the algorithms for which it has host keys; the + client lists the algorithms that it is willing to accept. + (There MAY be multiple host keys for a host, possibly with + different algorithms.) + + Some host keys may not support both signatures and encryption + (this can be determined from the algorithm), and thus not all + host keys are valid for all key exchange methods. + + Algorithm selection depends on whether the chosen key exchange + algorithm requires a signature or encryption capable host key. + It MUST be possible to determine this from the public key + algorithm name. The first algorithm on the client's list that + satisfies the requirements and is also supported by the server + MUST be chosen. If there is no such algorithm, both sides MUST + disconnect. + + encryption_algorithms + Lists the acceptable symmetric encryption algorithms in order + of preference. The chosen encryption algorithm to each + direction MUST be the first algorithm on the client's list + that is also on the server's list. If there is no such + algorithm, both sides MUST disconnect. + + Note that "none" must be explicitly listed if it is to be + acceptable. The defined algorithm names are listed in Section + Section 5.3. + + mac_algorithms + Lists the acceptable MAC algorithms in order of preference. + The chosen MAC algorithm MUST be the first algorithm on the + client's list that is also on the server's list. If there is + no such algorithm, both sides MUST disconnect. + + Note that "none" must be explicitly listed if it is to be + acceptable. The MAC algorithm names are listed in Section + Figure 1. + + compression_algorithms + Lists the acceptable compression algorithms in order of + preference. The chosen compression algorithm MUST be the first + algorithm on the client's list that is also on the server's + list. If there is no such algorithm, both sides MUST + disconnect. + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 15] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + Note that "none" must be explicitly listed if it is to be + acceptable. The compression algorithm names are listed in + Section Section 5.2. + + languages + This is a comma-separated list of language tags in order of + preference [RFC3066]. Both parties MAY ignore this list. If + there are no language preferences, this list SHOULD be empty. + Language tags SHOULD NOT be present unless they are known to be + needed by the sending party. + + first_kex_packet_follows + Indicates whether a guessed key exchange packet follows. If a + guessed packet will be sent, this MUST be TRUE. If no guessed + packet will be sent, this MUST be FALSE. + + After receiving the SSH_MSG_KEXINIT packet from the other side, + each party will know whether their guess was right. If the + other party's guess was wrong, and this field was TRUE, the + next packet MUST be silently ignored, and both sides MUST then + act as determined by the negotiated key exchange method. If + the guess was right, key exchange MUST continue using the + guessed packet. + + After the KEXINIT packet exchange, the key exchange algorithm is run. + It may involve several packet exchanges, as specified by the key + exchange method. + +6.2 Output from Key Exchange + + The key exchange produces two values: a shared secret K, and an + exchange hash H. Encryption and authentication keys are derived from + these. The exchange hash H from the first key exchange is + additionally used as the session identifier, which is a unique + identifier for this connection. It is used by authentication methods + as a part of the data that is signed as a proof of possession of a + private key. Once computed, the session identifier is not changed, + even if keys are later re-exchanged. + + + Each key exchange method specifies a hash function that is used in + the key exchange. The same hash algorithm MUST be used in key + derivation. Here, we'll call it HASH. + + + Encryption keys MUST be computed as HASH of a known value and K as + follows: + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 16] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + o Initial IV client to server: HASH(K || H || "A" || session_id) + (Here K is encoded as mpint and "A" as byte and session_id as raw + data."A" means the single character A, ASCII 65). + o Initial IV server to client: HASH(K || H || "B" || session_id) + o Encryption key client to server: HASH(K || H || "C" || session_id) + o Encryption key server to client: HASH(K || H || "D" || session_id) + o Integrity key client to server: HASH(K || H || "E" || session_id) + o Integrity key server to client: HASH(K || H || "F" || session_id) + + Key data MUST be taken from the beginning of the hash output. 128 + bits (16 bytes) MUST be used for algorithms with variable-length + keys. The only variable key length algorithm defined in this document + is arcfour). For other algorithms, as many bytes as are needed are + taken from the beginning of the hash value. If the key length needed + is longer than the output of the HASH, the key is extended by + computing HASH of the concatenation of K and H and the entire key so + far, and appending the resulting bytes (as many as HASH generates) to + the key. This process is repeated until enough key material is + available; the key is taken from the beginning of this value. In + other words: + + K1 = HASH(K || H || X || session_id) (X is e.g. "A") + K2 = HASH(K || H || K1) + K3 = HASH(K || H || K1 || K2) + ... + key = K1 || K2 || K3 || ... + + This process will lose entropy if the amount of entropy in K is + larger than the internal state size of HASH. + +6.3 Taking Keys Into Use + + Key exchange ends by each side sending an SSH_MSG_NEWKEYS message. + This message is sent with the old keys and algorithms. All messages + sent after this message MUST use the new keys and algorithms. + + + When this message is received, the new keys and algorithms MUST be + taken into use for receiving. + + + This message is the only valid message after key exchange, in + addition to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE + messages. The purpose of this message is to ensure that a party is + able to respond with a disconnect message that the other party can + understand if something goes wrong with the key exchange. + Implementations MUST NOT accept any other messages after key exchange + before receiving SSH_MSG_NEWKEYS. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 17] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + byte SSH_MSG_NEWKEYS + + +7. Diffie-Hellman Key Exchange + + The Diffie-Hellman key exchange provides a shared secret that can not + be determined by either party alone. The key exchange is combined + with a signature with the host key to provide host authentication. + + + In the following description (C is the client, S is the server; p is + a large safe prime, g is a generator for a subgroup of GF(p), and q + is the order of the subgroup; V_S is S's version string; V_C is C's + version string; K_S is S's public host key; I_C is C's KEXINIT + message and I_S S's KEXINIT message which have been exchanged before + this part begins): + + + 1. C generates a random number x (1 < x < q) and computes e = g^x + mod p. C sends "e" to S. + + 2. S generates a random number y (0 < y < q) and computes f = g^y + mod p. S receives "e". It computes K = e^y mod p, H = hash(V_C + || V_S || I_C || I_S || K_S || e || f || K) (these elements are + encoded according to their types; see below), and signature s on + H with its private host key. S sends "K_S || f || s" to C. The + signing operation may involve a second hashing operation. + + 3. C verifies that K_S really is the host key for S (e.g. using + certificates or a local database). C is also allowed to accept + the key without verification; however, doing so will render the + protocol insecure against active attacks (but may be desirable + for practical reasons in the short term in many environments). C + then computes K = f^x mod p, H = hash(V_C || V_S || I_C || I_S || + K_S || e || f || K), and verifies the signature s on H. + + Either side MUST NOT send or accept e or f values that are not in the + range [1, p-1]. If this condition is violated, the key exchange + fails. + + + This is implemented with the following messages. The hash algorithm + for computing the exchange hash is defined by the method name, and is + called HASH. The public key algorithm for signing is negotiated with + the KEXINIT messages. + + First, the client sends the following: + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 18] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + byte SSH_MSG_KEXDH_INIT + mpint e + + + The server responds with the following: + + byte SSH_MSG_KEXDH_REPLY + string server public host key and certificates (K_S) + mpint f + string signature of H + + The hash H is computed as the HASH hash of the concatenation of the + following: + + string V_C, the client's version string (CR and NL excluded) + string V_S, the server's version string (CR and NL excluded) + string I_C, the payload of the client's SSH_MSG_KEXINIT + string I_S, the payload of the server's SSH_MSG_KEXINIT + string K_S, the host key + mpint e, exchange value sent by the client + mpint f, exchange value sent by the server + mpint K, the shared secret + + This value is called the exchange hash, and it is used to + authenticate the key exchange. The exchange hash SHOULD be kept + secret. + + + The signature algorithm MUST be applied over H, not the original + data. Most signature algorithms include hashing and additional + padding. For example, "ssh-dss" specifies SHA-1 hashing; in that + case, the data is first hashed with HASH to compute H, and H is then + hashed with SHA-1 as part of the signing operation. + +7.1 diffie-hellman-group1-sha1 + + The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman key + exchange with SHA-1 as HASH, and Oakley group 14 [RFC3526] (2048-bit + MODP Group). It is included below in hexadecimal and decimal. + + The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor( 2^894 Pi + + 129093 ). Its hexadecimal value is: + + FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 + 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD + EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 + E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED + EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 19] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + FFFFFFFF FFFFFFFF. + + In decimal, this value is: + + 179769313486231590770839156793787453197860296048756011706444 + 423684197180216158519368947833795864925541502180565485980503 + 646440548199239100050792877003355816639229553136239076508735 + 759914822574862575007425302077447712589550957937778424442426 + 617334727629299387668709205606050270810842907692932019128194 + 467627007. + + The generator used with this prime is g = 2. The group order q is (p + - 1) / 2. + +8. Key Re-Exchange + + Key re-exchange is started by sending an SSH_MSG_KEXINIT packet when + not already doing a key exchange (as described in Section Section + 6.1). When this message is received, a party MUST respond with its + own SSH_MSG_KEXINIT message except when the received SSH_MSG_KEXINIT + already was a reply. Either party MAY initiate the re-exchange, but + roles MUST NOT be changed (i.e., the server remains the server, and + the client remains the client). + + + Key re-exchange is performed using whatever encryption was in effect + when the exchange was started. Encryption, compression, and MAC + methods are not changed before a new SSH_MSG_NEWKEYS is sent after + the key exchange (as in the initial key exchange). Re-exchange is + processed identically to the initial key exchange, except for the + session identifier that will remain unchanged. It is permissible to + change some or all of the algorithms during the re-exchange. Host + keys can also change. All keys and initialization vectors are + recomputed after the exchange. Compression and encryption contexts + are reset. + + + It is recommended that the keys are changed after each gigabyte of + transmitted data or after each hour of connection time, whichever + comes sooner. However, since the re-exchange is a public key + operation, it requires a fair amount of processing power and should + not be performed too often. + + + More application data may be sent after the SSH_MSG_NEWKEYS packet + has been sent; key exchange does not affect the protocols that lie + above the SSH transport layer. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 20] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +9. Service Request + + After the key exchange, the client requests a service. The service is + identified by a name. The format of names and procedures for defining + new names are defined in [SSH-ARCH]. + + + Currently, the following names have been reserved: + + ssh-userauth + ssh-connection + + Similar local naming policy is applied to the service names, as is + applied to the algorithm names; a local service should use the + "servicename@domain" syntax. + + byte SSH_MSG_SERVICE_REQUEST + string service name + + If the server rejects the service request, it SHOULD send an + appropriate SSH_MSG_DISCONNECT message and MUST disconnect. + + + When the service starts, it may have access to the session identifier + generated during the key exchange. + + + If the server supports the service (and permits the client to use + it), it MUST respond with the following: + + byte SSH_MSG_SERVICE_ACCEPT + string service name + + Message numbers used by services should be in the area reserved for + them (see Section 6 in [SSH-ARCH]). The transport level will + continue to process its own messages. + + + Note that after a key exchange with implicit server authentication, + the client MUST wait for response to its service request message + before sending any further data. + +10. Additional Messages + + Either party may send any of the following messages at any time. + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 21] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +10.1 Disconnection Message + + byte SSH_MSG_DISCONNECT + uint32 reason code + string description [RFC2279] + string language tag [RFC3066] + + This message causes immediate termination of the connection. All + implementations MUST be able to process this message; they SHOULD be + able to send this message. + + The sender MUST NOT send or receive any data after this message, and + the recipient MUST NOT accept any data after receiving this message. + The description field gives a more specific explanation in a + human-readable form. The error code gives the reason in a more + machine-readable format (suitable for localization), and can have the + following values: + + #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 + #define SSH_DISCONNECT_PROTOCOL_ERROR 2 + #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 + #define SSH_DISCONNECT_RESERVED 4 + #define SSH_DISCONNECT_MAC_ERROR 5 + #define SSH_DISCONNECT_COMPRESSION_ERROR 6 + #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 + #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 + #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 + #define SSH_DISCONNECT_CONNECTION_LOST 10 + #define SSH_DISCONNECT_BY_APPLICATION 11 + #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 + #define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 + #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 + #define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 + + If the description string is displayed, control character filtering + discussed in [SSH-ARCH] should be used to avoid attacks by sending + terminal control characters. + +10.2 Ignored Data Message + + byte SSH_MSG_IGNORE + string data + + All implementations MUST understand (and ignore) this message at any + time (after receiving the protocol version). No implementation is + required to send them. This message can be used as an additional + protection measure against advanced traffic analysis techniques. + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 22] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +10.3 Debug Message + + byte SSH_MSG_DEBUG + boolean always_display + string message [RFC2279] + string language tag [RFC3066] + + All implementations MUST understand this message, but they are + allowed to ignore it. This message is used to pass the other side + information that may help debugging. If always_display is TRUE, the + message SHOULD be displayed. Otherwise, it SHOULD NOT be displayed + unless debugging information has been explicitly requested by the + user. + + + The message doesn't need to contain a newline. It is, however, + allowed to consist of multiple lines separated by CRLF (Carriage + Return - Line Feed) pairs. + + + If the message string is displayed, terminal control character + filtering discussed in [SSH-ARCH] should be used to avoid attacks by + sending terminal control characters. + +10.4 Reserved Messages + + An implementation MUST respond to all unrecognized messages with an + SSH_MSG_UNIMPLEMENTED message in the order in which the messages were + received. Such messages MUST be otherwise ignored. Later protocol + versions may define other meanings for these message types. + + byte SSH_MSG_UNIMPLEMENTED + uint32 packet sequence number of rejected message + + +11. Summary of Message Numbers + + The following message numbers have been defined in this protocol: + + #define SSH_MSG_DISCONNECT 1 + #define SSH_MSG_IGNORE 2 + #define SSH_MSG_UNIMPLEMENTED 3 + #define SSH_MSG_DEBUG 4 + #define SSH_MSG_SERVICE_REQUEST 5 + #define SSH_MSG_SERVICE_ACCEPT 6 + + #define SSH_MSG_KEXINIT 20 + #define SSH_MSG_NEWKEYS 21 + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 23] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + /* Numbers 30-49 used for kex packets. + Different kex methods may reuse message numbers in + this range. */ + + #define SSH_MSG_KEXDH_INIT 30 + #define SSH_MSG_KEXDH_REPLY 31 + + +12. IANA Considerations + + This document is part of a set, the IANA considerations for the SSH + protocol as defined in [SSH-ARCH], [SSH-TRANS], [SSH-USERAUTH], + [SSH-CONNECT] are detailed in [SSH-NUMBERS]. + +13. Security Considerations + + This protocol provides a secure encrypted channel over an insecure + network. It performs server host authentication, key exchange, + encryption, and integrity protection. It also derives a unique + session id that may be used by higher-level protocols. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + +14. Intellectual Property + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementers or users of this specification can + be obtained from the IETF Secretariat. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + +15. Additional Information + + The current document editor is: [email protected]. Comments on + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 24] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + this internet draft should be sent to the IETF SECSH working group, + details at: http://ietf.org/html.charters/secsh-charter.html + +Normative + + [SSH-ARCH] + Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-15.txt, Oct 2003. + + [SSH-TRANS] + Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-17.txt, Oct 2003. + + [SSH-USERAUTH] + Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-18.txt, Oct 2003. + + [SSH-CONNECT] + Ylonen, T., "SSH Connection Protocol", I-D + draft-ietf-connect-18.txt, Oct 2003. + + [SSH-NUMBERS] + Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct + 2003. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +Informative + + [FIPS-186] + Federal Information Processing Standards Publication, + "FIPS PUB 186, Digital Signature Standard", May 1994. + + [FIPS-197] + NIST, "FIPS PUB 197 Advanced Encryption Standard (AES)", + November 2001. + + [FIPS-46-3] + U.S. Dept. of Commerce, "FIPS PUB 46-3, Data Encryption + Standard (DES)", October 1999. + + [RFC2459] Housley, R., Ford, W., Polk, T. and D. Solo, "Internet + X.509 Public Key Infrastructure Certificate and CRL + Profile", RFC 2459, January 1999. + + [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 25] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + STD 13, RFC 1034, November 1987. + + [RFC3066] Alvestrand, H., "Tags for the Identification of + Languages", BCP 47, RFC 3066, January 2001. + + [RFC1950] Deutsch, L. and J-L. Gailly, "ZLIB Compressed Data Format + Specification version 3.3", RFC 1950, May 1996. + + [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification + version 1.3", RFC 1951, May 1996. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + [RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: + Keyed-Hashing for Message Authentication", RFC 2104, + February 1997. + + [RFC2144] Adams, C., "The CAST-128 Encryption Algorithm", RFC 2144, + May 1997. + + [RFC2440] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer, + "OpenPGP Message Format", RFC 2440, November 1998. + + [RFC2693] Ellison, C., Frantz, B., Lampson, B., Rivest, R., Thomas, + B. and T. Ylonen, "SPKI Certificate Theory", RFC 2693, + September 1999. + + [RFC3526] Kivinen, T. and M. Kojo, "More Modular Exponential (MODP) + Diffie-Hellman groups for Internet Key Exchange (IKE)", + RFC 3526, May 2003. + + [SCHNEIER] + Schneier, B., "Applied Cryptography Second Edition: + protocols algorithms and source in code in C", 1996. + + [TWOFISH] Schneier, B., "The Twofish Encryptions Algorithm: A + 128-Bit Block Cipher, 1st Edition", March 1999. + + + + + + + + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 26] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Darren J. Moffat (editor) + Sun Microsystems, Inc + 17 Network Circle + Menlo Park 95025 + USA + + EMail: [email protected] + +Appendix A. Contibutors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 27] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 28] + +Internet-Draft SSH Transport Layer Protocol Oct 2003 + + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat, Editor Expires March 31, 2004 [Page 29]
\ No newline at end of file diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps new file mode 100644 index 0000000000..be5799dbce --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.2.ps @@ -0,0 +1,1881 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 75 0 595 747 +%%Title: Enscript Output +%%For: Magnus Thoang +%%Creator: GNU enscript 1.6.1 +%%CreationDate: Fri Oct 31 13:35:32 2003 +%%Orientation: Portrait +%%Pages: 8 0 +%%DocumentMedia: A4 595 842 0 () () +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +%%BeginProcSet: PStoPS 1 15 +userdict begin +[/showpage/erasepage/copypage]{dup where{pop dup load + type/operatortype eq{1 array cvx dup 0 3 index cvx put + bind def}{pop}ifelse}{pop}ifelse}forall +[/letter/legal/executivepage/a4/a4small/b5/com10envelope + /monarchenvelope/c5envelope/dlenvelope/lettersmall/note + /folio/quarto/a5]{dup where{dup wcheck{exch{}put} + {pop{}def}ifelse}{pop}ifelse}forall +/setpagedevice {pop}bind 1 index where{dup wcheck{3 1 roll put} + {pop def}ifelse}{def}ifelse +/PStoPSmatrix matrix currentmatrix def +/PStoPSxform matrix def/PStoPSclip{clippath}def +/defaultmatrix{PStoPSmatrix exch PStoPSxform exch concatmatrix}bind def +/initmatrix{matrix defaultmatrix setmatrix}bind def +/initclip[{matrix currentmatrix PStoPSmatrix setmatrix + [{currentpoint}stopped{$error/newerror false put{newpath}} + {/newpath cvx 3 1 roll/moveto cvx 4 array astore cvx}ifelse] + {[/newpath cvx{/moveto cvx}{/lineto cvx} + {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop} + stopped{$error/errorname get/invalidaccess eq{cleartomark + $error/newerror false put cvx exec}{stop}ifelse}if}bind aload pop + /initclip dup load dup type dup/operatortype eq{pop exch pop} + {dup/arraytype eq exch/packedarraytype eq or + {dup xcheck{exch pop aload pop}{pop cvx}ifelse} + {pop cvx}ifelse}ifelse + {newpath PStoPSclip clip newpath exec setmatrix} bind aload pop]cvx def +/initgraphics{initmatrix newpath initclip 1 setlinewidth + 0 setlinecap 0 setlinejoin []0 setdash 0 setgray + 10 setmiterlimit}bind def +end +%%EndProcSet +%%BeginResource: procset Enscript-Prolog 1.6 1 +% +% Procedures. +% + +/_S { % save current state + /_s save def +} def +/_R { % restore from saved state + _s restore +} def + +/S { % showpage protecting gstate + gsave + showpage + grestore +} bind def + +/MF { % fontname newfontname -> - make a new encoded font + /newfontname exch def + /fontname exch def + + /fontdict fontname findfont def + /newfont fontdict maxlength dict def + + fontdict { + exch + dup /FID eq { + % skip FID pair + pop pop + } { + % copy to the new font dictionary + exch newfont 3 1 roll put + } ifelse + } forall + + newfont /FontName newfontname put + + % insert only valid encoding vectors + encoding_vector length 256 eq { + newfont /Encoding encoding_vector put + } if + + newfontname newfont definefont pop +} def + +/SF { % fontname width height -> - set a new font + /height exch def + /width exch def + + findfont + [width 0 0 height 0 0] makefont setfont +} def + +/SUF { % fontname width height -> - set a new user font + /height exch def + /width exch def + + /F-gs-user-font MF + /F-gs-user-font width height SF +} def + +/M {moveto} bind def +/s {show} bind def + +/Box { % x y w h -> - define box path + /d_h exch def /d_w exch def /d_y exch def /d_x exch def + d_x d_y moveto + d_w 0 rlineto + 0 d_h rlineto + d_w neg 0 rlineto + closepath +} def + +/bgs { % x y height blskip gray str -> - show string with bg color + /str exch def + /gray exch def + /blskip exch def + /height exch def + /y exch def + /x exch def + + gsave + x y blskip sub str stringwidth pop height Box + gray setgray + fill + grestore + x y M str s +} def + +% Highlight bars. +/highlight_bars { % nlines lineheight output_y_margin gray -> - + gsave + setgray + /ymarg exch def + /lineheight exch def + /nlines exch def + + % This 2 is just a magic number to sync highlight lines to text. + 0 d_header_y ymarg sub 2 sub translate + + /cw d_output_w cols div def + /nrows d_output_h ymarg 2 mul sub lineheight div cvi def + + % for each column + 0 1 cols 1 sub { + cw mul /xp exch def + + % for each rows + 0 1 nrows 1 sub { + /rn exch def + rn lineheight mul neg /yp exch def + rn nlines idiv 2 mod 0 eq { + % Draw highlight bar. 4 is just a magic indentation. + xp 4 add yp cw 8 sub lineheight neg Box fill + } if + } for + } for + + grestore +} def + +% Line highlight bar. +/line_highlight { % x y width height gray -> - + gsave + /gray exch def + Box gray setgray fill + grestore +} def + +% Column separator lines. +/column_lines { + gsave + .1 setlinewidth + 0 d_footer_h translate + /cw d_output_w cols div def + 1 1 cols 1 sub { + cw mul 0 moveto + 0 d_output_h rlineto stroke + } for + grestore +} def + +% Column borders. +/column_borders { + gsave + .1 setlinewidth + 0 d_footer_h moveto + 0 d_output_h rlineto + d_output_w 0 rlineto + 0 d_output_h neg rlineto + closepath stroke + grestore +} def + +% Do the actual underlay drawing +/draw_underlay { + ul_style 0 eq { + ul_str true charpath stroke + } { + ul_str show + } ifelse +} def + +% Underlay +/underlay { % - -> - + gsave + 0 d_page_h translate + d_page_h neg d_page_w atan rotate + + ul_gray setgray + ul_font setfont + /dw d_page_h dup mul d_page_w dup mul add sqrt def + ul_str stringwidth pop dw exch sub 2 div ul_h_ptsize -2 div moveto + draw_underlay + grestore +} def + +/user_underlay { % - -> - + gsave + ul_x ul_y translate + ul_angle rotate + ul_gray setgray + ul_font setfont + 0 0 ul_h_ptsize 2 div sub moveto + draw_underlay + grestore +} def + +% Page prefeed +/page_prefeed { % bool -> - + statusdict /prefeed known { + statusdict exch /prefeed exch put + } { + pop + } ifelse +} def + +% Wrapped line markers +/wrapped_line_mark { % x y charwith charheight type -> - + /type exch def + /h exch def + /w exch def + /y exch def + /x exch def + + type 2 eq { + % Black boxes (like TeX does) + gsave + 0 setlinewidth + x w 4 div add y M + 0 h rlineto w 2 div 0 rlineto 0 h neg rlineto + closepath fill + grestore + } { + type 3 eq { + % Small arrows + gsave + .2 setlinewidth + x w 2 div add y h 2 div add M + w 4 div 0 rlineto + x w 4 div add y lineto stroke + + x w 4 div add w 8 div add y h 4 div add M + x w 4 div add y lineto + w 4 div h 8 div rlineto stroke + grestore + } { + % do nothing + } ifelse + } ifelse +} def + +% EPSF import. + +/BeginEPSF { + /b4_Inc_state save def % Save state for cleanup + /dict_count countdictstack def % Count objects on dict stack + /op_count count 1 sub def % Count objects on operand stack + userdict begin + /showpage { } def + 0 setgray 0 setlinecap + 1 setlinewidth 0 setlinejoin + 10 setmiterlimit [ ] 0 setdash newpath + /languagelevel where { + pop languagelevel + 1 ne { + false setstrokeadjust false setoverprint + } if + } if +} bind def + +/EndEPSF { + count op_count sub { pos } repeat % Clean up stacks + countdictstack dict_count sub { end } repeat + b4_Inc_state restore +} bind def + +% Check PostScript language level. +/languagelevel where { + pop /gs_languagelevel languagelevel def +} { + /gs_languagelevel 1 def +} ifelse +%%EndResource +%%BeginResource: procset Enscript-Encoding-88591 1.6 1 +/encoding_vector [ +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclam /quotedbl /numbersign +/dollar /percent /ampersand /quoteright +/parenleft /parenright /asterisk /plus +/comma /hyphen /period /slash +/zero /one /two /three +/four /five /six /seven +/eight /nine /colon /semicolon +/less /equal /greater /question +/at /A /B /C +/D /E /F /G +/H /I /J /K +/L /M /N /O +/P /Q /R /S +/T /U /V /W +/X /Y /Z /bracketleft +/backslash /bracketright /asciicircum /underscore +/quoteleft /a /b /c +/d /e /f /g +/h /i /j /k +/l /m /n /o +/p /q /r /s +/t /u /v /w +/x /y /z /braceleft +/bar /braceright /tilde /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef +/space /exclamdown /cent /sterling +/currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft +/logicalnot /hyphen /registered /macron +/degree /plusminus /twosuperior /threesuperior +/acute /mu /paragraph /bullet +/cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown +/Agrave /Aacute /Acircumflex /Atilde +/Adieresis /Aring /AE /Ccedilla +/Egrave /Eacute /Ecircumflex /Edieresis +/Igrave /Iacute /Icircumflex /Idieresis +/Eth /Ntilde /Ograve /Oacute +/Ocircumflex /Otilde /Odieresis /multiply +/Oslash /Ugrave /Uacute /Ucircumflex +/Udieresis /Yacute /Thorn /germandbls +/agrave /aacute /acircumflex /atilde +/adieresis /aring /ae /ccedilla +/egrave /eacute /ecircumflex /edieresis +/igrave /iacute /icircumflex /idieresis +/eth /ntilde /ograve /oacute +/ocircumflex /otilde /odieresis /divide +/oslash /ugrave /uacute /ucircumflex +/udieresis /yacute /thorn /ydieresis +] def +%%EndResource +%%EndProlog +%%BeginSetup +%%IncludeResource: font Courier-Bold +%%IncludeResource: font Courier +/HFpt_w 10 def +/HFpt_h 10 def +/Courier-Bold /HF-gs-font MF +/HF /HF-gs-font findfont [HFpt_w 0 0 HFpt_h 0 0] makefont def +/Courier /F-gs-font MF +/F-gs-font 10 10 SF +/#copies 1 def +/d_page_w 520 def +/d_page_h 747 def +/d_header_x 0 def +/d_header_y 747 def +/d_header_w 520 def +/d_header_h 0 def +/d_footer_x 0 def +/d_footer_y 0 def +/d_footer_w 520 def +/d_footer_h 0 def +/d_output_w 520 def +/d_output_h 747 def +/cols 1 def +userdict/PStoPSxform PStoPSmatrix matrix currentmatrix + matrix invertmatrix matrix concatmatrix + matrix invertmatrix put +%%EndSetup +%%Page: (0,1) 1 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 1 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 701 M +(Network Working Group T. Ylonen) s +5 690 M +(Internet-Draft SSH Communications Security Corp) s +5 679 M +(Expires: March 2, 2003 D. Moffat, Ed.) s +5 668 M +( Sun Microsystems, Inc) s +5 657 M +( September 2002) s +5 624 M +( SSH Authentication Protocol) s +5 613 M +( draft-ietf-secsh-userauth-18.txt) s +5 591 M +(Status of this Memo) s +5 569 M +( This document is an Internet-Draft and is in full conformance with) s +5 558 M +( all provisions of Section 10 of RFC2026.) s +5 536 M +( Internet-Drafts are working documents of the Internet Engineering) s +5 525 M +( Task Force \(IETF\), its areas, and its working groups. Note that other) s +5 514 M +( groups may also distribute working documents as Internet-Drafts.) s +5 492 M +( Internet-Drafts are draft documents valid for a maximum of six months) s +5 481 M +( and may be updated, replaced, or obsoleted by other documents at any) s +5 470 M +( time. It is inappropriate to use Internet-Drafts as reference) s +5 459 M +( material or to cite them other than as "work in progress.") s +5 437 M +( The list of current Internet-Drafts can be accessed at http://) s +5 426 M +( www.ietf.org/ietf/1id-abstracts.txt.) s +5 404 M +( The list of Internet-Draft Shadow Directories can be accessed at) s +5 393 M +( http://www.ietf.org/shadow.html.) s +5 371 M +( This Internet-Draft will expire on March 2, 2003.) s +5 349 M +(Copyright Notice) s +5 327 M +( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s +5 305 M +(Abstract) s +5 283 M +( SSH is a protocol for secure remote login and other secure network) s +5 272 M +( services over an insecure network. This document describes the SSH) s +5 261 M +( authentication protocol framework and public key, password, and) s +5 250 M +( host-based client authentication methods. Additional authentication) s +5 239 M +( methods are described in separate documents. The SSH authentication) s +5 228 M +( protocol runs on top of the SSH transport layer protocol and provides) s +5 217 M +( a single authenticated tunnel for the SSH connection protocol.) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 1]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 2 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(Table of Contents) s +5 668 M +( 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 657 M +( 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3) s +5 646 M +( 3. Conventions Used in This Document . . . . . . . . . . . . . 3) s +5 635 M +( 3.1 The Authentication Protocol Framework . . . . . . . . . . . 3) s +5 624 M +( 3.1.1 Authentication Requests . . . . . . . . . . . . . . . . . . 4) s +5 613 M +( 3.1.2 Responses to Authentication Requests . . . . . . . . . . . . 5) s +5 602 M +( 3.1.3 The "none" Authentication Request . . . . . . . . . . . . . 6) s +5 591 M +( 3.1.4 Completion of User Authentication . . . . . . . . . . . . . 6) s +5 580 M +( 3.1.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . 7) s +5 569 M +( 3.2 Authentication Protocol Message Numbers . . . . . . . . . . 7) s +5 558 M +( 3.3 Public Key Authentication Method: publickey . . . . . . . . 8) s +5 547 M +( 3.4 Password Authentication Method: password . . . . . . . . . . 10) s +5 536 M +( 3.5 Host-Based Authentication: hostbased . . . . . . . . . . . . 11) s +5 525 M +( 4. Security Considerations . . . . . . . . . . . . . . . . . . 12) s +5 514 M +( Normative . . . . . . . . . . . . . . . . . . . . . . . . . 13) s +5 503 M +( Informative . . . . . . . . . . . . . . . . . . . . . . . . 13) s +5 492 M +( Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 14) s +5 481 M +( Intellectual Property and Copyright Statements . . . . . . . 15) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 2]) s +_R +S +PStoPSsaved restore +%%Page: (2,3) 2 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 3 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(1. Contributors) s +5 668 M +( The major original contributors of this document were: Tatu Ylonen,) s +5 657 M +( Tero Kivinen, Timo J. Rinne, Sami Lehtinen \(all of SSH Communications) s +5 646 M +( Security Corp\), and Markku-Juhani O. Saarinen \(University of) s +5 635 M +( Jyvaskyla\)) s +5 613 M +( The document editor is: [email protected]. Comments on this) s +5 602 M +( internet draft should be sent to the IETF SECSH working group,) s +5 591 M +( details at: http://ietf.org/html.charters/secsh-charter.html) s +5 569 M +(2. Introduction) s +5 547 M +( The SSH authentication protocol is a general-purpose user) s +5 536 M +( authentication protocol. It is intended to be run over the SSH) s +5 525 M +( transport layer protocol [SSH-TRANS]. This protocol assumes that the) s +5 514 M +( underlying protocols provide integrity and confidentiality) s +5 503 M +( protection.) s +5 481 M +( This document should be read only after reading the SSH architecture) s +5 470 M +( document [SSH-ARCH]. This document freely uses terminology and) s +5 459 M +( notation from the architecture document without reference or further) s +5 448 M +( explanation.) s +5 426 M +( The service name for this protocol is "ssh-userauth".) s +5 404 M +( When this protocol starts, it receives the session identifier from) s +5 393 M +( the lower-level protocol \(this is the exchange hash H from the first) s +5 382 M +( key exchange\). The session identifier uniquely identifies this) s +5 371 M +( session and is suitable for signing in order to prove ownership of a) s +5 360 M +( private key. This protocol also needs to know whether the lower-level) s +5 349 M +( protocol provides confidentiality protection.) s +5 327 M +(3. Conventions Used in This Document) s +5 305 M +( The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",) s +5 294 M +( and "MAY" that appear in this document are to be interpreted as) s +5 283 M +( described in [RFC2119]) s +5 261 M +( The used data types and terminology are specified in the architecture) s +5 250 M +( document [SSH-ARCH]) s +5 228 M +( The architecture document also discusses the algorithm naming) s +5 217 M +( conventions that MUST be used with the SSH protocols.) s +5 195 M +(3.1 The Authentication Protocol Framework) s +5 173 M +( The server drives the authentication by telling the client which) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 3]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 4 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( authentication methods can be used to continue the exchange at any) s +5 679 M +( given time. The client has the freedom to try the methods listed by) s +5 668 M +( the server in any order. This gives the server complete control over) s +5 657 M +( the authentication process if desired, but also gives enough) s +5 646 M +( flexibility for the client to use the methods it supports or that are) s +5 635 M +( most convenient for the user, when multiple methods are offered by) s +5 624 M +( the server.) s +5 602 M +( Authentication methods are identified by their name, as defined in) s +5 591 M +( [SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed as) s +5 580 M +( supported. However, it MAY be sent by the client. The server MUST) s +5 569 M +( always reject this request, unless the client is to be allowed in) s +5 558 M +( without any authentication, in which case the server MUST accept this) s +5 547 M +( request. The main purpose of sending this request is to get the list) s +5 536 M +( of supported methods from the server.) s +5 514 M +( The server SHOULD have a timeout for authentication, and disconnect) s +5 503 M +( if the authentication has not been accepted within the timeout) s +5 492 M +( period. The RECOMMENDED timeout period is 10 minutes. Additionally,) s +5 481 M +( the implementation SHOULD limit the number of failed authentication) s +5 470 M +( attempts a client may perform in a single session \(the RECOMMENDED) s +5 459 M +( limit is 20 attempts\). If the threshold is exceeded, the server) s +5 448 M +( SHOULD disconnect.) s +5 426 M +(3.1.1 Authentication Requests) s +5 404 M +( All authentication requests MUST use the following message format.) s +5 393 M +( Only the first few fields are defined; the remaining fields depend on) s +5 382 M +( the authentication method.) s +5 360 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 349 M +( string user name \(in ISO-10646 UTF-8 encoding [RFC2279]\)) s +5 338 M +( string service name \(in US-ASCII\)) s +5 327 M +( string method name \(US-ASCII\)) s +5 316 M +( The rest of the packet is method-specific.) s +5 294 M +( The user name and service are repeated in every new authentication) s +5 283 M +( attempt, and MAY change. The server implementation MUST carefully) s +5 272 M +( check them in every message, and MUST flush any accumulated) s +5 261 M +( authentication states if they change. If it is unable to flush some) s +5 250 M +( authentication state, it MUST disconnect if the user or service name) s +5 239 M +( changes.) s +5 217 M +( The service name specifies the service to start after authentication.) s +5 206 M +( There may be several different authenticated services provided. If) s +5 195 M +( the requested service is not available, the server MAY disconnect) s +5 184 M +( immediately or at any later time. Sending a proper disconnect) s +5 173 M +( message is RECOMMENDED. In any case, if the service does not exist,) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 4]) s +_R +S +PStoPSsaved restore +%%Page: (4,5) 3 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 5 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( authentication MUST NOT be accepted.) s +5 668 M +( If the requested user does not exist, the server MAY disconnect, or) s +5 657 M +( MAY send a bogus list of acceptable authentication methods, but never) s +5 646 M +( accept any. This makes it possible for the server to avoid) s +5 635 M +( disclosing information on which accounts exist. In any case, if the) s +5 624 M +( user does not exist, the authentication request MUST NOT be accepted.) s +5 602 M +( While there is usually little point for clients to send requests that) s +5 591 M +( the server does not list as acceptable, sending such requests is not) s +5 580 M +( an error, and the server SHOULD simply reject requests that it does) s +5 569 M +( not recognize.) s +5 547 M +( An authentication request MAY result in a further exchange of) s +5 536 M +( messages. All such messages depend on the authentication method) s +5 525 M +( used, and the client MAY at any time continue with a new) s +5 514 M +( SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST) s +5 503 M +( abandon the previous authentication attempt and continue with the new) s +5 492 M +( one.) s +5 470 M +(3.1.2 Responses to Authentication Requests) s +5 448 M +( If the server rejects the authentication request, it MUST respond) s +5 437 M +( with the following:) s +5 415 M +( byte SSH_MSG_USERAUTH_FAILURE) s +5 404 M +( string authentications that can continue) s +5 393 M +( boolean partial success) s +5 371 M +( "Authentications that can continue" is a comma-separated list of) s +5 360 M +( authentication method names that may productively continue the) s +5 349 M +( authentication dialog.) s +5 327 M +( It is RECOMMENDED that servers only include those methods in the list) s +5 316 M +( that are actually useful. However, it is not illegal to include) s +5 305 M +( methods that cannot be used to authenticate the user.) s +5 283 M +( Already successfully completed authentications SHOULD NOT be included) s +5 272 M +( in the list, unless they really should be performed again for some) s +5 261 M +( reason.) s +5 239 M +( "Partial success" MUST be TRUE if the authentication request to which) s +5 228 M +( this is a response was successful. It MUST be FALSE if the request) s +5 217 M +( was not successfully processed.) s +5 195 M +( When the server accepts authentication, it MUST respond with the) s +5 184 M +( following:) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 5]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 6 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( byte SSH_MSG_USERAUTH_SUCCESS) s +5 668 M +( Note that this is not sent after each step in a multi-method) s +5 657 M +( authentication sequence, but only when the authentication is) s +5 646 M +( complete.) s +5 624 M +( The client MAY send several authentication requests without waiting) s +5 613 M +( for responses from previous requests. The server MUST process each) s +5 602 M +( request completely and acknowledge any failed requests with a) s +5 591 M +( SSH_MSG_USERAUTH_FAILURE message before processing the next request.) s +5 569 M +( A request that results in further exchange of messages will be) s +5 558 M +( aborted by a second request. It is not possible to send a second) s +5 547 M +( request without waiting for a response from the server, if the first) s +5 536 M +( request will result in further exchange of messages. No) s +5 525 M +( SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted method.) s +5 503 M +( SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When) s +5 492 M +( SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication) s +5 481 M +( requests received after that SHOULD be silently ignored.) s +5 459 M +( Any non-authentication messages sent by the client after the request) s +5 448 M +( that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST be passed) s +5 437 M +( to the service being run on top of this protocol. Such messages can) s +5 426 M +( be identified by their message numbers \(see Section Message Numbers) s +5 415 M +( \(Section 3.2\)\).) s +5 393 M +(3.1.3 The "none" Authentication Request) s +5 371 M +( A client may request a list of authentication methods that may) s +5 360 M +( continue by using the "none" authentication method.) s +5 338 M +( If no authentication at all is needed for the user, the server MUST) s +5 327 M +( return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST return) s +5 316 M +( SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of) s +5 305 M +( authentication methods that can continue.) s +5 283 M +( This method MUST NOT be listed as supported by the server.) s +5 261 M +(3.1.4 Completion of User Authentication) s +5 239 M +( Authentication is complete when the server has responded with) s +5 228 M +( SSH_MSG_USERAUTH_SUCCESS; all authentication related messages) s +5 217 M +( received after sending this message SHOULD be silently ignored.) s +5 195 M +( After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the) s +5 184 M +( requested service.) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 6]) s +_R +S +PStoPSsaved restore +%%Page: (6,7) 4 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 7 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(3.1.5 Banner Message) s +5 668 M +( In some jurisdictions, sending a warning message before) s +5 657 M +( authentication may be relevant for getting legal protection. Many) s +5 646 M +( UNIX machines, for example, normally display text from `/etc/issue',) s +5 635 M +( or use "tcp wrappers" or similar software to display a banner before) s +5 624 M +( issuing a login prompt.) s +5 602 M +( The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any time) s +5 591 M +( before authentication is successful. This message contains text to) s +5 580 M +( be displayed to the client user before authentication is attempted.) s +5 569 M +( The format is as follows:) s +5 547 M +( byte SSH_MSG_USERAUTH_BANNER) s +5 536 M +( string message \(ISO-10646 UTF-8\)) s +5 525 M +( string language tag \(as defined in [RFC3066]\)) s +5 503 M +( The client SHOULD by default display the message on the screen.) s +5 492 M +( However, since the message is likely to be sent for every login) s +5 481 M +( attempt, and since some client software will need to open a separate) s +5 470 M +( window for this warning, the client software may allow the user to) s +5 459 M +( explicitly disable the display of banners from the server. The) s +5 448 M +( message may consist of multiple lines.) s +5 426 M +( If the message string is displayed, control character filtering) s +5 415 M +( discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending) s +5 404 M +( terminal control characters.) s +5 382 M +(3.2 Authentication Protocol Message Numbers) s +5 360 M +( All message numbers used by this authentication protocol are in the) s +5 349 M +( range from 50 to 79, which is part of the range reserved for) s +5 338 M +( protocols running on top of the SSH transport layer protocol.) s +5 316 M +( Message numbers of 80 and higher are reserved for protocols running) s +5 305 M +( after this authentication protocol, so receiving one of them before) s +5 294 M +( authentication is complete is an error, to which the server MUST) s +5 283 M +( respond by disconnecting \(preferably with a proper disconnect message) s +5 272 M +( sent first to ease troubleshooting\).) s +5 250 M +( After successful authentication, such messages are passed to the) s +5 239 M +( higher-level service.) s +5 217 M +( These are the general authentication message codes:) s +5 195 M +( #define SSH_MSG_USERAUTH_REQUEST 50) s +5 184 M +( #define SSH_MSG_USERAUTH_FAILURE 51) s +5 173 M +( #define SSH_MSG_USERAUTH_SUCCESS 52) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 7]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 8 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( #define SSH_MSG_USERAUTH_BANNER 53) s +5 668 M +( In addition to the above, there is a range of message numbers) s +5 657 M +( \(60..79\) reserved for method-specific messages. These messages are) s +5 646 M +( only sent by the server \(client sends only SSH_MSG_USERAUTH_REQUEST) s +5 635 M +( messages\). Different authentication methods reuse the same message) s +5 624 M +( numbers.) s +5 602 M +(3.3 Public Key Authentication Method: publickey) s +5 580 M +( The only REQUIRED authentication method is public key authentication.) s +5 569 M +( All implementations MUST support this method; however, not all users) s +5 558 M +( need to have public keys, and most local policies are not likely to) s +5 547 M +( require public key authentication for all users in the near future.) s +5 525 M +( With this method, the possession of a private key serves as) s +5 514 M +( authentication. This method works by sending a signature created) s +5 503 M +( with a private key of the user. The server MUST check that the key) s +5 492 M +( is a valid authenticator for the user, and MUST check that the) s +5 481 M +( signature is valid. If both hold, the authentication request MUST be) s +5 470 M +( accepted; otherwise it MUST be rejected. \(Note that the server MAY) s +5 459 M +( require additional authentications after successful authentication.\)) s +5 437 M +( Private keys are often stored in an encrypted form at the client) s +5 426 M +( host, and the user must supply a passphrase before the signature can) s +5 415 M +( be generated. Even if they are not, the signing operation involves) s +5 404 M +( some expensive computation. To avoid unnecessary processing and user) s +5 393 M +( interaction, the following message is provided for querying whether) s +5 382 M +( authentication using the key would be acceptable.) s +5 360 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 349 M +( string user name) s +5 338 M +( string service) s +5 327 M +( string "publickey") s +5 316 M +( boolean FALSE) s +5 305 M +( string public key algorithm name) s +5 294 M +( string public key blob) s +5 272 M +( Public key algorithms are defined in the transport layer) s +5 261 M +( specification [SSH-TRANS]. The public key blob may contain) s +5 250 M +( certificates.) s +5 228 M +( Any public key algorithm may be offered for use in authentication.) s +5 217 M +( In particular, the list is not constrained by what was negotiated) s +5 206 M +( during key exchange. If the server does not support some algorithm,) s +5 195 M +( it MUST simply reject the request.) s +5 173 M +( The server MUST respond to this message with either) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 8]) s +_R +S +PStoPSsaved restore +%%Page: (8,9) 5 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 9 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( SSH_MSG_USERAUTH_FAILURE or with the following:) s +5 668 M +( byte SSH_MSG_USERAUTH_PK_OK) s +5 657 M +( string public key algorithm name from the request) s +5 646 M +( string public key blob from the request) s +5 624 M +( To perform actual authentication, the client MAY then send a) s +5 613 M +( signature generated using the private key. The client MAY send the) s +5 602 M +( signature directly without first verifying whether the key is) s +5 591 M +( acceptable. The signature is sent using the following packet:) s +5 569 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 558 M +( string user name) s +5 547 M +( string service) s +5 536 M +( string "publickey") s +5 525 M +( boolean TRUE) s +5 514 M +( string public key algorithm name) s +5 503 M +( string public key to be used for authentication) s +5 492 M +( string signature) s +5 470 M +( Signature is a signature by the corresponding private key over the) s +5 459 M +( following data, in the following order:) s +5 437 M +( string session identifier) s +5 426 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 415 M +( string user name) s +5 404 M +( string service) s +5 393 M +( string "publickey") s +5 382 M +( boolean TRUE) s +5 371 M +( string public key algorithm name) s +5 360 M +( string public key to be used for authentication) s +5 338 M +( When the server receives this message, it MUST check whether the) s +5 327 M +( supplied key is acceptable for authentication, and if so, it MUST) s +5 316 M +( check whether the signature is correct.) s +5 294 M +( If both checks succeed, this method is successful. Note that the) s +5 283 M +( server may require additional authentications. The server MUST) s +5 272 M +( respond with SSH_MSG_USERAUTH_SUCCESS \(if no more authentications are) s +5 261 M +( needed\), or SSH_MSG_USERAUTH_FAILURE \(if the request failed, or more) s +5 250 M +( authentications are needed\).) s +5 228 M +( The following method-specific message numbers are used by the) s +5 217 M +( publickey authentication method.) s +5 195 M +( /* Key-based */) s +5 184 M +( #define SSH_MSG_USERAUTH_PK_OK 60) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 9]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 10 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(3.4 Password Authentication Method: password) s +5 668 M +( Password authentication uses the following packets. Note that a) s +5 657 M +( server MAY request the user to change the password. All) s +5 646 M +( implementations SHOULD support password authentication.) s +5 624 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 613 M +( string user name) s +5 602 M +( string service) s +5 591 M +( string "password") s +5 580 M +( boolean FALSE) s +5 569 M +( string plaintext password \(ISO-10646 UTF-8\)) s +5 547 M +( Note that the password is encoded in ISO-10646 UTF-8. It is up to) s +5 536 M +( the server how it interprets the password and validates it against) s +5 525 M +( the password database. However, if the client reads the password in) s +5 514 M +( some other encoding \(e.g., ISO 8859-1 \(ISO Latin1\)\), it MUST convert) s +5 503 M +( the password to ISO-10646 UTF-8 before transmitting, and the server) s +5 492 M +( MUST convert the password to the encoding used on that system for) s +5 481 M +( passwords.) s +5 459 M +( Note that even though the cleartext password is transmitted in the) s +5 448 M +( packet, the entire packet is encrypted by the transport layer. Both) s +5 437 M +( the server and the client should check whether the underlying) s +5 426 M +( transport layer provides confidentiality \(i.e., if encryption is) s +5 415 M +( being used\). If no confidentiality is provided \(none cipher\),) s +5 404 M +( password authentication SHOULD be disabled. If there is no) s +5 393 M +( confidentiality or no MAC, password change SHOULD be disabled.) s +5 371 M +( Normally, the server responds to this message with success or) s +5 360 M +( failure. However, if the password has expired the server SHOULD) s +5 349 M +( indicate this by responding with SSH_MSG_USERAUTH_PASSWD_CHANGEREQ.) s +5 338 M +( In anycase the server MUST NOT allow an expired password to be used) s +5 327 M +( for authentication.) s +5 305 M +( byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) s +5 294 M +( string prompt \(ISO-10646 UTF-8\)) s +5 283 M +( string language tag \(as defined in [RFC3066]\)) s +5 261 M +( In this case, the client MAY continue with a different authentication) s +5 250 M +( method, or request a new password from the user and retry password) s +5 239 M +( authentication using the following message. The client MAY also send) s +5 228 M +( this message instead of the normal password authentication request) s +5 217 M +( without the server asking for it.) s +5 195 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 184 M +( string user name) s +5 173 M +( string service) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 10]) s +_R +S +PStoPSsaved restore +%%Page: (10,11) 6 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 11 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( string "password") s +5 679 M +( boolean TRUE) s +5 668 M +( string plaintext old password \(ISO-10646 UTF-8\)) s +5 657 M +( string plaintext new password \(ISO-10646 UTF-8\)) s +5 635 M +( The server must reply to request message with) s +5 624 M +( SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another) s +5 613 M +( SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as) s +5 602 M +( follows:) s +5 580 M +( SSH_MSG_USERAUTH_SUCCESS The password has been changed, and) s +5 569 M +( authentication has been successfully completed.) s +5 547 M +( SSH_MSG_USERAUTH_FAILURE with partial success The password has) s +5 536 M +( been changed, but more authentications are needed.) s +5 514 M +( SSH_MSG_USERAUTH_FAILURE without partial success The password has) s +5 503 M +( not been changed. Either password changing was not supported, or) s +5 492 M +( the old password was bad. Note that if the server has already) s +5 481 M +( sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we know that it supports) s +5 470 M +( changing the password.) s +5 448 M +( SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because) s +5 437 M +( the new password was not acceptable \(e.g. too easy to guess\).) s +5 415 M +( The following method-specific message numbers are used by the) s +5 404 M +( password authentication method.) s +5 382 M +( #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60) s +5 349 M +(3.5 Host-Based Authentication: hostbased) s +5 327 M +( Some sites wish to allow authentication based on the host where the) s +5 316 M +( user is coming from, and the user name on the remote host. While) s +5 305 M +( this form of authentication is not suitable for high-security sites,) s +5 294 M +( it can be very convenient in many environments. This form of) s +5 283 M +( authentication is OPTIONAL. When used, special care SHOULD be taken) s +5 272 M +( to prevent a regular user from obtaining the private host key.) s +5 250 M +( The client requests this form of authentication by sending the) s +5 239 M +( following message. It is similar to the UNIX "rhosts" and) s +5 228 M +( "hosts.equiv" styles of authentication, except that the identity of) s +5 217 M +( the client host is checked more rigorously.) s +5 195 M +( This method works by having the client send a signature created with) s +5 184 M +( the private key of the client host, which the server checks with that) s +5 173 M +( host's public key. Once the client host's identity is established,) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 11]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 12 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( authorization \(but no further authentication\) is performed based on) s +5 679 M +( the user names on the server and the client, and the client host) s +5 668 M +( name.) s +5 646 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 635 M +( string user name) s +5 624 M +( string service) s +5 613 M +( string "hostbased") s +5 602 M +( string public key algorithm for host key) s +5 591 M +( string public host key and certificates for client host) s +5 580 M +( string client host name \(FQDN; US-ASCII\)) s +5 569 M +( string user name on the client host \(ISO-10646 UTF-8\)) s +5 558 M +( string signature) s +5 536 M +( Public key algorithm names for use in "public key algorithm for host) s +5 525 M +( key" are defined in the transport layer specification. The "public) s +5 514 M +( host key for client host" may include certificates.) s +5 492 M +( Signature is a signature with the private host key of the following) s +5 481 M +( data, in this order:) s +5 459 M +( string session identifier) s +5 448 M +( byte SSH_MSG_USERAUTH_REQUEST) s +5 437 M +( string user name) s +5 426 M +( string service) s +5 415 M +( string "hostbased") s +5 404 M +( string public key algorithm for host key) s +5 393 M +( string public host key and certificates for client host) s +5 382 M +( string client host name \(FQDN; US-ASCII\)) s +5 371 M +( string user name on the client host\(ISO-10646 UTF-8\)) s +5 349 M +( The server MUST verify that the host key actually belongs to the) s +5 338 M +( client host named in the message, that the given user on that host is) s +5 327 M +( allowed to log in, and that the signature is a valid signature on the) s +5 316 M +( appropriate value by the given host key. The server MAY ignore the) s +5 305 M +( client user name, if it wants to authenticate only the client host.) s +5 283 M +( It is RECOMMENDED that whenever possible, the server perform) s +5 272 M +( additional checks to verify that the network address obtained from) s +5 261 M +( the \(untrusted\) network matches the given client host name. This) s +5 250 M +( makes exploiting compromised host keys more difficult. Note that) s +5 239 M +( this may require special handling for connections coming through a) s +5 228 M +( firewall.) s +5 206 M +(4. Security Considerations) s +5 184 M +( The purpose of this protocol is to perform client user) s +5 173 M +( authentication. It assumed that this runs over a secure transport) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 12]) s +_R +S +PStoPSsaved restore +%%Page: (12,13) 7 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 13 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( layer protocol, which has already authenticated the server machine,) s +5 679 M +( established an encrypted communications channel, and computed a) s +5 668 M +( unique session identifier for this session. The transport layer) s +5 657 M +( provides forward secrecy for password authentication and other) s +5 646 M +( methods that rely on secret data.) s +5 624 M +( Full security considerations for this protocol are provided in) s +5 613 M +( Section 8 of [SSH-ARCH]) s +5 591 M +(Normative) s +5 569 M +( [SSH-ARCH]) s +5 558 M +( Ylonen, T., "SSH Protocol Architecture", I-D) s +5 547 M +( draft-ietf-architecture-15.txt, Oct 2003.) s +5 525 M +( [SSH-TRANS]) s +5 514 M +( Ylonen, T., "SSH Transport Layer Protocol", I-D) s +5 503 M +( draft-ietf-transport-17.txt, Oct 2003.) s +5 481 M +( [SSH-USERAUTH]) s +5 470 M +( Ylonen, T., "SSH Authentication Protocol", I-D) s +5 459 M +( draft-ietf-userauth-18.txt, Oct 2003.) s +5 437 M +( [SSH-CONNECT]) s +5 426 M +( Ylonen, T., "SSH Connection Protocol", I-D) s +5 415 M +( draft-ietf-connect-18.txt, Oct 2003.) s +5 393 M +( [SSH-NUMBERS]) s +5 382 M +( Lehtinen, S. and D. Moffat, "SSH Protocol Assigned) s +5 371 M +( Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct) s +5 360 M +( 2003.) s +5 338 M +( [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate) s +5 327 M +( Requirement Levels", BCP 14, RFC 2119, March 1997.) s +5 305 M +(Informative) s +5 283 M +( [RFC3066] Alvestrand, H., "Tags for the Identification of) s +5 272 M +( Languages", BCP 47, RFC 3066, January 2001.) s +5 250 M +( [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO) s +5 239 M +( 10646", RFC 2279, January 1998.) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 13]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 14 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(Authors' Addresses) s +5 668 M +( Tatu Ylonen) s +5 657 M +( SSH Communications Security Corp) s +5 646 M +( Fredrikinkatu 42) s +5 635 M +( HELSINKI FIN-00100) s +5 624 M +( Finland) s +5 602 M +( EMail: [email protected]) s +5 569 M +( Darren J. Moffat \(editor\)) s +5 558 M +( Sun Microsystems, Inc) s +5 547 M +( 17 Network Circle) s +5 536 M +( Menlo Park 95025) s +5 525 M +( USA) s +5 503 M +( EMail: [email protected]) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 14]) s +_R +S +PStoPSsaved restore +%%Page: (14,15) 8 +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 0.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +/showpage{}def/copypage{}def/erasepage{}def +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 15 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +(Intellectual Property Statement) s +5 668 M +( The IETF takes no position regarding the validity or scope of any) s +5 657 M +( intellectual property or other rights that might be claimed to) s +5 646 M +( pertain to the implementation or use of the technology described in) s +5 635 M +( this document or the extent to which any license under such rights) s +5 624 M +( might or might not be available; neither does it represent that it) s +5 613 M +( has made any effort to identify any such rights. Information on the) s +5 602 M +( IETF's procedures with respect to rights in standards-track and) s +5 591 M +( standards-related documentation can be found in BCP-11. Copies of) s +5 580 M +( claims of rights made available for publication and any assurances of) s +5 569 M +( licenses to be made available, or the result of an attempt made to) s +5 558 M +( obtain a general license or permission for the use of such) s +5 547 M +( proprietary rights by implementors or users of this specification can) s +5 536 M +( be obtained from the IETF Secretariat.) s +5 514 M +( The IETF invites any interested party to bring to its attention any) s +5 503 M +( copyrights, patents or patent applications, or other proprietary) s +5 492 M +( rights which may cover technology that may be required to practice) s +5 481 M +( this standard. Please address the information to the IETF Executive) s +5 470 M +( Director.) s +5 448 M +( The IETF has been notified of intellectual property rights claimed in) s +5 437 M +( regard to some or all of the specification contained in this) s +5 426 M +( document. For more information consult the online list of claimed) s +5 415 M +( rights.) s +5 382 M +(Full Copyright Statement) s +5 360 M +( Copyright \(C\) The Internet Society \(2002\). All Rights Reserved.) s +5 338 M +( This document and translations of it may be copied and furnished to) s +5 327 M +( others, and derivative works that comment on or otherwise explain it) s +5 316 M +( or assist in its implementation may be prepared, copied, published) s +5 305 M +( and distributed, in whole or in part, without restriction of any) s +5 294 M +( kind, provided that the above copyright notice and this paragraph are) s +5 283 M +( included on all such copies and derivative works. However, this) s +5 272 M +( document itself may not be modified in any way, such as by removing) s +5 261 M +( the copyright notice or references to the Internet Society or other) s +5 250 M +( Internet organizations, except as needed for the purpose of) s +5 239 M +( developing Internet standards in which case the procedures for) s +5 228 M +( copyrights defined in the Internet Standards process must be) s +5 217 M +( followed, or as required to translate it into languages other than) s +5 206 M +( English.) s +5 184 M +( The limited permissions granted above are perpetual and will not be) s +5 173 M +( revoked by the Internet Society or its successors or assignees.) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 15]) s +_R +S +PStoPSsaved restore +userdict/PStoPSsaved save put +PStoPSmatrix setmatrix +595.000000 421.271378 translate +90 rotate +0.706651 dup scale +userdict/PStoPSmatrix matrix currentmatrix put +userdict/PStoPSclip{0 0 moveto + 595.000000 0 rlineto 0 842.000000 rlineto -595.000000 0 rlineto + closepath}put initclip +PStoPSxform concat +%%BeginPageSetup +_S +75 0 translate +/pagenum 16 def +/fname () def +/fdir () def +/ftail () def +/user_header_p false def +%%EndPageSetup +5 723 M +(Internet-Draft SSH Authentication Protocol September 2002) s +5 690 M +( This document and the information contained herein is provided on an) s +5 679 M +( "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING) s +5 668 M +( TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING) s +5 657 M +( BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION) s +5 646 M +( HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF) s +5 635 M +( MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.) s +5 602 M +(Acknowledgment) s +5 580 M +( Funding for the RFC Editor function is currently provided by the) s +5 569 M +( Internet Society.) s +5 129 M +(Ylonen & Moffat Expires March 2, 2003 [Page 16]) s +_R +S +PStoPSsaved restore +%%Trailer +%%Pages: 16 +%%DocumentNeededResources: font Courier-Bold Courier +%%EOF diff --git a/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt new file mode 100644 index 0000000000..9dae578a35 --- /dev/null +++ b/lib/ssh/doc/standard/draft-ietf-secsh-userauth-18.txt @@ -0,0 +1,896 @@ + + + +Network Working Group T. Ylonen +Internet-Draft SSH Communications Security Corp +Expires: March 2, 2003 D. Moffat, Ed. + Sun Microsystems, Inc + September 2002 + + + SSH Authentication Protocol + draft-ietf-secsh-userauth-18.txt + +Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that other + groups may also distribute working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at http:// + www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on March 2, 2003. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + SSH is a protocol for secure remote login and other secure network + services over an insecure network. This document describes the SSH + authentication protocol framework and public key, password, and + host-based client authentication methods. Additional authentication + methods are described in separate documents. The SSH authentication + protocol runs on top of the SSH transport layer protocol and provides + a single authenticated tunnel for the SSH connection protocol. + + + + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 1] + +Internet-Draft SSH Authentication Protocol September 2002 + + +Table of Contents + + 1. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Conventions Used in This Document . . . . . . . . . . . . . 3 + 3.1 The Authentication Protocol Framework . . . . . . . . . . . 3 + 3.1.1 Authentication Requests . . . . . . . . . . . . . . . . . . 4 + 3.1.2 Responses to Authentication Requests . . . . . . . . . . . . 5 + 3.1.3 The "none" Authentication Request . . . . . . . . . . . . . 6 + 3.1.4 Completion of User Authentication . . . . . . . . . . . . . 6 + 3.1.5 Banner Message . . . . . . . . . . . . . . . . . . . . . . . 7 + 3.2 Authentication Protocol Message Numbers . . . . . . . . . . 7 + 3.3 Public Key Authentication Method: publickey . . . . . . . . 8 + 3.4 Password Authentication Method: password . . . . . . . . . . 10 + 3.5 Host-Based Authentication: hostbased . . . . . . . . . . . . 11 + 4. Security Considerations . . . . . . . . . . . . . . . . . . 12 + Normative . . . . . . . . . . . . . . . . . . . . . . . . . 13 + Informative . . . . . . . . . . . . . . . . . . . . . . . . 13 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 14 + Intellectual Property and Copyright Statements . . . . . . . 15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 2] + +Internet-Draft SSH Authentication Protocol September 2002 + + +1. Contributors + + The major original contributors of this document were: Tatu Ylonen, + Tero Kivinen, Timo J. Rinne, Sami Lehtinen (all of SSH Communications + Security Corp), and Markku-Juhani O. Saarinen (University of + Jyvaskyla) + + The document editor is: [email protected]. Comments on this + internet draft should be sent to the IETF SECSH working group, + details at: http://ietf.org/html.charters/secsh-charter.html + +2. Introduction + + The SSH authentication protocol is a general-purpose user + authentication protocol. It is intended to be run over the SSH + transport layer protocol [SSH-TRANS]. This protocol assumes that the + underlying protocols provide integrity and confidentiality + protection. + + This document should be read only after reading the SSH architecture + document [SSH-ARCH]. This document freely uses terminology and + notation from the architecture document without reference or further + explanation. + + The service name for this protocol is "ssh-userauth". + + When this protocol starts, it receives the session identifier from + the lower-level protocol (this is the exchange hash H from the first + key exchange). The session identifier uniquely identifies this + session and is suitable for signing in order to prove ownership of a + private key. This protocol also needs to know whether the lower-level + protocol provides confidentiality protection. + +3. Conventions Used in This Document + + The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", + and "MAY" that appear in this document are to be interpreted as + described in [RFC2119] + + The used data types and terminology are specified in the architecture + document [SSH-ARCH] + + The architecture document also discusses the algorithm naming + conventions that MUST be used with the SSH protocols. + +3.1 The Authentication Protocol Framework + + The server drives the authentication by telling the client which + + + +Ylonen & Moffat Expires March 2, 2003 [Page 3] + +Internet-Draft SSH Authentication Protocol September 2002 + + + authentication methods can be used to continue the exchange at any + given time. The client has the freedom to try the methods listed by + the server in any order. This gives the server complete control over + the authentication process if desired, but also gives enough + flexibility for the client to use the methods it supports or that are + most convenient for the user, when multiple methods are offered by + the server. + + Authentication methods are identified by their name, as defined in + [SSH-ARCH]. The "none" method is reserved, and MUST NOT be listed as + supported. However, it MAY be sent by the client. The server MUST + always reject this request, unless the client is to be allowed in + without any authentication, in which case the server MUST accept this + request. The main purpose of sending this request is to get the list + of supported methods from the server. + + The server SHOULD have a timeout for authentication, and disconnect + if the authentication has not been accepted within the timeout + period. The RECOMMENDED timeout period is 10 minutes. Additionally, + the implementation SHOULD limit the number of failed authentication + attempts a client may perform in a single session (the RECOMMENDED + limit is 20 attempts). If the threshold is exceeded, the server + SHOULD disconnect. + +3.1.1 Authentication Requests + + All authentication requests MUST use the following message format. + Only the first few fields are defined; the remaining fields depend on + the authentication method. + + byte SSH_MSG_USERAUTH_REQUEST + string user name (in ISO-10646 UTF-8 encoding [RFC2279]) + string service name (in US-ASCII) + string method name (US-ASCII) + The rest of the packet is method-specific. + + The user name and service are repeated in every new authentication + attempt, and MAY change. The server implementation MUST carefully + check them in every message, and MUST flush any accumulated + authentication states if they change. If it is unable to flush some + authentication state, it MUST disconnect if the user or service name + changes. + + The service name specifies the service to start after authentication. + There may be several different authenticated services provided. If + the requested service is not available, the server MAY disconnect + immediately or at any later time. Sending a proper disconnect + message is RECOMMENDED. In any case, if the service does not exist, + + + +Ylonen & Moffat Expires March 2, 2003 [Page 4] + +Internet-Draft SSH Authentication Protocol September 2002 + + + authentication MUST NOT be accepted. + + If the requested user does not exist, the server MAY disconnect, or + MAY send a bogus list of acceptable authentication methods, but never + accept any. This makes it possible for the server to avoid + disclosing information on which accounts exist. In any case, if the + user does not exist, the authentication request MUST NOT be accepted. + + While there is usually little point for clients to send requests that + the server does not list as acceptable, sending such requests is not + an error, and the server SHOULD simply reject requests that it does + not recognize. + + An authentication request MAY result in a further exchange of + messages. All such messages depend on the authentication method + used, and the client MAY at any time continue with a new + SSH_MSG_USERAUTH_REQUEST message, in which case the server MUST + abandon the previous authentication attempt and continue with the new + one. + +3.1.2 Responses to Authentication Requests + + If the server rejects the authentication request, it MUST respond + with the following: + + byte SSH_MSG_USERAUTH_FAILURE + string authentications that can continue + boolean partial success + + "Authentications that can continue" is a comma-separated list of + authentication method names that may productively continue the + authentication dialog. + + It is RECOMMENDED that servers only include those methods in the list + that are actually useful. However, it is not illegal to include + methods that cannot be used to authenticate the user. + + Already successfully completed authentications SHOULD NOT be included + in the list, unless they really should be performed again for some + reason. + + "Partial success" MUST be TRUE if the authentication request to which + this is a response was successful. It MUST be FALSE if the request + was not successfully processed. + + When the server accepts authentication, it MUST respond with the + following: + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 5] + +Internet-Draft SSH Authentication Protocol September 2002 + + + byte SSH_MSG_USERAUTH_SUCCESS + + Note that this is not sent after each step in a multi-method + authentication sequence, but only when the authentication is + complete. + + The client MAY send several authentication requests without waiting + for responses from previous requests. The server MUST process each + request completely and acknowledge any failed requests with a + SSH_MSG_USERAUTH_FAILURE message before processing the next request. + + A request that results in further exchange of messages will be + aborted by a second request. It is not possible to send a second + request without waiting for a response from the server, if the first + request will result in further exchange of messages. No + SSH_MSG_USERAUTH_FAILURE message will be sent for the aborted method. + + SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When + SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication + requests received after that SHOULD be silently ignored. + + Any non-authentication messages sent by the client after the request + that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST be passed + to the service being run on top of this protocol. Such messages can + be identified by their message numbers (see Section Message Numbers + (Section 3.2)). + +3.1.3 The "none" Authentication Request + + A client may request a list of authentication methods that may + continue by using the "none" authentication method. + + If no authentication at all is needed for the user, the server MUST + return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST return + SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of + authentication methods that can continue. + + This method MUST NOT be listed as supported by the server. + +3.1.4 Completion of User Authentication + + Authentication is complete when the server has responded with + SSH_MSG_USERAUTH_SUCCESS; all authentication related messages + received after sending this message SHOULD be silently ignored. + + After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the + requested service. + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 6] + +Internet-Draft SSH Authentication Protocol September 2002 + + +3.1.5 Banner Message + + In some jurisdictions, sending a warning message before + authentication may be relevant for getting legal protection. Many + UNIX machines, for example, normally display text from `/etc/issue', + or use "tcp wrappers" or similar software to display a banner before + issuing a login prompt. + + The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any time + before authentication is successful. This message contains text to + be displayed to the client user before authentication is attempted. + The format is as follows: + + byte SSH_MSG_USERAUTH_BANNER + string message (ISO-10646 UTF-8) + string language tag (as defined in [RFC3066]) + + The client SHOULD by default display the message on the screen. + However, since the message is likely to be sent for every login + attempt, and since some client software will need to open a separate + window for this warning, the client software may allow the user to + explicitly disable the display of banners from the server. The + message may consist of multiple lines. + + If the message string is displayed, control character filtering + discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending + terminal control characters. + +3.2 Authentication Protocol Message Numbers + + All message numbers used by this authentication protocol are in the + range from 50 to 79, which is part of the range reserved for + protocols running on top of the SSH transport layer protocol. + + Message numbers of 80 and higher are reserved for protocols running + after this authentication protocol, so receiving one of them before + authentication is complete is an error, to which the server MUST + respond by disconnecting (preferably with a proper disconnect message + sent first to ease troubleshooting). + + After successful authentication, such messages are passed to the + higher-level service. + + These are the general authentication message codes: + + #define SSH_MSG_USERAUTH_REQUEST 50 + #define SSH_MSG_USERAUTH_FAILURE 51 + #define SSH_MSG_USERAUTH_SUCCESS 52 + + + +Ylonen & Moffat Expires March 2, 2003 [Page 7] + +Internet-Draft SSH Authentication Protocol September 2002 + + + #define SSH_MSG_USERAUTH_BANNER 53 + + In addition to the above, there is a range of message numbers + (60..79) reserved for method-specific messages. These messages are + only sent by the server (client sends only SSH_MSG_USERAUTH_REQUEST + messages). Different authentication methods reuse the same message + numbers. + +3.3 Public Key Authentication Method: publickey + + The only REQUIRED authentication method is public key authentication. + All implementations MUST support this method; however, not all users + need to have public keys, and most local policies are not likely to + require public key authentication for all users in the near future. + + With this method, the possession of a private key serves as + authentication. This method works by sending a signature created + with a private key of the user. The server MUST check that the key + is a valid authenticator for the user, and MUST check that the + signature is valid. If both hold, the authentication request MUST be + accepted; otherwise it MUST be rejected. (Note that the server MAY + require additional authentications after successful authentication.) + + Private keys are often stored in an encrypted form at the client + host, and the user must supply a passphrase before the signature can + be generated. Even if they are not, the signing operation involves + some expensive computation. To avoid unnecessary processing and user + interaction, the following message is provided for querying whether + authentication using the key would be acceptable. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + boolean FALSE + string public key algorithm name + string public key blob + + Public key algorithms are defined in the transport layer + specification [SSH-TRANS]. The public key blob may contain + certificates. + + Any public key algorithm may be offered for use in authentication. + In particular, the list is not constrained by what was negotiated + during key exchange. If the server does not support some algorithm, + it MUST simply reject the request. + + The server MUST respond to this message with either + + + +Ylonen & Moffat Expires March 2, 2003 [Page 8] + +Internet-Draft SSH Authentication Protocol September 2002 + + + SSH_MSG_USERAUTH_FAILURE or with the following: + + byte SSH_MSG_USERAUTH_PK_OK + string public key algorithm name from the request + string public key blob from the request + + To perform actual authentication, the client MAY then send a + signature generated using the private key. The client MAY send the + signature directly without first verifying whether the key is + acceptable. The signature is sent using the following packet: + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + boolean TRUE + string public key algorithm name + string public key to be used for authentication + string signature + + Signature is a signature by the corresponding private key over the + following data, in the following order: + + string session identifier + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "publickey" + boolean TRUE + string public key algorithm name + string public key to be used for authentication + + When the server receives this message, it MUST check whether the + supplied key is acceptable for authentication, and if so, it MUST + check whether the signature is correct. + + If both checks succeed, this method is successful. Note that the + server may require additional authentications. The server MUST + respond with SSH_MSG_USERAUTH_SUCCESS (if no more authentications are + needed), or SSH_MSG_USERAUTH_FAILURE (if the request failed, or more + authentications are needed). + + The following method-specific message numbers are used by the + publickey authentication method. + + /* Key-based */ + #define SSH_MSG_USERAUTH_PK_OK 60 + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 9] + +Internet-Draft SSH Authentication Protocol September 2002 + + +3.4 Password Authentication Method: password + + Password authentication uses the following packets. Note that a + server MAY request the user to change the password. All + implementations SHOULD support password authentication. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "password" + boolean FALSE + string plaintext password (ISO-10646 UTF-8) + + Note that the password is encoded in ISO-10646 UTF-8. It is up to + the server how it interprets the password and validates it against + the password database. However, if the client reads the password in + some other encoding (e.g., ISO 8859-1 (ISO Latin1)), it MUST convert + the password to ISO-10646 UTF-8 before transmitting, and the server + MUST convert the password to the encoding used on that system for + passwords. + + Note that even though the cleartext password is transmitted in the + packet, the entire packet is encrypted by the transport layer. Both + the server and the client should check whether the underlying + transport layer provides confidentiality (i.e., if encryption is + being used). If no confidentiality is provided (none cipher), + password authentication SHOULD be disabled. If there is no + confidentiality or no MAC, password change SHOULD be disabled. + + Normally, the server responds to this message with success or + failure. However, if the password has expired the server SHOULD + indicate this by responding with SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. + In anycase the server MUST NOT allow an expired password to be used + for authentication. + + byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ + string prompt (ISO-10646 UTF-8) + string language tag (as defined in [RFC3066]) + + In this case, the client MAY continue with a different authentication + method, or request a new password from the user and retry password + authentication using the following message. The client MAY also send + this message instead of the normal password authentication request + without the server asking for it. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + + + +Ylonen & Moffat Expires March 2, 2003 [Page 10] + +Internet-Draft SSH Authentication Protocol September 2002 + + + string "password" + boolean TRUE + string plaintext old password (ISO-10646 UTF-8) + string plaintext new password (ISO-10646 UTF-8) + + The server must reply to request message with + SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ. The meaning of these is as + follows: + + SSH_MSG_USERAUTH_SUCCESS The password has been changed, and + authentication has been successfully completed. + + SSH_MSG_USERAUTH_FAILURE with partial success The password has + been changed, but more authentications are needed. + + SSH_MSG_USERAUTH_FAILURE without partial success The password has + not been changed. Either password changing was not supported, or + the old password was bad. Note that if the server has already + sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we know that it supports + changing the password. + + SSH_MSG_USERAUTH_CHANGEREQ The password was not changed because + the new password was not acceptable (e.g. too easy to guess). + + The following method-specific message numbers are used by the + password authentication method. + + #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 + + +3.5 Host-Based Authentication: hostbased + + Some sites wish to allow authentication based on the host where the + user is coming from, and the user name on the remote host. While + this form of authentication is not suitable for high-security sites, + it can be very convenient in many environments. This form of + authentication is OPTIONAL. When used, special care SHOULD be taken + to prevent a regular user from obtaining the private host key. + + The client requests this form of authentication by sending the + following message. It is similar to the UNIX "rhosts" and + "hosts.equiv" styles of authentication, except that the identity of + the client host is checked more rigorously. + + This method works by having the client send a signature created with + the private key of the client host, which the server checks with that + host's public key. Once the client host's identity is established, + + + +Ylonen & Moffat Expires March 2, 2003 [Page 11] + +Internet-Draft SSH Authentication Protocol September 2002 + + + authorization (but no further authentication) is performed based on + the user names on the server and the client, and the client host + name. + + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "hostbased" + string public key algorithm for host key + string public host key and certificates for client host + string client host name (FQDN; US-ASCII) + string user name on the client host (ISO-10646 UTF-8) + string signature + + Public key algorithm names for use in "public key algorithm for host + key" are defined in the transport layer specification. The "public + host key for client host" may include certificates. + + Signature is a signature with the private host key of the following + data, in this order: + + string session identifier + byte SSH_MSG_USERAUTH_REQUEST + string user name + string service + string "hostbased" + string public key algorithm for host key + string public host key and certificates for client host + string client host name (FQDN; US-ASCII) + string user name on the client host(ISO-10646 UTF-8) + + The server MUST verify that the host key actually belongs to the + client host named in the message, that the given user on that host is + allowed to log in, and that the signature is a valid signature on the + appropriate value by the given host key. The server MAY ignore the + client user name, if it wants to authenticate only the client host. + + It is RECOMMENDED that whenever possible, the server perform + additional checks to verify that the network address obtained from + the (untrusted) network matches the given client host name. This + makes exploiting compromised host keys more difficult. Note that + this may require special handling for connections coming through a + firewall. + +4. Security Considerations + + The purpose of this protocol is to perform client user + authentication. It assumed that this runs over a secure transport + + + +Ylonen & Moffat Expires March 2, 2003 [Page 12] + +Internet-Draft SSH Authentication Protocol September 2002 + + + layer protocol, which has already authenticated the server machine, + established an encrypted communications channel, and computed a + unique session identifier for this session. The transport layer + provides forward secrecy for password authentication and other + methods that rely on secret data. + + Full security considerations for this protocol are provided in + Section 8 of [SSH-ARCH] + +Normative + + [SSH-ARCH] + Ylonen, T., "SSH Protocol Architecture", I-D + draft-ietf-architecture-15.txt, Oct 2003. + + [SSH-TRANS] + Ylonen, T., "SSH Transport Layer Protocol", I-D + draft-ietf-transport-17.txt, Oct 2003. + + [SSH-USERAUTH] + Ylonen, T., "SSH Authentication Protocol", I-D + draft-ietf-userauth-18.txt, Oct 2003. + + [SSH-CONNECT] + Ylonen, T., "SSH Connection Protocol", I-D + draft-ietf-connect-18.txt, Oct 2003. + + [SSH-NUMBERS] + Lehtinen, S. and D. Moffat, "SSH Protocol Assigned + Numbers", I-D draft-ietf-secsh-assignednumbers-05.txt, Oct + 2003. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +Informative + + [RFC3066] Alvestrand, H., "Tags for the Identification of + Languages", BCP 47, RFC 3066, January 2001. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 13] + +Internet-Draft SSH Authentication Protocol September 2002 + + +Authors' Addresses + + Tatu Ylonen + SSH Communications Security Corp + Fredrikinkatu 42 + HELSINKI FIN-00100 + Finland + + EMail: [email protected] + + + Darren J. Moffat (editor) + Sun Microsystems, Inc + 17 Network Circle + Menlo Park 95025 + USA + + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 14] + +Internet-Draft SSH Authentication Protocol September 2002 + + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + The IETF has been notified of intellectual property rights claimed in + regard to some or all of the specification contained in this + document. For more information consult the online list of claimed + rights. + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assignees. + + + +Ylonen & Moffat Expires March 2, 2003 [Page 15] + +Internet-Draft SSH Authentication Protocol September 2002 + + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Acknowledgment + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen & Moffat Expires March 2, 2003 [Page 16]
\ No newline at end of file diff --git a/lib/ssh/ebin/.gitignore b/lib/ssh/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssh/ebin/.gitignore diff --git a/lib/ssh/examples/Makefile b/lib/ssh/examples/Makefile new file mode 100644 index 0000000000..cd8b3c797a --- /dev/null +++ b/lib/ssh/examples/Makefile @@ -0,0 +1,76 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(SSH_VSN) + +# ---------------------------------------------------- +# Release Macros +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + + +MODULES = \ + ssh_sample_cli + +ERL_FILES= $(MODULES:=.erl) + +# TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +TARGET_FILES = $(MODULES:=.beam) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa ../ebin -I ../src +EBIN = . + +# ---------------------------------------------------- +# Make Rules +# ---------------------------------------------------- +debug opt: $(TARGET_FILES) + +debug: ERLC_FLAGS += -Ddebug + +clean: + rm -f $(TARGET_FILES) *~ *.beam + +docs: + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/examples + +release_docs_spec: + diff --git a/lib/ssh/examples/ssh_sample_cli.erl b/lib/ssh/examples/ssh_sample_cli.erl new file mode 100644 index 0000000000..2505c1b759 --- /dev/null +++ b/lib/ssh/examples/ssh_sample_cli.erl @@ -0,0 +1,353 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_sample_cli). + +%% api +-export([listen/1, listen/2]). + +%% %% our shell function +%% -export([start_our_shell/1]). + +%% our command functions +-export([cli_prime/1, cli_primes/1, cli_gcd/2, cli_lcm/2, + cli_factors/1, cli_exit/0, cli_rho/1, cli_help/0, + cli_crash/0, cli_users/0, cli_self/0, + cli_user/0, cli_host/0]). + +%% imports +-import(lists, [reverse/1, reverse/2, seq/2, prefix/2]). +-import(math, [sqrt/1]). + + +listen(Port) -> + listen(Port, []). + +listen(Port, Options) -> + ssh_cli:listen(fun(U, H) -> start_our_shell(U, H) end, Port, Options). + +%% our_routines +our_routines() -> + [ + {"crash", cli_crash, " crash the cli"}, + {"exit", cli_exit, " exit application"}, + {"factors", cli_factors,"<int> prime factors of <int>"}, + {"gcd", cli_gcd, "<int> <int> greatest common divisor"}, + {"help", cli_help, " help text"}, + {"lcm", cli_lcm, "<int> <int> least common multiplier"}, + {"prime", cli_prime, "<int> check for primality"}, + {"primes", cli_primes, "<int> print all primes up to <int>"}, + {"rho", cli_rho, "<int> prime factors using rho's alg."}, + {"who", cli_users, " lists users"}, + {"user", cli_user, " print name of user"}, + {"host", cli_host, " print host addr"}, + {"self", cli_self, " print my pid"} + ]. + +%% (we could of course generate this from module_info() something like this) +%% our_routines1() -> +%% {value, {exports, Exports}} = +%% lists:keysearch(exports, 1, module_info()), +%% get_cli(Exports, []). + +%% our_args1(N) -> our_args1(N, ""). +%% our_args1(0, S) -> S; +%% our_args1(N, S) -> our_args1(N-1, S ++ "<int> "). + +%% get_cli([], Acc) -> +%% lists:sort(Acc); +%% get_cli([{A, Arity} | Rest], Acc) -> +%% L = atom_to_list(A), +%% case lists:prefix("cli_", L) of +%% true -> get_cli(Rest, [{tl4(L), A, our_args1(Arity)} | Acc]); +%% false -> get_cli(Rest, Acc) +%% end. + +%% the longest common prefix of two strings +common_prefix([C | R1], [C | R2], Acc) -> + common_prefix(R1, R2, [C | Acc]); +common_prefix(_, _, Acc) -> + reverse(Acc). + +%% longest prefix in a list, given a prefix +longest_prefix(List, Prefix) -> + case [A || {A, _, _} <- List, prefix(Prefix, A)] of + [] -> + {none, List}; + [S | Rest] -> + NewPrefix0 = + lists:foldl(fun(A, P) -> + common_prefix(A, P, []) + end, S, Rest), + NewPrefix = nthtail(length(Prefix), NewPrefix0), + {prefix, NewPrefix, [S | Rest]} + end. + +%%% our expand function (called when the user presses TAB) +%%% input: a reversed list with the row to left of the cursor +%%% output: {yes|no, Expansion, ListofPossibleMatches} +%%% where the atom no yields a beep +%%% Expansion is a string inserted at the cursor +%%% List... is a list that will be printed +%%% Here we beep on prefixes that don't match and when the command +%%% filled in +expand([$ | _]) -> + {no, "", []}; +expand(RevBefore) -> + Before = reverse(RevBefore), + case longest_prefix(our_routines(), Before) of + {prefix, P, [_]} -> + {yes, P ++ " ", []}; + {prefix, "", M} -> + {yes, "", M}; + {prefix, P, _M} -> + {yes, P, []}; + {none, _M} -> + {no, "", []} + end. + +%%% spawns out shell loop, we use plain io to input and output +%%% over ssh (the group module is our group leader, and takes +%%% care of sending input to the ssh_sample_cli server) +start_our_shell(User, Peer) -> + spawn(fun() -> + io:setopts([{expand_fun, fun(Bef) -> expand(Bef) end}]), + io:format("Enter command\n"), + put(user, User), + put(peer_name, Peer), + our_shell_loop() + end). + +%%% an ordinary Read-Eval-Print-loop +our_shell_loop() -> + % Read + Line = io:get_line({format, "CLI> ", []}), + % Eval + Result = eval_cli(Line), + % Print + io:format("---> ~p\n", [Result]), + case Result of + done -> exit(normal); + crash -> 1 / 0; + _ -> our_shell_loop() + end. + +%%% translate a command to a function +command_to_function(Command) -> + case lists:keysearch(Command, 1, our_routines()) of + {value, {_, Proc, _}} -> Proc; + false -> unknown_cli + end. + +%%% evaluate a command line +eval_cli(Line) -> + case string:tokens(Line, " \n") of + [] -> []; + [Command | ArgStrings] -> + Proc = command_to_function(Command), + case fix_args(ArgStrings) of + {ok, Args} -> + case catch apply(?MODULE, Proc, Args) of + {'EXIT', Error} -> + {error, Error}; % wrong_number_of_arguments}; + Result -> + Result + end; + Error -> + Error + end + end. + +%%% make command arguments to integers +fix_args(ArgStrings) -> + case catch [list_to_integer(A) || A <- ArgStrings] of + {'EXIT', _} -> + {error, only_integer_arguments}; + Args -> + {ok, Args} + end. + +%%% the commands, check for reasonable arguments here too +cli_prime(N) when N < 1000000000 -> + rho(N) == [N] andalso is_prime(N); +cli_prime(N) when N < 10000 -> + is_prime(N). + +cli_primes(N) when N < 1000000 -> + primes(N). + +cli_gcd(A, B) when is_integer(A), is_integer(B) -> + gcd(A, B). + +cli_lcm(A, B) when is_integer(A), is_integer(B) -> + lcm(A, B). + +cli_factors(A) when A < 1000000 -> + factors(A). + +cli_user() -> + get(user). + +cli_host() -> + get(peer_name). + +cli_users() -> + case ssh_userauth:get_auth_users() of + {ok, UsersPids} -> + UsersPids; % [U || {U, _} <- UsersPids]; + E -> + E + end. + +cli_self() -> + self(). + +cli_crash() -> + crash. + +cli_rho(A) -> + rho(A). + +cli_exit() -> + done. + +help_str(L) -> + help_str(L, []). +help_str([], Acc) -> + lists:sort(Acc); +help_str([{CommandName, _, HelpS} | Rest], Acc) -> + C = string:left(CommandName, 10), + help_str(Rest, [[C, " ", HelpS, $\n] | Acc]). + +cli_help() -> + HelpString = ["CLI Sample\n" | help_str(our_routines())], + io:format("~s\n", [HelpString]). + +%% a quite simple Sieve of Erastothenes (not tail-recursive, though) +primes(Size) -> + era(sqrt(Size), seq(2,Size)). + +era(Max, [H|T]) when H =< Max -> + [H | era(Max, sieve([H|T], H))]; +era(_Max, L) -> + L. + +sieve([H|T], N) when H rem N =/= 0 -> + [H | sieve(T, N)]; +sieve([_H|T], N) -> + sieve(T, N); +sieve([], _N) -> + []. + +%% another sieve, for getting the next prime incrementally +next_prime([], _) -> + 2; +next_prime([2], 2) -> + 3; +next_prime(Primes, P) -> + next_prime1(Primes, P). + +next_prime1(Primes, P) -> + P1 = P + 2, + case divides(Primes, trunc(sqrt(P1)), P1) of + false -> P1; + true -> next_prime1(Primes, P1) + end. + +divides([], _, _) -> + false; +divides([A | _], Nsqrt, _) when A > Nsqrt -> + false; +divides([A | _], _, N) when N rem A == 0 -> + true; +divides([_ | R], Nsqrt, N) -> + divides(R, Nsqrt, N). + +is_prime(P) -> + lists:all(fun(A) -> P rem A =/= 0 end, primes(trunc(sqrt(P)))). + +%% Normal gcd, Euclid +gcd(R, Q) when abs(Q) < abs(R) -> gcd1(Q,R); +gcd(R, Q) -> gcd1(R,Q). + +gcd1(0, Q) -> Q; +gcd1(R, Q) -> + gcd1(Q rem R, R). + +%% Least common multiple of (R,Q) +lcm(0, _Q) -> 0; +lcm(_R, 0) -> 0; +lcm(R, Q) -> + (Q div gcd(R, Q)) * R. + +%%% Prime factors of a number (na�ve implementation) +factors(N) -> + Nsqrt = trunc(sqrt(N)), + factors([], N, 2, Nsqrt, []). + +factors(_Primes, N, Prime, Nsqrt, Factors) when Prime > Nsqrt -> + reverse(Factors, [N]); +factors(Primes, N, Prime, Nsqrt, Factors) -> + case N rem Prime of + 0 -> + %%io:format("factor ------- ~p\n", [Prime]), + N1 = N div Prime, + factors(Primes, N1, Prime, trunc(sqrt(N1)), [Prime|Factors]); + _ -> + Primes1 = Primes ++ [Prime], + Prime1 = next_prime(Primes1, Prime), + factors(Primes1, N, Prime1, Nsqrt, Factors) + end. + +%%% Prime factors using Rho's algorithm ("reminded" from wikipedia.org) +%%% (should perhaps have used Brent instead, but it's not as readable) +rho_pseudo(X, C, N) -> + (X * X + C) rem N. + +rho(N) when N > 1000 -> + case rho(2, 2, 1, N, fun(X) -> rho_pseudo(X, 1, N) end) of + failure -> + [N]; + F -> + lists:sort(rho(F) ++ rho(N div F)) + end; +rho(N) -> + factors(N). + +rho(X, Y, 1, N, Pseudo) -> + X1 = Pseudo(X), + Y1 = Pseudo(Pseudo(Y)), + D = gcd(absdiff(X1, Y1), N), + rho(X1, Y1, D, N, Pseudo); +rho(_X, _Y, D, N, _Pseudo) when 1 < D, D < N -> + D; +rho(_X, _Y, D, N, _Pseudo) when D == N -> + failure. + +absdiff(A, B) when A > B -> + A - B; +absdiff(A, B) -> + B - A. + +%%% nthtail as in lists, but no badarg if n > the length of list +nthtail(0, A) -> A; +nthtail(N, [_ | A]) -> nthtail(N-1, A); +nthtail(_, _) -> []. diff --git a/lib/ssh/info b/lib/ssh/info new file mode 100644 index 0000000000..41a2a2ccf0 --- /dev/null +++ b/lib/ssh/info @@ -0,0 +1,2 @@ +group: comm +short: Secure Shell application with sftp and ssh support
\ No newline at end of file diff --git a/lib/ssh/priv/.gitignore b/lib/ssh/priv/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssh/priv/.gitignore diff --git a/lib/ssh/src/DSS.asn1 b/lib/ssh/src/DSS.asn1 new file mode 100755 index 0000000000..77aca3808b --- /dev/null +++ b/lib/ssh/src/DSS.asn1 @@ -0,0 +1,20 @@ +DSS DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +-- EXPORTS ALL +-- All types and values defined in this module are exported for use +-- in other ASN.1 modules. + +DSAPrivateKey ::= SEQUENCE { + version INTEGER, + p INTEGER, -- p + q INTEGER, -- q + g INTEGER, -- q + y INTEGER, -- y + x INTEGER -- x +} + +END + + diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile new file mode 100644 index 0000000000..7abf06e52b --- /dev/null +++ b/lib/ssh/src/Makefile @@ -0,0 +1,157 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(SSH_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +MODULES= \ + ssh \ + ssh_sup \ + sshc_sup \ + sshd_sup \ + ssh_channel \ + ssh_connection \ + ssh_connection_handler \ + ssh_connection_manager \ + ssh_connection_controler \ + ssh_shell \ + ssh_system_sup \ + ssh_subsystem_sup \ + ssh_channel_sup \ + ssh_acceptor_sup \ + ssh_acceptor \ + ssh_app \ + ssh_auth\ + ssh_bits \ + ssh_cli \ + ssh_cm \ + ssh_dsa \ + ssh_file \ + ssh_io \ + ssh_math \ + ssh_no_io \ + ssh_rsa \ + ssh_sftp \ + ssh_sftpd \ + ssh_sftpd_file\ + ssh_sftpd_file_api \ + ssh_ssh \ + ssh_sshd \ + ssh_transport \ + ssh_userreg \ + ssh_xfer + +PUBLIC_HRL_FILES= ssh.hrl ssh_userauth.hrl ssh_xfer.hrl + +ERL_FILES= $(MODULES:%=%.erl) $(ASN_ERLS) + +ALL_MODULES= $(MODULES) $(ASN_MODULES) + +TARGET_FILES= $(ALL_MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +APP_FILE= ssh.app +APPUP_FILE= ssh.appup + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBIN)/$(APP_FILE) + +APPUP_SRC= $(APPUP_FILE).src +APPUP_TARGET= $(EBIN)/$(APPUP_FILE) + +ASN_MODULES = PKCS-1 DSS +ASN_ASNS = $(ASN_MODULES:%=%.asn1) +ASN_ERLS = $(ASN_MODULES:%=%.erl) +ASN_HRLS = $(ASN_MODULES:%=%.hrl) +ASN_DBS = $(ASN_MODULES:%=%.asn1db) +ASN_TABLES = $(ASN_MODULES:%=%.table) + +ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +inline + +INTERNAL_HRL_FILES = $(ASN_HRLS) ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa$(EBIN) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +debug: ERLC_FLAGS += -Ddebug + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + rm -f $(ASN_ERLS) $(ASN_HRLS) $(ASN_DBS) + +$(TARGET_FILES): ssh.hrl + +# $(EBIN)/ssh_sftpd_file.$(EMULATOR): ERLC_FLAGS += -pa$(EBIN) +# $(EBIN)/ssh_sftpd_file.$(EMULATOR): $(EBIN)/ssh_sftpd_file_api.$(EMULATOR) + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +%.hrl: %.asn1 + erlc $(ASN_FLAGS) $< + +DSS.hrl DSS.erl: DSS.asn1 +PKCS-1.hrl PKCS-1.erl: PKCS-1.asn1 + +$(EBIN)/ssh_file.$(EMULATOR): $(ASN_HRLS) + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(PUBLIC_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: + diff --git a/lib/ssh/src/PKCS-1.asn1 b/lib/ssh/src/PKCS-1.asn1 new file mode 100755 index 0000000000..e7d6b18c63 --- /dev/null +++ b/lib/ssh/src/PKCS-1.asn1 @@ -0,0 +1,116 @@ +PKCS-1 { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) + modules(0) pkcs-1(1) +} + +-- $Revision: 1.1 $ + +DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +-- IMPORTS id-sha256, id-sha384, id-sha512 +-- FROM NIST-SHA2 { +-- joint-iso-itu-t(2) country(16) us(840) organization(1) +-- gov(101) csor(3) nistalgorithm(4) modules(0) sha2(1) +-- }; + +pkcs-1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 +} + +rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } + +id-RSAES-OAEP OBJECT IDENTIFIER ::= { pkcs-1 7 } + +id-pSpecified OBJECT IDENTIFIER ::= { pkcs-1 9 } + +id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } + +md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } +md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } +sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } +sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } +sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } +sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } + +id-sha1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) oiw(14) secsig(3) + algorithms(2) 26 +} + +id-md2 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 +} + +id-md5 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 +} + +id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } + + +RSAPublicKey ::= SEQUENCE { + modulus INTEGER, -- n + publicExponent INTEGER -- e +} + +RSAPrivateKey ::= SEQUENCE { + version Version, + modulus INTEGER, -- n + publicExponent INTEGER, -- e + privateExponent INTEGER, -- d + prime1 INTEGER, -- p + prime2 INTEGER, -- q + exponent1 INTEGER, -- d mod (p-1) + exponent2 INTEGER, -- d mod (q-1) + coefficient INTEGER, -- (inverse of q) mod p + otherPrimeInfos OtherPrimeInfos OPTIONAL +} + +Version ::= INTEGER { two-prime(0), multi(1) } + (CONSTRAINED BY { + -- version must be multi if otherPrimeInfos present -- + }) + +OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo + +OtherPrimeInfo ::= SEQUENCE { + prime INTEGER, -- ri + exponent INTEGER, -- di + coefficient INTEGER -- ti +} + +Algorithm ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL +} + +AlgorithmNull ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters NULL +} + + +RSASSA-PSS-params ::= SEQUENCE { + hashAlgorithm [0] Algorithm, -- DEFAULT sha1, + maskGenAlgorithm [1] Algorithm, -- DEFAULT mgf1SHA1, + saltLength [2] INTEGER DEFAULT 20, + trailerField [3] TrailerField DEFAULT trailerFieldBC +} + +TrailerField ::= INTEGER { trailerFieldBC(1) } + +DigestInfo ::= SEQUENCE { + digestAlgorithm Algorithm, + digest OCTET STRING +} + +DigestInfoNull ::= SEQUENCE { + digestAlgorithm AlgorithmNull, + digest OCTET STRING +} + + +END -- PKCS1Definitions + diff --git a/lib/ssh/src/prebuild.skip b/lib/ssh/src/prebuild.skip new file mode 100644 index 0000000000..1d7552d98d --- /dev/null +++ b/lib/ssh/src/prebuild.skip @@ -0,0 +1,2 @@ +DSS.asn1db +PKCS-1.asn1db diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src new file mode 100644 index 0000000000..9319f39591 --- /dev/null +++ b/lib/ssh/src/ssh.app.src @@ -0,0 +1,48 @@ +%%% This is an -*- erlang -*- file. + +{application, ssh, + [{description, "SSH-2 for Erlang/OTP"}, + {vsn, "%VSN%"}, + {modules, ['DSS', + 'PKCS-1', + ssh, + ssh_app, + ssh_acceptor, + ssh_acceptor_sup, + ssh_auth, + ssh_bits, + ssh_cli, + ssh_channel, + ssh_channel_sup, + ssh_cm, + ssh_connection, + ssh_connection_handler, + ssh_connection_manager, + ssh_connection_controler, + ssh_shell, + sshc_sup, + sshd_sup, + ssh_dsa, + ssh_file, + ssh_io, + ssh_math, + ssh_no_io, + ssh_rsa, + ssh_sftp, + ssh_sftpd, + ssh_sftpd_file, + ssh_sftpd_file_api, + ssh_ssh, + ssh_sshd, + ssh_subsystem_sup, + ssh_sup, + ssh_system_sup, + ssh_transport, + ssh_userreg, + ssh_xfer]}, + {registered, []}, + {applications, [kernel, stdlib, crypto]}, + {env, []}, + {mod, {ssh_app, []}}]}. + + diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src new file mode 100644 index 0000000000..3bf772b42b --- /dev/null +++ b/lib/ssh/src/ssh.appup.src @@ -0,0 +1,37 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +{"%VSN%", + [ + {"1.1.6", [{restart_application, ssh}]}, + {"1.1.5", [{restart_application, ssh}]}, + {"1.1.4", [{restart_application, ssh}]}, + {"1.1.3", [{restart_application, ssh}]}, + {"1.1.2", [{restart_application, ssh}]} + ], + [ + {"1.1.6", [{restart_application, ssh}]}, + {"1.1.5", [{restart_application, ssh}]}, + {"1.1.4", [{restart_application, ssh}]}, + {"1.1.3", [{restart_application, ssh}]}, + {"1.1.2", [{restart_application, ssh}]} + ] +}. + + diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl new file mode 100644 index 0000000000..f9a986a8b6 --- /dev/null +++ b/lib/ssh/src/ssh.erl @@ -0,0 +1,339 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). + +-export([start/0, start/1, stop/0, connect/3, close/1, connection_info/2, + channel_info/3, + daemon/1, daemon/2, daemon/3, + stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2, + shell/1, shell/2, shell/3]). + +%%-------------------------------------------------------------------- +%% Function: start([, Type]) -> ok +%% +%% Type = permanent | transient | temporary +%% +%% Description: Starts the inets application. Default type +%% is temporary. see application(3) +%%-------------------------------------------------------------------- +start() -> + application:start(ssh). + +start(Type) -> + application:start(ssh, Type). + +%%-------------------------------------------------------------------- +%% Function: stop() -> ok +%% +%% Description: Stops the inets application. +%%-------------------------------------------------------------------- +stop() -> + application:stop(ssh). + +%%-------------------------------------------------------------------- +%% Function: connect(Host, Port, Options) -> +%% connect(Host, Port, Options, Timeout -> ConnectionRef | {error, Reason} +%% +%% Host - string() +%% Port - integer() +%% Options - [{Option, Value}] +%% Timeout - infinity | integer(). +%% +%% Description: Starts an ssh connection. +%%-------------------------------------------------------------------- +connect(Host, Port, Options) -> + connect(Host, Port, Options, infinity). +connect(Host, Port, Options, Timeout) -> + {SocketOpts, Opts} = handle_options(Options), + DisableIpv6 = proplists:get_value(ip_v6_disabled, Opts, false), + Inet = inetopt(DisableIpv6), + try sshc_sup:start_child([[{address, Host}, {port, Port}, + {role, client}, + {channel_pid, self()}, + {socket_opts, [Inet | SocketOpts]}, + {ssh_opts, [{host, Host}| Opts]}]]) of + {ok, ConnectionSup} -> + {ok, Manager} = + ssh_connection_controler:connection_manager(ConnectionSup), + MRef = erlang:monitor(process, Manager), + receive + {Manager, is_connected} -> + do_demonitor(MRef, Manager), + {ok, Manager}; + %% When the connection fails + %% ssh_connection_sup:connection_manager + %% might return undefined as the connection manager + %% could allready have terminated, so we will not + %% match the Manager in this case + {_, not_connected, {error, Reason}} -> + do_demonitor(MRef, Manager), + {error, Reason}; + {_, not_connected, Other} -> + do_demonitor(MRef, Manager), + {error, Other}; + {'DOWN', MRef, _, Manager, Reason} when is_pid(Manager) -> + receive %% Clear EXIT message from queue + {'EXIT', Manager, _What} -> + {error, Reason} + after 0 -> + {error, Reason} + end + after Timeout -> + do_demonitor(MRef, Manager), + ssh_connection_manager:stop(Manager), + {error, timeout} + end + catch + exit:{noproc, _} -> + {error, ssh_not_started} + end. + +do_demonitor(MRef, Manager) -> + erlang:demonitor(MRef), + receive + {'DOWN', MRef, _, Manager, _} -> + ok + after 0 -> + ok + end. + + +%%-------------------------------------------------------------------- +%% Function: close(ConnectionRef) -> ok +%% +%% Description: Closes an ssh connection. +%%-------------------------------------------------------------------- +close(ConnectionRef) -> + ssh_connection_manager:stop(ConnectionRef). + +%%-------------------------------------------------------------------- +%% Function: connection_info(ConnectionRef) -> [{Option, Value}] +%% +%% Description: Retrieves information about a connection. +%%-------------------------------------------------------------------- +connection_info(ConnectionRef, Options) -> + ssh_connection_manager:connection_info(ConnectionRef, Options). + +%%-------------------------------------------------------------------- +%% Function: channel_info(ConnectionRef) -> [{Option, Value}] +%% +%% Description: Retrieves information about a connection. +%%-------------------------------------------------------------------- +channel_info(ConnectionRef, ChannelId, Options) -> + ssh_connection_manager:channel_info(ConnectionRef, ChannelId, Options). + +%%-------------------------------------------------------------------- +%% Function: daemon(Port) -> +%% daemon(Port, Options) -> +%% daemon(Address, Port, Options) -> SshSystemRef +%% +%% Description: Starts a server listening for SSH connections +%% on the given port. +%%-------------------------------------------------------------------- +daemon(Port) -> + daemon(Port, []). + +daemon(Port, Options) -> + daemon(any, Port, Options). + +daemon(HostAddr, Port, Options0) -> + Options1 = case proplists:get_value(shell, Options0) of + undefined -> + [{shell, {shell, start, []}} | Options0]; + _ -> + Options0 + end, + DisableIpv6 = proplists:get_value(ip_v6_disabled, Options0, false), + {Host, Inet, Options} = case HostAddr of + any -> + {ok, Host0} = inet:gethostname(), + {Host0, inetopt(DisableIpv6), Options1}; + {_,_,_,_} -> + {HostAddr, inet, + [{ip, HostAddr} | Options1]}; + {_,_,_,_,_,_,_,_} -> + {HostAddr, inet6, + [{ip, HostAddr} | Options1]} + end, + start_daemon(Host, Port, [{role, server} | Options], Inet). + +%%-------------------------------------------------------------------- +%% Function: stop_listener(SysRef) -> ok +%% stop_listener(Address, Port) -> ok +%% +%% +%% Description: Stops the listener, but leaves +%% existing connections started by the listener up and running. +%%-------------------------------------------------------------------- +stop_listener(SysSup) -> + ssh_system_sup:stop_listener(SysSup). +stop_listener(Address, Port) -> + ssh_system_sup:stop_listener(Address, Port). + +%%-------------------------------------------------------------------- +%% Function: stop_daemon(SysRef) -> ok +%%% stop_daemon(Address, Port) -> ok +%% +%% +%% Description: Stops the listener and all connections started by +%% the listener. +%%-------------------------------------------------------------------- +stop_daemon(SysSup) -> + ssh_system_sup:stop_system(SysSup). +stop_daemon(Address, Port) -> + ssh_system_sup:stop_system(Address, Port). + +%%-------------------------------------------------------------------- +%% Function: shell(Host [,Port,Options]) -> {ok, ConnectionRef} | +%% {error, Reason} +%% +%% Host = string() +%% Port = integer() +%% Options = [{Option, Value}] +%% +%% Description: Starts an interactive shell to an SSH server on the +%% given <Host>. The function waits for user input, +%% and will not return until the remote shell is ended.(e.g. on +%% exit from the shell) +%%-------------------------------------------------------------------- +shell(Host) -> + shell(Host, ?SSH_DEFAULT_PORT, []). +shell(Host, Options) -> + shell(Host, ?SSH_DEFAULT_PORT, Options). +shell(Host, Port, Options) -> + case connect(Host, Port, Options) of + {ok, ConnectionRef} -> + case ssh_connection:session_channel(ConnectionRef, infinity) of + {ok,ChannelId} -> + Args = [{channel_cb, ssh_shell}, + {init_args,[ConnectionRef, ChannelId]}, + {cm, ConnectionRef}, {channel_id, ChannelId}], + {ok, State} = ssh_channel:init([Args]), + ssh_channel:enter_loop(State); + Error -> + Error + end; + Error -> + Error + end. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +start_daemon(Host, Port, Options, Inet) -> + {SocketOpts, Opts} = handle_options(Options), + case ssh_system_sup:system_supervisor(Host, Port) of + undefined -> + %% TODO: It would proably make more sense to call the + %% address option host but that is a too big change at the + %% monent. The name is a legacy name! + try sshd_sup:start_child([{address, Host}, + {port, Port}, {role, server}, + {socket_opts, [Inet | SocketOpts]}, + {ssh_opts, Opts}]) of + {ok, SysSup} -> + {ok, SysSup}; + {error, {already_started, _}} -> + {error, eaddrinuse} + catch + exit:{noproc, _} -> + {error, ssh_not_started} + end; + Sup -> + case ssh_system_sup:restart_acceptor(Host, Port) of + {ok, _} -> + {ok, Sup}; + _ -> + {error, eaddrinuse} + end + end. + +handle_options(Opts) -> + handle_options(proplists:unfold(Opts), [], []). +handle_options([], SockOpts, Opts) -> + {SockOpts, Opts}; +%% TODO: Could do some type checks here on plain ssh-opts +handle_options([{system_dir, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user_dir, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user_dir_fun, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{silently_accept_hosts, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user_interaction, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{public_key_alg, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{connect_timeout, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{password, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user_passwords, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{pwdfun, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{user_auth, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{key_cb, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{role, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{channel, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{compression, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{allow_user_interaction, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{infofun, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{connectfun, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{disconnectfun , _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{failfun, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{ip_v6_disabled, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{ip, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, [Opt |SockOpts], Opts); +handle_options([{ifaddr, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, [Opt |SockOpts], Opts); +handle_options([{fd, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, [Opt | SockOpts], Opts); +handle_options([{nodelay, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, [Opt | SockOpts], Opts); +handle_options([Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]). + +inetopt(true) -> + inet6; + +inetopt(false) -> + inet. + + diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl new file mode 100644 index 0000000000..0e4285295c --- /dev/null +++ b/lib/ssh/src/ssh.hrl @@ -0,0 +1,180 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%% +%% SSH definitions +%% + +-ifndef(SSH_HRL). +-define(SSH_HRL, 1). + +-define(SSH_DEFAULT_PORT, 22). +-define(SSH_MAX_PACKET_SIZE, (256*1024)). +-define(SSH_LENGHT_INDICATOR_SIZE, 4). + +-define(FALSE, 0). +-define(TRUE, 1). +%% basic binary constructors +-define(BOOLEAN(X), X:8/unsigned-big-integer). +-define(BYTE(X), X:8/unsigned-big-integer). +-define(UINT16(X), X:16/unsigned-big-integer). +-define(UINT32(X), X:32/unsigned-big-integer). +-define(UINT64(X), X:64/unsigned-big-integer). +-define(STRING(X), ?UINT32((size(X))), (X)/binary). + +%% building macros +-define(boolean(X), + case X of + true -> <<?BOOLEAN(1)>>; + false -> (<<?BOOLEAN(0)>>) + end). + +-define(byte(X), << ?BYTE(X) >> ). +-define(uint16(X), << ?UINT16(X) >> ). +-define(uint32(X), << ?UINT32(X) >> ). +-define(uint64(X), << ?UINT64(X) >> ). +-define(string(X), << ?STRING(list_to_binary(X)) >> ). +-define(binary(X), << ?STRING(X) >>). + +-ifdef(debug). +-define(dbg(Debug, Fmt, As), + case (Debug) of + true -> + io:format([$# | (Fmt)], (As)); + _ -> + ok + end). +-else. +-define(dbg(Debug, Fmt, As), ok). +-endif. + +-define(SSH_CIPHER_NONE, 0). +-define(SSH_CIPHER_3DES, 3). +-define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES). + +-record(ssh, + { + %%state, %% what it's waiting for + + role, %% client | server + peer, %% string version of peer address + + c_vsn, %% client version {Major,Minor} + s_vsn, %% server version {Major,Minor} + + c_version, %% client version string + s_version, %% server version string + + c_keyinit, %% binary payload of kexinit packet + s_keyinit, %% binary payload of kexinit packet + + algorithms, %% #alg{} + + kex, %% key exchange algorithm + hkey, %% host key algorithm + key_cb, %% Private/Public key callback module + io_cb, %% Interaction callback module + + send_mac = none, %% send MAC algorithm + send_mac_key, %% key used in send MAC algorithm + send_mac_size = 0, + + recv_mac = none, %% recv MAC algorithm + recv_mac_key, %% key used in recv MAC algorithm + recv_mac_size = 0, + + encrypt = none, %% encrypt algorithm + encrypt_keys, %% encrypt keys + encrypt_block_size = 8, + encrypt_ctx, + + decrypt = none, %% decrypt algorithm + decrypt_keys, %% decrypt keys + decrypt_block_size = 8, + decrypt_ctx, %% Decryption context + + compress = none, + compress_ctx, + decompress = none, + decompress_ctx, + + c_lng=none, %% client to server languages + s_lng=none, %% server to client languages + + user_ack = true, %% client + timeout = infinity, + + shared_secret, %% K from key exchange + exchanged_hash, %% H from key exchange + session_id, %% same as FIRST exchanged_hash + + opts = [], + send_sequence = 0, + recv_sequence = 0, + keyex_key, + keyex_info, + + %% User auth + user, + service, + userauth_quiet_mode, % boolean() + userauth_supported_methods , % + userauth_methods, + userauth_preference + }). + +-record(alg, + { + kex, + hkey, + send_mac, + recv_mac, + encrypt, + decrypt, + compress, + decompress, + c_lng, + s_lng + }). + +-record(ssh_key, + { + type, + public, + private, + comment = "" + }). + +-record(ssh_pty, {term = "", % e.g. "xterm" + width = 80, + height = 25, + pixel_width = 1024, + pixel_height = 768, + modes = <<>>}). + +%% assertion macro +-define(ssh_assert(Expr, Reason), + case Expr of + true -> ok; + _ -> exit(Reason) + end). + +-endif. % SSH_HRL defined diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl new file mode 100644 index 0000000000..d19fee14e1 --- /dev/null +++ b/lib/ssh/src/ssh_acceptor.erl @@ -0,0 +1,115 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_acceptor). + +%% Internal application API +-export([start_link/5]). + +%% spawn export +%% TODO: system messages +-export([acceptor_init/6, acceptor_loop/6]). + +-define(SLEEP_TIME, 200). + +%%==================================================================== +%% Internal application API +%%==================================================================== +start_link(Port, Address, SockOpts, Opts, AcceptTimeout) -> + Args = [self(), Port, Address, SockOpts, Opts, AcceptTimeout], + proc_lib:start_link(?MODULE, acceptor_init, Args). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) -> + {_, Callback, _} = + proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}), + case (catch do_socket_listen(Callback, Port, SockOpts)) of + {ok, ListenSocket} -> + proc_lib:init_ack(Parent, {ok, self()}), + acceptor_loop(Callback, + Port, Address, Opts, ListenSocket, AcceptTimeout); + Error -> + proc_lib:init_ack(Parent, Error), + error + end. + +do_socket_listen(Callback, Port, Opts) -> + case Callback:listen(Port, Opts) of + {error, eafnosupport} -> + Callback:listen(Port, lists:delete(inet6, Opts)); + Other -> + Other + end. + +acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) -> + case (catch Callback:accept(ListenSocket, AcceptTimeout)) of + {ok, Socket} -> + handle_connection(Callback, Address, Port, Opts, Socket), + ?MODULE:acceptor_loop(Callback, Port, Address, Opts, + ListenSocket, AcceptTimeout); + {error, Reason} -> + handle_error(Reason), + ?MODULE:acceptor_loop(Callback, Port, Address, Opts, + ListenSocket, AcceptTimeout); + {'EXIT', Reason} -> + handle_error(Reason), + ?MODULE:acceptor_loop(Callback, Port, Address, Opts, + ListenSocket, AcceptTimeout) + end. + +handle_connection(Callback, Address, Port, Options, Socket) -> + SystemSup = ssh_system_sup:system_supervisor(Address, Port), + ssh_system_sup:start_subsystem(SystemSup, Options), + ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup), + {ok, Pid} = + ssh_connection_controler:start_manager_child(ConnectionSup, + [server, Socket, Options]), + Callback:controlling_process(Socket, Pid), + SshOpts = proplists:get_value(ssh_opts, Options), + Pid ! {start_connection, server, [Address, Port, Socket, SshOpts]}. + +handle_error(timeout) -> + ok; + +handle_error(enfile) -> + %% Out of sockets... + timer:sleep(?SLEEP_TIME); + +handle_error(emfile) -> + %% Too many open files -> Out of sockets... + timer:sleep(?SLEEP_TIME); + +handle_error(closed) -> + error_logger:info_report("The ssh accept socket was closed by " + "a third party. " + "This will not have an impact on ssh " + "that will open a new accept socket and " + "go on as nothing happened. It does however " + "indicate that some other software is behaving " + "badly."), + exit(normal); + +handle_error(Reason) -> + String = lists:flatten(io_lib:format("Accept error: ~p", [Reason])), + error_logger:error_report(String), + exit({accept_failed, String}). diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl new file mode 100644 index 0000000000..707e3d3a5e --- /dev/null +++ b/lib/ssh/src/ssh_acceptor_sup.erl @@ -0,0 +1,95 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: The acceptor supervisor for ssh servers hangs under +%% ssh_system_sup. +%%---------------------------------------------------------------------- + +-module(ssh_acceptor_sup). +-behaviour(supervisor). + +-export([start_link/1, start_child/2, stop_child/2]). + +%% Supervisor callback +-export([init/1]). + +-define(DEFAULT_TIMEOUT, 50000). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(Servers) -> + supervisor:start_link(?MODULE, [Servers]). + +start_child(AccSup, ServerOpts) -> + Spec = child_spec(ServerOpts), + case supervisor:start_child(AccSup, Spec) of + {error, already_present} -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + Name = id(Address, Port), + supervisor:delete_child(?MODULE, Name), + supervisor:start_child(AccSup, Spec); + Reply -> + Reply + end. + +stop_child(Address, Port) -> + Name = id(Address, Port), + case supervisor:terminate_child(?MODULE, Name) of + ok -> + supervisor:delete_child(?MODULE, Name); + Error -> + Error + end. + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([ServerOpts]) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Children = [child_spec(ServerOpts)], + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +child_spec(ServerOpts) -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + Timeout = proplists:get_value(timeout, ServerOpts, ?DEFAULT_TIMEOUT), + Name = id(Address, Port), + SocketOpts = proplists:get_value(socket_opts, ServerOpts), + StartFunc = {ssh_acceptor, start_link, [Port, Address, + [{active, false}, + {reuseaddr, true}] ++ SocketOpts, + ServerOpts, Timeout]}, + Restart = permanent, + Shutdown = 3600, + Modules = [ssh_acceptor], + Type = worker, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +id(Address, Port) -> + {ssh_acceptor_sup, Address, Port}. + diff --git a/lib/ssh/src/ssh_app.erl b/lib/ssh/src/ssh_app.erl new file mode 100644 index 0000000000..5793d3a321 --- /dev/null +++ b/lib/ssh/src/ssh_app.erl @@ -0,0 +1,34 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%% Purpose : Application master for SSH. + +-module(ssh_app). + +-behaviour(application). + +-export([start/2, stop/1]). + +start(_Type, _State) -> + supervisor:start_link({local, ssh_sup}, ssh_sup, []). + +stop(_State) -> + ok. diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl new file mode 100644 index 0000000000..aa74528544 --- /dev/null +++ b/lib/ssh/src/ssh_auth.erl @@ -0,0 +1,423 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_auth). + +-include("ssh.hrl"). + +-include("ssh_auth.hrl"). +-include("ssh_transport.hrl"). + +-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1, + service_request_msg/1, init_userauth_request_msg/1, + userauth_request_msg/1, handle_userauth_request/3, + handle_userauth_info_request/3, handle_userauth_info_response/2, + userauth_messages/0 + ]). + +%%-------------------------------------------------------------------- +%%% Internal application API +%%-------------------------------------------------------------------- +publickey_msg([Cb, #ssh{user = User, + session_id = SessionId, + service = Service, + opts = Opts} = Ssh]) -> + ssh_bits:install_messages(userauth_pk_messages()), + Alg = Cb:alg_name(), + case ssh_file:private_identity_key(Alg, Opts) of + {ok, PrivKey} -> + PubKeyBlob = ssh_file:encode_public_key(PrivKey), + SigData = build_sig_data(SessionId, + User, Service, Alg, PubKeyBlob), + Sig = Cb:sign(PrivKey, SigData), + SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]), + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "publickey", + data = [?TRUE, + ?string(Alg), + ?binary(PubKeyBlob), + ?binary(SigBlob)]}, + Ssh); + _Error -> + not_ok + end. + +password_msg([#ssh{opts = Opts, io_cb = IoCb, + user = User, service = Service} = Ssh]) -> + ssh_bits:install_messages(userauth_passwd_messages()), + Password = case proplists:get_value(password, Opts) of + undefined -> + IoCb:read_password("ssh password: "); + PW -> + PW + end, + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "password", + data = + <<?BOOLEAN(?FALSE), + ?STRING(list_to_binary(Password))>>}, + Ssh). + +%% See RFC 4256 for info on keyboard-interactive +keyboard_interactive_msg([#ssh{user = User, + service = Service} = Ssh]) -> + ssh_bits:install_messages(userauth_keyboard_interactive_messages()), + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "keyboard-interactive", + data = << ?STRING(<<"">>), + ?STRING(<<>>) >> }, + Ssh). + +service_request_msg(Ssh) -> + ssh_transport:ssh_packet(#ssh_msg_service_request{name = "ssh-userauth"}, + Ssh#ssh{service = "ssh-userauth"}). + +init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> + case user_name(Opts) of + {ok, User} -> + Msg = #ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = "none", + data = <<>>}, + CbFirst = proplists:get_value(public_key_alg, Opts, + ?PREFERRED_PK_ALG), + CbSecond = other_cb(CbFirst), + AllowUserInt = proplists:get_value(allow_user_interaction, Opts, + true), + Prefs = method_preference(CbFirst, CbSecond, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}); + {error, no_user} -> + ErrStr = "Could not determine the users name", + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME, + description = ErrStr, + language = "en"}) + end. + +userauth_request_msg(#ssh{userauth_preference = []} = Ssh) -> + Msg = #ssh_msg_disconnect{code = + ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, + description = "Unable to connect using the available" + " authentication methods", + language = "en"}, + {disconnect, Msg, ssh_transport:ssh_packet(Msg, Ssh)}; + +userauth_request_msg(#ssh{userauth_methods = Methods, + userauth_preference = [{Pref, Module, + Function, Args} | Prefs]} + = Ssh0) -> + Ssh = Ssh0#ssh{userauth_preference = Prefs}, + case lists:member(Pref, Methods) of + true -> + case Module:Function(Args ++ [Ssh]) of + not_ok -> + userauth_request_msg(Ssh); + Result -> + Result + end; + false -> + userauth_request_msg(Ssh) + end. + + +handle_userauth_request(#ssh_msg_service_request{name = + Name = "ssh-userauth"}, + _, Ssh) -> + {ok, ssh_transport:ssh_packet(#ssh_msg_service_accept{name = Name}, + Ssh#ssh{service = "ssh-connection"})}; + +handle_userauth_request(#ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = "password", + data = Data}, _, + #ssh{opts = Opts} = Ssh) -> + <<_:8, ?UINT32(Sz), BinPwd:Sz/binary>> = Data, + Password = binary_to_list(BinPwd), + + case check_password(User, Password, Opts) of + true -> + {authorized, User, + ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)}; + false -> + {not_authorized, {User, {passwd, Password}}, + ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ + authentications = "", + partial_success = false}, Ssh)} + end; + +handle_userauth_request(#ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = "none"}, _, + #ssh{userauth_supported_methods = Methods} = Ssh) -> + {not_authorized, {User, undefined}, + ssh_transport:ssh_packet( + #ssh_msg_userauth_failure{authentications = Methods, + partial_success = false}, Ssh)}; + +handle_userauth_request(#ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = "publickey", + data = Data}, + SessionId, #ssh{opts = Opts} = Ssh) -> + <<?BYTE(HaveSig), ?UINT32(ALen), BAlg:ALen/binary, + ?UINT32(KLen), KeyBlob:KLen/binary, SigWLen/binary>> = Data, + Alg = binary_to_list(BAlg), + case HaveSig of + ?TRUE -> + case verify_sig(SessionId, User, "ssh-connection", Alg, + KeyBlob, SigWLen, Opts) of + ok -> + {authorized, User, + ssh_transport:ssh_packet( + #ssh_msg_userauth_success{}, Ssh)}; + {error, Reason} -> + {not_authorized, {User, {error, Reason}}, + ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ + authentications="publickey,password", + partial_success = false}, Ssh)} + end; + ?FALSE -> + ssh_bits:install_messages(userauth_pk_messages()), + {not_authorized, {User, undefined}, + ssh_transport:ssh_packet( + #ssh_msg_userauth_pk_ok{algorithm_name = Alg, + key_blob = KeyBlob}, Ssh)} + end; + +handle_userauth_request(#ssh_msg_userauth_request{user = User, + service = "ssh-connection", + method = Other}, _, + #ssh{userauth_supported_methods = Methods} = Ssh) -> + {not_authorized, {User, {authmethod, Other}}, + ssh_transport:ssh_packet( + #ssh_msg_userauth_failure{authentications = Methods, + partial_success = false}, Ssh)}. + +handle_userauth_info_request( + #ssh_msg_userauth_info_request{name = Name, + instruction = Instr, + num_prompts = NumPrompts, + data = Data}, IoCb, + #ssh{opts = Opts} = Ssh) -> + PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data), + Resps = keyboard_interact_get_responses(IoCb, Opts, + Name, Instr, PromptInfos), + %%?dbg(true, "keyboard_interactive_reply: resps=~n#~p ~n", [Resps]), + RespBin = list_to_binary( + lists:map(fun(S) -> <<?STRING(list_to_binary(S))>> end, + Resps)), + {ok, + ssh_transport:ssh_packet( + #ssh_msg_userauth_info_response{num_responses = NumPrompts, + data = RespBin}, Ssh)}. + +handle_userauth_info_response(#ssh_msg_userauth_info_response{}, + _Auth) -> + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, + description = "Server does not support" + "keyboard-interactive", + language = "en"}). +userauth_messages() -> + [ {ssh_msg_userauth_request, ?SSH_MSG_USERAUTH_REQUEST, + [string, + string, + string, + '...']}, + + {ssh_msg_userauth_failure, ?SSH_MSG_USERAUTH_FAILURE, + [string, + boolean]}, + + {ssh_msg_userauth_success, ?SSH_MSG_USERAUTH_SUCCESS, + []}, + + {ssh_msg_userauth_banner, ?SSH_MSG_USERAUTH_BANNER, + [string, + string]}]. +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +method_preference(Callback1, Callback2, true) -> + [{"publickey", ?MODULE, publickey_msg, [Callback1]}, + {"publickey", ?MODULE, publickey_msg,[Callback2]}, + {"password", ?MODULE, password_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} + ]; +method_preference(Callback1, Callback2, false) -> + [{"publickey", ?MODULE, publickey_msg, [Callback1]}, + {"publickey", ?MODULE, publickey_msg,[Callback2]}, + {"password", ?MODULE, password_msg, []} + ]. + +user_name(Opts) -> + Env = case os:type() of + {win32, _} -> + "USERNAME"; + {unix, _} -> + "LOGNAME" + end, + case proplists:get_value(user, Opts, os:getenv(Env)) of + false -> + case os:getenv("USER") of + false -> + {error, no_user}; + User -> + {ok, User} + end; + User -> + {ok, User} + end. + +check_password(User, Password, Opts) -> + %%?dbg(true, " ~p ~p ~p ~n", [User, Password, Opts]), + case proplists:get_value(pwdfun, Opts) of + undefined -> + Static = get_password_option(Opts, User), + Password == Static; + Cheker -> + Cheker(User, Password) + end. + +get_password_option(Opts, User) -> + Passwords = proplists:get_value(user_passwords, Opts, []), + case lists:keysearch(User, 1, Passwords) of + {value, {User, Pw}} -> Pw; + false -> proplists:get_value(password, Opts, false) + end. + +verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> + case ssh_file:lookup_user_key(User, Alg, Opts) of + {ok, OurKey} -> + {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg), + case OurKey of + Key -> + NewSig = build_sig_data(SessionId, + User, Service, Alg, KeyBlob), + <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen, + <<?UINT32(AlgLen), _Alg:AlgLen/binary, + ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig, + M = alg_to_module(Alg), + M:verify(OurKey, NewSig, Sig); + _ -> + {error, key_unacceptable} + end; + Error -> Error + end. + +build_sig_data(SessionId, User, Service, Alg, KeyBlob) -> + Sig = [?binary(SessionId), + ?SSH_MSG_USERAUTH_REQUEST, + ?string(User), + ?string(Service), + ?binary(<<"publickey">>), + ?TRUE, + ?string(Alg), + ?binary(KeyBlob)], + list_to_binary(Sig). + +decode_keyboard_interactive_prompts(NumPrompts, Data) -> + Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])), + pairwise_tuplify(ssh_bits:decode(Data, Types)). + +pairwise_tuplify([E1, E2 | Rest]) -> [{E1, E2} | pairwise_tuplify(Rest)]; +pairwise_tuplify([]) -> []. + + +keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) -> + NumPrompts = length(PromptInfos), + case proplists:get_value(keyboard_interact_fun, Opts) of + undefined when NumPrompts == 1 -> + %% Special case/fallback for just one prompt + %% (assumed to be the password prompt) + case proplists:get_value(password, Opts) of + undefined -> keyboard_interact(IoCb, Name, Instr, PromptInfos); + PW -> [PW] + end; + undefined -> + keyboard_interact(IoCb, Name, Instr, PromptInfos); + KbdInteractFun -> + Prompts = lists:map(fun({Prompt, _Echo}) -> Prompt end, + PromptInfos), + case KbdInteractFun(Name, Instr, Prompts) of + Rs when length(Rs) == NumPrompts -> + Rs; + Rs -> + erlang:error({mismatching_number_of_responses, + {got,Rs}, + {expected,NumPrompts}}) + end + end. + +keyboard_interact(IoCb, Name, Instr, Prompts) -> + if Name /= "" -> IoCb:format("~s", [Name]); + true -> ok + end, + if Instr /= "" -> IoCb:format("~s", [Instr]); + true -> ok + end, + lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt); + ({Prompt, false}) -> IoCb:read_password(Prompt) + end, + Prompts). + +userauth_passwd_messages() -> + [ + {ssh_msg_userauth_passwd_changereq, ?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, + [string, + string]} + ]. + +userauth_keyboard_interactive_messages() -> + [ {ssh_msg_userauth_info_request, ?SSH_MSG_USERAUTH_INFO_REQUEST, + [string, + string, + string, + uint32, + '...']}, + + {ssh_msg_userauth_info_response, ?SSH_MSG_USERAUTH_INFO_RESPONSE, + [uint32, + '...']} + ]. + +userauth_pk_messages() -> + [ {ssh_msg_userauth_pk_ok, ?SSH_MSG_USERAUTH_PK_OK, + [string, % algorithm name + binary]} % key blob + ]. + +alg_to_module("ssh-dss") -> + ssh_dsa; +alg_to_module("ssh-rsa") -> + ssh_rsa. + +other_cb(ssh_rsa) -> + ssh_dsa; +other_cb(ssh_dsa) -> + ssh_rsa. diff --git a/lib/ssh/src/ssh_auth.hrl b/lib/ssh/src/ssh_auth.hrl new file mode 100644 index 0000000000..80c5a6819b --- /dev/null +++ b/lib/ssh/src/ssh_auth.hrl @@ -0,0 +1,83 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: Ssh User Authentication Protocol + +-define(SUPPORTED_AUTH_METHODS, "publickey,keyboard_interactive,password"). + +-define(PREFERRED_PK_ALG, ssh_rsa). + +-define(SSH_MSG_USERAUTH_REQUEST, 50). +-define(SSH_MSG_USERAUTH_FAILURE, 51). +-define(SSH_MSG_USERAUTH_SUCCESS, 52). +-define(SSH_MSG_USERAUTH_BANNER, 53). +-define(SSH_MSG_USERAUTH_PK_OK, 60). +-define(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 60). +-define(SSH_MSG_USERAUTH_INFO_REQUEST, 60). +-define(SSH_MSG_USERAUTH_INFO_RESPONSE, 61). + +-record(ssh_msg_userauth_request, + { + user, %% string + service, %% string + method, %% string "publickey", "password" + data %% opaque + }). + +-record(ssh_msg_userauth_failure, + { + authentications, %% string + partial_success %% boolean + }). + +-record(ssh_msg_userauth_success, + { + }). + +-record(ssh_msg_userauth_banner, + { + message, %% string + language %% string + }). + +-record(ssh_msg_userauth_passwd_changereq, + { + prompt, %% string + languge %% string + }). + +-record(ssh_msg_userauth_pk_ok, + { + algorithm_name, % string + key_blob % string + }). + +-record(ssh_msg_userauth_info_request, + {name, + instruction, + language_tag, + num_prompts, + data}). + +-record(ssh_msg_userauth_info_response, + {num_responses, + data}). + diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl new file mode 100755 index 0000000000..21ddc5e8fe --- /dev/null +++ b/lib/ssh/src/ssh_bits.erl @@ -0,0 +1,483 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description : SSH 1/2 pdu elements encode/decode + +-module(ssh_bits). + +-include("ssh.hrl"). + +-export([encode/1, encode/2]). +-export([decode/1, decode/2, decode/3]). +-export([mpint/1, bignum/1, string/1, name_list/1]). +-export([b64_encode/1, b64_decode/1]). +-export([install_messages/1, uninstall_messages/1]). + +%% integer utils +-export([isize/1]). +-export([irandom/1, irandom/3]). +-export([random/1, random/3]). +-export([xor_bits/2, fill_bits/2]). +-export([i2bin/2, bin2i/1]). + +-import(lists, [foreach/2, reverse/1]). + +-define(name_list(X), + (fun(B) -> ?binary(B) end)(list_to_binary(name_concat(X)))). + + +name_concat([Name]) when is_atom(Name) -> atom_to_list(Name); +name_concat([Name]) when is_list(Name) -> Name; +name_concat([Name|Ns]) -> + if is_atom(Name) -> + [atom_to_list(Name),"," | name_concat(Ns)]; + is_list(Name) -> + [Name,"," | name_concat(Ns)] + end; +name_concat([]) -> []. + + +name_list(Ns) -> + ?name_list(Ns). + + +string(Str) -> + ?string(Str). + + +%% MP representaion (SSH2) +mpint(X) when X < 0 -> + if X == -1 -> + <<0,0,0,1,16#ff>>; + true -> + mpint_neg(X,0,[]) + end; +mpint(X) -> + if X == 0 -> + <<0,0,0,0>>; + true -> + mpint_pos(X,0,[]) + end. + +mpint_neg(-1,I,Ds=[MSB|_]) -> + if MSB band 16#80 =/= 16#80 -> + <<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>; + true -> + (<<?UINT32(I), (list_to_binary(Ds))/binary>>) + end; +mpint_neg(X,I,Ds) -> + mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]). + +mpint_pos(0,I,Ds=[MSB|_]) -> + if MSB band 16#80 == 16#80 -> + <<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>; + true -> + (<<?UINT32(I), (list_to_binary(Ds))/binary>>) + end; +mpint_pos(X,I,Ds) -> + mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]). + + +%% BIGNUM representation SSH1 +bignum(X) -> + XSz = isize(X), + Pad = (8 - (XSz rem 8)) rem 8, + <<?UINT16(XSz),0:Pad/unsigned-integer,X:XSz/big-unsigned-integer>>. + + +install_messages(Codes) -> + foreach(fun({Name, Code, Ts}) -> + %% ?dbg(true, "install msg: ~s = ~w ~w~n", +%% [Name,Code,Ts]), + put({msg_name,Code}, {Name,Ts}), + put({msg_code,Name}, {Code,Ts}) + end, Codes). + +uninstall_messages(Codes) -> + foreach(fun({Name, Code, _Ts}) -> + %% ?dbg(true, "uninstall msg: ~s = ~w ~w~n", +%% [Name,Code,_Ts]), + erase({msg_name,Code}), + erase({msg_code,Name}) + end, Codes). + +%% +%% Encode a record, the type spec is expected to be +%% in process dictionary under the key {msg_code, RecodeName} +%% +encode(Record) -> + case get({msg_code, element(1, Record)}) of + undefined -> + {error, unimplemented}; + {Code, Ts} -> + Data = enc(tl(tuple_to_list(Record)), Ts), + list_to_binary([Code, Data]) + end. + +encode(List, Types) -> + list_to_binary(enc(List, Types)). + +%% +%% Encode record element +%% +enc(Xs, Ts) -> + enc(Xs, Ts, 0). + +enc(Xs, [Type|Ts], Offset) -> + case Type of + boolean -> + X=hd(Xs), + [?boolean(X) | enc(tl(Xs), Ts, Offset+1)]; + byte -> + X=hd(Xs), + [?byte(X) | enc(tl(Xs), Ts,Offset+1)]; + uint16 -> + X=hd(Xs), + [?uint16(X) | enc(tl(Xs), Ts,Offset+2)]; + uint32 -> + X=hd(Xs), + [?uint32(X) | enc(tl(Xs), Ts,Offset+4)]; + uint64 -> + X=hd(Xs), + [?uint64(X) | enc(tl(Xs), Ts,Offset+8)]; + mpint -> + Y=mpint(hd(Xs)), + [Y | enc(tl(Xs), Ts,Offset+size(Y))]; + bignum -> + Y=bignum(hd(Xs)), + [Y | enc(tl(Xs),Ts,Offset+size(Y))]; + string -> + X0=hd(Xs), + Y=?string(X0), + [Y | enc(tl(Xs),Ts,Offset+size(Y))]; + binary -> + X0=hd(Xs), + Y=?binary(X0), + [Y | enc(tl(Xs), Ts,Offset+size(Y))]; + name_list -> + X0=hd(Xs), + Y=?name_list(X0), + [Y | enc(tl(Xs), Ts, Offset+size(Y))]; + cookie -> + [random(16) | enc(tl(Xs), Ts, Offset+16)]; + {pad,N} -> + K = (N - (Offset rem N)) rem N, + [fill_bits(K,0) | enc(Xs, Ts, Offset+K)]; + '...' when Ts==[] -> + X=hd(Xs), + if is_binary(X) -> + [X]; + is_list(X) -> + [list_to_binary(X)]; + X==undefined -> + [] + end + end; +enc([], [],_) -> + []. + + + +%% +%% Decode a SSH record the type is encoded as the first byte +%% and the type spec MUST be installed in {msg_name, ID} +%% + +decode(Binary = <<?BYTE(ID), _/binary>>) -> + case get({msg_name, ID}) of + undefined -> + {unknown, Binary}; + {Name, Ts} -> + {_, Elems} = decode(Binary,1,Ts), + list_to_tuple([Name | Elems]) + end. + +%% +%% Decode a binary form offset 0 +%% + +decode(Binary, Types) when is_binary(Binary) andalso is_list(Types) -> + {_,Elems} = decode(Binary, 0, Types), + Elems. + + +%% +%% Decode a binary from byte offset Offset +%% return {UpdatedOffset, DecodedElements} +%% +decode(Binary, Offset, Types) -> + decode(Binary, Offset, Types, []). + +decode(Binary, Offset, [Type|Ts], Acc) -> + case Type of + boolean -> + <<_:Offset/binary, ?BOOLEAN(X0), _/binary>> = Binary, + X = if X0 == 0 -> false; true -> true end, + decode(Binary, Offset+1, Ts, [X | Acc]); + + byte -> + <<_:Offset/binary, ?BYTE(X), _/binary>> = Binary, + decode(Binary, Offset+1, Ts, [X | Acc]); + + uint16 -> + <<_:Offset/binary, ?UINT16(X), _/binary>> = Binary, + decode(Binary, Offset+2, Ts, [X | Acc]); + + uint32 -> + <<_:Offset/binary, ?UINT32(X), _/binary>> = Binary, + decode(Binary, Offset+4, Ts, [X | Acc]); + + uint64 -> + <<_:Offset/binary, ?UINT64(X), _/binary>> = Binary, + decode(Binary, Offset+8, Ts, [X | Acc]); + + mpint -> + <<_:Offset/binary, ?UINT32(L), X0:L/binary,_/binary>> = Binary, + Sz = L*8, + <<X:Sz/big-signed-integer>> = X0, + decode(Binary, Offset+4+L, Ts, [X | Acc]); + + bignum -> + <<_:Offset/binary, ?UINT16(Bits),_/binary>> = Binary, + L = (Bits+7) div 8, + Pad = (8 - (Bits rem 8)) rem 8, + <<_:Offset/binary, _:16, _:Pad, X:Bits/big-unsigned-integer, + _/binary>> = Binary, + decode(Binary, Offset+2+L, Ts, [X | Acc]); + + string -> + Size = size(Binary), + if Size < Offset + 4 -> + %% empty string at end + {Size, reverse(["" | Acc])}; + true -> + <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = + Binary, + decode(Binary, Offset+4+L, Ts, [binary_to_list(X) | + Acc]) + end; + + binary -> + <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary, + decode(Binary, Offset+4+L, Ts, [X | Acc]); + + name_list -> + <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary, + List = string:tokens(binary_to_list(X), ","), + decode(Binary, Offset+4+L, Ts, [List | Acc]); + + cookie -> + <<_:Offset/binary, X:16/binary, _/binary>> = Binary, + decode(Binary, Offset+16, Ts, [X | Acc]); + + {pad,N} -> %% pad offset to a multiple of N + K = (N - (Offset rem N)) rem N, + decode(Binary, Offset+K, Ts, Acc); + + + '...' when Ts==[] -> + <<_:Offset/binary, X/binary>> = Binary, + {Offset+size(X), reverse([X | Acc])} + end; +decode(_Binary, Offset, [], Acc) -> + {Offset, reverse(Acc)}. + + + +%% HACK WARNING :-) +-define(VERSION_MAGIC, 131). +-define(SMALL_INTEGER_EXT, $a). +-define(INTEGER_EXT, $b). +-define(SMALL_BIG_EXT, $n). +-define(LARGE_BIG_EXT, $o). + +isize(N) when N > 0 -> + case term_to_binary(N) of + <<?VERSION_MAGIC, ?SMALL_INTEGER_EXT, X>> -> + isize_byte(X); + <<?VERSION_MAGIC, ?INTEGER_EXT, X3,X2,X1,X0>> -> + isize_bytes([X3,X2,X1,X0]); + <<?VERSION_MAGIC, ?SMALL_BIG_EXT, S:8/big-unsigned-integer, 0, + Ds:S/binary>> -> + K = S - 1, + <<_:K/binary, Top>> = Ds, + isize_byte(Top)+K*8; + <<?VERSION_MAGIC, ?LARGE_BIG_EXT, S:32/big-unsigned-integer, 0, + Ds:S/binary>> -> + K = S - 1, + <<_:K/binary, Top>> = Ds, + isize_byte(Top)+K*8 + end; +isize(0) -> 0. + +%% big endian byte list +isize_bytes([0|L]) -> + isize_bytes(L); +isize_bytes([Top|L]) -> + isize_byte(Top) + length(L)*8. + +%% Well could be improved +isize_byte(X) -> + if X >= 2#10000000 -> 8; + X >= 2#1000000 -> 7; + X >= 2#100000 -> 6; + X >= 2#10000 -> 5; + X >= 2#1000 -> 4; + X >= 2#100 -> 3; + X >= 2#10 -> 2; + X >= 2#1 -> 1; + true -> 0 + end. + +%% Convert integer into binary +%% When XLen is the wanted size in octets of the output +i2bin(X, XLen) -> + XSz = isize(X), + Sz = XLen*8, + if Sz < XSz -> + exit(integer_to_large); + true -> + (<<X:Sz/big-unsigned-integer>>) + end. + +%% Convert a binary into an integer +%% +bin2i(X) -> + Sz = size(X)*8, + <<Y:Sz/big-unsigned-integer>> = X, + Y. + +%% +%% Create a binary with constant bytes +%% +fill_bits(N,C) -> + list_to_binary(fill(N,C)). + +fill(0,_C) -> []; +fill(1,C) -> [C]; +fill(N,C) -> + Cs = fill(N div 2, C), + Cs1 = [Cs,Cs], + if N band 1 == 0 -> + Cs1; + true -> + [C,Cs,Cs] + end. + +%% xor 2 binaries +xor_bits(XBits, YBits) -> + XSz = size(XBits)*8, + YSz = size(YBits)*8, + Sz = if XSz < YSz -> XSz; true -> YSz end, %% min + <<X:Sz, _/binary>> = XBits, + <<Y:Sz, _/binary>> = YBits, + <<(X bxor Y):Sz>>. + +%% +%% irandom(N) +%% +%% Generate a N bits size random number +%% note that the top most bit is always set +%% to guarantee that the number is N bits +%% +irandom(Bits) -> + irandom(Bits, 1, 0). + +%% irandom_odd(Bits) -> +%% irandom(Bits, 1, 1). + +%% +%% irandom(N, Top, Bottom) +%% +%% Generate a N bits size random number +%% Where Top = 0 - do not set top bit +%% = 1 - set the most significant bit +%% = 2 - set two most significant bits +%% Bot = 0 - do not set the least signifcant bit +%% Bot = 1 - set the least signifcant bit (i.e always odd) +%% +irandom(0, _Top, _Bottom) -> + 0; +irandom(Bits, Top, Bottom) -> + Bytes = (Bits+7) div 8, + Skip = (8-(Bits rem 8)) rem 8, + TMask = case Top of + 0 -> 0; + 1 -> 16#80; + 2 -> 16#c0 + end, + BMask = case Bottom of + 0 -> 0; + 1 -> (1 bsl Skip) + end, + <<X:Bits/big-unsigned-integer, _:Skip>> = random(Bytes, TMask, BMask), + X. + +%% +%% random/1 +%% Generate N random bytes +%% +random(N) -> + random(N, 0, 0). + +random(N, TMask, BMask) -> + list_to_binary(rnd(N, TMask, BMask)). + +%% random/3 +%% random(Bytes, TopMask, BotMask) +%% where +%% Bytes is the number of bytes to generate +%% TopMask is bitwised or'ed to the first byte +%% BotMask is bitwised or'ed to the last byte +%% +rnd(0, _TMask, _BMask) -> + []; +rnd(1, TMask, BMask) -> + [(rand8() bor TMask) bor BMask]; +rnd(N, TMask, BMask) -> + [(rand8() bor TMask) | rnd_n(N-1, BMask)]. + +rnd_n(1, BMask) -> + [rand8() bor BMask]; +rnd_n(I, BMask) -> + [rand8() | rnd_n(I-1, BMask)]. + +rand8() -> + (rand32() bsr 8) band 16#ff. + +rand32() -> + random:uniform(16#100000000) -1. + +%% +%% Base 64 encode/decode +%% + +b64_encode(Bs) when is_list(Bs) -> + base64:encode(Bs); +b64_encode(Bin) when is_binary(Bin) -> + base64:encode(Bin). + +b64_decode(Bin) when is_binary(Bin) -> + base64:mime_decode(Bin); +b64_decode(Cs) when is_list(Cs) -> + base64:mime_decode(Cs). + + diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl new file mode 100644 index 0000000000..3d67065ee1 --- /dev/null +++ b/lib/ssh/src/ssh_channel.erl @@ -0,0 +1,328 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_channel). + +-include("ssh_connect.hrl"). + +-behaviour(gen_server). + +%%% API +-export([behaviour_info/1, start/4, start/5, start_link/4, start_link/5, call/2, call/3, + cast/2, reply/2, enter_loop/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +%% Internal application API +-export([cache_create/0, cache_lookup/2, cache_update/2, + cache_delete/1, cache_delete/2, cache_foldl/3, + cache_find/2]). + +-record(state, { + cm, + channel_cb, + channel_state, + channel_id, + close_sent = false + }). + +%%==================================================================== +%% API +%%==================================================================== + +%%% Optionel callbacks handle_call/3, handle_cast/2, handle_msg/2, +%%% code_change/3 +behaviour_info(callbacks) -> + [ + {init, 1}, + {terminate, 2}, + {handle_ssh_msg, 2}, + {handle_msg, 2} + ]. + + +call(ChannelPid, Msg) -> + call(ChannelPid, Msg, infinity). + +call(ChannelPid, Msg, TimeOute) -> + try gen_server:call(ChannelPid, Msg, TimeOute) of + Result -> + Result + catch + exit:{noproc, _} -> + {error, closed}; + exit:{timeout, _} -> + {error, timeout} + end. + + +cast(ChannelPid, Msg) -> + gen_server:cast(ChannelPid, Msg). + + +reply(From, Msg) -> + gen_server:reply(From, Msg). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> + start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + +start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> + Options = [{channel_cb, CallBack}, + {channel_id, ChannelId}, + {init_args, CbInitArgs}, + {cm, ConnectionManager}, + {exec, Exec}], + gen_server:start(?MODULE, [Options], []). + +start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> + start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + +start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> + Options = [{channel_cb, CallBack}, + {channel_id, ChannelId}, + {init_args, CbInitArgs}, + {cm, ConnectionManager}, + {exec, Exec}], + gen_server:start_link(?MODULE, [Options], []). + +enter_loop(State) -> + gen_server:enter_loop(?MODULE, [], State). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([Options]) -> + Cb = proplists:get_value(channel_cb, Options), + ConnectionManager = proplists:get_value(cm, Options), + ChannelId = proplists:get_value(channel_id, Options), + process_flag(trap_exit, true), + InitArgs = + case proplists:get_value(exec, Options) of + undefined -> + proplists:get_value(init_args, Options); + Exec -> + proplists:get_value(init_args, Options) ++ [Exec] + end, + try Cb:init(InitArgs) of + {ok, ChannelState} -> + State = #state{cm = ConnectionManager, + channel_cb = Cb, + channel_id = ChannelId, + channel_state = ChannelState}, + self() ! {ssh_channel_up, ChannelId, ConnectionManager}, + {ok, State}; + {ok, ChannelState, Timeout} -> + State = #state{cm = ConnectionManager, + channel_cb = Cb, + channel_id = ChannelId, + channel_state = ChannelState}, + self() ! {ssh_channel_up, ChannelId, ConnectionManager}, + {ok, State, Timeout}; + {stop, Why} -> + {stop, Why} + catch + _:Reason -> + {stop, Reason} + end. + +%%-------------------------------------------------------------------- +%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% Description: Handling call messages +%%-------------------------------------------------------------------- +handle_call(Request, From, #state{channel_cb = Module, + channel_state = ChannelState} = State) -> + try Module:handle_call(Request, From, ChannelState) of + Result -> + handle_cb_result(Result, State) + catch + error:{undef, _} -> + {noreply, State} + end. + + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast(Msg, #state{channel_cb = Module, + channel_state = ChannelState} = State) -> + + try Module:handle_cast(Msg, ChannelState) of + Result -> + handle_cb_result(Result, State) + catch + error:{undef, _} -> + {noreply, State} + end. + +%%-------------------------------------------------------------------- +%% Function: handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling all non call/cast messages +%%-------------------------------------------------------------------- +handle_info({ssh_cm, ConnectionManager, {closed, _ChannelId}}, + #state{cm = ConnectionManager, + close_sent = true} = State) -> + {stop, normal, State}; +handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}}, + #state{cm = ConnectionManager, + close_sent = false} = State) -> + %% To be on the safe side, i.e. the manager has already been terminated. + (catch ssh_connection:close(ConnectionManager, ChannelId)), + {stop, normal, State}; + +handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, + channel_cb = Module, + channel_state = ChannelState0} = State) -> + case Module:handle_ssh_msg(Msg, ChannelState0) of + {ok, ChannelState} -> + adjust_window(Msg), + {noreply, State#state{channel_state = ChannelState}}; + {ok, ChannelState, Timeout} -> + adjust_window(Msg), + {noreply, State#state{channel_state = ChannelState}, Timeout}; + {stop, ChannelId, ChannelState} -> + ssh_connection:close(ConnectionManager, ChannelId), + {stop, normal, State#state{close_sent = true, + channel_state = ChannelState}} + end; + +handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module, + channel_state = ChannelState0} = State) -> + case Module:handle_msg(Msg, ChannelState0) of + {ok, ChannelState} -> + {noreply, State#state{channel_state = ChannelState}}; + {ok, ChannelState, Timeout} -> + {noreply, State#state{channel_state = ChannelState}, Timeout}; + {stop, ChannelId, ChannelState} -> + ssh_connection:close(ConnectionManager, ChannelId), + {stop, normal, State#state{close_sent = true, + channel_state = ChannelState}} + end. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(Reason, #state{cm = ConnectionManager, + channel_id = ChannelId, + close_sent = false} = State) -> + ssh_connection:close(ConnectionManager, ChannelId), + terminate(Reason, State#state{close_sent = true}); +terminate(_, #state{channel_cb = Cb, channel_state = ChannelState}) -> + catch Cb:terminate(Cb, ChannelState), + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(OldVsn, #state{channel_cb = Module, + channel_state = ChannelState0} = State, Extra) -> + {ok, ChannelState} = Module:code_change(OldVsn, ChannelState0, Extra), + {ok, State#state{channel_state = ChannelState}}. + +%%==================================================================== +%% Internal application API +%%==================================================================== +cache_create() -> + ets:new(cm_tab, [set,{keypos, #channel.local_id}]). + +cache_lookup(Cache, Key) -> + case ets:lookup(Cache, Key) of + [Channel] -> + Channel; + [] -> + undefined + end. + +cache_update(Cache, #channel{local_id = Id} = Entry) when Id =/= undefined -> + ets:insert(Cache, Entry). + +cache_delete(Cache, Key) -> + ets:delete(Cache, Key). + +cache_delete(Cache) -> + ets:delete(Cache). + +cache_foldl(Fun, Acc, Cache) -> + ets:foldl(Fun, Acc, Cache). + +cache_find(ChannelPid, Cache) -> + case ets:match_object(Cache, #channel{user = ChannelPid}) of + [] -> + undefined; + [Channel] -> + Channel + end. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +handle_cb_result({reply, Reply, ChannelState}, State) -> + {reply, Reply, State#state{channel_state = ChannelState}}; +handle_cb_result({reply, Reply, ChannelState, Timeout}, State) -> + {reply, Reply,State#state{channel_state = ChannelState}, Timeout}; +handle_cb_result({noreply, ChannelState}, State) -> + {noreply, State#state{channel_state = ChannelState}}; +handle_cb_result({noreply, ChannelState, Timeout}, State) -> + {noreply, State#state{channel_state = ChannelState}, Timeout}; +handle_cb_result({stop, Reason, Reply, ChannelState}, State) -> + {stop, Reason, Reply, State#state{channel_state = ChannelState}}; +handle_cb_result({stop, Reason, ChannelState}, State) -> + {stop, Reason, State#state{channel_state = ChannelState}}. + +adjust_window({ssh_cm, ConnectionManager, + {data, ChannelId, _, Data}}) -> + ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data)); +adjust_window(_) -> + ok. + + diff --git a/lib/ssh/src/ssh_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl new file mode 100644 index 0000000000..c184fed627 --- /dev/null +++ b/lib/ssh/src/ssh_channel_sup.erl @@ -0,0 +1,54 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Ssh channel supervisor. +%%---------------------------------------------------------------------- +-module(ssh_channel_sup). + +-behaviour(supervisor). + +-export([start_link/1, start_child/2]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(Args) -> + supervisor:start_link(?MODULE, [Args]). + +start_child(Sup, ChildSpec) -> + supervisor:start_child(Sup, ChildSpec). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init(_Args) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Children = [], + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl new file mode 100644 index 0000000000..964f35121a --- /dev/null +++ b/lib/ssh/src/ssh_cli.erl @@ -0,0 +1,500 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Description: a gen_server implementing a simple +%% terminal (using the group module) for a CLI +%% over SSH + +-module(ssh_cli). + +-behaviour(ssh_channel). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). + +%% ssh_channel callbacks +-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]). + +%% backwards compatibility +-export([listen/1, listen/2, listen/3, listen/4, stop/1]). + +%% state +-record(state, { + cm, + channel, + pty, + group, + buf, + shell, + exec + }). + +%%==================================================================== +%% ssh_channel callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} +%% +%% Description: Initiates the CLI +%%-------------------------------------------------------------------- +init([Shell, Exec]) -> + {ok, #state{shell = Shell, exec = Exec}}; +init([Shell]) -> + {ok, #state{shell = Shell}}. + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles channel messages received on the ssh-connection. +%%-------------------------------------------------------------------- +handle_ssh_msg({ssh_cm, _ConnectionManager, + {data, _ChannelId, _Type, Data}}, + #state{group = Group} = State) -> + Group ! {self(), {data, binary_to_list(Data)}}, + {ok, State}; + +handle_ssh_msg({ssh_cm, ConnectionManager, + {pty, ChannelId, WantReply, + {TermName, Width, Height, PixWidth, PixHeight, Modes}}}, + State0) -> + State = State0#state{pty = + #ssh_pty{term = TermName, + width = not_zero(Width, 80), + height = not_zero(Height, 24), + pixel_width = PixWidth, + pixel_height = PixHeight, + modes = Modes}}, + set_echo(State), + ssh_connection:reply_request(ConnectionManager, WantReply, + success, ChannelId), + {ok, State}; + +handle_ssh_msg({ssh_cm, ConnectionManager, + {env, ChannelId, WantReply, _Var, _Value}}, State) -> + ssh_connection:reply_request(ConnectionManager, + WantReply, failure, ChannelId), + {ok, State}; + +handle_ssh_msg({ssh_cm, ConnectionManager, + {window_change, ChannelId, Width, Height, PixWidth, PixHeight}}, + #state{buf = Buf, pty = Pty0} = State) -> + Pty = Pty0#ssh_pty{width = Width, height = Height, + pixel_width = PixWidth, + pixel_height = PixHeight}, + {Chars, NewBuf} = io_request({window_change, Pty0}, Buf, Pty), + write_chars(ConnectionManager, ChannelId, Chars), + {ok, State#state{pty = Pty, buf = NewBuf}}; + +handle_ssh_msg({ssh_cm, ConnectionManager, + {shell, ChannelId, WantReply}}, State) -> + NewState = start_shell(ConnectionManager, State), + ssh_connection:reply_request(ConnectionManager, WantReply, + success, ChannelId), + {ok, NewState#state{channel = ChannelId, + cm = ConnectionManager}}; + +handle_ssh_msg({ssh_cm, ConnectionManager, + {exec, ChannelId, WantReply, Cmd}}, #state{exec=undefined} = State) -> + {Reply, Status} = exec(Cmd), + write_chars(ConnectionManager, + ChannelId, io_lib:format("~p\n", [Reply])), + ssh_connection:reply_request(ConnectionManager, WantReply, + success, ChannelId), + ssh_connection:exit_status(ConnectionManager, ChannelId, Status), + ssh_connection:send_eof(ConnectionManager, ChannelId), + {stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionManager}}; +handle_ssh_msg({ssh_cm, ConnectionManager, + {exec, ChannelId, WantReply, Cmd}}, State) -> + NewState = start_shell(ConnectionManager, Cmd, State), + ssh_connection:reply_request(ConnectionManager, WantReply, + success, ChannelId), + {ok, NewState#state{channel = ChannelId, + cm = ConnectionManager}}; + +handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) -> + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) -> + %% Ignore signals according to RFC 4254 section 6.9. + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, State) -> + Report = io_lib:format("Connection closed by peer ~n Error ~p~n", + [Error]), + error_logger:error_report(Report), + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, 0}}, State) -> + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State) -> + + Report = io_lib:format("Connection closed by peer ~n Status ~p~n", + [Status]), + error_logger:error_report(Report), + {stop, ChannelId, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles other channel messages. +%%-------------------------------------------------------------------- +handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, + #state{channel = ChannelId, + cm = ConnectionManager} = State) -> + {ok, State}; + +handle_msg({Group, Req}, #state{group = Group, buf = Buf, pty = Pty, + cm = ConnectionManager, + channel = ChannelId} = State) -> + {Chars, NewBuf} = io_request(Req, Buf, Pty), + write_chars(ConnectionManager, ChannelId, Chars), + {ok, State#state{buf = NewBuf}}; + +handle_msg({'EXIT', Group, _Reason}, #state{group = Group, + channel = ChannelId} = State) -> + {stop, ChannelId, State}; + +handle_msg(_, State) -> + {ok, State}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: Called when the channel process is trminated +%%-------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +exec(Cmd) -> + eval(parse(scan(Cmd))). + +scan(Cmd) -> + erl_scan:string(Cmd). + +parse({ok, Tokens, _}) -> + erl_parse:parse_exprs(Tokens); +parse(Error) -> + Error. + +eval({ok, Expr_list}) -> + case (catch erl_eval:exprs(Expr_list, + erl_eval:new_bindings())) of + {value, Value, _NewBindings} -> + {Value, 0}; + {'EXIT', {Error, _}} -> + {Error, -1}; + Error -> + {Error, -1} + end; +eval(Error) -> + {Error, -1}. + +%%% io_request, handle io requests from the user process, +%%% Note, this is not the real I/O-protocol, but the mockup version +%%% used between edlin and a user_driver. The protocol tags are +%%% similar, but the message set is different. +%%% The protocol only exists internally between edlin and a character +%%% displaying device... +%%% We are *not* really unicode aware yet, we just filter away characters +%%% beyond the latin1 range. We however handle the unicode binaries... +io_request({window_change, OldTty}, Buf, Tty) -> + window_change(Tty, OldTty, Buf); +io_request({put_chars, Cs}, Buf, Tty) -> + put_chars(bin_to_list(Cs), Buf, Tty); +io_request({put_chars, unicode, Cs}, Buf, Tty) -> + put_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty); +io_request({insert_chars, Cs}, Buf, Tty) -> + insert_chars(bin_to_list(Cs), Buf, Tty); +io_request({insert_chars, unicode, Cs}, Buf, Tty) -> + insert_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty); +io_request({move_rel, N}, Buf, Tty) -> + move_rel(N, Buf, Tty); +io_request({delete_chars,N}, Buf, Tty) -> + delete_chars(N, Buf, Tty); +io_request(beep, Buf, _Tty) -> + {[7], Buf}; + +%% New in R12 +io_request({get_geometry,columns},Buf,Tty) -> + {ok, Tty#ssh_pty.width, Buf}; +io_request({get_geometry,rows},Buf,Tty) -> + {ok, Tty#ssh_pty.height, Buf}; +io_request({requests,Rs}, Buf, Tty) -> + io_requests(Rs, Buf, Tty, []); +io_request(tty_geometry, Buf, Tty) -> + io_requests([{move_rel, 0}, {put_chars, unicode, [10]}], Buf, Tty, []); + %{[], Buf}; +io_request(_R, Buf, _Tty) -> + {[], Buf}. + +io_requests([R|Rs], Buf, Tty, Acc) -> + {Chars, NewBuf} = io_request(R, Buf, Tty), + io_requests(Rs, NewBuf, Tty, [Acc|Chars]); +io_requests([], Buf, _Tty, Acc) -> + {Acc, Buf}. + +%%% return commands for cursor navigation, assume everything is ansi +%%% (vt100), add clauses for other terminal types if needed +ansi_tty(N, L) -> + ["\e[", integer_to_list(N), L]. + +get_tty_command(up, N, _TerminalType) -> + ansi_tty(N, $A); +get_tty_command(down, N, _TerminalType) -> + ansi_tty(N, $B); +get_tty_command(right, N, _TerminalType) -> + ansi_tty(N, $C); +get_tty_command(left, N, _TerminalType) -> + ansi_tty(N, $D). + + +-define(PAD, 10). +-define(TABWIDTH, 8). + +%% convert input characters to buffer and to writeout +%% Note that the buf is reversed but the buftail is not +%% (this is handy; the head is always next to the cursor) +conv_buf([], AccBuf, AccBufTail, AccWrite, Col) -> + {AccBuf, AccBufTail, lists:reverse(AccWrite), Col}; +conv_buf([13, 10 | Rest], _AccBuf, AccBufTail, AccWrite, _Col) -> + conv_buf(Rest, [], tl2(AccBufTail), [10, 13 | AccWrite], 0); +conv_buf([13 | Rest], _AccBuf, AccBufTail, AccWrite, _Col) -> + conv_buf(Rest, [], tl1(AccBufTail), [13 | AccWrite], 0); +conv_buf([10 | Rest], _AccBuf, AccBufTail, AccWrite, _Col) -> + conv_buf(Rest, [], tl1(AccBufTail), [10, 13 | AccWrite], 0); +conv_buf([C | Rest], AccBuf, AccBufTail, AccWrite, Col) -> + conv_buf(Rest, [C | AccBuf], tl1(AccBufTail), [C | AccWrite], Col + 1). + + +%%% put characters at current position (possibly overwriting +%%% characters after current position in buffer) +put_chars(Chars, {Buf, BufTail, Col}, _Tty) -> + {NewBuf, NewBufTail, WriteBuf, NewCol} = + conv_buf(Chars, Buf, BufTail, [], Col), + {WriteBuf, {NewBuf, NewBufTail, NewCol}}. + +%%% insert character at current position +insert_chars([], {Buf, BufTail, Col}, _Tty) -> + {[], {Buf, BufTail, Col}}; +insert_chars(Chars, {Buf, BufTail, Col}, Tty) -> + {NewBuf, _NewBufTail, WriteBuf, NewCol} = + conv_buf(Chars, Buf, [], [], Col), + M = move_cursor(NewCol + length(BufTail), NewCol, Tty), + {[WriteBuf, BufTail | M], {NewBuf, BufTail, NewCol}}. + +%%% delete characters at current position, (backwards if negative argument) +delete_chars(0, {Buf, BufTail, Col}, _Tty) -> + {[], {Buf, BufTail, Col}}; +delete_chars(N, {Buf, BufTail, Col}, Tty) when N > 0 -> + NewBufTail = nthtail(N, BufTail), + M = move_cursor(Col + length(NewBufTail) + N, Col, Tty), + {[NewBufTail, lists:duplicate(N, $ ) | M], + {Buf, NewBufTail, Col}}; +delete_chars(N, {Buf, BufTail, Col}, Tty) -> % N < 0 + NewBuf = nthtail(-N, Buf), + NewCol = Col + N, + M1 = move_cursor(Col, NewCol, Tty), + M2 = move_cursor(NewCol + length(BufTail) - N, NewCol, Tty), + {[M1, BufTail, lists:duplicate(-N, $ ) | M2], + {NewBuf, BufTail, NewCol}}. + +%%% Window change, redraw the current line (and clear out after it +%%% if current window is wider than previous) +window_change(Tty, OldTty, Buf) + when OldTty#ssh_pty.width == Tty#ssh_pty.width -> + {[], Buf}; +window_change(Tty, OldTty, {Buf, BufTail, Col}) -> + M1 = move_cursor(Col, 0, OldTty), + N = max(Tty#ssh_pty.width - OldTty#ssh_pty.width, 0) * 2, + S = lists:reverse(Buf, [BufTail | lists:duplicate(N, $ )]), + M2 = move_cursor(length(Buf) + length(BufTail) + N, Col, Tty), + {[M1, S | M2], {Buf, BufTail, Col}}. + +%% move around in buffer, respecting pad characters +step_over(0, Buf, [?PAD | BufTail], Col) -> + {[?PAD | Buf], BufTail, Col+1}; +step_over(0, Buf, BufTail, Col) -> + {Buf, BufTail, Col}; +step_over(N, [C | Buf], BufTail, Col) when N < 0 -> + N1 = ifelse(C == ?PAD, N, N+1), + step_over(N1, Buf, [C | BufTail], Col-1); +step_over(N, Buf, [C | BufTail], Col) when N > 0 -> + N1 = ifelse(C == ?PAD, N, N-1), + step_over(N1, [C | Buf], BufTail, Col+1). + +%%% an empty line buffer +empty_buf() -> {[], [], 0}. + +%%% col and row from position with given width +col(N, W) -> N rem W. +row(N, W) -> N div W. + +%%% move relative N characters +move_rel(N, {Buf, BufTail, Col}, Tty) -> + {NewBuf, NewBufTail, NewCol} = step_over(N, Buf, BufTail, Col), + M = move_cursor(Col, NewCol, Tty), + {M, {NewBuf, NewBufTail, NewCol}}. + +%%% give move command for tty +move_cursor(A, A, _Tty) -> + []; +move_cursor(From, To, #ssh_pty{width=Width, term=Type}) -> + Tcol = case col(To, Width) - col(From, Width) of + 0 -> ""; + I when I < 0 -> get_tty_command(left, -I, Type); + I -> get_tty_command(right, I, Type) + end, + Trow = case row(To, Width) - row(From, Width) of + 0 -> ""; + J when J < 0 -> get_tty_command(up, -J, Type); + J -> get_tty_command(down, J, Type) + end, + [Tcol | Trow]. + +%% %%% write out characters +%% %%% make sure that there is data to send +%% %%% before calling ssh_connection:send +write_chars(ConnectionManager, ChannelId, Chars) -> + case erlang:iolist_size(Chars) of + 0 -> + ok; + _ -> + ssh_connection:send(ConnectionManager, ChannelId, + ?SSH_EXTENDED_DATA_DEFAULT, Chars) + end. + +%%% tail, works with empty lists +tl1([_|A]) -> A; +tl1(_) -> []. + +%%% second tail +tl2([_,_|A]) -> A; +tl2(_) -> []. + +%%% nthtail as in lists, but no badarg if n > the length of list +nthtail(0, A) -> A; +nthtail(N, [_ | A]) when N > 0 -> nthtail(N-1, A); +nthtail(_, _) -> []. + +%%% utils +max(A, B) when A > B -> A; +max(_A, B) -> B. + +ifelse(Cond, A, B) -> + case Cond of + true -> A; + _ -> B + end. + +bin_to_list(B) when is_binary(B) -> + binary_to_list(B); +bin_to_list(L) when is_list(L) -> + lists:flatten([bin_to_list(A) || A <- L]); +bin_to_list(I) when is_integer(I) -> + I. + +start_shell(ConnectionManager, State) -> + Shell = State#state.shell, + ShellFun = case is_function(Shell) of + true -> + case erlang:fun_info(Shell, arity) of + {arity, 1} -> + {ok, User} = + ssh_userreg:lookup_user(ConnectionManager), + fun() -> Shell(User) end; + {arity, 2} -> + {ok, User} = + ssh_userreg:lookup_user(ConnectionManager), + {ok, PeerAddr} = + ssh_cm:get_peer_addr(ConnectionManager), + fun() -> Shell(User, PeerAddr) end; + _ -> + Shell + end; + _ -> + Shell + end, + Echo = get_echo(State#state.pty), + Group = group:start(self(), ShellFun, [{echo, Echo}]), + State#state{group = Group, buf = empty_buf()}. + +start_shell(_ConnectionManager, Cmd, #state{exec={M, F, A}} = State) -> + Group = group:start(self(), {M, F, A++[Cmd]}, [{echo,false}]), + State#state{group = Group, buf = empty_buf()}. + + +% Pty can be undefined if the client never sets any pty options before +% starting the shell. +get_echo(undefined) -> + true; +get_echo(#ssh_pty{modes = Modes}) -> + case proplists:get_value(echo, Modes, 1) of + 0 -> + false; + _ -> + true + end. + +% Group is undefined if the pty options are sent between open and +% shell messages. +set_echo(#state{group = undefined}) -> + ok; +set_echo(#state{group = Group, pty = Pty}) -> + Echo = get_echo(Pty), + Group ! {self(), echo, Echo}. + +not_zero(0, B) -> + B; +not_zero(A, _) -> + A. + +%%% Backwards compatibility + +%%-------------------------------------------------------------------- +%% Function: listen(...) -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts a listening server +%% Note that the pid returned is NOT the pid of this gen_server; +%% this server is started when an SSH connection is made on the +%% listening port +%%-------------------------------------------------------------------- +listen(Shell) -> + listen(Shell, 22). + +listen(Shell, Port) -> + listen(Shell, Port, []). + +listen(Shell, Port, Opts) -> + listen(Shell, any, Port, Opts). + +listen(Shell, HostAddr, Port, Opts) -> + ssh:daemon(HostAddr, Port, [{shell, Shell} | Opts]). + + +%%-------------------------------------------------------------------- +%% Function: stop(Pid) -> ok +%% Description: Stops the listener +%%-------------------------------------------------------------------- +stop(Pid) -> + ssh:stop_listener(Pid). diff --git a/lib/ssh/src/ssh_cm.erl b/lib/ssh/src/ssh_cm.erl new file mode 100755 index 0000000000..c4d535df9a --- /dev/null +++ b/lib/ssh/src/ssh_cm.erl @@ -0,0 +1,237 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description : Backwards compatibility wrapper + +-module(ssh_cm). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). + +%% -define(DEFAULT_PACKET_SIZE, 32768). +%% -define(DEFAULT_WINDOW_SIZE, 2*?DEFAULT_PACKET_SIZE). +%%-define(DEFAULT_TIMEOUT, 5000). + +-export([connect/1, connect/2, connect/3]). +-export([listen/2, listen/3, listen/4, stop_listener/1]). +-export([stop/1]). + +-deprecated({connect, 1, next_major_release}). +-deprecated({connect, 2, next_major_release}). +-deprecated({connect, 3, next_major_release}). +-deprecated({listen, 2, next_major_release}). +-deprecated({listen, 3, next_major_release}). +-deprecated({listen, 4, next_major_release}). +-deprecated({stop_listener, 1, next_major_release}). +-deprecated({stop, 1, next_major_release}). + +-export([adjust_window/3, attach/2, attach/3, detach/2, + tcpip_forward/3, cancel_tcpip_forward/3, direct_tcpip/6, + direct_tcpip/8, close/2, shell/2, exec/4, + send/3, send/4, + send_ack/3, send_ack/4, send_ack/5, send_eof/2, + session_open/2, session_open/4, subsystem/4, + open_pty/3, open_pty/7, open_pty/9, + set_user_ack/4, + setenv/5, signal/3, winch/4]). + +-deprecated({adjust_window, 3, next_major_release}). +-deprecated({attach, 2, next_major_release}). +-deprecated({attach, 3, next_major_release}). +-deprecated({detach, 2, next_major_release}). +-deprecated({tcpip_forward, 3, next_major_release}). +-deprecated({cancel_tcpip_forward, 3, next_major_release}). +-deprecated({direct_tcpip, 6, next_major_release}). +-deprecated({direct_tcpip, 8, next_major_release}). +-deprecated({close, 2, next_major_release}). +-deprecated({shell, 2, next_major_release}). +-deprecated({exec, 4, next_major_release}). +-deprecated({send, 3, next_major_release}). +-deprecated({send, 4, next_major_release}). +-deprecated({send_ack, 3, next_major_release}). +-deprecated({send_ack, 4, next_major_release}). +-deprecated({send_ack, 5, next_major_release}). +-deprecated({send_eof, 2, next_major_release}). +-deprecated({session_open, 2, next_major_release}). +-deprecated({session_open, 4, next_major_release}). +-deprecated({subsystem, 4, next_major_release}). +-deprecated({open_pty, 3, next_major_release}). +-deprecated({open_pty, 7, next_major_release}). +-deprecated({open_pty, 9, next_major_release}). +-deprecated({set_user_ack, 4, next_major_release}). +-deprecated({setenv, 5, next_major_release}). +-deprecated({signal, 3, next_major_release}). +-deprecated({winch, 4, next_major_release}). + +-export([info/1, info/2, recv_window/3, + send_window/3, renegotiate/1, renegotiate/2, + get_peer_addr/1]). + +%%==================================================================== +%% API +%%==================================================================== +connect(Host) -> + connect(Host, []). +connect(Host, Opts) -> + connect(Host, ?SSH_DEFAULT_PORT, Opts). +connect(Host, Port, Opts) -> + ssh:connect(Host, Port, Opts). + +listen(ChannelSpec, Port) -> + listen(ChannelSpec, Port, []). +listen(ChannelSpec, Port, Opts) -> + listen(ChannelSpec, any, Port, Opts). +listen(ChannelSpec, "localhost", Port, Opts) -> + listen(ChannelSpec, any, Port, Opts); +listen(_ChannelSpec, Host, Port, Opts) -> + ssh:daemon(Host, Port, Opts). + +stop_listener(SysSup) -> + ssh_system_sup:stop_listener(SysSup). +stop(Cm) -> + ssh:close(Cm). + +%% CM Client commands +session_open(Cm, Timeout) -> + session_open(Cm, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). + +session_open(Cm, InitialWindowSize, MaxPacketSize, Timeout) -> + ssh_connection:session_channel(Cm, InitialWindowSize, MaxPacketSize, + Timeout). + + +setenv(Cm, Channel, Var, Value, Timeout) -> + ssh_connection:setenv(Cm, Channel, Var, Value, Timeout). + +shell(Cm, Channel) -> + ssh_connection:shell(Cm, Channel). + +exec(Cm, Channel, Command, Timeout) -> + ssh_connection:exec(Cm, Channel, Command, Timeout). + +subsystem(Cm, Channel, SubSystem, Timeout) -> + ssh_connection:subsystem(Cm, Channel, SubSystem, Timeout). + +%% Not needed for backwards compatibility for now +attach(_Cm, _Timeout) -> + ok. + +attach(_Cm, _ChannelPid, _Timeout) -> + ok. + +detach(_Cm, _Timeout) -> + ok. + +%% Not needed, send_ack is now call! Temp backwardcompability +set_user_ack(_, _, _, _) -> + ok. + +adjust_window(Cm, Channel, Bytes) -> + ssh_connection:adjust_window(Cm, Channel, Bytes). + +close(Cm, Channel) -> + ssh_connection:close(Cm, Channel). + +send_eof(Cm, Channel) -> + ssh_connection:send_eof(Cm, Channel). + +send(Cm, Channel, Data) -> + ssh_connection:send(Cm, Channel, 0, Data). + +send(Cm, Channel, Type, Data) -> + ssh_connection:send(Cm, Channel, Type, Data). + +%% Send ack is not needed +send_ack(Cm, Channel, Data) -> + send_ack(Cm, Channel, 0, Data, infinity). + +send_ack(Cm, Channel, Type, Data) -> + send_ack(Cm, Channel, Type, Data, infinity). + +send_ack(Cm, Channel, Type, Data, Timeout) -> + ssh_connection:send(Cm, Channel, Type, Data, Timeout). + +%% ---------------------------------------------------------------------- +%% These functions replacers are not officially supported but proably will be +%% when we had time to test them. +%% ---------------------------------------------------------------------- +direct_tcpip(Cm, RemoteHost, RemotePort, OrigIP, OrigPort, Timeout) -> + direct_tcpip(Cm, RemoteHost, RemotePort, OrigIP, OrigPort, + ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). + +direct_tcpip(Cm, RemoteIP, RemotePort, OrigIP, OrigPort, + InitialWindowSize, MaxPacketSize, Timeout) -> + ssh_connection:direct_tcpip(Cm, RemoteIP, RemotePort, + OrigIP, OrigPort, + InitialWindowSize, + MaxPacketSize, Timeout). + +tcpip_forward(Cm, BindIP, BindPort) -> + ssh_connection:tcpip_forward(Cm, BindIP, BindPort). + +cancel_tcpip_forward(Cm, BindIP, Port) -> + ssh_connection:cancel_tcpip_forward(Cm, BindIP, Port). + +open_pty(Cm, Channel, Timeout) -> + open_pty(Cm, Channel, os:getenv("TERM"), 80, 24, [], Timeout). + +open_pty(Cm, Channel, Term, Width, Height, PtyOpts, Timeout) -> + open_pty(Cm, Channel, Term, Width, Height, 0, 0, PtyOpts, Timeout). + +open_pty(Cm, Channel, Term, Width, Height, PixWidth, PixHeight, + PtyOpts, Timeout) -> + ssh_connection:open_pty(Cm, Channel, Term, + Width, Height, PixWidth, + PixHeight, PtyOpts, Timeout). +winch(Cm, Channel, Width, Height) -> + winch(Cm, Channel, Width, Height, 0, 0). +winch(Cm, Channel, Width, Height, PixWidth, PixHeight) -> + ssh_connection:window_change(Cm, Channel, Width, + Height, PixWidth, PixHeight). +signal(Cm, Channel, Sig) -> + ssh_connection:signal(Cm, Channel, Sig). + +%% ---------------------------------------------------------------------- +%% These functions replacers are not officially supported and +%% the format of them will proably change when and +%% if they get supported. +%% ---------------------------------------------------------------------- +info(Cm) -> + info(Cm, all). + +info(Cm, ChannelPid) -> + ssh_connection_manager:info(Cm, ChannelPid). + +send_window(Cm, Channel, Timeout) -> + ssh_connection_manager:send_window(Cm, Channel, Timeout). + +recv_window(Cm, Channel, Timeout) -> + ssh_connection_manager:recv_window(Cm, Channel, Timeout). + +renegotiate(Cm) -> + renegotiate(Cm, []). +renegotiate(Cm, _Opts) -> + %%TODO: How should this work, backwards compat? + ssh_connection_manager:renegotiate(Cm). + +get_peer_addr(Cm) -> + ssh_connection_manager:peer_addr(Cm). + diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl new file mode 100755 index 0000000000..a5a4e42cd8 --- /dev/null +++ b/lib/ssh/src/ssh_connect.hrl @@ -0,0 +1,264 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description : SSH connection protocol + +-define(DEFAULT_PACKET_SIZE, 32768). +-define(DEFAULT_WINDOW_SIZE, 2*?DEFAULT_PACKET_SIZE). +-define(DEFAULT_TIMEOUT, 5000). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% CONNECT messages +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%---------------------------------------------------------------------- +%%% # SSH_MSG_xxx +%%% Description: Packet types used by the connection protocol. +%%%---------------------------------------------------------------------- +-define(SSH_MSG_GLOBAL_REQUEST, 80). +-define(SSH_MSG_REQUEST_SUCCESS, 81). +-define(SSH_MSG_REQUEST_FAILURE, 82). +-define(SSH_MSG_CHANNEL_OPEN, 90). +-define(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 91). +-define(SSH_MSG_CHANNEL_OPEN_FAILURE, 92). +-define(SSH_MSG_CHANNEL_WINDOW_ADJUST, 93). +-define(SSH_MSG_CHANNEL_DATA, 94). +-define(SSH_MSG_CHANNEL_EXTENDED_DATA, 95). +-define(SSH_MSG_CHANNEL_EOF, 96). +-define(SSH_MSG_CHANNEL_CLOSE, 97). +-define(SSH_MSG_CHANNEL_REQUEST, 98). +-define(SSH_MSG_CHANNEL_SUCCESS, 99). +-define(SSH_MSG_CHANNEL_FAILURE, 100). + +-record(ssh_msg_global_request, + { + name, + want_reply, + data %% ... + }). + +-record(ssh_msg_request_success, + { + data %% ... + }). + +-record(ssh_msg_request_failure, + { + }). + + +-record(ssh_msg_channel_open, + { + channel_type, + sender_channel, + initial_window_size, + maximum_packet_size, + data %% ... + }). + +-record(ssh_msg_channel_open_confirmation, + { + recipient_channel, + sender_channel, + initial_window_size, + maximum_packet_size, + data %% ... + }). + + +%%%---------------------------------------------------------------------- +%%% # SSH_OPEN_xxx +%%% Description: Reason codes for SSH_MSG_OPEN_FAILURE packages. +%%%---------------------------------------------------------------------- + +-define(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, 1). +-define(SSH_OPEN_CONNECT_FAILED, 2). +-define(SSH_OPEN_UNKNOWN_CHANNEL_TYPE, 3). +-define(SSH_OPEN_RESOURCE_SHORTAGE, 4). + +-record(ssh_msg_channel_open_failure, + { + recipient_channel, + reason, + description, + lang + }). + + +-record(ssh_msg_channel_window_adjust, + { + recipient_channel, + bytes_to_add + }). + +-record(ssh_msg_channel_data, + { + recipient_channel, + data + }). + +%%%---------------------------------------------------------------------- +%%% # SSH_EXTENDED_DATA_xxx +%%% Description: Type codes for SSH_MSG_CHANNEL_EXTENDED_DATA packages +%%%---------------------------------------------------------------------- +-define(SSH_EXTENDED_DATA_DEFAULT, 0). +-define(SSH_EXTENDED_DATA_STDERR, 1). + +-record(ssh_msg_channel_extended_data, + { + recipient_channel, + data_type_code, + data + }). + +-record(ssh_msg_channel_eof, + { + recipient_channel + }). + +-record(ssh_msg_channel_close, + { + recipient_channel + }). + + +-record(ssh_msg_channel_request, + { + recipient_channel, + request_type, + want_reply, + data %% ... + }). + + +-record(ssh_msg_channel_success, + { + recipient_channel + }). + + +-record(ssh_msg_channel_failure, + { + recipient_channel + }). + +-define(TTY_OP_END,0). %% Indicates end of options. +-define(VINTR,1). %% Interrupt character; 255 if none. Similarly for the + %% other characters. Not all of these characters are + %% supported on all systems. +-define(VQUIT,2). %% The quit character (sends SIGQUIT signal on POSIX + %% systems). +-define(VERASE,3). %% Erase the character to left of the cursor. +-define(VKILL,4). %% Kill the current input line. +-define(VEOF,5). %% End-of-file character (sends EOF from the terminal). +-define(VEOL,6). %% End-of-line character in addition to carriage return + %% or,and). linefeed. +-define(VEOL2,7). %% Additional end-of-line character. +-define(VSTART,8). %% Continues paused output (normally control-Q). +-define(VSTOP,9). %% Pauses output (normally control-S). +-define(VSUSP,10). %% Suspends the current program. +-define(VDSUSP,11). %% Another suspend character. +-define(VREPRINT,12). %% Reprints the current input line. +-define(VWERASE,13). %% Erases a word left of cursor. +-define(VLNEXT,14). %% Enter the next character typed literally, even if it + %% is a special character +-define(VFLUSH,15). %% Character to flush output. +-define(VSWTCH,16). %% Switch to a different shell layer. +-define(VSTATUS,17). %% Prints system status line (load, command, pid etc). +-define(VDISCARD,18). %% Toggles the flushing of terminal output. +-define(IGNPAR,30). %% The ignore parity flag. The parameter SHOULD be 0 if + %% this flag is FALSE set, and 1 if it is TRUE. +-define(PARMRK,31). %% Mark parity and framing errors. +-define(INPCK,32). %% Enable checking of parity errors. +-define(ISTRIP,33). %% Strip 8th bit off characters. +-define(INLCR,34). %% Map NL into CR on input. +-define(IGNCR,35). %% Ignore CR on input. +-define(ICRNL,36). %% Map CR to NL on input. +-define(IUCLC,37). %% Translate uppercase characters to lowercase. +-define(IXON,38). %% Enable output flow control. +-define(IXANY,39). %% Any char will restart after stop. +-define(IXOFF,40). %% Enable input flow control. +-define(IMAXBEL,41). %% Ring bell on input queue full. +-define(ISIG,50). %% Enable signals INTR, QUIT, [D]SUSP. +-define(ICANON,51). %% Canonicalize input lines. +-define(XCASE,52). %% Enable input and output of uppercase characters by + %% preceding their lowercase equivalents with `\'. +-define(ECHO,53). %% Enable echoing. +-define(ECHOE,54). %% Visually erase chars. +-define(ECHOK,55). %% Kill character discards current line. +-define(ECHONL,56). %% Echo NL even if ECHO is off. +-define(NOFLSH,57). %% Don't flush after interrupt. +-define(TOSTOP,58). %% Stop background jobs from output. +-define(IEXTEN,59). %% Enable extensions. +-define(ECHOCTL,60). %% Echo control characters as ^(Char). +-define(ECHOKE,61). %% Visual erase for line kill. +-define(PENDIN,62). %% Retype pending input. +-define(OPOST,70). %% Enable output processing. +-define(OLCUC,71). %% Convert lowercase to uppercase. +-define(ONLCR,72). %% Map NL to CR-NL. +-define(OCRNL,73). %% Translate carriage return to newline (output). +-define(ONOCR,74). %% Translate newline to carriage return-newline + %% (output). +-define(ONLRET,75). %% Newline performs a carriage return (output). +-define(CS7,90). %% 7 bit mode. +-define(CS8,91). %% 8 bit mode. +-define(PARENB,92). %% Parity enable. +-define(PARODD,93). %% Odd parity, else even. + +%% Specifies the input baud rate in bits per second. +-define(TTY_OP_ISPEED,128). +%% Specifies the output baud rate in bits per second. +-define(TTY_OP_OSPEED,129). + +-record(channel, + { + type, %% "session", "x11", "forwarded-tcpip", "direct-tcpip" + sys, %% "none", "shell", "exec" "subsystem" + user, %% "user" process id (default to cm user) + flow_control, + + local_id, %% local channel id + + recv_window_size, + recv_packet_size, + recv_close = false, + + remote_id, %% remote channel id + send_window_size, + send_packet_size, + sent_close = false, + send_buf = [] + }). + +-record(connection, { + requests = [], %% [{ChannelId, Pid}...] awaiting reply on request, + channel_cache, + channel_pids = [], + port_bindings, + channel_id_seed, + cli_spec, + address, + port, + options, + exec + }). diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl new file mode 100644 index 0000000000..0aaf1c18d2 --- /dev/null +++ b/lib/ssh/src/ssh_connection.erl @@ -0,0 +1,1366 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%---------------------------------------------------------------------- +%% Purpose: Details of connection protocol +%%---------------------------------------------------------------------- + +-module(ssh_connection). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). +-include("ssh_transport.hrl"). + +-export([session_channel/2, session_channel/4, + exec/4, shell/2, subsystem/4, send/3, send/4, send/5, + send_eof/2, adjust_window/3, open_pty/3, open_pty/7, + open_pty/9, setenv/5, window_change/4, window_change/6, + direct_tcpip/6, direct_tcpip/8, tcpip_forward/3, + cancel_tcpip_forward/3, signal/3, exit_status/3, encode_ip/1, close/2, + reply_request/4]). + +-export([channel_data/6, handle_msg/4, channel_eof_msg/1, + channel_close_msg/1, channel_success_msg/1, channel_failure_msg/1, + channel_adjust_window_msg/2, channel_data_msg/3, + channel_open_msg/5, channel_open_confirmation_msg/4, + channel_open_failure_msg/4, channel_request_msg/4, + global_request_msg/3, request_failure_msg/0, + request_success_msg/1, bind/4, unbind/3, unbind_channel/2, + bound_channel/3, messages/0]). + +%%-------------------------------------------------------------------- +%%% Internal application API +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Function: session_channel(ConnectionManager +%% [, InitialWindowSize, MaxPacketSize], +%% Timeout) -> {ok, } +%% ConnectionManager = pid() +%% InitialWindowSize = integer() +%% MaxPacketSize = integer() +%% +%% Description: Opens a channel for a ssh session. A session is a +%% remote execution of a program. The program may be a shell, an +%% application, a system command, or some built-in subsystem. +%% -------------------------------------------------------------------- +session_channel(ConnectionManager, Timeout) -> + session_channel(ConnectionManager, + ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, + Timeout). +session_channel(ConnectionManager, InitialWindowSize, + MaxPacketSize, Timeout) -> + ssh_connection_manager:open_channel(ConnectionManager, "session", <<>>, + InitialWindowSize, + MaxPacketSize, Timeout). +%%-------------------------------------------------------------------- +%% Function: exec(ConnectionManager, ChannelId, Command, Timeout) -> +%% +%% ConnectionManager = pid() +%% ChannelId = integer() +%% Cmd = string() +%% Timeout = integer() +%% +%% Description: Will request that the server start the +%% execution of the given command. +%%-------------------------------------------------------------------- +exec(ConnectionManager, ChannelId, Command, TimeOut) -> + ssh_connection_manager:request(ConnectionManager, self(), ChannelId, "exec", + true, [?string(Command)], TimeOut). +%%-------------------------------------------------------------------- +%% Function: shell(ConnectionManager, ChannelId) -> +%% +%% ConnectionManager = pid() +%% ChannelId = integer() +%% +%% Description: Will request that the user's default shell (typically +%% defined in /etc/passwd in UNIX systems) be started at the other +%% end. +%%-------------------------------------------------------------------- +shell(ConnectionManager, ChannelId) -> + ssh_connection_manager:request(ConnectionManager, self(), ChannelId, + "shell", false, <<>>, 0). +%%-------------------------------------------------------------------- +%% Function: subsystem(ConnectionManager, ChannelId, SubSystem, TimeOut) -> +%% +%% ConnectionManager = pid() +%% ChannelId = integer() +%% SubSystem = string() +%% TimeOut = integer() +%% +%% +%% Description: Executes a predefined subsystem. +%%-------------------------------------------------------------------- +subsystem(ConnectionManager, ChannelId, SubSystem, TimeOut) -> + ssh_connection_manager:request(ConnectionManager, self(), + ChannelId, "subsystem", + true, [?string(SubSystem)], TimeOut). +%%-------------------------------------------------------------------- +%% Function: send(ConnectionManager, ChannelId, Type, Data, [TimeOut]) -> +%% +%% +%% Description: Sends channel data. +%%-------------------------------------------------------------------- +send(ConnectionManager, ChannelId, Data) -> + send(ConnectionManager, ChannelId, 0, Data, infinity). +send(ConnectionManager, ChannelId, Data, TimeOut) when is_integer(TimeOut) -> + send(ConnectionManager, ChannelId, 0, Data, TimeOut); +send(ConnectionManager, ChannelId, Type, Data) -> + send(ConnectionManager, ChannelId, Type, Data, infinity). +send(ConnectionManager, ChannelId, Type, Data, TimeOut) -> + ssh_connection_manager:send(ConnectionManager, ChannelId, + Type, Data, TimeOut). +%%-------------------------------------------------------------------- +%% Function: send_eof(ConnectionManager, ChannelId) -> +%% +%% +%% Description: Sends eof on the channel <ChannelId>. +%%-------------------------------------------------------------------- +send_eof(ConnectionManager, Channel) -> + ssh_connection_manager:send_eof(ConnectionManager, Channel). + +%%-------------------------------------------------------------------- +%% Function: adjust_window(ConnectionManager, Channel, Bytes) -> +%% +%% +%% Description: Adjusts the ssh flowcontrol window. +%%-------------------------------------------------------------------- +adjust_window(ConnectionManager, Channel, Bytes) -> + ssh_connection_manager:adjust_window(ConnectionManager, Channel, Bytes). + +%%-------------------------------------------------------------------- +%% Function: setenv(ConnectionManager, ChannelId, Var, Value, TimeOut) -> +%% +%% +%% Description: Environment variables may be passed to the shell/command to be +%% started later. +%%-------------------------------------------------------------------- +setenv(ConnectionManager, ChannelId, Var, Value, TimeOut) -> + ssh_connection_manager:request(ConnectionManager, ChannelId, + "env", true, [?string(Var), ?string(Value)], TimeOut). + + +%%-------------------------------------------------------------------- +%% Function: close(ConnectionManager, ChannelId) -> +%% +%% +%% Description: Sends a close message on the channel <ChannelId>. +%%-------------------------------------------------------------------- +close(ConnectionManager, ChannelId) -> + ssh_connection_manager:close(ConnectionManager, ChannelId). + + +%%-------------------------------------------------------------------- +%% Function: reply_request(ConnectionManager, WantReply, Status, CannelId) ->_ +%% +%% +%% Description: Send status replies to requests that want such replies. +%%-------------------------------------------------------------------- +reply_request(ConnectionManager, true, Status, ChannelId) -> + ConnectionManager ! {ssh_cm, self(), {Status, ChannelId}}, + ok; +reply_request(_,false, _, _) -> + ok. + + +%%-------------------------------------------------------------------- +%% Function: window_change(ConnectionManager, Channel, Width, Height) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +window_change(ConnectionManager, Channel, Width, Height) -> + window_change(ConnectionManager, Channel, Width, Height, 0, 0). +window_change(ConnectionManager, Channel, Width, Height, + PixWidth, PixHeight) -> + ssh_connection_manager:request(ConnectionManager, Channel, + "window-change", false, + [?uint32(Width), ?uint32(Height), + ?uint32(PixWidth), ?uint32(PixHeight)], 0). +%%-------------------------------------------------------------------- +%% Function: signal(ConnectionManager, Channel, Sig) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +signal(ConnectionManager, Channel, Sig) -> + ssh_connection_manager:request(ConnectionManager, Channel, + "signal", false, [?string(Sig)], 0). + +%%-------------------------------------------------------------------- +%% Function: signal(ConnectionManager, Channel, Status) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +exit_status(ConnectionManager, Channel, Status) -> + ssh_connection_manager:request(ConnectionManager, Channel, + "exit-status", false, [?uint32(Status)], 0). + + +%%-------------------------------------------------------------------- +%% Function: open_pty(ConnectionManager, Channel, TimeOut) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +open_pty(ConnectionManager, Channel, TimeOut) -> + open_pty(ConnectionManager, Channel, + os:getenv("TERM"), 80, 24, [], TimeOut). + +open_pty(ConnectionManager, Channel, Term, Width, Height, PtyOpts, TimeOut) -> + open_pty(ConnectionManager, Channel, Term, Width, + Height, 0, 0, PtyOpts, TimeOut). + +open_pty(ConnectionManager, Channel, Term, Width, Height, + PixWidth, PixHeight, PtyOpts, TimeOut) -> + ssh_connection_manager:request(ConnectionManager, + Channel, "pty-req", true, + [?string(Term), + ?uint32(Width), ?uint32(Height), + ?uint32(PixWidth),?uint32(PixHeight), + encode_pty_opts(PtyOpts)], TimeOut). + + +%%-------------------------------------------------------------------- +%% Function: direct_tcpip(ConnectionManager, RemoteHost, +%% RemotePort, OrigIP, OrigPort, Timeout) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +direct_tcpip(ConnectionManager, RemoteHost, + RemotePort, OrigIP, OrigPort, Timeout) -> + direct_tcpip(ConnectionManager, RemoteHost, RemotePort, OrigIP, OrigPort, + ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). + +direct_tcpip(ConnectionManager, RemoteIP, RemotePort, OrigIP, OrigPort, + InitialWindowSize, MaxPacketSize, Timeout) -> + case {encode_ip(RemoteIP), encode_ip(OrigIP)} of + {false, _} -> + {error, einval}; + {_, false} -> + {error, einval}; + {RIP, OIP} -> + ssh_connection_manager:open_channel(ConnectionManager, + "direct-tcpip", + [?string(RIP), + ?uint32(RemotePort), + ?string(OIP), + ?uint32(OrigPort)], + InitialWindowSize, + MaxPacketSize, + Timeout) + end. +%%-------------------------------------------------------------------- +%% Function: tcpip_forward(ConnectionManager, BindIP, BindPort) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +tcpip_forward(ConnectionManager, BindIP, BindPort) -> + case encode_ip(BindIP) of + false -> + {error, einval}; + IPStr -> + ssh_connection_manager:global_request(ConnectionManager, + "tcpip-forward", true, + [?string(IPStr), + ?uint32(BindPort)]) + end. +%%-------------------------------------------------------------------- +%% Function: cancel_tcpip_forward(ConnectionManager, BindIP, Port) -> +%% +%% +%% Description: Not yet officialy supported. +%%-------------------------------------------------------------------- +cancel_tcpip_forward(ConnectionManager, BindIP, Port) -> + case encode_ip(BindIP) of + false -> + {error, einval}; + IPStr -> + ssh_connection_manager:global_request(ConnectionManager, + "cancel-tcpip-forward", true, + [?string(IPStr), + ?uint32(Port)]) + end. + +%%-------------------------------------------------------------------- +%%% Internal API +%%-------------------------------------------------------------------- +channel_data(ChannelId, DataType, Data, Connection, ConnectionPid, From) + when is_list(Data)-> + channel_data(ChannelId, DataType, + list_to_binary(Data), Connection, ConnectionPid, From); + +channel_data(ChannelId, DataType, Data, + #connection{channel_cache = Cache} = Connection, ConnectionPid, + From) -> + + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{remote_id = Id} = Channel0 -> + {SendList, Channel} = update_send_window(Channel0, DataType, + Data, Connection), + Replies = + lists:map(fun({SendDataType, SendData}) -> + {connection_reply, ConnectionPid, + channel_data_msg(Id, + SendDataType, + SendData)} + end, SendList), + FlowCtrlMsgs = flow_control(Replies, + Channel#channel{flow_control = From}, + Cache), + {{replies, Replies ++ FlowCtrlMsgs}, Connection}; + undefined -> + {noreply, Connection} + end. + +handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId, + sender_channel = RemoteId, + initial_window_size = WindowSz, + maximum_packet_size = PacketSz}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + + #channel{remote_id = undefined} = Channel = + ssh_channel:cache_lookup(Cache, ChannelId), + + ssh_channel:cache_update(Cache, Channel#channel{ + remote_id = RemoteId, + send_window_size = WindowSz, + send_packet_size = PacketSz}), + {Reply, Connection} = reply_msg(Channel, Connection0, {open, ChannelId}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_open_failure{recipient_channel = ChannelId, + reason = Reason, + description = Descr, + lang = Lang}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + ssh_channel:cache_delete(Cache, ChannelId), + {Reply, Connection} = + reply_msg(Channel, Connection0, {open_error, Reason, Descr, Lang}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = reply_msg(Channel, Connection0, success), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = reply_msg(Channel, Connection0, failure), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = reply_msg(Channel, Connection0, {eof, ChannelId}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId}, + #connection{channel_cache = Cache} = Connection0, + ConnectionPid, _) -> + + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{sent_close = Closed, remote_id = RemoteId} = Channel -> + ssh_channel:cache_delete(Cache, ChannelId), + {CloseMsg, Connection} = + reply_msg(Channel, Connection0, {closed, ChannelId}), + case Closed of + true -> + {{replies, [CloseMsg]}, Connection}; + false -> + RemoteCloseMsg = channel_close_msg(RemoteId), + {{replies, + [{connection_reply, + ConnectionPid, RemoteCloseMsg}, + CloseMsg]}, Connection} + end; + undefined -> + {{replies, []}, Connection0} + end; + +handle_msg(#ssh_msg_channel_data{recipient_channel = ChannelId, + data = Data}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + + #channel{recv_window_size = Size} = Channel = + ssh_channel:cache_lookup(Cache, ChannelId), + WantedSize = Size - size(Data), + ssh_channel:cache_update(Cache, Channel#channel{ + recv_window_size = WantedSize}), + {Replies, Connection} = + channel_data_reply(Cache, Channel, Connection0, 0, Data), + {{replies, Replies}, Connection}; + +handle_msg(#ssh_msg_channel_extended_data{recipient_channel = ChannelId, + data_type_code = DataType, + data = Data}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + + #channel{recv_window_size = Size} = Channel = + ssh_channel:cache_lookup(Cache, ChannelId), + WantedSize = Size - size(Data), + ssh_channel:cache_update(Cache, Channel#channel{ + recv_window_size = WantedSize}), + {Replies, Connection} = + channel_data_reply(Cache, Channel, Connection0, DataType, Data), + {{replies, Replies}, Connection}; + +handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId, + bytes_to_add = Add}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, _) -> + + #channel{send_window_size = Size} = + Channel0 = ssh_channel:cache_lookup(Cache, ChannelId), + + {SendList, Channel} = %% TODO: Datatype 0 ? + update_send_window(Channel0#channel{send_window_size = Size + Add}, + 0, <<>>, Connection), + + Replies = lists:map(fun({Type, Data}) -> + {connection_reply, ConnectionPid, + channel_data_msg(ChannelId, Type, Data)} + end, SendList), + FlowCtrlMsgs = flow_control(Channel, Cache), + {{replies, Replies ++ FlowCtrlMsgs}, Connection}; + +handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type, + sender_channel = ChannelId, + initial_window_size = WindowSz, + maximum_packet_size = PacketSz}, Connection0, + ConnectionPid, server) -> + + try setup_session(Connection0, ConnectionPid, ChannelId, + Type, WindowSz, PacketSz) of + Result -> + Result + catch _:_ -> + FailMsg = channel_open_failure_msg(ChannelId, + ?SSH_OPEN_CONNECT_FAILED, + "Connection refused", "en"), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, + Connection0} + end; + +handle_msg(#ssh_msg_channel_open{channel_type = "session", + sender_channel = RemoteId}, + Connection, ConnectionPid, client) -> + %% Client implementations SHOULD reject any session channel open + %% requests to make it more difficult for a corrupt server to attack the + %% client. See See RFC 4254 6.1. + FailMsg = channel_open_failure_msg(RemoteId, + ?SSH_OPEN_CONNECT_FAILED, + "Connection refused", "en"), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, + Connection}; + +handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type, + sender_channel = RemoteId, + initial_window_size = RWindowSz, + maximum_packet_size = RPacketSz, + data = Data}, + #connection{channel_cache = Cache} = Connection0, + ConnectionPid, server) -> + <<?UINT32(ALen), Address:ALen/binary, ?UINT32(Port), + ?UINT32(OLen), Orig:OLen/binary, ?UINT32(OrigPort)>> = Data, + + case bound_channel(Address, Port, Connection0) of + undefined -> + FailMsg = channel_open_failure_msg(RemoteId, + ?SSH_OPEN_CONNECT_FAILED, + "Connection refused", "en"), + {{replies, + [{connection_reply, ConnectionPid, FailMsg}]}, Connection0}; + ChannelPid -> + {ChannelId, Connection1} = new_channel_id(Connection0), + LWindowSz = ?DEFAULT_WINDOW_SIZE, + LPacketSz = ?DEFAULT_PACKET_SIZE, + Channel = #channel{type = Type, + sys = "none", + user = ChannelPid, + local_id = ChannelId, + recv_window_size = LWindowSz, + recv_packet_size = LPacketSz, + send_window_size = RWindowSz, + send_packet_size = RPacketSz}, + ssh_channel:cache_update(Cache, Channel), + OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId, + LWindowSz, LPacketSz), + {OpenMsg, Connection} = + reply_msg(Channel, Connection1, + {open, Channel, {forwarded_tcpip, + decode_ip(Address), Port, + decode_ip(Orig), OrigPort}}), + {{replies, [{connection_reply, ConnectionPid, OpenConfMsg}, + OpenMsg]}, Connection} + end; + +handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip", + sender_channel = RemoteId}, + Connection, ConnectionPid, client) -> + %% Client implementations SHOULD reject direct TCP/IP open requests for + %% security reasons. See RFC 4254 7.2. + FailMsg = channel_open_failure_msg(RemoteId, + ?SSH_OPEN_CONNECT_FAILED, + "Connection refused", "en"), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection}; + + +handle_msg(#ssh_msg_channel_open{sender_channel = ChannelId}, Connection, + ConnectionPid, _) -> + FailMsg = channel_open_failure_msg(ChannelId, + ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, + "Not allowed", "en"), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "exit-status", + data = Data}, + #connection{channel_cache = Cache} = Connection, _, _) -> + <<?UINT32(Status)>> = Data, + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = + reply_msg(Channel, Connection, {exit_status, ChannelId, Status}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "exit-signal", + want_reply = false, + data = Data}, + #connection{channel_cache = Cache} = Connection0, + ConnectionPid, _) -> + <<?UINT32(SigLen), SigName:SigLen/binary, + ?BOOLEAN(_Core), + ?UINT32(ErrLen), Err:ErrLen/binary, + ?UINT32(LangLen), Lang:LangLen/binary>> = Data, + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + RemoteId = Channel#channel.remote_id, + {Reply, Connection} = reply_msg(Channel, Connection0, + {exit_signal, ChannelId, + binary_to_list(SigName), + binary_to_list(Err), + binary_to_list(Lang)}), + CloseMsg = channel_close_msg(RemoteId), + {{replies, [{connection_reply, ConnectionPid, CloseMsg}, Reply]}, + Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "xon-xoff", + want_reply = false, + data = Data}, + #connection{channel_cache = Cache} = Connection, _, _) -> + <<?BOOLEAN(CDo)>> = Data, + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = + reply_msg(Channel, Connection, {xon_xoff, ChannelId, CDo=/= 0}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "window-change", + want_reply = false, + data = Data}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + <<?UINT32(Width),?UINT32(Height), + ?UINT32(PixWidth), ?UINT32(PixHeight)>> = Data, + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = + reply_msg(Channel, Connection0, {window_change, ChannelId, + Width, Height, + PixWidth, PixHeight}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "signal", + data = Data}, + #connection{channel_cache = Cache} = Connection0, _, _) -> + <<?UINT32(SigLen), SigName:SigLen/binary>> = Data, + + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + {Reply, Connection} = + reply_msg(Channel, Connection0, {signal, ChannelId, + binary_to_list(SigName)}), + {{replies, [Reply]}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "subsystem", + want_reply = WantReply, + data = Data}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, server) -> + <<?UINT32(SsLen), SsName:SsLen/binary>> = Data, + + #channel{remote_id = RemoteId} = Channel0 = + ssh_channel:cache_lookup(Cache, ChannelId), + + ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)}, + + try start_subsytem(SsName, Connection, Channel0, ReplyMsg) of + {ok, Pid} -> + erlang:monitor(process, Pid), + Channel = Channel0#channel{user = Pid}, + ssh_channel:cache_update(Cache, Channel), + Reply = {connection_reply, ConnectionPid, + channel_success_msg(RemoteId)}, + {{replies, [Reply]}, Connection} + catch _:_ -> + Reply = {connection_reply, ConnectionPid, + channel_failure_msg(RemoteId)}, + {{replies, [Reply]}, Connection} + end; + +handle_msg(#ssh_msg_channel_request{request_type = "subsystem"}, + Connection, _, client) -> + %% The client SHOULD ignore subsystem requests. See RFC 4254 6.5. + {{replies, []}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "pty-req", + want_reply = WantReply, + data = Data}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, server) -> + <<?UINT32(TermLen), BTermName:TermLen/binary, + ?UINT32(Width),?UINT32(Height), + ?UINT32(PixWidth), ?UINT32(PixHeight), + Modes/binary>> = Data, + TermName = binary_to_list(BTermName), + + PtyRequest = {TermName, Width, Height, + PixWidth, PixHeight, decode_pty_opts(Modes)}, + + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + + handle_cli_msg(Connection, ConnectionPid, Channel, + {pty, ChannelId, WantReply, PtyRequest}); + +handle_msg(#ssh_msg_channel_request{request_type = "pty-req"}, + Connection, _, client) -> + %% The client SHOULD ignore pty requests. See RFC 4254 6.2. + {{replies, []}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "shell", + want_reply = WantReply}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, server) -> + + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + + handle_cli_msg(Connection, ConnectionPid, Channel, + {shell, ChannelId, WantReply}); + +handle_msg(#ssh_msg_channel_request{request_type = "shell"}, + Connection, _, client) -> + %% The client SHOULD ignore shell requests. See RFC 4254 6.5. + {{replies, []}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "exec", + want_reply = WantReply, + data = Data}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, server) -> + <<?UINT32(Len), Command:Len/binary>> = Data, + + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + + handle_cli_msg(Connection, ConnectionPid, Channel, + {exec, ChannelId, WantReply, binary_to_list(Command)}); + +handle_msg(#ssh_msg_channel_request{request_type = "exec"}, + Connection, _, client) -> + %% The client SHOULD ignore exec requests. See RFC 4254 6.5. + {{replies, []}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = "env", + want_reply = WantReply, + data = Data}, + #connection{channel_cache = Cache} = Connection, + ConnectionPid, server) -> + + <<?UINT32(VarLen), + Var:VarLen/binary, ?UINT32(ValueLen), Value:ValueLen/binary>> = Data, + + Channel = ssh_channel:cache_lookup(Cache, ChannelId), + + handle_cli_msg(Connection, ConnectionPid, Channel, + {env, ChannelId, WantReply, Var, Value}); + +handle_msg(#ssh_msg_channel_request{request_type = "env"}, + Connection, _, client) -> + %% The client SHOULD ignore env requests. + {{replies, []}, Connection}; + +handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = _Other, + want_reply = WantReply}, Connection, + ConnectionPid, _) -> + ?dbg(true, "ssh_msg ssh_msg_channel_request: Other=~p\n", + [_Other]), + if WantReply == true -> + FailMsg = channel_failure_msg(ChannelId), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, + Connection}; + true -> + {noreply, Connection} + end; + +handle_msg(#ssh_msg_global_request{name = _Type, + want_reply = WantReply, + data = _Data}, Connection, + ConnectionPid, _) -> + if WantReply == true -> + FailMsg = request_failure_msg(), + {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, + Connection}; + true -> + {noreply, Connection} + end; + +%%% This transport message will also be handled at the connection level +handle_msg(#ssh_msg_disconnect{code = Code, + description = Description, + language = _Lang }, + #connection{channel_cache = Cache} = Connection0, _, _) -> + {Connection, Replies} = + ssh_channel:cache_foldl(fun(Channel, {Connection1, Acc}) -> + {Reply, Connection2} = + reply_msg(Channel, + Connection1, {closed, Channel#channel.local_id}), + {Connection2, [Reply | Acc]} + end, {Connection0, []}, Cache), + + ssh_channel:cache_delete(Cache), + {disconnect, {Code, Description}, {{replies, Replies}, Connection}}. + +handle_cli_msg(#connection{channel_cache = Cache} = Connection0, + ConnectionPid, + #channel{user = undefined, + local_id = ChannelId} = Channel0, Reply0) -> + + case (catch start_cli(Connection0, ChannelId)) of + {ok, Pid} -> + erlang:monitor(process, Pid), + Channel = Channel0#channel{user = Pid}, + ssh_channel:cache_update(Cache, Channel), + {Reply, Connection} = reply_msg(Channel, Connection0, Reply0), + {{replies, [Reply]}, Connection}; + _ -> + Reply = {connection_reply, ConnectionPid, + request_failure_msg()}, + {{replies, [Reply]}, Connection0} + end; + +handle_cli_msg(Connection0, _, Channel, Reply0) -> + {Reply, Connection} = reply_msg(Channel, Connection0, Reply0), + {{replies, [Reply]}, Connection}. + + +channel_eof_msg(ChannelId) -> + #ssh_msg_channel_eof{recipient_channel = ChannelId}. + +channel_close_msg(ChannelId) -> + #ssh_msg_channel_close {recipient_channel = ChannelId}. + +channel_success_msg(ChannelId) -> + #ssh_msg_channel_success{recipient_channel = ChannelId}. + +channel_failure_msg(ChannelId) -> + #ssh_msg_channel_failure{recipient_channel = ChannelId}. + +channel_adjust_window_msg(ChannelId, Bytes) -> + #ssh_msg_channel_window_adjust{recipient_channel = ChannelId, + bytes_to_add = Bytes}. + +channel_data_msg(ChannelId, 0, Data) -> + #ssh_msg_channel_data{recipient_channel = ChannelId, + data = Data}; +channel_data_msg(ChannelId, Type, Data) -> + #ssh_msg_channel_extended_data{recipient_channel = ChannelId, + data_type_code = Type, + data = Data}. + +channel_open_msg(Type, ChannelId, WindowSize, MaxPacketSize, Data) -> + #ssh_msg_channel_open{channel_type = Type, + sender_channel = ChannelId, + initial_window_size = WindowSize, + maximum_packet_size = MaxPacketSize, + data = Data + }. + +channel_open_confirmation_msg(RemoteId, LID, WindowSize, PacketSize) -> + #ssh_msg_channel_open_confirmation{recipient_channel = RemoteId, + sender_channel = LID, + initial_window_size = WindowSize, + maximum_packet_size = PacketSize}. + +channel_open_failure_msg(RemoteId, Reason, Description, Lang) -> + #ssh_msg_channel_open_failure{recipient_channel = RemoteId, + reason = Reason, + description = Description, + lang = Lang}. + +channel_request_msg(ChannelId, Type, WantReply, Data) -> + #ssh_msg_channel_request{recipient_channel = ChannelId, + request_type = Type, + want_reply = WantReply, + data = Data}. + +global_request_msg(Type, WantReply, Data) -> + #ssh_msg_global_request{name = Type, + want_reply = WantReply, + data = Data}. +request_failure_msg() -> + #ssh_msg_request_failure{}. + +request_success_msg(Data) -> + #ssh_msg_request_success{data = Data}. + +bind(IP, Port, ChannelPid, Connection) -> + Binds = [{{IP, Port}, ChannelPid} + | lists:keydelete({IP, Port}, 1, + Connection#connection.port_bindings)], + Connection#connection{port_bindings = Binds}. + +unbind(IP, Port, Connection) -> + Connection#connection{ + port_bindings = + lists:keydelete({IP, Port}, 1, + Connection#connection.port_bindings)}. +unbind_channel(ChannelPid, Connection) -> + Binds = [{Bind, ChannelP} || {Bind, ChannelP} + <- Connection#connection.port_bindings, + ChannelP =/= ChannelPid], + Connection#connection{port_bindings = Binds}. + +bound_channel(IP, Port, Connection) -> + case lists:keysearch({IP, Port}, 1, Connection#connection.port_bindings) of + {value, {{IP, Port}, ChannelPid}} -> ChannelPid; + _ -> undefined + end. + +messages() -> + [ {ssh_msg_global_request, ?SSH_MSG_GLOBAL_REQUEST, + [string, + boolean, + '...']}, + + {ssh_msg_request_success, ?SSH_MSG_REQUEST_SUCCESS, + ['...']}, + + {ssh_msg_request_failure, ?SSH_MSG_REQUEST_FAILURE, + []}, + + {ssh_msg_channel_open, ?SSH_MSG_CHANNEL_OPEN, + [string, + uint32, + uint32, + uint32, + '...']}, + + {ssh_msg_channel_open_confirmation, ?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, + [uint32, + uint32, + uint32, + uint32, + '...']}, + + {ssh_msg_channel_open_failure, ?SSH_MSG_CHANNEL_OPEN_FAILURE, + [uint32, + uint32, + string, + string]}, + + {ssh_msg_channel_window_adjust, ?SSH_MSG_CHANNEL_WINDOW_ADJUST, + [uint32, + uint32]}, + + {ssh_msg_channel_data, ?SSH_MSG_CHANNEL_DATA, + [uint32, + binary]}, + + {ssh_msg_channel_extended_data, ?SSH_MSG_CHANNEL_EXTENDED_DATA, + [uint32, + uint32, + binary]}, + + {ssh_msg_channel_eof, ?SSH_MSG_CHANNEL_EOF, + [uint32]}, + + {ssh_msg_channel_close, ?SSH_MSG_CHANNEL_CLOSE, + [uint32]}, + + {ssh_msg_channel_request, ?SSH_MSG_CHANNEL_REQUEST, + [uint32, + string, + boolean, + '...']}, + + {ssh_msg_channel_success, ?SSH_MSG_CHANNEL_SUCCESS, + [uint32]}, + + {ssh_msg_channel_failure, ?SSH_MSG_CHANNEL_FAILURE, + [uint32]} + ]. + +encode_ip(Addr) when is_tuple(Addr) -> + case catch inet_parse:ntoa(Addr) of + {'EXIT',_} -> false; + A -> A + end; +encode_ip(Addr) when is_list(Addr) -> + case inet_parse:address(Addr) of + {ok, _} -> Addr; + Error -> + case inet:getaddr(Addr, inet) of + {ok, A} -> + inet_parse:ntoa(A); + Error -> false + end + end. + +start_channel(Address, Port, Cb, Id, Args) -> + start_channel(Address, Port, Cb, Id, Args, undefined). + +start_channel(Address, Port, Cb, Id, Args, Exec) -> + ChildSpec = child_spec(Cb, Id, Args, Exec), + SystemSup = ssh_system_sup:system_supervisor(Address, Port), + ChannelSup = ssh_system_sup:channel_supervisor(SystemSup), + ssh_channel_sup:start_child(ChannelSup, ChildSpec). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +setup_session(#connection{channel_cache = Cache} = Connection0, + ConnectionPid, RemoteId, + Type, WindowSize, PacketSize) -> + {ChannelId, Connection} = new_channel_id(Connection0), + + Channel = #channel{type = Type, + sys = "ssh", + local_id = ChannelId, + recv_window_size = ?DEFAULT_WINDOW_SIZE, + recv_packet_size = ?DEFAULT_PACKET_SIZE, + send_window_size = WindowSize, + send_packet_size = PacketSize, + remote_id = RemoteId + }, + ssh_channel:cache_update(Cache, Channel), + OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId, + ?DEFAULT_WINDOW_SIZE, + ?DEFAULT_PACKET_SIZE), + + {{replies, [{connection_reply, ConnectionPid, OpenConfMsg}]}, Connection}. + + +check_subsystem("sftp"= SsName, Options) -> + case proplists:get_value(subsystems, Options, no_subsys) of + no_subsys -> + {SsName, {Cb, Opts}} = ssh_sftpd:subsystem_spec([]), + {Cb, Opts}; + SubSystems -> + proplists:get_value(SsName, SubSystems, {none, []}) + end; + +check_subsystem(SsName, Options) -> + Subsystems = proplists:get_value(subsystems, Options, []), + case proplists:get_value(SsName, Subsystems, {none, []}) of + Fun when is_function(Fun) -> + {Fun, []}; + {_, _} = Value -> + Value + end. + +child_spec(Callback, Id, Args, Exec) -> + Name = make_ref(), + StartFunc = {ssh_channel, start_link, [self(), Id, Callback, Args, Exec]}, + Restart = temporary, + Shutdown = 3600, + Type = worker, + {Name, StartFunc, Restart, Shutdown, Type, [ssh_channel]}. + +%% Backwards compatibility +start_cli(#connection{address = Address, port = Port, cli_spec = {Fun, [Shell]}, + options = Options}, + _ChannelId) when is_function(Fun) -> + case Fun(Shell, Address, Port, Options) of + NewFun when is_function(NewFun) -> + {ok, NewFun()}; + Pid when is_pid(Pid) -> + {ok, Pid} + end; + +start_cli(#connection{address = Address, port = Port, + cli_spec = {CbModule, Args}, exec = Exec}, ChannelId) -> + start_channel(Address, Port, CbModule, ChannelId, Args, Exec). + +start_subsytem(BinName, #connection{address = Address, port = Port, + options = Options}, + #channel{local_id = ChannelId, remote_id = RemoteChannelId}, + ReplyMsg) -> + Name = binary_to_list(BinName), + case check_subsystem(Name, Options) of + {Callback, Opts} when is_atom(Callback), Callback =/= none -> + start_channel(Address, Port, Callback, ChannelId, Opts); + {Other, _} when Other =/= none -> + handle_backwards_compatibility(Other, self(), + ChannelId, RemoteChannelId, + Options, Address, Port, + {ssh_cm, self(), ReplyMsg}) + end. + +channel_data_reply(_, #channel{local_id = ChannelId} = Channel, + Connection0, DataType, Data) -> + {Reply, Connection} = + reply_msg(Channel, Connection0, {data, ChannelId, DataType, Data}), + {[Reply], Connection}. + +new_channel_id(Connection) -> + ID = Connection#connection.channel_id_seed, + {ID, Connection#connection{channel_id_seed = ID + 1}}. + +reply_msg(Channel, Connection, {open, _} = Reply) -> + request_reply_or_data(Channel, Connection, Reply); +reply_msg(Channel, Connection, {open_error, _, _, _} = Reply) -> + request_reply_or_data(Channel, Connection, Reply); +reply_msg(Channel, Connection, success = Reply) -> + request_reply_or_data(Channel, Connection, Reply); +reply_msg(Channel, Connection, failure = Reply) -> + request_reply_or_data(Channel, Connection, Reply); +reply_msg(Channel, Connection, {closed, _} = Reply) -> + request_reply_or_data(Channel, Connection, Reply); +reply_msg(#channel{user = ChannelPid}, Connection, Reply) -> + {{channel_data, ChannelPid, Reply}, Connection}. + +request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid}, + #connection{requests = Requests} = + Connection, Reply) -> + case lists:keysearch(ChannelId, 1, Requests) of + {value, {ChannelId, From}} -> + {{channel_requst_reply, From, Reply}, + Connection#connection{requests = + lists:keydelete(ChannelId, 1, Requests)}}; + false -> + {{channel_data, ChannelPid, Reply}, Connection} + end. + +update_send_window(Channel0, DataType, Data, + #connection{channel_cache = Cache}) -> + Buf0 = if Data == <<>> -> + Channel0#channel.send_buf; + true -> + Channel0#channel.send_buf ++ [{DataType, Data}] + end, + {Buf1, NewSz, Buf2} = get_window(Buf0, + Channel0#channel.send_packet_size, + Channel0#channel.send_window_size), + + Channel = Channel0#channel{send_window_size = NewSz, send_buf = Buf2}, + ssh_channel:cache_update(Cache, Channel), + {Buf1, Channel}. + +get_window(Bs, PSz, WSz) -> + get_window(Bs, PSz, WSz, []). + +get_window(Bs, _PSz, 0, Acc) -> + {lists:reverse(Acc), 0, Bs}; +get_window([B0 = {DataType, Bin} | Bs], PSz, WSz, Acc) -> + BSz = size(Bin), + if BSz =< WSz -> %% will fit into window + if BSz =< PSz -> %% will fit into a packet + get_window(Bs, PSz, WSz-BSz, [B0|Acc]); + true -> %% split into packet size + <<Bin1:PSz/binary, Bin2/binary>> = Bin, + get_window([setelement(2, B0, Bin2) | Bs], + PSz, WSz-PSz, + [{DataType, Bin1}|Acc]) + end; + WSz =< PSz -> %% use rest of window + <<Bin1:WSz/binary, Bin2/binary>> = Bin, + get_window([setelement(2, B0, Bin2) | Bs], + PSz, WSz-WSz, + [{DataType, Bin1}|Acc]); + true -> %% use packet size + <<Bin1:PSz/binary, Bin2/binary>> = Bin, + get_window([setelement(2, B0, Bin2) | Bs], + PSz, WSz-PSz, + [{DataType, Bin1}|Acc]) + end; +get_window([], _PSz, WSz, Acc) -> + {lists:reverse(Acc), WSz, []}. + +flow_control(Channel, Cache) -> + flow_control([window_adjusted], Channel, Cache). + +flow_control([], Channel, Cache) -> + ssh_channel:cache_update(Cache, Channel), + []; +flow_control([_|_], #channel{flow_control = From} = Channel, Cache) -> + case From of + undefined -> + []; + _ -> + [{flow_control, Cache, Channel, From, ok}] + end. + +encode_pty_opts(Opts) -> + Bin = list_to_binary(encode_pty_opts2(Opts)), + Len = size(Bin), + <<?UINT32(Len), Bin/binary>>. + +encode_pty_opts2([]) -> + [?TTY_OP_END]; +encode_pty_opts2([{vintr,Value} | Opts]) -> + [?VINTR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vquit,Value} | Opts]) -> + [?VQUIT, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{verase,Value} | Opts]) -> + [?VERASE, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vkill,Value} | Opts]) -> + [?VKILL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{veof,Value} | Opts]) -> + [?VEOF, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{veol,Value} | Opts]) -> + [?VEOL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{veol2,Value} | Opts]) -> + [?VEOL2, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vstart,Value} | Opts]) -> + [?VSTART, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vstop,Value} | Opts]) -> + [?VSTOP, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vsusp,Value} | Opts]) -> + [?VSUSP, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vdsusp,Value} | Opts]) -> + [?VDSUSP, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vreprint,Value} | Opts]) -> + [?VREPRINT, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vwerase,Value} | Opts]) -> + [ ?VWERASE, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vlnext,Value} | Opts]) -> + [?VLNEXT, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vflush,Value} | Opts]) -> + [?VFLUSH, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vswtch,Value} | Opts]) -> + [?VSWTCH, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vstatus,Value} | Opts]) -> + [?VSTATUS, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{vdiscard,Value} | Opts]) -> + [?VDISCARD, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{ignpar,Value} | Opts]) -> + [?IGNPAR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{parmrk,Value} | Opts]) -> + [?PARMRK, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{inpck,Value} | Opts]) -> + [?INPCK, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{istrip,Value} | Opts]) -> + [?ISTRIP, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{inlcr,Value} | Opts]) -> + [?INLCR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{igncr,Value} | Opts]) -> + [?IGNCR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{icrnl,Value} | Opts]) -> + [?ICRNL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{iuclc,Value} | Opts]) -> + [?IUCLC, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{ixon,Value} | Opts]) -> + [?IXON, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{ixany,Value} | Opts]) -> + [?IXANY, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{ixoff,Value} | Opts]) -> + [?IXOFF, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{imaxbel,Value} | Opts]) -> + [?IMAXBEL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{isig,Value} | Opts]) -> + [?ISIG, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{icanon,Value} | Opts]) -> + [?ICANON, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{xcase,Value} | Opts]) -> + [?XCASE, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echo,Value} | Opts]) -> + [?ECHO, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echoe,Value} | Opts]) -> + [?ECHOE, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echok,Value} | Opts]) -> + [?ECHOK, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echonl,Value} | Opts]) -> + [?ECHONL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{noflsh,Value} | Opts]) -> + [?NOFLSH, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{tostop,Value} | Opts]) -> + [?TOSTOP, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{iexten,Value} | Opts]) -> + [?IEXTEN, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echoctl,Value} | Opts]) -> + [?ECHOCTL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{echoke,Value} | Opts]) -> + [?ECHOKE, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{pendin,Value} | Opts]) -> + [?PENDIN, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{opost,Value} | Opts]) -> + [?OPOST, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{olcuc,Value} | Opts]) -> + [?OLCUC, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{onlcr,Value} | Opts]) -> + [?ONLCR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{ocrnl,Value} | Opts]) -> + [?OCRNL, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{onocr,Value} | Opts]) -> + [?ONOCR, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{onlret,Value} | Opts]) -> + [?ONLRET, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{cs7,Value} | Opts]) -> + [?CS7, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{cs8,Value} | Opts]) -> + [?CS8, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{parenb,Value} | Opts]) -> + [?PARENB, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{parodd,Value} | Opts]) -> + [?PARODD, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{tty_op_ispeed,Value} | Opts]) -> + [?TTY_OP_ISPEED, ?uint32(Value) | encode_pty_opts2(Opts)]; +encode_pty_opts2([{tty_op_ospeed,Value} | Opts]) -> + [?TTY_OP_OSPEED, ?uint32(Value) | encode_pty_opts2(Opts)]. + +decode_pty_opts(<<>>) -> + []; +decode_pty_opts(<<0, 0, 0, 0>>) -> + []; +decode_pty_opts(<<?UINT32(Len), Modes:Len/binary>>) -> + decode_pty_opts2(Modes); +decode_pty_opts(Binary) -> + decode_pty_opts2(Binary). + +decode_pty_opts2(<<?TTY_OP_END>>) -> + []; +decode_pty_opts2(<<Code, ?UINT32(Value), Tail/binary>>) -> + Op = case Code of + ?VINTR -> vintr; + ?VQUIT -> vquit; + ?VERASE -> verase; + ?VKILL -> vkill; + ?VEOF -> veof; + ?VEOL -> veol; + ?VEOL2 -> veol2; + ?VSTART -> vstart; + ?VSTOP -> vstop; + ?VSUSP -> vsusp; + ?VDSUSP -> vdsusp; + ?VREPRINT -> vreprint; + ?VWERASE -> vwerase; + ?VLNEXT -> vlnext; + ?VFLUSH -> vflush; + ?VSWTCH -> vswtch; + ?VSTATUS -> vstatus; + ?VDISCARD -> vdiscard; + ?IGNPAR -> ignpar; + ?PARMRK -> parmrk; + ?INPCK -> inpck; + ?ISTRIP -> istrip; + ?INLCR -> inlcr; + ?IGNCR -> igncr; + ?ICRNL -> icrnl; + ?IUCLC -> iuclc; + ?IXON -> ixon; + ?IXANY -> ixany; + ?IXOFF -> ixoff; + ?IMAXBEL -> imaxbel; + ?ISIG -> isig; + ?ICANON -> icanon; + ?XCASE -> xcase; + ?ECHO -> echo; + ?ECHOE -> echoe; + ?ECHOK -> echok; + ?ECHONL -> echonl; + ?NOFLSH -> noflsh; + ?TOSTOP -> tostop; + ?IEXTEN -> iexten; + ?ECHOCTL -> echoctl; + ?ECHOKE -> echoke; + ?PENDIN -> pendin; + ?OPOST -> opost; + ?OLCUC -> olcuc; + ?ONLCR -> onlcr; + ?OCRNL -> ocrnl; + ?ONOCR -> onocr; + ?ONLRET -> onlret; + ?CS7 -> cs7; + ?CS8 -> cs8; + ?PARENB -> parenb; + ?PARODD -> parodd; + ?TTY_OP_ISPEED -> tty_op_ispeed; + ?TTY_OP_OSPEED -> tty_op_ospeed; + _ -> Code + end, + [{Op, Value} | decode_pty_opts2(Tail)]. + +decode_ip(Addr) when is_binary(Addr) -> + case inet_parse:address(binary_to_list(Addr)) of + {error,_} -> Addr; + {ok,A} -> A + end. + +%% This is really awful and that is why it is beeing phased out. +handle_backwards_compatibility({_,_,_,_,_,_} = ChildSpec, _, _, _, _, + Address, Port, _) -> + SystemSup = ssh_system_sup:system_supervisor(Address, Port), + ChannelSup = ssh_system_sup:channel_supervisor(SystemSup), + ssh_channel_sup:start_child(ChannelSup, ChildSpec); + +handle_backwards_compatibility(Module, ConnectionManager, ChannelId, + RemoteChannelId, Opts, + _, _, Msg) when is_atom(Module) -> + {ok, SubSystemPid} = gen_server:start_link(Module, [Opts], []), + SubSystemPid ! + {ssh_cm, ConnectionManager, + {open, ChannelId, RemoteChannelId, {session}}}, + SubSystemPid ! Msg, + {ok, SubSystemPid}; + +handle_backwards_compatibility(Fun, ConnectionManager, ChannelId, + RemoteChannelId, + _, _, _, Msg) when is_function(Fun) -> + SubSystemPid = Fun(), + SubSystemPid ! + {ssh_cm, ConnectionManager, + {open, ChannelId, RemoteChannelId, {session}}}, + SubSystemPid ! Msg, + {ok, SubSystemPid}; + +handle_backwards_compatibility(ChildSpec, + ConnectionManager, + ChannelId, RemoteChannelId, _, + Address, Port, Msg) -> + SystemSup = ssh_system_sup:system_supervisor(Address, Port), + ChannelSup = ssh_system_sup:channel_supervisor(SystemSup), + {ok, SubSystemPid} + = ssh_channel_sup:start_child(ChannelSup, ChildSpec), + SubSystemPid ! + {ssh_cm, ConnectionManager, + {open, ChannelId, RemoteChannelId, {session}}}, + SubSystemPid ! Msg, + {ok, SubSystemPid}. diff --git a/lib/ssh/src/ssh_connection_controler.erl b/lib/ssh/src/ssh_connection_controler.erl new file mode 100644 index 0000000000..7960eb11c6 --- /dev/null +++ b/lib/ssh/src/ssh_connection_controler.erl @@ -0,0 +1,137 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%-------------------------------------------------------------------- +%% File : ssh_connection_controler.erl +%% Description : +%% +%%-------------------------------------------------------------------- + +-module(ssh_connection_controler). + +-behaviour(gen_server). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([start_link/1, start_handler_child/2, start_manager_child/2, + connection_manager/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + code_change/3, terminate/2, stop/1]). + +-record(state, {role, manager, handler, timeout}). + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: start/0 +%%----------------------------------------------------------------- +start_link(Args) -> + gen_server:start_link(?MODULE, [Args], []). + +%% Will be called from the manager child process +start_handler_child(ServerRef, Args) -> + gen_server:call(ServerRef, {handler, self(), Args}, infinity). + +%% Will be called from the acceptor process +start_manager_child(ServerRef, Args) -> + gen_server:call(ServerRef, {manager, Args}, infinity). + +connection_manager(ServerRef) -> + {ok, gen_server:call(ServerRef, manager, infinity)}. + +%%----------------------------------------------------------------- +%% Internal interface functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: stop/1 +%%----------------------------------------------------------------- +stop(Pid) -> + gen_server:cast(Pid, stop). + +%%----------------------------------------------------------------- +%% Server functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: init/1 +%%----------------------------------------------------------------- +init([Opts]) -> + process_flag(trap_exit, true), + case proplists:get_value(role, Opts) of + client -> + {ok, Manager} = ssh_connection_manager:start_link([client, Opts]), + {ok, #state{role = client, manager = Manager}}; + _server -> + %% Children started by acceptor process + {ok, #state{role = server}} + end. + + +%%----------------------------------------------------------------- +%% Func: terminate/2 +%%----------------------------------------------------------------- +terminate(_Reason, #state{}) -> + ok. + +%%----------------------------------------------------------------- +%% Func: handle_call/3 +%%----------------------------------------------------------------- +handle_call({handler, Pid, [Role, Socket, Opts]}, _From, State) -> + {ok, Handler} = ssh_connection_handler:start_link(Role, Pid, Socket, Opts), + {reply, {ok, Handler}, State#state{handler = Handler}}; +handle_call({manager, [server = Role, Socket, Opts]}, _From, State) -> + {ok, Manager} = ssh_connection_manager:start_link([Role, Socket, Opts]), + {reply, {ok, Manager}, State#state{manager = Manager}}; +handle_call({manager, [client = Role | Opts]}, _From, State) -> + {ok, Manager} = ssh_connection_manager:start_link([Role, Opts]), + {reply, {ok, Manager}, State#state{manager = Manager}}; +handle_call(manager, _From, State) -> + {reply, State#state.manager, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; +handle_call(_, _, State) -> + {noreply, State, State#state.timeout}. + +%%----------------------------------------------------------------- +%% Func: handle_cast/2 +%%----------------------------------------------------------------- +handle_cast(stop, State) -> + {stop, normal, State}; +handle_cast(_, State) -> + {noreply, State, State#state.timeout}. + +%%----------------------------------------------------------------- +%% Func: handle_info/2 +%%----------------------------------------------------------------- +%% handle_info(ssh_connected, State) -> +%% {stop, normal, State}; +%% Servant termination. +handle_info({'EXIT', _Pid, normal}, State) -> + {stop, normal, State}. + +%%----------------------------------------------------------------- +%% Func: code_change/3 +%%----------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl new file mode 100644 index 0000000000..5240b4b4c5 --- /dev/null +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -0,0 +1,879 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: Handles the setup of an ssh connection, e.i. both the +%% setup SSH Transport Layer Protocol (RFC 4253) and Authentication +%% Protocol (RFC 4252). Details of the different protocols are +%% implemented in ssh_transport.erl, ssh_auth.erl +%% ---------------------------------------------------------------------- + +-module(ssh_connection_handler). + +-behaviour(gen_fsm). + +-include("ssh.hrl"). +-include("ssh_transport.hrl"). +-include("ssh_auth.hrl"). +-include("ssh_connect.hrl"). + +-export([start_link/4, send/2, renegotiate/1, send_event/2, + connection_info/3, + peer_address/1]). + +%% gen_fsm callbacks +-export([hello/2, kexinit/2, key_exchange/2, new_keys/2, + userauth/2, connected/2]). + +-export([init/1, state_name/3, handle_event/3, + handle_sync_event/4, handle_info/3, terminate/3, code_change/4]). + +%% spawn export +-export([ssh_info_handler/3]). + +-record(state, { + transport_protocol, % ex: tcp + transport_cb, + transport_close_tag, + ssh_params, % #ssh{} - from ssh.hrl + socket, % socket() + decoded_data_buffer, % binary() + encoded_data_buffer, % binary() + undecoded_packet_length, % integer() + key_exchange_init_msg, % #ssh_msg_kexinit{} + renegotiate = false, % boolean() + manager, % pid() + connection_queue, + address, + port, + opts + }). + +-define(DBG_MESSAGE, true). + +%%==================================================================== +%% Internal application API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> ok,Pid} | ignore | {error,Error} +%% Description:Creates a gen_fsm process which calls Module:init/1 to +%% initialize. To ensure a synchronized start-up procedure, this function +%% does not return until Module:init/1 has returned. +%%-------------------------------------------------------------------- +start_link(Role, Manager, Socket, Options) -> + gen_fsm:start_link(?MODULE, [Role, Manager, Socket, Options], []). + +send(ConnectionHandler, Data) -> + send_all_state_event(ConnectionHandler, {send, Data}). + +renegotiate(ConnectionHandler) -> + send_all_state_event(ConnectionHandler, renegotiate). + +connection_info(ConnectionHandler, From, Options) -> + send_all_state_event(ConnectionHandler, {info, From, Options}). + +%% Replaced with option to connection_info/3. For now keep +%% for backwards compatibility +peer_address(ConnectionHandler) -> + sync_send_all_state_event(ConnectionHandler, peer_address). + +%%==================================================================== +%% gen_fsm callbacks +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, StateName, State} | +%% {ok, StateName, State, Timeout} | +%% ignore | +%% {stop, StopReason} +%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or +%% gen_fsm:start_link/3,4, this function is called by the new process to +%% initialize. +%%-------------------------------------------------------------------- +init([Role, Manager, Socket, SshOpts]) -> + {A,B,C} = erlang:now(), + random:seed(A, B, C), + {NumVsn, StrVsn} = ssh_transport:versions(Role, SshOpts), + ssh_bits:install_messages(ssh_transport:transport_messages(NumVsn)), + {Protocol, Callback, CloseTag} = + proplists:get_value(transport, SshOpts, {tcp, gen_tcp, tcp_closed}), + Ssh = init_ssh(Role, NumVsn, StrVsn, SshOpts, Socket), + {ok, hello, #state{ssh_params = + Ssh#ssh{send_sequence = 0, recv_sequence = 0}, + socket = Socket, + decoded_data_buffer = <<>>, + encoded_data_buffer = <<>>, + transport_protocol = Protocol, + transport_cb = Callback, + transport_close_tag = CloseTag, + manager = Manager, + opts = SshOpts + }}. +%%-------------------------------------------------------------------- +%% Function: +%% state_name(Event, State) -> {next_state, NextStateName, NextState}| +%% {next_state, NextStateName, +%% NextState, Timeout} | +%% {stop, Reason, NewState} +%% Description:There should be one instance of this function for each possible +%% state name. Whenever a gen_fsm receives an event sent using +%% gen_fsm:send_event/2, the instance of this function with the same name as +%% the current state name StateName is called to handle the event. It is also +%% called if a timeout occurs. +%%-------------------------------------------------------------------- +hello(socket_control, #state{socket = Socket, ssh_params = Ssh} = State) -> + VsnMsg = ssh_transport:hello_version_msg(string_version(Ssh)), + send_msg(VsnMsg, State), + inet:setopts(Socket, [{packet, line}]), + {next_state, hello, next_packet(State)}; + +hello({info_line, _Line}, State) -> + {next_state, hello, next_packet(State)}; + +hello({version_exchange, Version}, #state{ssh_params = Ssh0, + socket = Socket} = State) -> + {NumVsn, StrVsn} = ssh_transport:handle_hello_version(Version), + case handle_version(NumVsn, StrVsn, Ssh0) of + {ok, Ssh1} -> + inet:setopts(Socket, [{packet,0}, {mode,binary}]), + {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1), + send_msg(SshPacket, State), + {next_state, kexinit, next_packet(State#state{ssh_params = Ssh, + key_exchange_init_msg = + KeyInitMsg})}; + not_supported -> + DisconnectMsg = + #ssh_msg_disconnect{code = + ?SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, + description = "Protocol version " ++ StrVsn + ++ " not supported", + language = "en"}, + handle_disconnect(DisconnectMsg, State) + end. + +kexinit({#ssh_msg_kexinit{} = Kex, Payload}, + #state{ssh_params = #ssh{role = Role} = Ssh0, + key_exchange_init_msg = OwnKex} = + State) -> + Ssh1 = ssh_transport:key_init(opposite_role(Role), Ssh0, Payload), + try ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of + {ok, NextKexMsg, Ssh} when Role == client -> + send_msg(NextKexMsg, State), + {next_state, key_exchange, + next_packet(State#state{ssh_params = Ssh})}; + {ok, Ssh} when Role == server -> + {next_state, key_exchange, + next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end. + +key_exchange(#ssh_msg_kexdh_init{} = Msg, + #state{ssh_params = #ssh{role = server} =Ssh0} = State) -> + try ssh_transport:handle_kexdh_init(Msg, Ssh0) of + {ok, KexdhReply, Ssh1} -> + send_msg(KexdhReply, State), + {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1), + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +key_exchange(#ssh_msg_kexdh_reply{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + try ssh_transport:handle_kexdh_reply(Msg, Ssh0) of + {ok, NewKeys, Ssh} -> + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +key_exchange(#ssh_msg_kex_dh_gex_group{} = Msg, + #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> + try ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0) of + {ok, NextKexMsg, Ssh1} -> + send_msg(NextKexMsg, State), + {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1), + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + try ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0) of + {ok, NextKexMsg, Ssh} -> + send_msg(NextKexMsg, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; +key_exchange(#ssh_msg_kex_dh_gex_reply{} = Msg, + #state{ssh_params = #ssh{role = client} = Ssh0} = State) -> + try ssh_transport:handle_kex_dh_gex_reply(Msg, Ssh0) of + {ok, NewKeys, Ssh} -> + send_msg(NewKeys, State), + {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end. + +new_keys(#ssh_msg_newkeys{} = Msg, #state{ssh_params = Ssh0} = State0) -> + try ssh_transport:handle_new_keys(Msg, Ssh0) of + {ok, Ssh} -> + {NextStateName, State} = + after_new_keys(State0#state{ssh_params = Ssh}), + {next_state, NextStateName, next_packet(State)} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State0), + {stop, normal, State0} + end. + +userauth(#ssh_msg_service_request{name = "ssh-userauth"} = Msg, + #state{ssh_params = #ssh{role = server, + session_id = SessionId} = Ssh0} = State) -> + ssh_bits:install_messages(ssh_auth:userauth_messages()), + try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of + {ok, {Reply, Ssh}} -> + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +userauth(#ssh_msg_service_accept{name = "ssh-userauth"}, + #state{ssh_params = #ssh{role = client, + service = "ssh-userauth"} = Ssh0} = + State) -> + {Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0), + send_msg(Msg, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}; + +userauth(#ssh_msg_userauth_request{service = "ssh-connection", + method = "none"} = Msg, + #state{ssh_params = #ssh{session_id = SessionId, role = server, + service = "ssh-connection"} = Ssh0 + } = State) -> + try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of + {not_authorized, {_User, _Reason}, {Reply, Ssh}} -> + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +userauth(#ssh_msg_userauth_request{service = "ssh-connection", + method = Method} = Msg, + #state{ssh_params = #ssh{session_id = SessionId, role = server, + service = "ssh-connection", + peer = {_, Address}} = Ssh0, + opts = Opts, manager = Pid} = State) -> + try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of + {authorized, User, {Reply, Ssh}} -> + send_msg(Reply, State), + ssh_userreg:register_user(User, Pid), + Pid ! ssh_connected, + connected_fun(User, Address, Method, Opts), + {next_state, connected, + next_packet(State#state{ssh_params = Ssh})}; + {not_authorized, {User, Reason}, {Reply, Ssh}} -> + retry_fun(User, Reason, Opts), + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +userauth(#ssh_msg_userauth_info_request{} = Msg, + #state{ssh_params = #ssh{role = client, + io_cb = IoCb} = Ssh0} = State) -> + try ssh_auth:handle_userauth_info_request(Msg, IoCb, Ssh0) of + {ok, {Reply, Ssh}} -> + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +userauth(#ssh_msg_userauth_info_response{} = Msg, + #state{ssh_params = #ssh{role = server} = Ssh0} = State) -> + try ssh_auth:handle_userauth_info_response(Msg, Ssh0) of + {ok, {Reply, Ssh}} -> + send_msg(Reply, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + catch + #ssh_msg_disconnect{} = DisconnectMsg -> + handle_disconnect(DisconnectMsg, State) + end; + +userauth(#ssh_msg_userauth_success{}, #state{ssh_params = #ssh{role = client}, + manager = Pid} = State) -> + Pid ! ssh_connected, + {next_state, connected, next_packet(State)}; + +userauth(#ssh_msg_userauth_failure{}, + #state{ssh_params = #ssh{role = client, + userauth_methods = []}} + = State) -> + Msg = #ssh_msg_disconnect{code = + ?SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, + description = "Unable to connect using the available" + " authentication methods", + language = "en"}, + handle_disconnect(Msg, State); + +%% Server tells us which authentication methods that are allowed +userauth(#ssh_msg_userauth_failure{authentications = Methodes}, + #state{ssh_params = #ssh{role = client, + userauth_methods = none} = Ssh0} = State) -> + AuthMethods = string:tokens(Methodes, ","), + {Msg, Ssh} = ssh_auth:userauth_request_msg( + Ssh0#ssh{userauth_methods = AuthMethods}), + send_msg(Msg, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}; + +%% The prefered authentication method failed try next method +userauth(#ssh_msg_userauth_failure{}, + #state{ssh_params = #ssh{role = client} = Ssh0, + manager = Pid} = State) -> + case ssh_auth:userauth_request_msg(Ssh0) of + {disconnect, Event, {Msg, _}} -> + try + send_msg(Msg, State), + ssh_connection_manager:event(Pid, Event) + catch + exit:{noproc, _Reason} -> + Report = io_lib:format("Connection Manager terminated: ~p~n", + [Pid]), + error_logger:info_report(Report); + exit:Exit -> + Report = io_lib:format("Connection Manager returned:~n~p~n~p~n", + [Msg, Exit]), + error_logger:info_report(Report) + end, + {stop, normal, State}; + {Msg, Ssh} -> + send_msg(Msg, State), + {next_state, userauth, next_packet(State#state{ssh_params = Ssh})} + end; + +userauth(#ssh_msg_userauth_banner{}, + #state{ssh_params = #ssh{userauth_quiet_mode = true, + role = client}} = State) -> + {next_state, userauth, next_packet(State)}; +userauth(#ssh_msg_userauth_banner{message = Msg}, + #state{ssh_params = + #ssh{userauth_quiet_mode = false, role = client}} = State) -> + io:format("~s", [Msg]), + {next_state, userauth, next_packet(State)}. + +connected({#ssh_msg_kexinit{}, _Payload} = Event, State) -> + kexinit(Event, State#state{renegotiate = true}). + +%%-------------------------------------------------------------------- +%% Function: +%% state_name(Event, From, State) -> {next_state, NextStateName, NextState} | +%% {next_state, NextStateName, +%% NextState, Timeout} | +%% {reply, Reply, NextStateName, NextState}| +%% {reply, Reply, NextStateName, +%% NextState, Timeout} | +%% {stop, Reason, NewState}| +%% {stop, Reason, Reply, NewState} +%% Description: There should be one instance of this function for each +%% possible state name. Whenever a gen_fsm receives an event sent using +%% gen_fsm:sync_send_event/2,3, the instance of this function with the same +%% name as the current state name StateName is called to handle the event. +%%-------------------------------------------------------------------- +state_name(_Event, _From, State) -> + Reply = ok, + {reply, Reply, state_name, State}. + +%%-------------------------------------------------------------------- +%% Function: +%% handle_event(Event, StateName, State) -> {next_state, NextStateName, +%% NextState} | +%% {next_state, NextStateName, +%% NextState, Timeout} | +%% {stop, Reason, NewState} +%% Description: Whenever a gen_fsm receives an event sent using +%% gen_fsm:send_all_state_event/2, this function is called to handle +%% the event. +%%-------------------------------------------------------------------- +handle_event({send, Data}, StateName, #state{ssh_params = Ssh0} = State) -> + {Packet, Ssh} = ssh_transport:pack(Data, Ssh0), + send_msg(Packet, State), + {next_state, StateName, next_packet(State#state{ssh_params = Ssh})}; + +handle_event(#ssh_msg_disconnect{} = Msg, _StateName, + #state{manager = Pid} = State) -> + (catch ssh_connection_manager:event(Pid, Msg)), + {stop, normal, State}; + +handle_event(#ssh_msg_ignore{}, StateName, State) -> + {next_state, StateName, next_packet(State)}; + +handle_event(#ssh_msg_debug{always_display = true, message = DbgMsg}, + StateName, State) -> + io:format("DEBUG: ~p\n", [DbgMsg]), + {next_state, StateName, next_packet(State)}; + +handle_event(#ssh_msg_debug{}, StateName, State) -> + {next_state, StateName, next_packet(State)}; + +handle_event(#ssh_msg_unimplemented{}, StateName, State) -> + {next_state, StateName, next_packet(State)}; + +handle_event(renegotiate, connected, #state{ssh_params = Ssh0} + = State) -> + {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0), + send_msg(SshPacket, State), + {next_state, connected, + next_packet(State#state{ssh_params = Ssh, + key_exchange_init_msg = KeyInitMsg, + renegotiate = true})}; + +handle_event(renegotiate, StateName, State) -> + %% Allready in keyexcahange so ignore + {next_state, StateName, State}; + +handle_event({info, From, Options}, StateName, #state{ssh_params = Ssh} = State) -> + spawn(?MODULE, ssh_info_handler, [Options, Ssh, From]), + {next_state, StateName, State}; + +handle_event({unknown, Data}, StateName, State) -> + Msg = #ssh_msg_unimplemented{sequence = Data}, + send_msg(Msg, State), + {next_state, StateName, next_packet(State)}. +%%-------------------------------------------------------------------- +%% Function: +%% handle_sync_event(Event, From, StateName, +%% State) -> {next_state, NextStateName, NextState} | +%% {next_state, NextStateName, NextState, +%% Timeout} | +%% {reply, Reply, NextStateName, NextState}| +%% {reply, Reply, NextStateName, NextState, +%% Timeout} | +%% {stop, Reason, NewState} | +%% {stop, Reason, Reply, NewState} +%% Description: Whenever a gen_fsm receives an event sent using +%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle +%% the event. +%%-------------------------------------------------------------------- + +%% Replaced with option to connection_info/3. For now keep +%% for backwards compatibility +handle_sync_event(peer_address, _From, StateName, + #state{ssh_params = #ssh{peer = {_, Address}}} = State) -> + {reply, {ok, Address}, StateName, State}. + +%%-------------------------------------------------------------------- +%% Function: +%% handle_info(Info,StateName,State)-> {next_state, NextStateName, NextState}| +%% {next_state, NextStateName, NextState, +%% Timeout} | +%% {stop, Reason, NewState} +%% Description: This function is called by a gen_fsm when it receives any +%% other message than a synchronous or asynchronous event +%% (or a system message). +%%-------------------------------------------------------------------- +handle_info({Protocol, Socket, "SSH-" ++ _ = Version}, hello, + #state{socket = Socket, + transport_protocol = Protocol} = State ) -> + event({version_exchange, Version}, hello, State); + +handle_info({Protocol, Socket, Info}, hello, + #state{socket = Socket, + transport_protocol = Protocol} = State) -> + event({info_line, Info}, hello, State); + +handle_info({Protocol, Socket, Data}, Statename, + #state{socket = Socket, + transport_protocol = Protocol, + ssh_params = #ssh{decrypt_block_size = BlockSize, + recv_mac_size = MacSize} = Ssh0, + decoded_data_buffer = <<>>, + encoded_data_buffer = EncData0} = State0) -> + + %% Implementations SHOULD decrypt the length after receiving the + %% first 8 (or cipher block size, whichever is larger) bytes of a + %% packet. (RFC 4253: Section 6 - Binary Packet Protocol) + case size(EncData0) + size(Data) >= max(8, BlockSize) of + true -> + {Ssh, SshPacketLen, DecData, EncData} = + ssh_transport:decrypt_first_block(<<EncData0/binary, + Data/binary>>, Ssh0), + case SshPacketLen > ?SSH_MAX_PACKET_SIZE of + true -> + DisconnectMsg = + #ssh_msg_disconnect{code = + ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad packet length " + ++ integer_to_list(SshPacketLen), + language = "en"}, + handle_disconnect(DisconnectMsg, State0); + false -> + RemainingSshPacketLen = + (SshPacketLen + ?SSH_LENGHT_INDICATOR_SIZE) - + BlockSize + MacSize, + State = State0#state{ssh_params = Ssh}, + handle_ssh_packet_data(RemainingSshPacketLen, + DecData, EncData, Statename, + State) + end; + false -> + {next_state, Statename, + next_packet(State0#state{encoded_data_buffer = + <<EncData0/binary, Data/binary>>})} + end; + +handle_info({Protocol, Socket, Data}, Statename, + #state{socket = Socket, + transport_protocol = Protocol, + decoded_data_buffer = DecData, + encoded_data_buffer = EncData, + undecoded_packet_length = Len} = + State) when is_integer(Len) -> + handle_ssh_packet_data(Len, DecData, <<EncData/binary, Data/binary>>, + Statename, State); + +handle_info({CloseTag, _Socket}, _StateName, + #state{transport_close_tag = CloseTag, %%manager = Pid, + ssh_params = #ssh{role = _Role, opts = _Opts}} = State) -> + %%ok = ssh_connection_manager:delivered(Pid), + {stop, normal, State}. +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, StateName, State) -> void() +%% Description:This function is called by a gen_fsm when it is about +%% to terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_fsm terminates with +%% Reason. The return value is ignored. +%%-------------------------------------------------------------------- +terminate(normal, _, #state{transport_cb = Transport, + socket = Socket}) -> + (catch Transport:close(Socket)), + ok; + +terminate(shutdown, _, State) -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "Application disconnect", + language = "en"}, + handle_disconnect(DisconnectMsg, State); + +terminate(Reason, _, State) -> + Desc = io_lib:format("Erlang ssh connection handler failed with reason: " + "~p , please report this to [email protected] \n", + [Reason]), + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_CONNECTION_LOST, + description = Desc, + language = "en"}, + handle_disconnect(DisconnectMsg, State). + +%%-------------------------------------------------------------------- +%% Function: +%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(_OldVsn, StateName, State, _Extra) -> + {ok, StateName, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +init_ssh(client = Role, Vsn, Version, Options, Socket) -> + IOCb = case proplists:get_value(user_interaction, Options, true) of + true -> + ssh_io; + false -> + ssh_no_io + end, + + AuthMethods = proplists:get_value(auth_methods, Options, + ?SUPPORTED_AUTH_METHODS), + {ok, PeerAddr} = inet:peername(Socket), + + PeerName = proplists:get_value(host, Options), + + #ssh{role = Role, + c_vsn = Vsn, + c_version = Version, + key_cb = proplists:get_value(key_cb, Options, ssh_file), + io_cb = IOCb, + userauth_quiet_mode = proplists:get_value(quiet_mode, Options, false), + opts = Options, + userauth_supported_methods = AuthMethods, + peer = {PeerName, PeerAddr} + }; + +init_ssh(server = Role, Vsn, Version, Options, Socket) -> + + AuthMethods = proplists:get_value(auth_methods, Options, + ?SUPPORTED_AUTH_METHODS), + {ok, PeerAddr} = inet:peername(Socket), + + #ssh{role = Role, + s_vsn = Vsn, + s_version = Version, + key_cb = proplists:get_value(key_cb, Options, ssh_file), + io_cb = proplists:get_value(io_cb, Options, ssh_io), + opts = Options, + userauth_supported_methods = AuthMethods, + peer = {undefined, PeerAddr} + }. + +send_msg(Msg, #state{socket = Socket, transport_cb = Transport}) -> + Transport:send(Socket, Msg). + +handle_version({2, 0} = NumVsn, StrVsn, Ssh0) -> + Ssh = counterpart_versions(NumVsn, StrVsn, Ssh0), + {ok, Ssh}; +handle_version(_,_,_) -> + not_supported. + +string_version(#ssh{role = client, c_version = Vsn}) -> + Vsn; +string_version(#ssh{role = server, s_version = Vsn}) -> + Vsn. + +send_event(FsmPid, Event) -> + gen_fsm:send_event(FsmPid, Event). + +send_all_state_event(FsmPid, Event) -> + gen_fsm:send_all_state_event(FsmPid, Event). + +sync_send_all_state_event(FsmPid, Event) -> + gen_fsm:sync_send_all_state_event(FsmPid, Event). + +%% simulate send_all_state_event(self(), Event) +event(#ssh_msg_disconnect{} = Event, StateName, State) -> + handle_event(Event, StateName, State); +event(#ssh_msg_ignore{} = Event, StateName, State) -> + handle_event(Event, StateName, State); +event(#ssh_msg_debug{} = Event, StateName, State) -> + handle_event(Event, StateName, State); +event(#ssh_msg_unimplemented{} = Event, StateName, State) -> + handle_event(Event, StateName, State); +%% simulate send_event(self(), Event) +event(Event, StateName, State) -> + ?MODULE:StateName(Event, State). + +generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName, + #state{manager = Pid} = State0, EncData) + when Byte == ?SSH_MSG_GLOBAL_REQUEST; + Byte == ?SSH_MSG_REQUEST_SUCCESS; + Byte == ?SSH_MSG_REQUEST_FAILURE; + Byte == ?SSH_MSG_CHANNEL_OPEN; + Byte == ?SSH_MSG_CHANNEL_OPEN_CONFIRMATION; + Byte == ?SSH_MSG_CHANNEL_OPEN_FAILURE; + Byte == ?SSH_MSG_CHANNEL_WINDOW_ADJUST; + Byte == ?SSH_MSG_CHANNEL_DATA; + Byte == ?SSH_MSG_CHANNEL_EXTENDED_DATA; + Byte == ?SSH_MSG_CHANNEL_EOF; + Byte == ?SSH_MSG_CHANNEL_CLOSE; + Byte == ?SSH_MSG_CHANNEL_REQUEST; + Byte == ?SSH_MSG_CHANNEL_SUCCESS; + Byte == ?SSH_MSG_CHANNEL_FAILURE -> + ssh_connection_manager:event(Pid, Msg), + State = generate_event_new_state(State0, EncData), + next_packet(State), + {next_state, StateName, State}; + +generate_event(Msg, StateName, State0, EncData) -> + Event = ssh_bits:decode(Msg), + State = generate_event_new_state(State0, EncData), + case Event of + #ssh_msg_kexinit{} -> + %% We need payload for verification later. + event({Event, Msg}, StateName, State); + _ -> + event(Event, StateName, State) + end. + +generate_event_new_state(#state{ssh_params = + #ssh{recv_sequence = SeqNum0} + = Ssh} = State, EncData) -> + SeqNum = ssh_transport:next_seqnum(SeqNum0), + State#state{ssh_params = Ssh#ssh{recv_sequence = SeqNum}, + decoded_data_buffer = <<>>, + encoded_data_buffer = EncData, + undecoded_packet_length = undefined}. + + +next_packet(#state{decoded_data_buffer = <<>>, + encoded_data_buffer = Buff, + socket = Socket, + transport_protocol = Protocol} = + State) when Buff =/= <<>> andalso size(Buff) >= 8 -> + %% More data from the next packet has been received + %% Fake a socket-recive message so that the data will be processed + self() ! {Protocol, Socket, <<>>} , + State; + +next_packet(#state{socket = Socket} = State) -> + inet:setopts(Socket, [{active, once}]), + State. + +after_new_keys(#state{renegotiate = true} = State) -> + {connected, State#state{renegotiate = false}}; +after_new_keys(#state{renegotiate = false, + ssh_params = #ssh{role = client} = Ssh0} = State) -> + ssh_bits:install_messages(ssh_auth:userauth_messages()), + {Msg, Ssh} = ssh_auth:service_request_msg(Ssh0), + send_msg(Msg, State), + {userauth, State#state{ssh_params = Ssh}}; +after_new_keys(#state{renegotiate = false, + ssh_params = #ssh{role = server}} = State) -> + {userauth, State}. + +max(N, M) when N > M -> + N; +max(_, M) -> + M. + +handle_ssh_packet_data(RemainingSshPacketLen, DecData, EncData, StateName, + State) -> + EncSize = size(EncData), + case RemainingSshPacketLen > EncSize of + true -> + {next_state, StateName, + next_packet(State#state{decoded_data_buffer = DecData, + encoded_data_buffer = EncData, + undecoded_packet_length = + RemainingSshPacketLen})}; + false -> + handle_ssh_packet(RemainingSshPacketLen, StateName, + State#state{decoded_data_buffer = DecData, + encoded_data_buffer = EncData}) + + end. + +handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0, + encoded_data_buffer = EncData0, + ssh_params = Ssh0, + transport_protocol = _Protocol, + socket = _Socket} = State0) -> + {Ssh1, DecData, EncData, Mac} = + ssh_transport:unpack(EncData0, Length, Ssh0), + SshPacket = <<DecData0/binary, DecData/binary>>, + case ssh_transport:is_valid_mac(Mac, SshPacket, Ssh1) of + true -> + PacketData = ssh_transport:msg_data(SshPacket), + {Ssh1, Msg} = ssh_transport:decompress(Ssh1, PacketData), + generate_event(Msg, StateName, + State0#state{ssh_params = Ssh1, + %% Important to be set for + %% next_packet + decoded_data_buffer = <<>>}, EncData); + false -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Bad mac", + language = "en"}, + handle_disconnect(DisconnectMsg, State0) + end. + +handle_disconnect(#ssh_msg_disconnect{} = Msg, + #state{ssh_params = Ssh0, manager = Pid} = State) -> + {SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0), + try + send_msg(SshPacket, State), + ssh_connection_manager:event(Pid, Msg) + catch + exit:{noproc, _Reason} -> + Report = io_lib:format("~p Connection Manager terminated: ~p~n", + [self(), Pid]), + error_logger:info_report(Report); + exit:Exit -> + Report = io_lib:format("Connection Manager returned:~n~p~n~p~n", + [Msg, Exit]), + error_logger:info_report(Report) + end, + {stop, normal, State#state{ssh_params = Ssh}}. + +counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) -> + Ssh#ssh{c_vsn = NumVsn , c_version = StrVsn}; +counterpart_versions(NumVsn, StrVsn, #ssh{role = client} = Ssh) -> + Ssh#ssh{s_vsn = NumVsn , s_version = StrVsn}. + +opposite_role(client) -> + server; +opposite_role(server) -> + client. +connected_fun(User, PeerAddr, Method, Opts) -> + case proplists:get_value(connectfun, Opts) of + undefined -> + ok; + Fun -> + catch Fun(User, PeerAddr, Method) + end. + +retry_fun(_, undefined, _) -> + ok; + +retry_fun(User, {error, Reason}, Opts) -> + case proplists:get_value(failfun, Opts) of + undefined -> + ok; + Fun -> + catch Fun(User, Reason) + end; + +retry_fun(User, Reason, Opts) -> + case proplists:get_value(infofun, Opts) of + undefined -> + ok; + Fun -> + catch Fun(User, Reason) + end. + +ssh_info_handler(Options, Ssh, From) -> + Info = ssh_info(Options, Ssh, []), + ssh_connection_manager:send_msg({channel_requst_reply, From, Info}). + +ssh_info([], _, Acc) -> + Acc; + +ssh_info([client_version | Rest], #ssh{c_vsn = IntVsn, + c_version = StringVsn} = SshParams, Acc) -> + ssh_info(Rest, SshParams, [{client_version, {IntVsn, StringVsn}} | Acc]); + +ssh_info([server_version | Rest], #ssh{s_vsn = IntVsn, + s_version = StringVsn} = SshParams, Acc) -> + ssh_info(Rest, SshParams, [{server_version, {IntVsn, StringVsn}} | Acc]); + +ssh_info([peer | Rest], #ssh{peer = Peer} = SshParams, Acc) -> + ssh_info(Rest, SshParams, [{peer, Peer} | Acc]); + +ssh_info([ _ | Rest], SshParams, Acc) -> + ssh_info(Rest, SshParams, Acc). diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl new file mode 100644 index 0000000000..3863005e74 --- /dev/null +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -0,0 +1,760 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: Handles multiplexing to ssh channels and global connection +%% requests e.i. the SSH Connection Protocol (RFC 4254), that provides +%% interactive login sessions, remote execution of commands, forwarded +%% TCP/IP connections, and forwarded X11 connections. Details of the +%% protocol is implemented in ssh_connection.erl +%% ---------------------------------------------------------------------- +-module(ssh_connection_manager). + +-behaviour(gen_server). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). +-include("ssh_transport.hrl"). + +-export([start_link/1]). + +-export([info/1, info/2, + renegotiate/1, connection_info/2, channel_info/3, + peer_addr/1, send_window/3, recv_window/3, adjust_window/3, + close/2, stop/1, send/5, + send_eof/2]). + +-export([open_channel/6, request/6, request/7, global_request/4, event/2, + cast/2]). + +%% Internal application API and spawn +-export([send_msg/1, ssh_channel_info_handler/3]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(DBG_MESSAGE, true). + +-record(state, + { + role, + client, + starter, + connection, % pid() + connection_state, % #connection{} + latest_channel_id = 0, + opts, + channel_args, + connected + }). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +start_link(Opts) -> + gen_server:start_link(?MODULE, Opts, []). + +open_channel(ConnectionManager, ChannelType, ChannelSpecificData, + InitialWindowSize, MaxPacketSize, Timeout) -> + case (catch call(ConnectionManager, {open, self(), ChannelType, + InitialWindowSize, + MaxPacketSize, ChannelSpecificData}, + Timeout)) of + {open, Channel} -> + {ok, Channel}; + Error -> + %% TODO: Best way? + Error + end. + +request(ConnectionManager, ChannelPid, ChannelId, Type, true, Data, Timeout) -> + call(ConnectionManager, {request, ChannelPid, ChannelId, Type, Data}, Timeout); +request(ConnectionManager, ChannelPid, ChannelId, Type, false, Data, _) -> + cast(ConnectionManager, {request, ChannelPid, ChannelId, Type, Data}). + +request(ConnectionManager, ChannelId, Type, true, Data, Timeout) -> + call(ConnectionManager, {request, ChannelId, Type, Data}, Timeout); +request(ConnectionManager, ChannelId, Type, false, Data, _) -> + cast(ConnectionManager, {request, ChannelId, Type, Data}). + +global_request(ConnectionManager, Type, true = Reply, Data) -> + case call(ConnectionManager, + {global_request, self(), Type, Reply, Data}) of + {ssh_cm, ConnectionManager, {success, _}} -> + ok; + {ssh_cm, ConnectionManager, {failure, _}} -> + error + end; + +global_request(ConnectionManager, Type, false = Reply, Data) -> + cast(ConnectionManager, {global_request, self(), Type, Reply, Data}). + +event(ConnectionManager, BinMsg) -> + call(ConnectionManager, {ssh_msg, self(), BinMsg}). + +info(ConnectionManager) -> + info(ConnectionManager, {info, all}). + +info(ConnectionManager, ChannelProcess) -> + call(ConnectionManager, {info, ChannelProcess}). + +%% TODO: Do we really want this function? Should not +%% renegotiation be triggered by configurable timer +%% or amount of data sent counter! +renegotiate(ConnectionManager) -> + cast(ConnectionManager, renegotiate). + +connection_info(ConnectionManager, Options) -> + call(ConnectionManager, {connection_info, Options}). + +channel_info(ConnectionManager, ChannelId, Options) -> + call(ConnectionManager, {channel_info, ChannelId, Options}). + +%% Replaced by option peer to connection_info/2 keep for now +%% for Backwards compatibility! +peer_addr(ConnectionManager) -> + call(ConnectionManager, {peer_addr, self()}). + +%% Backwards compatibility! +send_window(ConnectionManager, Channel, TimeOut) -> + call(ConnectionManager, {send_window, Channel}, TimeOut). +%% Backwards compatibility! +recv_window(ConnectionManager, Channel, TimeOut) -> + call(ConnectionManager, {recv_window, Channel}, TimeOut). + +adjust_window(ConnectionManager, Channel, Bytes) -> + cast(ConnectionManager, {adjust_window, Channel, Bytes}). + +close(ConnectionManager, ChannelId) -> + try call(ConnectionManager, {close, ChannelId}) of + ok -> + ok + catch + exit:{noproc, _} -> + ok + end. + +stop(ConnectionManager) -> + try call(ConnectionManager, stop) of + ok -> + ok + catch + exit:{noproc, _} -> + ok + end. + +send(ConnectionManager, ChannelId, Type, Data, Timeout) -> + call(ConnectionManager, {data, ChannelId, Type, Data}, Timeout). + +send_eof(ConnectionManager, ChannelId) -> + cast(ConnectionManager, {eof, ChannelId}). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([server, _Socket, Opts]) -> + process_flag(trap_exit, true), + ssh_bits:install_messages(ssh_connection:messages()), + Cache = ssh_channel:cache_create(), + {ok, #state{role = server, + connection_state = #connection{channel_cache = Cache, + channel_id_seed = 0, + port_bindings = [], + requests = [], + channel_pids = []}, + opts = Opts, + connected = false}}; + +init([client, Opts]) -> + process_flag(trap_exit, true), + {links, [Parent]} = process_info(self(), links), + ssh_bits:install_messages(ssh_connection:messages()), + Cache = ssh_channel:cache_create(), + Address = proplists:get_value(address, Opts), + Port = proplists:get_value(port, Opts), + SocketOpts = proplists:get_value(socket_opts, Opts), + Options = proplists:get_value(ssh_opts, Opts), + ChannelPid = proplists:get_value(channel_pid, Opts), + self() ! + {start_connection, client, [Parent, Address, Port, + ChannelPid, SocketOpts, Options]}, + {ok, #state{role = client, + client = ChannelPid, + connection_state = #connection{channel_cache = Cache, + channel_id_seed = 0, + port_bindings = [], + requests = [], + channel_pids = []}, + opts = Opts, + connected = false}}. + +%%-------------------------------------------------------------------- +%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% Description: Handling call messages +%%-------------------------------------------------------------------- +handle_call({request, ChannelPid, ChannelId, Type, Data}, From, State0) -> + {{replies, Replies}, State} = handle_request(ChannelPid, + ChannelId, Type, Data, + true, From, State0), + %% Sends message to the connection handler process, reply to + %% channel is sent later when reply arrives from the connection + %% handler. + lists:foreach(fun send_msg/1, Replies), + {noreply, State}; + +handle_call({request, ChannelId, Type, Data}, From, State0) -> + {{replies, Replies}, State} = handle_request(ChannelId, Type, Data, + true, From, State0), + %% Sends message to the connection handler process, reply to + %% channel is sent later when reply arrives from the connection + %% handler. + lists:foreach(fun send_msg/1, Replies), + {noreply, State}; + +%% Message from ssh_connection_handler +handle_call({ssh_msg, Pid, Msg}, From, + #state{connection_state = Connection0, + role = Role, opts = Opts, connected = IsConnected, + client = ClientPid} + = State) -> + + %% To avoid that not all data sent by the other side is processes before + %% possible crash in ssh_connection_handler takes down the connection. + gen_server:reply(From, ok), + + ConnectionMsg = decode_ssh_msg(Msg), + try ssh_connection:handle_msg(ConnectionMsg, Connection0, Pid, Role) of + {{replies, Replies}, Connection} -> + lists:foreach(fun send_msg/1, Replies), + {noreply, State#state{connection_state = Connection}}; + {noreply, Connection} -> + {noreply, State#state{connection_state = Connection}}; + {disconnect, {_, Reason}, {{replies, Replies}, Connection}} + when Role == client andalso (not IsConnected) -> + lists:foreach(fun send_msg/1, Replies), + ClientPid ! {self(), not_connected, Reason}, + {stop, normal, State#state{connection = Connection}}; + {disconnect, Reason, {{replies, Replies}, Connection}} -> + lists:foreach(fun send_msg/1, Replies), + SSHOpts = proplists:get_value(ssh_opts, Opts), + disconnect_fun(Reason, SSHOpts), + {stop, normal, State#state{connection_state = Connection}} + catch + exit:{noproc, Reason} -> + Report = io_lib:format("Connection probably terminated:~n~p~n~p~n", + [ConnectionMsg, Reason]), + error_logger:info_report(Report), + {noreply, State}; + error:Error -> + Report = io_lib:format("Connection message returned:~n~p~n~p~n", + [ConnectionMsg, Error]), + error_logger:info_report(Report), + {noreply, State}; + exit:Exit -> + Report = io_lib:format("Connection message returned:~n~p~n~p~n", + [ConnectionMsg, Exit]), + error_logger:info_report(Report), + {noreply, State} + end; + +handle_call({global_request, Pid, _, _, _} = Request, From, + #state{connection_state = + #connection{channel_cache = Cache}} = State0) -> + State1 = handle_global_request(Request, State0), + Channel = ssh_channel:cache_find(Pid, Cache), + State = add_request(true, Channel#channel.local_id, From, State1), + {noreply, State}; + +handle_call({data, ChannelId, Type, Data}, From, + #state{connection_state = #connection{channel_cache = _Cache} + = Connection0, + connection = ConnectionPid} = State) -> + channel_data(ChannelId, Type, Data, Connection0, ConnectionPid, From, + State); + +handle_call({connection_info, Options}, From, + #state{connection = Connection} = State) -> + ssh_connection_handler:connection_info(Connection, From, Options), + %% Reply will be sent by the connection handler by calling + %% ssh_connection_handler:send_msg/1. + {noreply, State}; + +handle_call({channel_info, ChannelId, Options}, From, + #state{connection_state = #connection{channel_cache = Cache}} = State) -> + + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{} = Channel -> + spawn(?MODULE, ssh_channel_info_handler, [Options, Channel, From]), + {noreply, State}; + undefined -> + {reply, []} + end; + +handle_call({info, ChannelPid}, _From, + #state{connection_state = + #connection{channel_cache = Cache}} = State) -> + Result = ssh_channel:cache_foldl( + fun(Channel, Acc) when ChannelPid == all; + Channel#channel.user == ChannelPid -> + [Channel | Acc]; + (_, Acc) -> + Acc + end, [], Cache), + {reply, {ok, Result}, State}; + +handle_call({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data}, + From, #state{connection = Pid, + connection_state = + #connection{channel_cache = Cache}} = State0) -> + {ChannelId, State1} = new_channel_id(State0), + Msg = ssh_connection:channel_open_msg(Type, ChannelId, + InitialWindowSize, + MaxPacketSize, Data), + send_msg({connection_reply, Pid, Msg}), + Channel = #channel{type = Type, + sys = "none", + user = ChannelPid, + local_id = ChannelId, + recv_window_size = InitialWindowSize, + recv_packet_size = MaxPacketSize}, + ssh_channel:cache_update(Cache, Channel), + State = add_request(true, ChannelId, From, State1), + {noreply, State}; + +handle_call({send_window, ChannelId}, _From, + #state{connection_state = + #connection{channel_cache = Cache}} = State) -> + Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{send_window_size = WinSize, + send_packet_size = Packsize} -> + {ok, {WinSize, Packsize}}; + undefined -> + {error, einval} + end, + {reply, Reply, State}; + +handle_call({recv_window, ChannelId}, _From, + #state{connection_state = #connection{channel_cache = Cache}} + = State) -> + + Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{recv_window_size = WinSize, + recv_packet_size = Packsize} -> + {ok, {WinSize, Packsize}}; + undefined -> + {error, einval} + end, + {reply, Reply, State}; + +%% Replaced by option peer to connection_info/2 keep for now +%% for Backwards compatibility! +handle_call({peer_addr, _ChannelId}, _From, + #state{connection = Pid} = State) -> + Reply = ssh_connection_handler:peer_address(Pid), + {reply, Reply, State}; + +handle_call(opts, _, #state{opts = Opts} = State) -> + {reply, Opts, State}; + +handle_call({close, ChannelId}, _, + #state{connection = Pid, connection_state = + #connection{channel_cache = Cache}} = State) -> + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{remote_id = Id} -> + send_msg({connection_reply, Pid, + ssh_connection:channel_close_msg(Id)}), + {reply, ok, State}; + undefined -> + {reply, ok, State} + end; + +handle_call(stop, _, #state{role = _client, + client = ChannelPid, + connection = Pid} = State) -> + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "Application disconnect", + language = "en"}, + (catch gen_fsm:send_all_state_event(Pid, DisconnectMsg)), +% ssh_connection_handler:send(Pid, DisconnectMsg), + {stop, normal, ok, State}; +handle_call(stop, _, State) -> + {stop, normal, ok, State}; + +%% API violation make it the violaters problem +%% by ignoring it. The violating process will get +%% a timeout or hang. +handle_call(_, _, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast({request, ChannelPid, ChannelId, Type, Data}, State0) -> + {{replies, Replies}, State} = handle_request(ChannelPid, ChannelId, + Type, Data, + false, none, State0), + lists:foreach(fun send_msg/1, Replies), + {noreply, State}; + +handle_cast({request, ChannelId, Type, Data}, State0) -> + {{replies, Replies}, State} = handle_request(ChannelId, Type, Data, + false, none, State0), + lists:foreach(fun send_msg/1, Replies), + {noreply, State}; + +handle_cast({global_request, _, _, _, _} = Request, State0) -> + State = handle_global_request(Request, State0), + {noreply, State}; + +handle_cast(renegotiate, #state{connection = Pid} = State) -> + ssh_connection_handler:renegotiate(Pid), + {noreply, State}; + +handle_cast({adjust_window, ChannelId, Bytes}, + #state{connection = Pid, connection_state = + #connection{channel_cache = Cache}} = State) -> + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{recv_window_size = WinSize, remote_id = Id} = Channel -> + ssh_channel:cache_update(Cache, Channel#channel{recv_window_size = + WinSize + Bytes}), + Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes), + send_msg({connection_reply, Pid, Msg}); + undefined -> + ignore + end, + {noreply, State}; + +handle_cast({eof, ChannelId}, + #state{connection = Pid, connection_state = + #connection{channel_cache = Cache}} = State) -> + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{remote_id = Id} -> + send_msg({connection_reply, Pid, + ssh_connection:channel_eof_msg(Id)}), + {noreply, State}; + undefined -> + {noreply, State} + end; + +handle_cast({success, ChannelId}, #state{connection = Pid} = State) -> + Msg = ssh_connection:channel_success_msg(ChannelId), + send_msg({connection_reply, Pid, Msg}), + {noreply, State}; + +handle_cast({failure, ChannelId}, #state{connection = Pid} = State) -> + Msg = ssh_connection:channel_failure_msg(ChannelId), + send_msg({connection_reply, Pid, Msg}), + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling all non call/cast messages +%%-------------------------------------------------------------------- +handle_info({start_connection, server, + [Address, Port, Socket, Options]}, + #state{connection_state = CState} = State) -> + {ok, Connection} = ssh_transport:accept(Address, Port, Socket, Options), + Shell = proplists:get_value(shell, Options), + Exec = proplists:get_value(exec, Options), + CliSpec = proplists:get_value(ssh_cli, Options, {ssh_cli, [Shell]}), + {noreply, State#state{connection = Connection, + connection_state = + CState#connection{address = Address, + port = Port, + cli_spec = CliSpec, + options = Options, + exec = Exec}}}; + +handle_info({start_connection, client, + [Parent, Address, Port, ChannelPid, SocketOpts, Options]}, + State) -> + case (catch ssh_transport:connect(Parent, Address, + Port, SocketOpts, Options)) of + {ok, Connection} -> + erlang:monitor(process, ChannelPid), + {noreply, State#state{connection = Connection}}; + Reason -> + ChannelPid ! {self(), not_connected, Reason}, + {stop, normal, State} + end; + +handle_info({ssh_cm, _Sender, Msg}, State0) -> + %% Backwards compatibility! + State = cm_message(Msg, State0), + {noreply, State}; + +%% Nop backwards compatibility +handle_info({same_user, _}, State) -> + {noreply, State}; + +handle_info(ssh_connected, #state{role = client, client = Pid} + = State) -> + Pid ! {self(), is_connected}, + {noreply, State#state{connected = true}}; + +handle_info(ssh_connected, #state{role = server} = State) -> + {noreply, State#state{connected = true}}; + +handle_info({'DOWN', _Ref, process, ChannelPid, normal}, State0) -> + handle_down(handle_channel_down(ChannelPid, State0)); + +handle_info({'DOWN', _Ref, process, ChannelPid, shutdown}, State0) -> + handle_down(handle_channel_down(ChannelPid, State0)); + +handle_info({'DOWN', _Ref, process, ChannelPid, Reason}, State0) -> + Report = io_lib:format("Pid ~p DOWN ~p\n", [ChannelPid, Reason]), + error_logger:error_report(Report), + handle_down(handle_channel_down(ChannelPid, State0)); + +handle_info({'EXIT', _, _}, State) -> + %% Handled in 'DOWN' + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(Reason, #state{connection_state = + #connection{requests = Requests}, + opts = Opts}) -> + SSHOpts = proplists:get_value(ssh_opts, Opts), + disconnect_fun(Reason, SSHOpts), + (catch lists:foreach(fun({_, From}) -> + gen_server:reply(From, {error, connection_closed}) + end, Requests)), + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +channel_data(Id, Type, Data, Connection0, ConnectionPid, From, State) -> + case ssh_connection:channel_data(Id, Type, Data, Connection0, + ConnectionPid, From) of + {{replies, Replies}, Connection} -> + lists:foreach(fun send_msg/1, Replies), + {noreply, State#state{connection_state = Connection}}; + {noreply, Connection} -> + {noreply, State#state{connection_state = Connection}} + end. + +call(Pid, Msg) -> + call(Pid, Msg, infinity). +call(Pid, Msg, Timeout) -> + try gen_server:call(Pid, Msg, Timeout) of + Result -> + Result + catch + exit:{timeout, _} -> + {error, timeout} + end. + +cast(Pid, Msg) -> + gen_server:cast(Pid, Msg). + +decode_ssh_msg(BinMsg) when is_binary(BinMsg)-> + ssh_bits:decode(BinMsg); +decode_ssh_msg(Msg) -> + Msg. + + +send_msg(Msg) -> + case catch do_send_msg(Msg) of + {'EXIT', Reason}-> + Report = io_lib:format("Connection Manager fail to send:~n~p~n" + "Reason why it failed was:~n~p~n", + [Msg, Reason]), + error_logger:info_report(Report); + _ -> + ok + end. + +do_send_msg({channel_data, Pid, Data}) -> + Pid ! {ssh_cm, self(), Data}; +do_send_msg({channel_requst_reply, From, Data}) -> + gen_server:reply(From, Data); +do_send_msg({connection_reply, Pid, Data}) -> + Msg = ssh_bits:encode(Data), + ssh_connection_handler:send(Pid, Msg); +do_send_msg({flow_control, Cache, Channel, From, Msg}) -> + ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), + gen_server:reply(From, Msg). + +handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, + #state{connection = Pid, + connection_state = + #connection{channel_cache = Cache}} = State0) -> + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{remote_id = Id} = Channel -> + update_sys(Cache, Channel, Type, ChannelPid), + Msg = ssh_connection:channel_request_msg(Id, Type, + WantReply, Data), + Replies = [{connection_reply, Pid, Msg}], + State = add_request(WantReply, ChannelId, From, State0), + {{replies, Replies}, State}; + undefined -> + {{replies, []}, State0} + end. + +handle_request(ChannelId, Type, Data, WantReply, From, + #state{connection = Pid, + connection_state = + #connection{channel_cache = Cache}} = State0) -> + case ssh_channel:cache_lookup(Cache, ChannelId) of + #channel{remote_id = Id} -> + Msg = ssh_connection:channel_request_msg(Id, Type, + WantReply, Data), + Replies = [{connection_reply, Pid, Msg}], + State = add_request(WantReply, ChannelId, From, State0), + {{replies, Replies}, State}; + undefined -> + {{replies, []}, State0} + end. + +handle_down({{replies, Replies}, State}) -> + lists:foreach(fun send_msg/1, Replies), + {noreply, State}. + +handle_channel_down(ChannelPid, #state{connection_state = + #connection{channel_cache = Cache}} = + State) -> + ssh_channel:cache_foldl( + fun(Channel, Acc) when Channel#channel.user == ChannelPid -> + ssh_channel:cache_delete(Cache, + Channel#channel.local_id), + Acc; + (_,Acc) -> + Acc + end, [], Cache), + {{replies, []}, State}. + +update_sys(Cache, Channel, Type, ChannelPid) -> + ssh_channel:cache_update(Cache, + Channel#channel{sys = Type, user = ChannelPid}). + +add_request(false, _ChannelId, _From, State) -> + State; +add_request(true, ChannelId, From, #state{connection_state = + #connection{requests = Requests0} = + Connection} = State) -> + Requests = [{ChannelId, From} | Requests0], + State#state{connection_state = Connection#connection{requests = Requests}}. + +new_channel_id(#state{connection_state = #connection{channel_id_seed = Id} = + Connection} + = State) -> + {Id, State#state{connection_state = + Connection#connection{channel_id_seed = Id + 1}}}. + +handle_global_request({global_request, ChannelPid, + "tcpip-forward" = Type, WantReply, + <<?UINT32(IPLen), + IP:IPLen/binary, ?UINT32(Port)>> = Data}, + #state{connection = ConnectionPid, + connection_state = + #connection{channel_cache = Cache} + = Connection0} = State) -> + ssh_channel:cache_update(Cache, #channel{user = ChannelPid, + type = "forwarded-tcpip", + sys = none}), + Connection = ssh_connection:bind(IP, Port, ChannelPid, Connection0), + Msg = ssh_connection:global_request_msg(Type, WantReply, Data), + send_msg({connection_reply, ConnectionPid, Msg}), + State#state{connection_state = Connection}; + +handle_global_request({global_request, _Pid, "cancel-tcpip-forward" = Type, + WantReply, <<?UINT32(IPLen), + IP:IPLen/binary, ?UINT32(Port)>> = Data}, + #state{connection = Pid, + connection_state = Connection0} = State) -> + Connection = ssh_connection:unbind(IP, Port, Connection0), + Msg = ssh_connection:global_request_msg(Type, WantReply, Data), + send_msg({connection_reply, Pid, Msg}), + State#state{connection_state = Connection}; + +handle_global_request({global_request, _Pid, "cancel-tcpip-forward" = Type, + WantReply, Data}, #state{connection = Pid} = State) -> + Msg = ssh_connection:global_request_msg(Type, WantReply, Data), + send_msg({connection_reply, Pid, Msg}), + State. + +cm_message(Msg, State) -> + {noreply, NewState} = handle_cast(Msg, State), + NewState. + +disconnect_fun(Reason, Opts) -> + case proplists:get_value(disconnectfun, Opts) of + undefined -> + ok; + Fun -> + catch Fun(Reason) + end. + +ssh_channel_info_handler(Options, Channel, From) -> + Info = ssh_channel_info(Options, Channel, []), + send_msg({channel_requst_reply, From, Info}). + +ssh_channel_info([], _, Acc) -> + Acc; + +ssh_channel_info([recv_window | Rest], #channel{recv_window_size = WinSize, + recv_packet_size = Packsize + } = Channel, Acc) -> + ssh_channel_info(Rest, Channel, [{recv_window, {{win_size, WinSize}, + {packet_size, Packsize}}} | Acc]); +ssh_channel_info([send_window | Rest], #channel{send_window_size = WinSize, + send_packet_size = Packsize + } = Channel, Acc) -> + ssh_channel_info(Rest, Channel, [{send_window, {{win_size, WinSize}, + {packet_size, Packsize}}} | Acc]); +ssh_channel_info([ _ | Rest], Channel, Acc) -> + ssh_channel_info(Rest, Channel, Acc). + + + diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl new file mode 100755 index 0000000000..ec24fbcd01 --- /dev/null +++ b/lib/ssh/src/ssh_dsa.erl @@ -0,0 +1,95 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: dsa public-key sign and verify + +-module(ssh_dsa). + +-export([verify/3]). +-export([sign/2]). +-export([alg_name/0]). + +-include("ssh.hrl"). + +%% start() -> +%% crypto:start(). + +%% sign_file(File, Opts) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:private_host_dsa_key(user, Opts), +%% sign(Key, Bin). + +%% verify_file(File, Sig) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:public_host_key(user, dsa), +%% verify(Key, Bin, Sig). + +sign(_Private=#ssh_key { private={P,Q,G,X} },Mb) -> + K = ssh_bits:irandom(160) rem Q, + R = ssh_math:ipow(G, K, P) rem Q, + Ki = ssh_math:invert(K, Q), + <<M:160/big-unsigned-integer>> = crypto:sha(Mb), + S = (Ki * (M + X*R)) rem Q, + <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>. + + +%% the paramiko client sends a bad sig sometimes, +%% instead of crashing, we nicely return error, the +%% typcally manifests itself as Sb being 39 bytes +%% instead of 40. + +verify(Public, Mb, Sb) -> + case catch xverify(Public, Mb, Sb) of + {'EXIT', _Reason} -> + %store({Public, Mb, Sb, _Reason}), + {error, inconsistent_key}; + ok -> + %store({Public, Mb, Sb, ok}) + ok + end. + +%% store(Term) -> +%% {ok, Fd} = file:open("/tmp/dsa", [append]), +%% io:format(Fd, "~p~n~n~n", [Term]), +%% file:close(Fd). + + +xverify(_Public=#ssh_key { public={P,Q,G,Y} },Mb,Sb) -> + <<R0:160/big-unsigned-integer, S0:160/big-unsigned-integer>> = Sb, + ?ssh_assert(R0 >= 0 andalso R0 < Q andalso + S0 >= 0 andalso S0 < Q, out_of_range), + W = ssh_math:invert(S0,Q), + <<M0:160/big-unsigned-integer>> = crypto:sha(Mb), + U1 = (M0*W) rem Q, + U2 = (R0*W) rem Q, + T1 = ssh_math:ipow(G,U1,P), + T2 = ssh_math:ipow(Y,U2,P), + V = ((T1*T2) rem P) rem Q, + if V == R0 -> + ok; + true -> + {error, inconsistent_key} + end. + +alg_name() -> + "ssh-dss". diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl new file mode 100755 index 0000000000..8a3c903e51 --- /dev/null +++ b/lib/ssh/src/ssh_file.erl @@ -0,0 +1,530 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SSH file handling + +-module(ssh_file). + +-include("ssh.hrl"). +-include("PKCS-1.hrl"). +-include("DSS.hrl"). + +-export([public_host_dsa_key/2,private_host_dsa_key/2, + public_host_rsa_key/2,private_host_rsa_key/2, + public_host_key/2,private_host_key/2, + lookup_host_key/3, add_host_key/3, % del_host_key/2, + lookup_user_key/3, ssh_dir/2, file_name/3]). + +-export([private_identity_key/2]). +%% , public_identity_key/2, +%% identity_keys/2]). + +-export([encode_public_key/1, decode_public_key_v2/2]). + +-import(lists, [reverse/1, append/1]). + +-define(DBG_PATHS, true). + +%% API +public_host_dsa_key(Type, Opts) -> + File = file_name(Type, "ssh_host_dsa_key.pub", Opts), + read_public_key_v2(File, "ssh-dss"). + +private_host_dsa_key(Type, Opts) -> + File = file_name(Type, "ssh_host_dsa_key", Opts), + read_private_key_v2(File, "ssh-dss"). + +public_host_rsa_key(Type, Opts) -> + File = file_name(Type, "ssh_host_rsa_key.pub", Opts), + read_public_key_v2(File, "ssh-rsa"). + +private_host_rsa_key(Type, Opts) -> + File = file_name(Type, "ssh_host_rsa_key", Opts), + read_private_key_v2(File, "ssh-rsa"). + +public_host_key(Type, Opts) -> + File = file_name(Type, "ssh_host_key", Opts), + case read_private_key_v1(File,public) of + {error, enoent} -> + read_public_key_v1(File++".pub"); + Result -> + Result + end. + + +private_host_key(Type, Opts) -> + File = file_name(Type, "ssh_host_key", Opts), + read_private_key_v1(File,private). + + + +%% in: "host" out: "host,1.2.3.4. +add_ip(Host) -> + case inet:getaddr(Host, inet) of + {ok, Addr} -> + case ssh_connection:encode_ip(Addr) of + false -> Host; + IPString -> Host ++ "," ++ IPString + end; + _ -> Host + end. + +replace_localhost("localhost") -> + {ok, Hostname} = inet:gethostname(), + Hostname; +replace_localhost(Host) -> + Host. + +%% lookup_host_key +%% return {ok, Key(s)} or {error, not_found} +%% + +lookup_host_key(Host, Alg, Opts) -> + Host1 = replace_localhost(Host), + do_lookup_host_key(Host1, Alg, Opts). + +do_lookup_host_key(Host, Alg, Opts) -> + case file:open(file_name(user, "known_hosts", Opts), [read]) of + {ok, Fd} -> + Res = lookup_host_key_fd(Fd, Host, Alg), + file:close(Fd), + Res; + {error, enoent} -> {error, not_found}; + Error -> Error + end. + +add_host_key(Host, Key, Opts) -> + Host1 = add_ip(replace_localhost(Host)), + case file:open(file_name(user, "known_hosts", Opts),[write,append]) of + {ok, Fd} -> + Res = add_key_fd(Fd, Host1, Key), + file:close(Fd), + Res; + Error -> + Error + end. + +%% del_host_key(Host, Opts) -> +%% Host1 = replace_localhost(Host), +%% case file:open(file_name(user, "known_hosts", Opts),[write,read]) of +%% {ok, Fd} -> +%% Res = del_key_fd(Fd, Host1), +%% file:close(Fd), +%% Res; +%% Error -> +%% Error +%% end. + +identity_key_filename("ssh-dss") -> "id_dsa"; +identity_key_filename("ssh-rsa") -> "id_rsa". + +private_identity_key(Alg, Opts) -> + Path = file_name(user, identity_key_filename(Alg), Opts), + read_private_key_v2(Path, Alg). + +read_public_key_v2(File, Type) -> + case file:read_file(File) of + {ok,Bin} -> + List = binary_to_list(Bin), + case lists:prefix(Type, List) of + true -> + List1 = lists:nthtail(length(Type), List), + K_S = ssh_bits:b64_decode(List1), + decode_public_key_v2(K_S, Type); + false -> + {error, bad_format} + end; + Error -> + Error + end. + +decode_public_key_v2(K_S, "ssh-rsa") -> + case ssh_bits:decode(K_S,[string,mpint,mpint]) of + ["ssh-rsa", E, N] -> + {ok, #ssh_key { type = rsa, + public = {N,E}, + comment=""}}; + _ -> + {error, bad_format} + end; +decode_public_key_v2(K_S, "ssh-dss") -> + case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of + ["ssh-dss",P,Q,G,Y] -> + {ok,#ssh_key { type = dsa, + public = {P,Q,G,Y} + }}; + _A -> + {error, bad_format} + end; +decode_public_key_v2(_, _) -> + {error, bad_format}. + + +read_public_key_v1(File) -> + case file:read_file(File) of + {ok,Bin} -> + List = binary_to_list(Bin), + case io_lib:fread("~d ~d ~d ~s", List) of + {ok,[_Sz,E,N,Comment],_} -> + {ok,#ssh_key { type = rsa, + public ={N,E}, + comment = Comment }}; + _Error -> + {error, bad_format} + end; + Error -> + Error + end. + +%% pem_type("ssh-dss") -> "DSA"; +%% pem_type("ssh-rsa") -> "RSA". + +read_private_key_v2(File, Type) -> + case catch (public_key:pem_to_der(File)) of + {ok, [{_, Bin, not_encrypted}]} -> + decode_private_key_v2(Bin, Type); + Error -> %% Note we do not handle password encrypted keys at the moment + {error, Error} + end. +%% case file:read_file(File) of +%% {ok,Bin} -> +%% case read_pem(binary_to_list(Bin), pem_type(Type)) of +%% {ok,Bin1} -> +%% decode_private_key_v2(Bin1, Type); +%% Error -> +%% Error +%% end; +%% Error -> +%% Error +%% end. + +decode_private_key_v2(Private,"ssh-rsa") -> + case 'PKCS-1':decode( 'RSAPrivateKey', Private) of + {ok,RSA} -> %% FIXME Check for two-prime version + {ok, #ssh_key { type = rsa, + public = {RSA#'RSAPrivateKey'.modulus, + RSA#'RSAPrivateKey'.publicExponent}, + private = {RSA#'RSAPrivateKey'.modulus, + RSA#'RSAPrivateKey'.privateExponent} + }}; + Error -> + Error + end; +decode_private_key_v2(Private, "ssh-dss") -> + case 'DSS':decode('DSAPrivateKey', Private) of + {ok,DSA} -> %% FIXME Check for two-prime version + {ok, #ssh_key { type = dsa, + public = {DSA#'DSAPrivateKey'.p, + DSA#'DSAPrivateKey'.q, + DSA#'DSAPrivateKey'.g, + DSA#'DSAPrivateKey'.y}, + private= {DSA#'DSAPrivateKey'.p, + DSA#'DSAPrivateKey'.q, + DSA#'DSAPrivateKey'.g, + DSA#'DSAPrivateKey'.x} + }}; + _ -> + {error,bad_format} + end. + +%% SSH1 private key format +%% <<"SSH PRIVATE KEY FILE FORMATE 1.1\n" 0:8 +%% CipherNum:8, Reserved:32, +%% NSz/uint32, N/bignum, E/bignum, Comment/string, +%% +%% [ R0:8 R1:8 R0:8 R1:8, D/bignum, IQMP/bignum, Q/bignum, P/bignum, Pad(8)]>> +%% +%% where [ ] is encrypted using des3 (ssh1 version) and +%% a posssibly empty pass phrase using md5(passphase) as key +%% + +read_private_key_v1(File, Type) -> + case file:read_file(File) of + {ok,<<"SSH PRIVATE KEY FILE FORMAT 1.1\n",0, + CipherNum,_Resereved:32,Bin/binary>>} -> + decode_private_key_v1(Bin, CipherNum,Type); + {ok,_} -> + {error, bad_format}; + Error -> + Error + end. + +decode_private_key_v1(Bin, CipherNum, Type) -> + case ssh_bits:decode(Bin,0,[uint32, bignum, bignum, string]) of + {Offset,[_NSz,N,E,Comment]} -> + if Type == public -> + {ok,#ssh_key { type=rsa, + public={N,E}, + comment=Comment}}; + Type == private -> + <<_:Offset/binary, Encrypted/binary>> = Bin, + case ssh_bits:decode(decrypt1(Encrypted, CipherNum),0, + [uint32, bignum, bignum, + bignum, bignum,{pad,8}]) of + {_,[_,D,IQMP,Q,P]} -> + {ok,#ssh_key { type=rsa, + public={N,E}, + private={D,IQMP,Q,P}, + comment=Comment}}; + _ -> + {error,bad_format} + end + end; + _ -> + {error,bad_format} + end. + + +decrypt1(Bin, CipherNum) -> + decrypt1(Bin, CipherNum,""). + +decrypt1(Bin, CipherNum, Phrase) -> + if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" -> + Bin; + CipherNum == ?SSH_CIPHER_3DES -> + <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase), + K3 = K1, + IV = <<0,0,0,0,0,0,0,0>>, + Bin1 = crypto:des_cbc_decrypt(K3,IV,Bin), + Bin2 = crypto:des_cbc_encrypt(K2,IV,Bin1), + crypto:des_cbc_decrypt(K1,IV,Bin2) + end. + +%% encrypt1(Bin, CipherNum) -> +%% encrypt1(Bin, CipherNum,""). + +%% encrypt1(Bin, CipherNum, Phrase) -> +%% if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" -> +%% Bin; +%% CipherNum == ?SSH_CIPHER_3DES -> +%% <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase), +%% K3 = K1, +%% IV = <<0,0,0,0,0,0,0,0>>, +%% Bin1 = crypto:des_cbc_encrypt(K1,IV,Bin), +%% Bin2 = crypto:des_cbc_decrypt(K2,IV,Bin1), +%% crypto:des_cbc_encrypt(K3,IV,Bin2) +%% end. + +lookup_host_key_fd(Fd, Host, Alg) -> + case io:get_line(Fd, '') of + eof -> + {error, not_found}; + Line -> + case string:tokens(Line, " ") of + [HostList, Alg, KeyData] -> +%% io:format(" ~p lookup_host_key_fd: HostList ~p Alg ~p KeyData ~p\n", +%% [Host, HostList, Alg, KeyData]), + case lists:member(Host, string:tokens(HostList, ",")) of + true -> + decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg); + false -> + lookup_host_key_fd(Fd, Host, Alg) + end; + _ -> + lookup_host_key_fd(Fd, Host, Alg) + end + end. + + + +%% del_key_fd(Fd, Host) -> +%% del_key_fd(Fd, Host, 0, 0). + +%% del_key_fd(Fd, Host, ReadPos0, WritePos0) -> +%% case io:get_line(Fd, '') of +%% eof -> +%% if ReadPos0 == WritePos0 -> +%% ok; +%% true -> +%% file:truncate(Fd) +%% end; +%% Line -> +%% {ok,ReadPos1} = file:position(Fd, cur), +%% case string:tokens(Line, " ") of +%% [HostList, _Type, _KeyData] -> +%% case lists:member(Host, string:tokens(HostList, ",")) of +%% true -> +%% del_key_fd(Fd, Host, ReadPos1, WritePos0); +%% false -> +%% if ReadPos0 == WritePos0 -> +%% del_key_fd(Fd, Host, ReadPos1, ReadPos1); +%% true -> +%% file:position(Fd, WritePos0), +%% file:write(Fd, Line), +%% {ok,WritePos1} = file:position(Fd,cur), +%% del_key_fd(Fd, Host, ReadPos1, WritePos1) +%% end +%% end; +%% _ -> +%% if ReadPos0 == WritePos0 -> +%% del_key_fd(Fd, Host, ReadPos1, ReadPos1); +%% true -> +%% file:position(Fd, WritePos0), +%% file:write(Fd, Line), +%% {ok,WritePos1} = file:position(Fd,cur), +%% del_key_fd(Fd, Host, ReadPos1, WritePos1) +%% end +%% end +%% end. + + +add_key_fd(Fd, Host, Key) -> + case Key#ssh_key.type of + rsa -> + {N,E} = Key#ssh_key.public, + DK = ssh_bits:b64_encode( + ssh_bits:encode(["ssh-rsa",E,N], + [string,mpint,mpint])), + file:write(Fd, [Host, " ssh-rsa ", DK, "\n"]); + dsa -> + {P,Q,G,Y} = Key#ssh_key.public, + DK = ssh_bits:b64_encode( + ssh_bits:encode(["ssh-dss",P,Q,G,Y], + [string,mpint,mpint,mpint,mpint])), + file:write(Fd, [Host, " ssh-dss ", DK, "\n"]) + end. + + +%% read_pem(Cs, Type) -> +%% case read_line(Cs) of +%% {"-----BEGIN "++Rest,Cs1} -> +%% case string:tokens(Rest, " ") of +%% [Type, "PRIVATE", "KEY-----"] -> +%% read_pem64(Cs1, [], Type); +%% _ -> +%% {error, bad_format} +%% end; +%% {"",Cs1} when Cs1 =/= "" -> +%% read_pem(Cs1,Type); +%% {_,""} -> +%% {error, bad_format} +%% end. + +%% read_pem64(Cs, Acc, Type) -> +%% case read_line(Cs) of +%% {"-----END "++Rest,_Cs1} -> +%% case string:tokens(Rest, " ") of +%% [Type, "PRIVATE", "KEY-----"] -> +%% {ok,ssh_bits:b64_decode(append(reverse(Acc)))}; +%% Toks -> +%% error_logger:format("ssh: TOKENS=~p\n", [Toks]), +%% {error, bad_format} +%% end; +%% {B64, Cs1} when Cs1 =/= "" -> +%% read_pem64(Cs1, [B64|Acc], Type); +%% _What -> +%% {error, bad_format} +%% end. + + +%% read_line(Cs) -> read_line(Cs,[]). +%% read_line([$\r,$\n|T], Acc) -> {reverse(Acc), T}; +%% read_line([$\n|T], Acc) -> {reverse(Acc), T}; +%% read_line([C|T], Acc) -> read_line(T,[C|Acc]); +%% read_line([], Acc) -> {reverse(Acc),[]}. + +lookup_user_key(User, Alg, Opts) -> + SshDir = ssh_dir({remoteuser,User}, Opts), + case lookup_user_key_f(User, SshDir, Alg, "authorized_keys", Opts) of + {ok, Key} -> + {ok, Key}; + _ -> + lookup_user_key_f(User, SshDir, Alg, "authorized_keys2", Opts) + end. + +lookup_user_key_f(_User, [], _Alg, _F, _Opts) -> + {error, nouserdir}; +lookup_user_key_f(_User, nouserdir, _Alg, _F, _Opts) -> + {error, nouserdir}; +lookup_user_key_f(_User, Dir, Alg, F, _Opts) -> + FileName = filename:join(Dir, F), + case file:open(FileName, [read]) of + {ok, Fd} -> + Res = lookup_user_key_fd(Fd, Alg), + file:close(Fd), + Res; + {error, Reason} -> + {error, {{openerr, Reason}, {file, FileName}}} + end. + +lookup_user_key_fd(Fd, Alg) -> + case io:get_line(Fd, '') of + eof -> + {error, not_found}; + Line -> + case string:tokens(Line, " ") of + [Alg, KeyData, _] -> + %% io:format("lookup_user_key_fd: HostList ~p Alg ~p KeyData ~p\n", + %% [HostList, Alg, KeyData]), + decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg); + _Other -> + %%?dbg(false, "key_fd Other: ~w ~w\n", [Alg, _Other]), + lookup_user_key_fd(Fd, Alg) + end + end. + + +encode_public_key(#ssh_key{type = rsa, public = {N, E}}) -> + ssh_bits:encode(["ssh-rsa",E,N], + [string,mpint,mpint]); +encode_public_key(#ssh_key{type = dsa, public = {P,Q,G,Y}}) -> + ssh_bits:encode(["ssh-dss",P,Q,G,Y], + [string,mpint,mpint,mpint,mpint]). + +%% +%% Utils +%% + +%% server use this to find individual keys for +%% an individual user when user tries to login +%% with publickey +ssh_dir({remoteuser, User}, Opts) -> + case proplists:get_value(user_dir_fun, Opts) of + undefined -> + case proplists:get_value(user_dir, Opts) of + undefined -> + default_user_dir(); + Dir -> + Dir + end; + FUN -> + FUN(User) + end; + +%% client use this to find client ssh keys +ssh_dir(user, Opts) -> + case proplists:get_value(user_dir, Opts, false) of + false -> default_user_dir(); + D -> D + end; + +%% server use this to find server host keys +ssh_dir(system, Opts) -> + proplists:get_value(system_dir, Opts, "/etc/ssh"). + +file_name(Type, Name, Opts) -> + FN = filename:join(ssh_dir(Type, Opts), Name), + %%?dbg(?DBG_PATHS, "file_name: ~p\n", [FN]), + FN. + +default_user_dir()-> + {ok,[[Home|_]]} = init:get_argument(home), + filename:join(Home, ".ssh"). diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl new file mode 100755 index 0000000000..0e343c20b4 --- /dev/null +++ b/lib/ssh/src/ssh_io.erl @@ -0,0 +1,79 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: user interaction for SSH + +-module(ssh_io). + +-export([yes_no/1, read_password/1, read_line/1, format/2]). +-import(lists, [reverse/1]). + + +read_line(Prompt) when is_list(Prompt) -> + io:get_line(list_to_atom(Prompt)); +read_line(Prompt) when is_atom(Prompt) -> + io:get_line(Prompt). + +read_ln(Prompt) -> + trim(read_line(Prompt)). + +yes_no(Prompt) -> + io:format("~s [y/n]?", [Prompt]), + case read_ln('') of + "y" -> yes; + "n" -> no; + "Y" -> yes; + "N" -> no; + _ -> + io:format("please answer y or n\n"), + yes_no(Prompt) + end. + + +read_password(Prompt) -> + format("~s", [listify(Prompt)]), + case io:get_password() of + "" -> + read_password(Prompt); + Pass -> Pass + end. + +listify(A) when is_atom(A) -> + atom_to_list(A); +listify(L) when is_list(L) -> + L. + +format(Fmt, Args) -> + io:format(Fmt, Args). + + +trim(Line) when is_list(Line) -> + reverse(trim1(reverse(trim1(Line)))); +trim(Other) -> Other. + +trim1([$\s|Cs]) -> trim(Cs); +trim1([$\r|Cs]) -> trim(Cs); +trim1([$\n|Cs]) -> trim(Cs); +trim1([$\t|Cs]) -> trim(Cs); +trim1(Cs) -> Cs. + + + diff --git a/lib/ssh/src/ssh_math.erl b/lib/ssh/src/ssh_math.erl new file mode 100755 index 0000000000..efe7f56979 --- /dev/null +++ b/lib/ssh/src/ssh_math.erl @@ -0,0 +1,131 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SSH math utilities + +-module(ssh_math). + +-export([ilog2/1, ipow/3, invert/2, ipow2/3]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% INTEGER utils +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% number of bits (used) in a integer = isize(N) = |log2(N)|+1 +ilog2(N) -> + ssh_bits:isize(N) - 1. + + +%% calculate A^B mod M +ipow(A, B, M) when M > 0, B >= 0 -> + crypto:mod_exp(A, B, M). + +ipow2(A, B, M) when M > 0, B >= 0 -> + if A == 1 -> + 1; + true -> + ipow2(A, B, M, 1) + end. + +ipow2(A, 1, M, Prod) -> + (A*Prod) rem M; +ipow2(_A, 0, _M, Prod) -> + Prod; +ipow2(A, B, M, Prod) -> + B1 = B bsr 1, + A1 = (A*A) rem M, + if B - B1 == B1 -> + ipow2(A1, B1, M, Prod); + true -> + ipow2(A1, B1, M, (A*Prod) rem M) + end. + +%% %% +%% %% Normal gcd +%% %% +%% gcd(R, Q) when abs(Q) < abs(R) -> gcd1(Q,R); +%% gcd(R, Q) -> gcd1(R,Q). + +%% gcd1(0, Q) -> Q; +%% gcd1(R, Q) -> +%% gcd1(Q rem R, R). + + +%% %% +%% %% Least common multiple of (R,Q) +%% %% +%% lcm(0, _Q) -> 0; +%% lcm(_R, 0) -> 0; +%% lcm(R, Q) -> +%% (Q div gcd(R, Q)) * R. + +%% %% +%% %% Extended gcd gcd(R,Q) -> {G, {A,B}} such that G == R*A + Q*B +%% %% +%% %% Here we could have use for a bif divrem(Q, R) -> {Quote, Remainder} +%% %% +%% egcd(R,Q) when abs(Q) < abs(R) -> egcd1(Q,R,1,0,0,1); +%% egcd(R,Q) -> egcd1(R,Q,0,1,1,0). + +%% egcd1(0,Q,_,_,Q1,Q2) -> {Q, {Q2,Q1}}; +%% egcd1(R,Q,R1,R2,Q1,Q2) -> +%% D = Q div R, +%% egcd1(Q rem R, R, Q1-D*R1, Q2-D*R2, R1, R2). + +%% +%% Invert an element X mod P +%% Calculated as {1, {A,B}} = egcd(X,P), +%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element +%% +%% X > 0, P > 0, X < P (P should be prime) +%% +invert(X,P) when X > 0, P > 0, X < P -> + I = inv(X,P,1,0), + if + I < 0 -> P + I; + true -> I + end. + +inv(0,_,_,Q) -> Q; +inv(X,P,R1,Q1) -> + D = P div X, + inv(P rem X, X, Q1 - D*R1, R1). + + +%% %% +%% %% Integer square root +%% %% + +%% isqrt(0) -> 0; +%% isqrt(1) -> 1; +%% isqrt(X) when X >= 0 -> +%% R = X div 2, +%% isqrt(X div R, R, X). + +%% isqrt(Q,R,X) when Q < R -> +%% R1 = (R+Q) div 2, +%% isqrt(X div R1, R1, X); +%% isqrt(_, R, _) -> R. + + diff --git a/lib/ssh/src/ssh_no_io.erl b/lib/ssh/src/ssh_no_io.erl new file mode 100644 index 0000000000..5f363ae6c2 --- /dev/null +++ b/lib/ssh/src/ssh_no_io.erl @@ -0,0 +1,39 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: ssh_io replacement that throws on everything + +-module(ssh_no_io). + +-export([yes_no/1, read_password/1, read_line/1, format/2]). + +yes_no(_Prompt) -> + throw({no_io_allowed, yes_no}). + +read_password(_Prompt) -> + throw({no_io_allowed, read_password}). + +read_line(_Prompt) -> + throw({no_io_allowed, read_line}). + +format(_Fmt, _Args) -> + throw({no_io_allowed, format}). + diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl new file mode 100755 index 0000000000..7c2bf9a2bf --- /dev/null +++ b/lib/ssh/src/ssh_rsa.erl @@ -0,0 +1,299 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: rsa public-key sign and verify + +-module(ssh_rsa). + +-export([verify/3, sign/2]). +-export([alg_name/0]). + +-include("ssh.hrl"). +-include("PKCS-1.hrl"). + + +-define(MGF(Seed,Len), mgf1((Seed),(Len))). +-define(HASH(X), crypto:sha((X))). +-define(HLen, 20). + +%% start() -> +%% crypto:start(). + +%% sign_file(File) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:private_host_rsa_key(user), +%% sign(Key, Bin). + +%% verify_file(File, Sig) -> +%% start(), +%% {ok,Bin} = file:read_file(File), +%% {ok,Key} = ssh_file:public_host_rsa_key(user), +%% verify(Key, Bin, Sig). + +sign(Private,Mb) -> + rsassa_pkcs1_v1_5_sign(Private,Mb). + +verify(Public,Mb,Sb) -> + rsassa_pkcs1_v1_5_verify(Public,Mb,Sb). + + + +%% Integer to octet string +i2osp(X, XLen) -> + ssh_bits:i2bin(X, XLen). + +%% Octet string to Integer +os2ip(X) -> + ssh_bits:bin2i(X). + +%% decrypt1, M = message representative +%% rsaep(#ssh_key { public={N,E}}, M) -> +%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range), +%% ssh_math:ipow(M, E, N). + +%% encrypt1, C = cipher representative +%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) -> +%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range), +%% ssh_math:ipow(C, D, N). + +%% sign1, M = message representative +rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) -> + ?ssh_assert((M >= 0 andalso M =< N-1), out_of_range), + ssh_math:ipow(M, D, N). + +%% verify1, S =signature representative +rsavp1(#ssh_key { public={N,E}}, S) -> + ?ssh_assert(S >= 0 andalso S =< N-1, out_of_range), + ssh_math:ipow(S, E, N). + + +%% M messaage +%% rsaes_oaep_encrypt(Public, M) -> +%% rsaes_oaep_encrypt(Public, M, <<>>). + +%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) -> +%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), +%% K = (ssh_bits:isize(N)+7) div 8, +%% MLen = size(M), +%% %% LLen = size(L), +%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long), +%% LHash = ?HASH(L), +%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0), +%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>, +%% Seed = ssh_bits:random(?HLen), +%% DbMask = ?MGF(Seed, K - ?HLen - 1), +%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), +%% SeedMask = ?MGF(MaskedDB, ?HLen), +%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask), +%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>, +%% Mc = os2ip(EM), +%% C = rsaep(Public, Mc), +%% i2osp(C, K). + +%% rsaes_oaep_decrypt(Key, C) -> +%% rsaes_oaep_decrypt(Key, C, <<>>). + +%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) -> +%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), +%% K = (ssh_bits:isize(N)+7) div 8, +%% ?ssh_assert(K == 2*?HLen + 2, decryption_error), +%% C = os2ip(Cb), +%% M = rsadp(Private, C), +%% EM = i2osp(M, K), +%% LHash = ?HASH(L), +%% MLen = K - ?HLen -1, +%% case EM of +%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> -> +%% SeedMask = ?MGF(MaskedDB, ?HLen), +%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask), +%% DbMask = ?MGF(Seed, K - ?HLen - 1), +%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), +%% PSLen = K - MLen - 2*?HLen - 2, +%% case DB of +%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> -> +%% M; +%% _ -> +%% exit(decryption_error) +%% end; +%% _ -> +%% exit(decryption_error) +%% end. + + +%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) -> +%% K = (ssh_bits:isize(N)+7) div 8, +%% MLen = size(M), +%% ?ssh_assert(MLen =< K - 11, message_to_long), +%% PS = ssh_bits:random(K - MLen - 3), +%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>, +%% Mc = os2ip(EM), +%% C = rsaep(Public, Mc), +%% i2osp(C, K). + + +%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}}, +%% Cb) -> +%% K = (ssh_bits:isize(N)+7) div 8, +%% CLen = size(Cb), +%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error), +%% C = os2ip(Cb), +%% M = rsadp(Private, C), +%% EM = i2osp(M, K), +%% PSLen = K - CLen - 3, +%% case EM of +%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> -> +%% M; +%% _ -> +%% exit(decryption_error) +%% end. + +%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) -> +%% ModBits = ssh_bits:isize(N), +%% K = (ModBits+7) div 8, +%% EM = emsa_pss_encode(Mb, ModBits - 1), +%% M = os2ip(EM), +%% S = rsasp1(Private, M), +%% i2osp(S, K). + +%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) -> +%% ModBits = ssh_bits:isize(N), +%% K = (ModBits+7) div 8, +%% ?ssh_assert(size(Sb) == K, invalid_signature), +%% S = os2ip(Sb), +%% M = rsavp1(Public,S), +%% EMLen = (ModBits-1+7) div 8, +%% EM = i2osp(M, EMLen), +%% emsa_pss_verify(Mb, EM, ModBits-1). + + +rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) -> + K = (ssh_bits:isize(N)+7) div 8, + EM = emsa_pkcs1_v1_5_encode(Mb, K), + M = os2ip(EM), + S = rsasp1(Private, M), + i2osp(S, K). + +rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) -> + K = (ssh_bits:isize(N)+7) div 8, + ?ssh_assert(size(Sb) == K, invalid_signature), + S = os2ip(Sb), + M = rsavp1(Public, S), + EM = i2osp(M, K), + %?dbg(true, "verify K=~p S=~w ~n#M=~w~n#EM=~w~n", [K, S, M, EM]), + case emsa_pkcs1_v1_5_encode(Mb, K) of + EM -> ok; + _S -> + io:format("S: ~p~n", [_S]), + {error, invalid_signature} % exit(invalid_signature) + end. + + +emsa_pkcs1_v1_5_encode(M, EMLen) -> + H = ?HASH(M), + %% Must use speical xxNull types here! + Alg = #'AlgorithmNull' { algorithm = ?'id-sha1', + parameters = <<>> }, + {ok,TCode} = 'PKCS-1':encode('DigestInfoNull', + #'DigestInfoNull'{ digestAlgorithm = Alg, + digest = H }), + T = list_to_binary(TCode), + TLen = size(T), + ?ssh_assert(EMLen >= TLen + 11, message_to_short), + PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff), + <<16#00, 16#01, PS/binary, 16#00, T/binary>>. + + +%% emsa_pss_encode(M, EMBits) -> +%% emsa_pss_encode(M, EMBits, 0). + +%% emsa_pss_encode(M, EMBits, SLen) -> +%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), +%% EMLen = (EMBits + 7) div 8, +%% MHash = ?HASH(M), +%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error), +%% Salt = ssh_bits:random(SLen), +%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, +%% MHash, Salt], +%% H = ?HASH(M1), +%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0), +%% DB = <<PS/binary, 16#01, Salt/binary>>, +%% DbMask = ?MGF(H, EMLen - ?HLen -1), +%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), +%% ZLen = 8*EMLen - EMBits, +%% NZLen = (8 - (ZLen rem 8)) rem 8, +%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB, +%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>, +%% <<MaskedDB2/binary, H/binary, 16#BC>>. + + +%% emsa_pss_verify(M, EM, EMBits) -> +%% emsa_pss_verify(M, EM, EMBits, 0). + +%% emsa_pss_verify(M, EM, EMBits, SLen) -> +%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), +%% EMLen = (EMBits + 7) div 8, +%% MHash = ?HASH(M), +%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent), +%% MaskLen = (EMLen - ?HLen - 1)-1, +%% ZLen = 8*EMLen - EMBits, +%% NZLen = (8 - (ZLen rem 8)) rem 8, +%% case EM of +%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> -> +%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>, +%% DbMask = ?MGF(H, EMLen - ?HLen - 1), +%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), +%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1, +%% PS = ssh_bits:fill_bits(PSLen1, 0), +%% case DB of +%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> -> +%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, +%% MHash, Salt], +%% case ?HASH(M1) of +%% H -> ok; +%% _ -> exit(inconsistent) +%% end; +%% _ -> +%% exit(inconsistent) +%% end; +%% _ -> +%% exit(inconsistent) +%% end. + + + +%% Mask generating function MGF1 +%% mgf1(MGFSeed, MaskLen) -> +%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""), +%% <<R:MaskLen/binary, _/binary>> = T, +%% R. + +%% mgf1_loop(Counter, N, _, T) when Counter > N -> +%% list_to_binary(T); +%% mgf1_loop(Counter, N, MGFSeed, T) -> +%% C = i2osp(Counter, 4), +%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]). + + + + +alg_name() -> + "ssh-rsa". diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl new file mode 100755 index 0000000000..cbfa208f6f --- /dev/null +++ b/lib/ssh/src/ssh_sftp.erl @@ -0,0 +1,1148 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SFTP protocol front-end + +-module(ssh_sftp). + +-behaviour(ssh_channel). + +-include_lib("kernel/include/file.hrl"). +-include("ssh.hrl"). +-include("ssh_xfer.hrl"). + +%% API + +-export([start_channel/1, start_channel/2, start_channel/3, stop_channel/1]). + +-export([open/3, opendir/2, close/2, readdir/2, pread/4, read/3, + open/4, opendir/3, close/3, readdir/3, pread/5, read/4, + apread/4, aread/3, pwrite/4, write/3, apwrite/4, awrite/3, + pwrite/5, write/4, + position/3, real_path/2, read_file_info/2, get_file_info/2, + position/4, real_path/3, read_file_info/3, get_file_info/3, + write_file_info/3, read_link_info/2, read_link/2, make_symlink/3, + write_file_info/4, read_link_info/3, read_link/3, make_symlink/4, + rename/3, delete/2, make_dir/2, del_dir/2, send_window/1, + rename/4, delete/3, make_dir/3, del_dir/3, send_window/2, + recv_window/1, list_dir/2, read_file/2, write_file/3, + recv_window/2, list_dir/3, read_file/3, write_file/4]). + +%% Deprecated +-export([connect/1, connect/2, connect/3, stop/1]). + +-deprecated({connect, 1, next_major_release}). +-deprecated({connect, 2, next_major_release}). +-deprecated({connect, 3, next_major_release}). +-deprecated({stop, 1, next_major_release}). + +%% ssh_channel callbacks +-export([init/1, handle_call/3, handle_msg/2, handle_ssh_msg/2, terminate/2]). +%% TODO: Should be placed elsewhere ssh_sftpd should not call functions in ssh_sftp! +-export([info_to_attr/1, attr_to_info/1]). + +-record(state, + { + xf, + rep_buf = <<>>, + req_id, + req_list = [], %% {ReqId, Fun} + inf %% list of fileinf + }). + +-record(fileinf, + { + handle, + offset, + size, + mode + }). + +-define(FILEOP_TIMEOUT, infinity). + +-define(NEXT_REQID(S), + S#state { req_id = (S#state.req_id + 1) band 16#ffffffff}). + +-define(XF(S), S#state.xf). +-define(REQID(S), S#state.req_id). + +%%==================================================================== +%% API +%%==================================================================== +start_channel(Cm) when is_pid(Cm) -> + start_channel(Cm, []); +start_channel(Host) when is_list(Host) -> + start_channel(Host, []). +start_channel(Cm, Opts) when is_pid(Cm) -> + Timeout = proplists:get_value(timeout, Opts, infinity), + case ssh_xfer:attach(Cm, []) of + {ok, ChannelId, Cm} -> + case ssh_channel:start(Cm, ChannelId, + ?MODULE, [Cm, ChannelId, Timeout]) of + {ok, Pid} -> + case wait_for_version_negotiation(Pid, Timeout) of + ok -> + {ok, Pid}; + TimeOut -> + TimeOut + end; + {error, Reason} -> + {error, Reason}; + ignore -> + {error, ignore} + end; + Error -> + Error + end; + +start_channel(Host, Opts) -> + start_channel(Host, 22, Opts). +start_channel(Host, Port, Opts) -> + Timeout = proplists:get_value(timeout, Opts, infinity), + case ssh_xfer:connect(Host, Port, proplists:delete(timeout, Opts)) of + {ok, ChannelId, Cm} -> + case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm, + ChannelId, Timeout]) of + {ok, Pid} -> + case wait_for_version_negotiation(Pid, Timeout) of + ok -> + {ok, Pid, Cm}; + TimeOut -> + TimeOut + end; + {error, Reason} -> + {error, Reason}; + ignore -> + {error, ignore} + end; + Error -> + Error + end. + +stop_channel(Pid) -> + case process_info(Pid, [trap_exit]) of + [{trap_exit, Bool}] -> + process_flag(trap_exit, true), + link(Pid), + exit(Pid, ssh_sftp_stop_channel), + receive + {'EXIT', Pid, normal} -> + ok + after 5000 -> + exit(Pid, kill), + receive + {'EXIT', Pid, killed} -> + ok + end + end, + process_flag(trap_exit, Bool), + ok; + undefined -> + ok + end. + +wait_for_version_negotiation(Pid, Timeout) -> + call(Pid, wait_for_version_negotiation, Timeout). + +open(Pid, File, Mode) -> + open(Pid, File, Mode, ?FILEOP_TIMEOUT). +open(Pid, File, Mode, FileOpTimeout) -> + call(Pid, {open, false, File, Mode}, FileOpTimeout). + +opendir(Pid, Path) -> + opendir(Pid, Path, ?FILEOP_TIMEOUT). +opendir(Pid, Path, FileOpTimeout) -> + call(Pid, {opendir, false, Path}, FileOpTimeout). + +close(Pid, Handle) -> + close(Pid, Handle, ?FILEOP_TIMEOUT). +close(Pid, Handle, FileOpTimeout) -> + call(Pid, {close,false,Handle}, FileOpTimeout). + +readdir(Pid,Handle) -> + readdir(Pid,Handle, ?FILEOP_TIMEOUT). +readdir(Pid,Handle, FileOpTimeout) -> + call(Pid, {readdir,false,Handle}, FileOpTimeout). + +pread(Pid, Handle, Offset, Len) -> + pread(Pid, Handle, Offset, Len, ?FILEOP_TIMEOUT). +pread(Pid, Handle, Offset, Len, FileOpTimeout) -> + call(Pid, {pread,false,Handle, Offset, Len}, FileOpTimeout). + +read(Pid, Handle, Len) -> + read(Pid, Handle, Len, ?FILEOP_TIMEOUT). +read(Pid, Handle, Len, FileOpTimeout) -> + call(Pid, {read,false,Handle, Len}, FileOpTimeout). + +%% TODO this ought to be a cast! Is so in all practial meaning +%% even if it is obscure! +apread(Pid, Handle, Offset, Len) -> + call(Pid, {pread,true,Handle, Offset, Len}, infinity). + +%% TODO this ought to be a cast! +aread(Pid, Handle, Len) -> + call(Pid, {read,true,Handle, Len}, infinity). + +pwrite(Pid, Handle, Offset, Data) -> + pwrite(Pid, Handle, Offset, Data, ?FILEOP_TIMEOUT). +pwrite(Pid, Handle, Offset, Data, FileOpTimeout) -> + call(Pid, {pwrite,false,Handle,Offset,Data}, FileOpTimeout). + +write(Pid, Handle, Data) -> + write(Pid, Handle, Data, ?FILEOP_TIMEOUT). +write(Pid, Handle, Data, FileOpTimeout) -> + call(Pid, {write,false,Handle,Data}, FileOpTimeout). + +%% TODO this ought to be a cast! Is so in all practial meaning +%% even if it is obscure! +apwrite(Pid, Handle, Offset, Data) -> + call(Pid, {pwrite,true,Handle,Offset,Data}, infinity). + +%% TODO this ought to be a cast! Is so in all practial meaning +%% even if it is obscure! +awrite(Pid, Handle, Data) -> + call(Pid, {write,true,Handle,Data}, infinity). + +position(Pid, Handle, Pos) -> + position(Pid, Handle, Pos, ?FILEOP_TIMEOUT). +position(Pid, Handle, Pos, FileOpTimeout) -> + call(Pid, {position, Handle, Pos}, FileOpTimeout). + +real_path(Pid, Path) -> + real_path(Pid, Path, ?FILEOP_TIMEOUT). +real_path(Pid, Path, FileOpTimeout) -> + call(Pid, {real_path, false, Path}, FileOpTimeout). + +read_file_info(Pid, Name) -> + read_file_info(Pid, Name, ?FILEOP_TIMEOUT). +read_file_info(Pid, Name, FileOpTimeout) -> + call(Pid, {read_file_info,false,Name}, FileOpTimeout). + +get_file_info(Pid, Handle) -> + get_file_info(Pid, Handle, ?FILEOP_TIMEOUT). +get_file_info(Pid, Handle, FileOpTimeout) -> + call(Pid, {get_file_info,false,Handle}, FileOpTimeout). + +write_file_info(Pid, Name, Info) -> + write_file_info(Pid, Name, Info, ?FILEOP_TIMEOUT). +write_file_info(Pid, Name, Info, FileOpTimeout) -> + call(Pid, {write_file_info,false,Name, Info}, FileOpTimeout). + +read_link_info(Pid, Name) -> + read_link_info(Pid, Name, ?FILEOP_TIMEOUT). +read_link_info(Pid, Name, FileOpTimeout) -> + call(Pid, {read_link_info,false,Name}, FileOpTimeout). + +read_link(Pid, LinkName) -> + read_link(Pid, LinkName, ?FILEOP_TIMEOUT). +read_link(Pid, LinkName, FileOpTimeout) -> + case call(Pid, {read_link,false,LinkName}, FileOpTimeout) of + {ok, [{Name, _Attrs}]} -> + {ok, Name}; + ErrMsg -> + ErrMsg + end. + +make_symlink(Pid, Name, Target) -> + make_symlink(Pid, Name, Target, ?FILEOP_TIMEOUT). +make_symlink(Pid, Name, Target, FileOpTimeout) -> + call(Pid, {make_symlink,false, Name, Target}, FileOpTimeout). + +rename(Pid, FromFile, ToFile) -> + rename(Pid, FromFile, ToFile, ?FILEOP_TIMEOUT). +rename(Pid, FromFile, ToFile, FileOpTimeout) -> + call(Pid, {rename,false,FromFile, ToFile}, FileOpTimeout). + +delete(Pid, Name) -> + delete(Pid, Name, ?FILEOP_TIMEOUT). +delete(Pid, Name, FileOpTimeout) -> + call(Pid, {delete,false,Name}, FileOpTimeout). + +make_dir(Pid, Name) -> + make_dir(Pid, Name, ?FILEOP_TIMEOUT). +make_dir(Pid, Name, FileOpTimeout) -> + call(Pid, {make_dir,false,Name}, FileOpTimeout). + +del_dir(Pid, Name) -> + del_dir(Pid, Name, ?FILEOP_TIMEOUT). +del_dir(Pid, Name, FileOpTimeout) -> + call(Pid, {del_dir,false,Name}, FileOpTimeout). + +%% TODO : send_window and recv_window - Really needed? Not documented! +%% internal use maybe should be handled in other way! +send_window(Pid) -> + send_window(Pid, ?FILEOP_TIMEOUT). +send_window(Pid, FileOpTimeout) -> + call(Pid, send_window, FileOpTimeout). + +recv_window(Pid) -> + recv_window(Pid, ?FILEOP_TIMEOUT). +recv_window(Pid, FileOpTimeout) -> + call(Pid, recv_window, FileOpTimeout). + + +list_dir(Pid, Name) -> + list_dir(Pid, Name, ?FILEOP_TIMEOUT). + +list_dir(Pid, Name, FileOpTimeout) -> + case opendir(Pid, Name, FileOpTimeout) of + {ok,Handle} -> + Res = do_list_dir(Pid, Handle, FileOpTimeout, []), + close(Pid, Handle, FileOpTimeout), + case Res of + {ok, List} -> + NList = lists:foldl(fun({Nm, _Info},Acc) -> + [Nm|Acc] end, + [], List), + {ok,NList}; + Error -> Error + end; + Error -> + Error + end. + +do_list_dir(Pid, Handle, FileOpTimeout, Acc) -> + case readdir(Pid, Handle, FileOpTimeout) of + {ok, []} -> + {ok, Acc}; + {ok, Names} -> + do_list_dir(Pid, Handle, FileOpTimeout, Acc ++ Names); + eof -> + {ok, Acc}; + Error -> + Error + end. + + +read_file(Pid, Name) -> + read_file(Pid, Name, ?FILEOP_TIMEOUT). + +read_file(Pid, Name, FileOpTimeout) -> + case open(Pid, Name, [read, binary], FileOpTimeout) of + {ok, Handle} -> + {ok,{_WindowSz,PacketSz}} = recv_window(Pid, FileOpTimeout), + Res = read_file_loop(Pid, Handle, PacketSz, FileOpTimeout, []), + close(Pid, Handle), + Res; + Error -> + Error + end. + +read_file_loop(Pid, Handle, PacketSz, FileOpTimeout, Acc) -> + case read(Pid, Handle, PacketSz, FileOpTimeout) of + {ok, Data} -> + read_file_loop(Pid, Handle, PacketSz, FileOpTimeout, [Data|Acc]); + eof -> + {ok, list_to_binary(lists:reverse(Acc))}; + Error -> + Error + end. + +write_file(Pid, Name, List) -> + write_file(Pid, Name, List, ?FILEOP_TIMEOUT). + +write_file(Pid, Name, List, FileOpTimeout) when is_list(List) -> + write_file(Pid, Name, list_to_binary(List), FileOpTimeout); +write_file(Pid, Name, Bin, FileOpTimeout) -> + case open(Pid, Name, [write, binary], FileOpTimeout) of + {ok, Handle} -> + {ok,{_Window,Packet}} = send_window(Pid, FileOpTimeout), + Res = write_file_loop(Pid, Handle, 0, Bin, size(Bin), Packet, + FileOpTimeout), + close(Pid, Handle, FileOpTimeout), + Res; + Error -> + Error + end. + +write_file_loop(_Pid, _Handle, _Pos, _Bin, 0, _PacketSz,_FileOpTimeout) -> + ok; +write_file_loop(Pid, Handle, Pos, Bin, Remain, PacketSz, FileOpTimeout) -> + if Remain >= PacketSz -> + <<_:Pos/binary, Data:PacketSz/binary, _/binary>> = Bin, + case write(Pid, Handle, Data, FileOpTimeout) of + ok -> + write_file_loop(Pid, Handle, + Pos+PacketSz, Bin, Remain-PacketSz, + PacketSz, FileOpTimeout); + Error -> + Error + end; + true -> + <<_:Pos/binary, Data/binary>> = Bin, + write(Pid, Handle, Data, FileOpTimeout) + end. + +%%==================================================================== +%% SSh channel callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} +%% +%% Description: +%%-------------------------------------------------------------------- +init([Cm, ChannelId, Timeout]) -> + erlang:monitor(process, Cm), + case ssh_connection:subsystem(Cm, ChannelId, "sftp", Timeout) of + success -> + Xf = #ssh_xfer{cm = Cm, + channel = ChannelId}, + {ok, #state{xf = Xf, + req_id = 0, + rep_buf = <<>>, + inf = new_inf()}}; + failure -> + {stop, {error, "server failed to start sftp subsystem"}}; + Error -> + {stop, Error} + end. + +%%-------------------------------------------------------------------- +%% Function: handle_call/3 +%% Description: Handling call messages +%% Returns: {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | (terminate/2 is called) +%% {stop, Reason, State} (terminate/2 is called) +%%-------------------------------------------------------------------- +handle_call({{timeout, infinity}, wait_for_version_negotiation}, From, + #state{xf = #ssh_xfer{vsn = undefined} = Xf} = State) -> + {noreply, State#state{xf = Xf#ssh_xfer{vsn = From}}}; + +handle_call({{timeout, Timeout}, wait_for_version_negotiation}, From, + #state{xf = #ssh_xfer{vsn = undefined} = Xf} = State) -> + timer:send_after(Timeout, {timeout, undefined, From}), + {noreply, State#state{xf = Xf#ssh_xfer{vsn = From}}}; + +handle_call({_, wait_for_version_negotiation}, _, State) -> + {reply, ok, State}; + +handle_call({{timeout, infinity}, Msg}, From, State) -> + do_handle_call(Msg, From, State); +handle_call({{timeout, Timeout}, Msg}, From, #state{req_id = Id} = State) -> + timer:send_after(Timeout, {timeout, Id, From}), + do_handle_call(Msg, From, State). + +do_handle_call({open, Async,FileName,Mode}, From, #state{xf = XF} = State) -> + {Access,Flags,Attrs} = open_mode(XF#ssh_xfer.vsn, Mode), + ReqID = State#state.req_id, + ssh_xfer:open(XF, ReqID, FileName, Access, Flags, Attrs), + case Async of + true -> + {reply, {async,ReqID}, + update_request_info(ReqID, State, + fun({ok,Handle},State1) -> + open2(ReqID,FileName,Handle,Mode,Async, + From,State1); + (Rep,State1) -> + async_reply(ReqID, Rep, From, State1) + end)}; + false -> + {noreply, + update_request_info(ReqID, State, + fun({ok,Handle},State1) -> + open2(ReqID,FileName,Handle,Mode,Async, + From,State1); + (Rep,State1) -> + sync_reply(Rep, From, State1) + end)} + end; + +do_handle_call({opendir,Async,Path}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:opendir(?XF(State), ReqID, Path), + make_reply(ReqID, Async, From, State); + +do_handle_call({readdir,Async,Handle}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:readdir(?XF(State), ReqID, Handle), + make_reply(ReqID, Async, From, State); + +do_handle_call({close,_Async,Handle}, From, State) -> + %% wait until all operations on handle are done + case get_size(Handle, State) of + undefined -> + ReqID = State#state.req_id, + ssh_xfer:close(?XF(State), ReqID, Handle), + make_reply_post(ReqID, false, From, State, + fun(Rep, State1) -> + {Rep, erase_handle(Handle, State1)} + end); + _ -> + case lseek_position(Handle, cur, State) of + {ok,_} -> + ReqID = State#state.req_id, + ssh_xfer:close(?XF(State), ReqID, Handle), + make_reply_post(ReqID, false, From, State, + fun(Rep, State1) -> + {Rep, erase_handle(Handle, State1)} + end); + Error -> + {reply, Error, State} + end + end; + +do_handle_call({pread,Async,Handle,At,Length}, From, State) -> + case lseek_position(Handle, At, State) of + {ok,Offset} -> + ReqID = State#state.req_id, + ssh_xfer:read(?XF(State),ReqID,Handle,Offset,Length), + %% To get multiple async read to work we must update the offset + %% before the operation begins + State1 = update_offset(Handle, Offset+Length, State), + make_reply_post(ReqID,Async,From,State1, + fun({ok,Data}, State2) -> + case get_mode(Handle, State2) of + binary -> {{ok,Data}, State2}; + text -> + {{ok,binary_to_list(Data)}, State2} + end; + (Rep, State2) -> + {Rep, State2} + end); + Error -> + {reply, Error, State} + end; + +do_handle_call({read,Async,Handle,Length}, From, State) -> + case lseek_position(Handle, cur, State) of + {ok,Offset} -> + ReqID = State#state.req_id, + ssh_xfer:read(?XF(State),ReqID,Handle,Offset,Length), + %% To get multiple async read to work we must update the offset + %% before the operation begins + State1 = update_offset(Handle, Offset+Length, State), + make_reply_post(ReqID,Async,From,State1, + fun({ok,Data}, State2) -> + case get_mode(Handle, State2) of + binary -> {{ok,Data}, State2}; + text -> + {{ok,binary_to_list(Data)}, State2} + end; + (Rep, State2) -> {Rep, State2} + end); + Error -> + {reply, Error, State} + end; + +do_handle_call({pwrite,Async,Handle,At,Data0}, From, State) -> + case lseek_position(Handle, At, State) of + {ok,Offset} -> + Data = if + is_binary(Data0) -> + Data0; + is_list(Data0) -> + list_to_binary(Data0) + end, + ReqID = State#state.req_id, + Size = size(Data), + ssh_xfer:write(?XF(State),ReqID,Handle,Offset,Data), + State1 = update_size(Handle, Offset+Size, State), + make_reply(ReqID, Async, From, State1); + Error -> + {reply, Error, State} + end; + +do_handle_call({write,Async,Handle,Data0}, From, State) -> + case lseek_position(Handle, cur, State) of + {ok,Offset} -> + Data = if + is_binary(Data0) -> + Data0; + is_list(Data0) -> + list_to_binary(Data0) + end, + ReqID = State#state.req_id, + Size = size(Data), + ssh_xfer:write(?XF(State),ReqID,Handle,Offset,Data), + State1 = update_offset(Handle, Offset+Size, State), + make_reply(ReqID, Async, From, State1); + Error -> + {reply, Error, State} + end; + +do_handle_call({position,Handle,At}, _From, State) -> + %% We could make this auto sync when all request to Handle is done? + case lseek_position(Handle, At, State) of + {ok,Offset} -> + {reply, {ok, Offset}, update_offset(Handle, Offset, State)}; + Error -> + {reply, Error, State} + end; + +do_handle_call({rename,Async,FromFile,ToFile}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:rename(?XF(State),ReqID,FromFile,ToFile,[overwrite]), + make_reply(ReqID, Async, From, State); + +do_handle_call({delete,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:remove(?XF(State), ReqID, Name), + make_reply(ReqID, Async, From, State); + +do_handle_call({make_dir,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:mkdir(?XF(State), ReqID, Name, + #ssh_xfer_attr{ type = directory }), + make_reply(ReqID, Async, From, State); + +do_handle_call({del_dir,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:rmdir(?XF(State), ReqID, Name), + make_reply(ReqID, Async, From, State); + +do_handle_call({real_path,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:realpath(?XF(State), ReqID, Name), + make_reply(ReqID, Async, From, State); + +do_handle_call({read_file_info,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:stat(?XF(State), ReqID, Name, all), + make_reply(ReqID, Async, From, State); + +do_handle_call({get_file_info,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:fstat(?XF(State), ReqID, Name, all), + make_reply(ReqID, Async, From, State); + +do_handle_call({read_link_info,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:lstat(?XF(State), ReqID, Name, all), + make_reply(ReqID, Async, From, State); + +do_handle_call({read_link,Async,Name}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:readlink(?XF(State), ReqID, Name), + make_reply(ReqID, Async, From, State); + +do_handle_call({make_symlink, Async, Path, TargetPath}, From, State) -> + ReqID = State#state.req_id, + ssh_xfer:symlink(?XF(State), ReqID, Path, TargetPath), + make_reply(ReqID, Async, From, State); + +do_handle_call({write_file_info,Async,Name,Info}, From, State) -> + ReqID = State#state.req_id, + A = info_to_attr(Info), + ssh_xfer:setstat(?XF(State), ReqID, Name, A), + make_reply(ReqID, Async, From, State); + +%% TODO: Do we really want this format? Function send_window +%% is not documented and seems to be used only inernaly! +%% It is backwards compatible for now. +do_handle_call(send_window, _From, State) -> + XF = State#state.xf, + [{send_window,{{win_size, Size0},{packet_size, Size1}}}] = + ssh:channel_info(XF#ssh_xfer.cm, XF#ssh_xfer.channel, [send_window]), + {reply, {ok, {Size0, Size1}}, State}; + +%% TODO: Do we really want this format? Function recv_window +%% is not documented and seems to be used only inernaly! +%% It is backwards compatible for now. +do_handle_call(recv_window, _From, State) -> + XF = State#state.xf, + [{recv_window,{{win_size, Size0},{packet_size, Size1}}}] = + ssh:channel_info(XF#ssh_xfer.cm, XF#ssh_xfer.channel, [recv_window]), + {reply, {ok, {Size0, Size1}}, State}; + +%% Backwards compatible +do_handle_call(stop, _From, State) -> + {stop, shutdown, ok, State}; + +do_handle_call(Call, _From, State) -> + {reply, {error, bad_call, Call, State}, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles channel messages +%%-------------------------------------------------------------------- +handle_ssh_msg({ssh_cm, _ConnectionManager, + {data, _ChannelId, 0, Data}}, #state{rep_buf = Data0} = + State0) -> + State = handle_reply(State0, <<Data0/binary,Data/binary>>), + {ok, State}; + +handle_ssh_msg({ssh_cm, _ConnectionManager, + {data, _ChannelId, 1, Data}}, State) -> + error_logger:format("ssh: STDERR: ~s\n", [binary_to_list(Data)]), + {ok, State}; + +handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) -> + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) -> + %% Ignore signals according to RFC 4254 section 6.9. + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, + State0) -> + State = reply_all(State0, {error, Error}), + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State0) -> + State = reply_all(State0, {error, {exit_status, Status}}), + {stop, ChannelId, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles channel messages +%%-------------------------------------------------------------------- +handle_msg({ssh_channel_up, _, _}, #state{xf = Xf} = State) -> + ssh_xfer:protocol_version_request(Xf), + {ok, State}; + +%% Version negotiation timed out +handle_msg({timeout, undefined, From}, + #state{xf = #ssh_xfer{channel = ChannelId}} = State) -> + ssh_channel:reply(From, {error, timeout}), + {stop, ChannelId, State}; + +handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) -> + case lists:keysearch(Id, 1, ReqList0) of + false -> + {ok, State}; + _ -> + ReqList = lists:keydelete(Id, 1, ReqList0), + ssh_channel:reply(From, {error, timeout}), + {ok, State#state{req_list = ReqList}} + end; + +%% Connection manager goes down +handle_msg({'DOWN', _Ref, _Type, _Process, _}, + #state{xf = #ssh_xfer{channel = ChannelId}} = State) -> + {stop, ChannelId, State}; + +%% Stopped by user +handle_msg({'EXIT', _, ssh_sftp_stop_channel}, + #state{xf = #ssh_xfer{channel = ChannelId}} = State) -> + {stop, ChannelId, State}; + +handle_msg(_, State) -> + {ok, State}. +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: Called when the channel process is terminated +%%-------------------------------------------------------------------- +%% Backwards compatible +terminate(shutdown, #state{xf = #ssh_xfer{cm = Cm}} = State) -> + reply_all(State, {error, closed}), + ssh:close(Cm); + +terminate(_Reason, State) -> + reply_all(State, {error, closed}). + +%%==================================================================== +%% Internal functions +%%==================================================================== +call(Pid, Msg, TimeOut) -> + ssh_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity). + +handle_reply(State, <<?UINT32(Len),Reply:Len/binary,Rest/binary>>) -> + do_handle_reply(State, Reply, Rest); +handle_reply(State, Data) -> + State#state{rep_buf = Data}. + +do_handle_reply(#state{xf = Xf} = State, + <<?SSH_FXP_VERSION, ?UINT32(Version), BinExt/binary>>, Rest) -> + Ext = ssh_xfer:decode_ext(BinExt), + case Xf#ssh_xfer.vsn of + undefined -> + ok; + From -> + ssh_channel:reply(From, ok) + end, + State#state{xf = Xf#ssh_xfer{vsn = Version, ext = Ext}, rep_buf = Rest}; + +do_handle_reply(State0, Data, Rest) -> + case catch ssh_xfer:xf_reply(?XF(State0), Data) of + {'EXIT', _Reason} -> + handle_reply(State0, Rest); + XfReply -> + State = handle_req_reply(State0, XfReply), + handle_reply(State, Rest) + end. + +handle_req_reply(State0, {_, ReqID, _} = XfReply) -> + case lists:keysearch(ReqID, 1, State0#state.req_list) of + false -> + State0; + {value,{_,Fun}} -> + List = lists:keydelete(ReqID, 1, State0#state.req_list), + State1 = State0#state { req_list = List }, + case catch Fun(xreply(XfReply),State1) of + {'EXIT', _} -> + State1; + State -> + State + end + end. + +xreply({handle,_,H}) -> {ok, H}; +xreply({data,_,Data}) -> {ok, Data}; +xreply({name,_,Names}) -> {ok, Names}; +xreply({attrs, _, A}) -> {ok, attr_to_info(A)}; +xreply({extended_reply,_,X}) -> {ok, X}; +xreply({status,_,{ok, _Err, _Lang, _Rep}}) -> ok; +xreply({status,_,{eof, _Err, _Lang, _Rep}}) -> eof; +xreply({status,_,{Stat, _Err, _Lang, _Rep}}) -> {error, Stat}; +xreply({Code, _, Reply}) -> {Code, Reply}. + +update_request_info(ReqID, State, Fun) -> + List = [{ReqID,Fun} | State#state.req_list], + ID = (State#state.req_id + 1) band 16#ffffffff, + State#state { req_list = List, req_id = ID }. + +async_reply(ReqID, Reply, _From={To,_}, State) -> + To ! {async_reply, ReqID, Reply}, + State. + +sync_reply(Reply, From, State) -> + catch (ssh_channel:reply(From, Reply)), + State. + +open2(OrigReqID,FileName,Handle,Mode,Async,From,State) -> + I0 = State#state.inf, + FileMode = case lists:member(binary, Mode) orelse lists:member(raw, Mode) of + true -> binary; + false -> text + end, + I1 = add_new_handle(Handle, FileMode, I0), + State0 = State#state{inf = I1}, + ReqID = State0#state.req_id, + ssh_xfer:stat(State0#state.xf, ReqID, FileName, [size]), + case Async of + true -> + update_request_info(ReqID, State0, + fun({ok,FI},State1) -> + Size = FI#file_info.size, + State2 = if is_integer(Size) -> + put_size(Handle, Size, State1); + true -> + State1 + end, + async_reply(OrigReqID, {ok,Handle}, From, State2); + (_, State1) -> + async_reply(OrigReqID, {ok,Handle}, From, State1) + end); + false -> + update_request_info(ReqID, State0, + fun({ok,FI},State1) -> + Size = FI#file_info.size, + State2 = if is_integer(Size) -> + put_size(Handle, Size, State1); + true -> + State1 + end, + sync_reply({ok,Handle}, From, State2); + (_, State1) -> + sync_reply({ok,Handle}, From, State1) + end) + end. + +reply_all(State, Reply) -> + List = State#state.req_list, + lists:foreach(fun({_ReqID,Fun}) -> + catch Fun(Reply,State) + end, List), + State#state {req_list = []}. + +make_reply(ReqID, true, From, State) -> + {reply, {async, ReqID}, + update_request_info(ReqID, State, + fun(Reply,State1) -> + async_reply(ReqID,Reply,From,State1) + end)}; + +make_reply(ReqID, false, From, State) -> + {noreply, + update_request_info(ReqID, State, + fun(Reply,State1) -> + sync_reply(Reply, From, State1) + end)}. + +make_reply_post(ReqID, true, From, State, PostFun) -> + {reply, {async, ReqID}, + update_request_info(ReqID, State, + fun(Reply,State1) -> + case catch PostFun(Reply, State1) of + {'EXIT',_} -> + async_reply(ReqID,Reply, From, State1); + {Reply1, State2} -> + async_reply(ReqID,Reply1, From, State2) + end + end)}; + +make_reply_post(ReqID, false, From, State, PostFun) -> + {noreply, + update_request_info(ReqID, State, + fun(Reply,State1) -> + case catch PostFun(Reply, State1) of + {'EXIT',_} -> + sync_reply(Reply, From, State1); + {Reply1, State2} -> + sync_reply(Reply1, From, State2) + end + end)}. + +%% convert: file_info -> ssh_xfer_attr +info_to_attr(I) when is_record(I, file_info) -> + #ssh_xfer_attr { permissions = I#file_info.mode, + size = I#file_info.size, + type = I#file_info.type, + owner = I#file_info.uid, + group = I#file_info.gid, + atime = datetime_to_unix(I#file_info.atime), + mtime = datetime_to_unix(I#file_info.mtime), + createtime = datetime_to_unix(I#file_info.ctime)}. + +%% convert: ssh_xfer_attr -> file_info +attr_to_info(A) when is_record(A, ssh_xfer_attr) -> + #file_info{ + size = A#ssh_xfer_attr.size, + type = A#ssh_xfer_attr.type, + access = read_write, %% FIXME: read/write/read_write/none + atime = unix_to_datetime(A#ssh_xfer_attr.atime), + mtime = unix_to_datetime(A#ssh_xfer_attr.mtime), + ctime = unix_to_datetime(A#ssh_xfer_attr.createtime), + mode = A#ssh_xfer_attr.permissions, + links = 1, + major_device = 0, + minor_device = 0, + inode = 0, + uid = A#ssh_xfer_attr.owner, + gid = A#ssh_xfer_attr.group}. + + +%% Added workaround for sftp timestam problem. (Timestamps should be +%% in UTC but they where not) . The workaround uses a deprecated +%% function i calandar. This will work as expected most of the time +%% but has problems for the same reason as +%% calendar:local_time_to_universal_time/1. We consider it better that +%% the timestamps work as expected most of the time instead of none of +%% the time. Hopfully the file-api will be updated so that we can +%% solve this problem in a better way in the future. + +unix_to_datetime(undefined) -> + undefined; +unix_to_datetime(UTCSecs) -> + UTCDateTime = + calendar:gregorian_seconds_to_datetime(UTCSecs + 62167219200), + erlang:universaltime_to_localtime(UTCDateTime). + +datetime_to_unix(undefined) -> + undefined; +datetime_to_unix(LocalDateTime) -> + UTCDateTime = erlang:localtime_to_universaltime(LocalDateTime), + calendar:datetime_to_gregorian_seconds(UTCDateTime) - 62167219200. + + +open_mode(Vsn,Modes) when Vsn >= 5 -> + open_mode5(Modes); +open_mode(_Vsn, Modes) -> + open_mode3(Modes). + +open_mode5(Modes) -> + A = #ssh_xfer_attr{type = regular}, + {Fl, Ac} = case {lists:member(write, Modes), + lists:member(read, Modes), + lists:member(append, Modes)} of + {_, _, true} -> + {[append_data], + [read_attributes, + append_data, write_attributes]}; + {true, false, false} -> + {[create_truncate], + [write_data, write_attributes]}; + {true, true, _} -> + {[open_or_create], + [read_data, read_attributes, + write_data, write_attributes]}; + {false, true, _} -> + {[open_existing], + [read_data, read_attributes]} + end, + {Ac, Fl, A}. + +open_mode3(Modes) -> + A = #ssh_xfer_attr{type = regular}, + Fl = case {lists:member(write, Modes), + lists:member(read, Modes), + lists:member(append, Modes)} of + {_, _, true} -> + [append]; + {true, false, false} -> + [write, creat, trunc]; + {true, true, _} -> + [read, write]; + {false, true, _} -> + [read] + end, + {[], Fl, A}. + +%% accessors for inf dict +new_inf() -> dict:new(). + +add_new_handle(Handle, FileMode, Inf) -> + dict:store(Handle, #fileinf{offset=0, size=0, mode=FileMode}, Inf). + +update_size(Handle, NewSize, State) -> + OldSize = get_size(Handle, State), + if NewSize > OldSize -> + put_size(Handle, NewSize, State); + true -> + State + end. + +%% set_offset(Handle, NewOffset) -> +%% put({offset,Handle}, NewOffset). + +update_offset(Handle, NewOffset, State0) -> + State1 = put_offset(Handle, NewOffset, State0), + update_size(Handle, NewOffset, State1). + +%% access size and offset for handle +put_size(Handle, Size, State) -> + Inf0 = State#state.inf, + case dict:find(Handle, Inf0) of + {ok, FI} -> + State#state{inf=dict:store(Handle, FI#fileinf{size=Size}, Inf0)}; + _ -> + State#state{inf=dict:store(Handle, #fileinf{size=Size,offset=0}, + Inf0)} + end. + +put_offset(Handle, Offset, State) -> + Inf0 = State#state.inf, + case dict:find(Handle, Inf0) of + {ok, FI} -> + State#state{inf=dict:store(Handle, FI#fileinf{offset=Offset}, + Inf0)}; + _ -> + State#state{inf=dict:store(Handle, #fileinf{size=Offset, + offset=Offset}, Inf0)} + end. + +get_size(Handle, State) -> + case dict:find(Handle, State#state.inf) of + {ok, FI} -> + FI#fileinf.size; + _ -> + undefined + end. + +%% get_offset(Handle, State) -> +%% {ok, FI} = dict:find(Handle, State#state.inf), +%% FI#fileinf.offset. + +get_mode(Handle, State) -> + case dict:find(Handle, State#state.inf) of + {ok, FI} -> + FI#fileinf.mode; + _ -> + undefined + end. + +erase_handle(Handle, State) -> + FI = dict:erase(Handle, State#state.inf), + State#state{inf = FI}. + +%% +%% Caluclate a integer offset +%% +lseek_position(Handle, Pos, State) -> + case dict:find(Handle, State#state.inf) of + {ok, #fileinf{offset=O, size=S}} -> + lseek_pos(Pos, O, S); + _ -> + {error, einval} + end. + +lseek_pos(_Pos, undefined, _) -> + {error, einval}; +lseek_pos(Pos, _CurOffset, _CurSize) + when is_integer(Pos) andalso 0 =< Pos andalso Pos < ?SSH_FILEXFER_LARGEFILESIZE -> + {ok,Pos}; +lseek_pos(bof, _CurOffset, _CurSize) -> + {ok,0}; +lseek_pos(cur, CurOffset, _CurSize) -> + {ok,CurOffset}; +lseek_pos(eof, _CurOffset, CurSize) -> + {ok,CurSize}; +lseek_pos({bof, Offset}, _CurOffset, _CurSize) + when is_integer(Offset) andalso 0 =< Offset andalso Offset < ?SSH_FILEXFER_LARGEFILESIZE -> + {ok, Offset}; +lseek_pos({cur, Offset}, CurOffset, _CurSize) + when is_integer(Offset) andalso -(?SSH_FILEXFER_LARGEFILESIZE) =< Offset andalso + Offset < ?SSH_FILEXFER_LARGEFILESIZE -> + NewOffset = CurOffset + Offset, + if NewOffset < 0 -> + {ok, 0}; + true -> + {ok, NewOffset} + end; +lseek_pos({eof, Offset}, _CurOffset, CurSize) + when is_integer(Offset) andalso -(?SSH_FILEXFER_LARGEFILESIZE) =< Offset andalso + Offset < ?SSH_FILEXFER_LARGEFILESIZE -> + NewOffset = CurSize + Offset, + if NewOffset < 0 -> + {ok, 0}; + true -> + {ok, NewOffset} + end; +lseek_pos(_, _, _) -> + {error, einval}. + + +%%%%%% Deprecated %%%% +connect(Cm) when is_pid(Cm) -> + connect(Cm, []); +connect(Host) when is_list(Host) -> + connect(Host, []). +connect(Cm, Opts) when is_pid(Cm) -> + Timeout = proplists:get_value(timeout, Opts, infinity), + case ssh_xfer:attach(Cm, []) of + {ok, ChannelId, Cm} -> + ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm, ChannelId, + Timeout]); + Error -> + Error + end; +connect(Host, Opts) -> + connect(Host, 22, Opts). +connect(Host, Port, Opts) -> + Timeout = proplists:get_value(timeout, Opts, infinity), + case ssh_xfer:connect(Host, Port, proplists:delete(timeout, Opts)) of + {ok, ChannelId, Cm} -> + ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm, + ChannelId, Timeout]); + Error -> + Error + end. + + +stop(Pid) -> + call(Pid, stop, infinity). + diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl new file mode 100644 index 0000000000..10b8ede1e4 --- /dev/null +++ b/lib/ssh/src/ssh_sftpd.erl @@ -0,0 +1,932 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SFTP server daemon + +-module(ssh_sftpd). + +%%-behaviour(gen_server). +-behaviour(ssh_channel). + +-include_lib("kernel/include/file.hrl"). + +-include("ssh.hrl"). +-include("ssh_xfer.hrl"). + +%%-------------------------------------------------------------------- +%% External exports +-export([subsystem_spec/1, + listen/1, listen/2, listen/3, stop/1]). + +-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2, code_change/3]). + +-record(state, { + xf, % [{channel,ssh_xfer states}...] + cwd, % current dir (on first connect) + root, % root dir + remote_channel, % remote channel + pending, % binary() + file_handler, % atom() - callback module + file_state, % state for the file callback module + max_files, % integer >= 0 max no files sent during READDIR + handles % list of open handles + %% handle is either {<int>, directory, {Path, unread|eof}} or + %% {<int>, file, {Path, IoDevice}} + }). + +%%==================================================================== +%% API +%%==================================================================== +subsystem_spec(Options) -> + {"sftp", {?MODULE, Options}}. + +%%% DEPRECATED START %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%-------------------------------------------------------------------- +%% Function: listen() -> Pid | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +listen(Port) -> + listen(any, Port, []). +listen(Port, Options) -> + listen(any, Port, Options). +listen(Addr, Port, Options) -> + SubSystems = [subsystem_spec(Options)], + ssh:daemon(Addr, Port, [{subsystems, SubSystems} |Options]). + +%%-------------------------------------------------------------------- +%% Function: stop(Pid) -> ok +%% Description: Stops the listener +%%-------------------------------------------------------------------- +stop(Pid) -> + ssh_cli:stop(Pid). + + +%%% DEPRECATED END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%==================================================================== +%% subsystem callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init(Options) -> + {FileMod, FS0} = case proplists:get_value(file_handler, Options, + {ssh_sftpd_file,[]}) of + {F, S} -> + {F, S}; + F -> + {F, []} + end, + + {{ok, Default}, FS1} = FileMod:get_cwd(FS0), + CWD = proplists:get_value(cwd, Options, Default), + + Root0 = proplists:get_value(root, Options, ""), + + %% Get the root of the file system (symlinks must be followed, + %% otherwise the realpath call won't work). But since symbolic links + %% isn't supported on all plattforms we have to use the root property + %% supplied by the user. + {Root, State} = + case resolve_symlinks(Root0, + #state{root = Root0, + file_handler = FileMod, + file_state = FS1}) of + {{ok, Root1}, State0} -> + {Root1, State0}; + {{error, _}, State0} -> + {Root0, State0} + end, + MaxLength = proplists:get_value(max_files, Options, 0), + + Vsn = proplists:get_value(vsn, Options, 5), + + {ok, State#state{cwd = CWD, root = Root, max_files = MaxLength, + handles = [], pending = <<>>, + xf = #ssh_xfer{vsn = Vsn, ext = []}}}. + + +%%-------------------------------------------------------------------- +%% Function: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: +%%-------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles channel messages +%%-------------------------------------------------------------------- +handle_ssh_msg({ssh_cm, _ConnectionManager, + {data, _ChannelId, Type, Data}}, State) -> + State1 = handle_data(Type, Data, State), + {ok, State1}; + +handle_ssh_msg({ssh_cm, _, {eof, ChannelId}}, State) -> + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) -> + %% Ignore signals according to RFC 4254 section 6.9. + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, State) -> + Report = io_lib:format("Connection closed by peer ~n Error ~p~n", + [Error]), + error_logger:error_report(Report), + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, 0}}, State) -> + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State) -> + + Report = io_lib:format("Connection closed by peer ~n Status ~p~n", + [Status]), + error_logger:error_report(Report), + {stop, ChannelId, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles other messages +%%-------------------------------------------------------------------- +handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, + #state{xf =Xf} = State) -> + {ok, State#state{xf = Xf#ssh_xfer{cm = ConnectionManager, + channel = ChannelId}}}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(_, #state{handles=Handles, file_handler=FileMod, file_state=FS}) -> + CloseFun = fun({_, file, {_, Fd}}, FS0) -> + {_Res, FS1} = FileMod:close(Fd, FS0), + FS1; + (_, FS0) -> + FS0 + end, + lists:foldl(CloseFun, FS, Handles), + ok. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +handle_data(0, <<?UINT32(Len), Msg:Len/binary, Rest/binary>>, + State = #state{pending = <<>>}) -> + <<Op, ?UINT32(ReqId), Data/binary>> = Msg, + NewState = handle_op(Op, ReqId, Data, State), + case Rest of + <<>> -> + NewState; + _ -> + handle_data(0, Rest, NewState) + end; + +handle_data(0, Data, State = #state{pending = <<>>}) -> + State#state{pending = Data}; + +handle_data(Type, Data, State = #state{pending = Pending}) -> + handle_data(Type, <<Pending/binary, Data/binary>>, + State#state{pending = <<>>}). + +handle_op(?SSH_FXP_INIT, Version, B, State) when is_binary(B) -> + XF = State#state.xf, + Vsn = lists:min([XF#ssh_xfer.vsn, Version]), + XF1 = XF#ssh_xfer{vsn = Vsn}, + ssh_xfer:xf_send_reply(XF1, ?SSH_FXP_VERSION, <<?UINT32(Vsn)>>), + State#state{xf = XF1}; +handle_op(?SSH_FXP_REALPATH, ReqId, + <<?UINT32(Rlen), RPath:Rlen/binary>>, + State0) -> + RelPath0 = binary_to_list(RPath), + RelPath = relate_file_name(RelPath0, State0, _Canonicalize=false), + {Res, State} = resolve_symlinks(RelPath, State0), + case Res of + {ok, AbsPath} -> + NewAbsPath = chroot_filename(AbsPath, State), + ?dbg(true, "handle_op ?SSH_FXP_REALPATH: RelPath=~p AbsPath=~p\n", + [RelPath, NewAbsPath]), + XF = State#state.xf, + Attr = #ssh_xfer_attr{type=directory}, + ssh_xfer:xf_send_name(XF, ReqId, NewAbsPath, Attr), + State; + {error, _} = Error -> + send_status(Error, ReqId, State) + end; +handle_op(?SSH_FXP_OPENDIR, ReqId, + <<?UINT32(RLen), RPath:RLen/binary>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + RelPath = binary_to_list(RPath), + AbsPath = relate_file_name(RelPath, State0), + + XF = State0#state.xf, + {IsDir, FS1} = FileMod:is_dir(AbsPath, FS0), + State1 = State0#state{file_state = FS1}, + case IsDir of + false -> + ssh_xfer:xf_send_status(XF, ReqId, ?SSH_FX_NOT_A_DIRECTORY, + "Not a directory"), + State1; + true -> + add_handle(State1, XF, ReqId, directory, {RelPath,unread}) + end; +handle_op(?SSH_FXP_READDIR, ReqId, + <<?UINT32(HLen), BinHandle:HLen/binary>>, + State) -> + XF = State#state.xf, + case get_handle(State#state.handles, BinHandle) of + {_Handle, directory, {_RelPath, eof}} -> + ssh_xfer:xf_send_status(XF, ReqId, ?SSH_FX_EOF), + State; + {Handle, directory, {RelPath, Status}} -> + read_dir(State, XF, ReqId, Handle, RelPath, Status); + _ -> + ssh_xfer:xf_send_status(XF, ReqId, ?SSH_FX_INVALID_HANDLE), + State + end; +handle_op(?SSH_FXP_CLOSE, ReqId, + <<?UINT32(HLen), BinHandle:HLen/binary>>, + State = #state{handles = Handles, xf = XF, + file_handler = FileMod, file_state = FS0}) -> + case get_handle(Handles, BinHandle) of + {Handle, Type, T} -> + FS1 = case Type of + file -> + close_our_file(T, FileMod, FS0); + _ -> + FS0 + end, + ssh_xfer:xf_send_status(XF, ReqId, ?SSH_FX_OK), + State#state{handles = lists:keydelete(Handle, 1, Handles), + file_state = FS1}; + _ -> + ssh_xfer:xf_send_status(XF, ReqId, ?SSH_FX_INVALID_HANDLE), + State + end; +handle_op(?SSH_FXP_LSTAT, ReqId, Data, State) -> + stat((State#state.xf)#ssh_xfer.vsn, ReqId, Data, State, read_link_info); +handle_op(?SSH_FXP_STAT, ReqId, Data, State) -> + stat((State#state.xf)#ssh_xfer.vsn, ReqId, Data, State, read_file_info); +handle_op(?SSH_FXP_FSTAT, ReqId, Data, State) -> + fstat((State#state.xf)#ssh_xfer.vsn, ReqId, Data, State); +handle_op(?SSH_FXP_OPEN, ReqId, Data, State) -> + open((State#state.xf)#ssh_xfer.vsn, ReqId, Data, State); +handle_op(?SSH_FXP_READ, ReqId, <<?UINT32(HLen), BinHandle:HLen/binary, + ?UINT64(Offset), ?UINT32(Len)>>, + State) -> + case get_handle(State#state.handles, BinHandle) of + {_Handle, file, {_Path, IoDevice}} -> + read_file(ReqId, IoDevice, Offset, Len, State); + _ -> + ssh_xfer:xf_send_status(State#state.xf, ReqId, + ?SSH_FX_INVALID_HANDLE), + State + end; +handle_op(?SSH_FXP_WRITE, ReqId, + <<?UINT32(HLen), BinHandle:HLen/binary, ?UINT64(Offset), + ?UINT32(Len), Data:Len/binary>>, State) -> + case get_handle(State#state.handles, BinHandle) of + {_Handle, file, {_Path, IoDevice}} -> + write_file(ReqId, IoDevice, Offset, Data, State); + _ -> + ssh_xfer:xf_send_status(State#state.xf, ReqId, + ?SSH_FX_INVALID_HANDLE), + State + end; +handle_op(?SSH_FXP_READLINK, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, + State = #state{file_handler = FileMod, file_state = FS0}) -> + RelPath = binary_to_list(BPath), + AbsPath = relate_file_name(RelPath, State), + {Res, FS1} = FileMod:read_link(AbsPath, FS0), + case Res of + {ok, NewPath} -> + ssh_xfer:xf_send_name(State#state.xf, ReqId, NewPath, + #ssh_xfer_attr{type=regular}); + {error, Error} -> + ssh_xfer:xf_send_status(State#state.xf, ReqId, + ssh_xfer:encode_erlang_status(Error)) + end, + State#state{file_state = FS1}; +handle_op(?SSH_FXP_SETSTAT, ReqId, <<?UINT32(PLen), BPath:PLen/binary, + Attr/binary>>, State0) -> + Path = relate_file_name(BPath, State0), + {Status, State1} = set_stat(Attr, Path, State0), + send_status(Status, ReqId, State1); +handle_op(?SSH_FXP_MKDIR, ReqId, <<?UINT32(PLen), BPath:PLen/binary, + Attr/binary>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + Path = relate_file_name(BPath, State0), + {Res, FS1} = FileMod:make_dir(Path, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + ok -> + {_, State2} = set_stat(Attr, Path, State1), + send_status(ok, ReqId, State2); + {error, Error} -> + send_status({error, Error}, ReqId, State1) + end; +handle_op(?SSH_FXP_FSETSTAT, ReqId, <<?UINT32(HLen), BinHandle:HLen/binary, + Attr/binary>>, + State0 = #state{handles = Handles}) -> + + case get_handle(Handles, BinHandle) of + {_Handle, _Type, {Path,_}} -> + {Status, State1} = set_stat(Attr, Path, State0), + send_status(Status, ReqId, State1); + _ -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_INVALID_HANDLE), + State0 + end; +handle_op(?SSH_FXP_REMOVE, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + Path = relate_file_name(BPath, State0), + %% case FileMod:is_dir(Path) of %% This version 6 we still have ver 5 + %% true -> + %% ssh_xfer:xf_send_status(State#state.xf, ReqId, + %% ?SSH_FX_FILE_IS_A_DIRECTORY); + %% false -> + {Status, FS1} = FileMod:delete(Path, FS0), + State1 = State0#state{file_state = FS1}, + send_status(Status, ReqId, State1); + %%end; +handle_op(?SSH_FXP_RMDIR, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + Path = relate_file_name(BPath, State0), + {Status, FS1} = FileMod:del_dir(Path, FS0), + State1 = State0#state{file_state = FS1}, + send_status(Status, ReqId, State1); + +handle_op(?SSH_FXP_RENAME, ReqId, + Bin = <<?UINT32(PLen), _:PLen/binary, ?UINT32(PLen2), + _:PLen2/binary>>, + State = #state{xf = #ssh_xfer{vsn = Vsn}}) when Vsn==3; Vsn==4 -> + handle_op(?SSH_FXP_RENAME, ReqId, <<Bin/binary, 0:32>>, State); + +handle_op(?SSH_FXP_RENAME, ReqId, + <<?UINT32(PLen), BPath:PLen/binary, ?UINT32(PLen2), + BPath2:PLen2/binary, ?UINT32(Flags)>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + Path = relate_file_name(BPath, State0), + Path2 = relate_file_name(BPath2, State0), + case Flags band ?SSH_FXP_RENAME_ATOMIC of + 0 -> + case Flags band ?SSH_FXP_RENAME_OVERWRITE of + 0 -> + {Res, FS1} = FileMod:read_link_info(Path2, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + {ok, _Info} -> + ssh_xfer:xf_send_status( + State1#state.xf, + ReqId, + ?SSH_FX_FILE_ALREADY_EXISTS), + State1; + _ -> + rename(Path, Path2, ReqId, State1) + end; + _ -> + rename(Path, Path2, ReqId, State0) + end; + _ -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_OP_UNSUPPORTED), + State0 + end; +handle_op(?SSH_FXP_SYMLINK, ReqId, + <<?UINT32(PLen), BPath:PLen/binary, ?UINT32(PLen2), + BPath2:PLen2/binary>>, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + Path = relate_file_name(BPath, State0), + Path2 = relate_file_name(BPath2, State0), + {Status, FS1} = FileMod:make_symlink(Path2, Path, FS0), + State1 = State0#state{file_state = FS1}, + send_status(Status, ReqId, State1). + +new_handle([], H) -> + H; +new_handle([{N, _} | Rest], H) when N > H -> + new_handle(Rest, N+1); +new_handle([_ | Rest], H) -> + new_handle(Rest, H). + +add_handle(State, XF, ReqId, Type, DirFileTuple) -> + Handles = State#state.handles, + Handle = new_handle(Handles, 0), + ssh_xfer:xf_send_handle(XF, ReqId, integer_to_list(Handle)), + State#state{handles = [{Handle, Type, DirFileTuple} | Handles]}. + +get_handle(Handles, BinHandle) -> + case (catch list_to_integer(binary_to_list(BinHandle))) of + I when is_integer(I) -> + case lists:keysearch(I, 1, Handles) of + {value, T} -> T; + false -> error + end; + _ -> + error + end. + +%%% read_dir/5: read directory, send names, and return new state +read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0}, + XF, ReqId, Handle, RelPath, {cache, Files}) -> + AbsPath = relate_file_name(RelPath, State0), + ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]), + if + length(Files) > MaxLength -> + {ToSend, NewCache} = lists:split(MaxLength, Files), + {NamesAndAttrs, FS1} = get_attrs(AbsPath, ToSend, FileMod, FS0), + ssh_xfer:xf_send_names(XF, ReqId, NamesAndAttrs), + Handles = lists:keyreplace(Handle, 1, + State0#state.handles, + {Handle, directory, {RelPath,{cache, NewCache}}}), + State0#state{handles = Handles, file_state = FS1}; + true -> + {NamesAndAttrs, FS1} = get_attrs(AbsPath, Files, FileMod, FS0), + ssh_xfer:xf_send_names(XF, ReqId, NamesAndAttrs), + Handles = lists:keyreplace(Handle, 1, + State0#state.handles, + {Handle, directory, {RelPath,eof}}), + State0#state{handles = Handles, file_state = FS1} + end; +read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0}, + XF, ReqId, Handle, RelPath, _Status) -> + AbsPath = relate_file_name(RelPath, State0), + ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]), + {Res, FS1} = FileMod:list_dir(AbsPath, FS0), + case Res of + {ok, Files} when MaxLength == 0 orelse MaxLength > length(Files) -> + {NamesAndAttrs, FS2} = get_attrs(AbsPath, Files, FileMod, FS1), + ssh_xfer:xf_send_names(XF, ReqId, NamesAndAttrs), + Handles = lists:keyreplace(Handle, 1, + State0#state.handles, + {Handle, directory, {RelPath,eof}}), + State0#state{handles = Handles, file_state = FS2}; + {ok, Files} -> + {ToSend, Cache} = lists:split(MaxLength, Files), + {NamesAndAttrs, FS2} = get_attrs(AbsPath, ToSend, FileMod, FS1), + ssh_xfer:xf_send_names(XF, ReqId, NamesAndAttrs), + Handles = lists:keyreplace(Handle, 1, + State0#state.handles, + {Handle, directory, {RelPath,{cache, Cache}}}), + State0#state{handles = Handles, file_state = FS2}; + {error, Error} -> + State1 = State0#state{file_state = FS1}, + send_status({error, Error}, ReqId, State1) + end. + + +%%% get_attrs: get stat of each file and return +get_attrs(RelPath, Files, FileMod, FS) -> + get_attrs(RelPath, Files, FileMod, FS, []). + +get_attrs(_RelPath, [], _FileMod, FS, Acc) -> + {lists:reverse(Acc), FS}; +get_attrs(RelPath, [F | Rest], FileMod, FS0, Acc) -> + Path = filename:absname(F, RelPath), + ?dbg(true, "get_attrs fun: F=~p\n", [F]), + case FileMod:read_link_info(Path, FS0) of + {{ok, Info}, FS1} -> + Attrs = ssh_sftp:info_to_attr(Info), + get_attrs(RelPath, Rest, FileMod, FS1, [{F, Attrs} | Acc]); + {{error, enoent}, FS1} -> + get_attrs(RelPath, Rest, FileMod, FS1, Acc); + {Error, FS1} -> + {Error, FS1} + end. + +close_our_file({_,Fd}, FileMod, FS0) -> + {_Res, FS1} = FileMod:close(Fd, FS0), + FS1. + +%%% stat: do the stat +stat(Vsn, ReqId, Data, State, F) when Vsn =< 3-> + <<?UINT32(BLen), BPath:BLen/binary>> = Data, + stat(ReqId, binary_to_list(BPath), State, F); +stat(Vsn, ReqId, Data, State, F) when Vsn >= 4-> + <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(_Flags)>> = Data, + stat(ReqId, binary_to_list(BPath), State, F). + +fstat(Vsn, ReqId, Data, State) when Vsn =< 3-> + <<?UINT32(HLen), Handle:HLen/binary>> = Data, + fstat(ReqId, Handle, State); +fstat(Vsn, ReqId, Data, State) when Vsn >= 4-> + <<?UINT32(HLen), Handle:HLen/binary, ?UINT32(_Flags)>> = Data, + fstat(ReqId, Handle, State). + +fstat(ReqId, BinHandle, State) -> + case get_handle(State#state.handles, BinHandle) of + {_Handle, _Type, {Path, _}} -> + stat(ReqId, Path, State, read_file_info); + _ -> + ssh_xfer:xf_send_status(State#state.xf, ReqId, + ?SSH_FX_INVALID_HANDLE), + State + end. + +stat(ReqId, RelPath, State0=#state{file_handler=FileMod, + file_state=FS0}, F) -> + AbsPath = relate_file_name(RelPath, State0), + XF = State0#state.xf, + ?dbg(false, "stat: AbsPath=~p\n", [AbsPath]), + {Res, FS1} = FileMod:F(AbsPath, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + {ok, FileInfo} -> + ssh_xfer:xf_send_attr(XF, ReqId, + ssh_sftp:info_to_attr(FileInfo)), + State1; + {error, E} -> + send_status({error, E}, ReqId, State1) + end. + +decode_4_open_flag(create_new) -> + [write]; +decode_4_open_flag(create_truncate) -> + [write]; +decode_4_open_flag(truncate_existing) -> + [write]; +decode_4_open_flag(open_existing) -> + [read]. + +decode_4_flags([OpenFlag | Flags]) -> + decode_4_flags(Flags, decode_4_open_flag(OpenFlag)). + +decode_4_flags([], Flags) -> + Flags; +decode_4_flags([append_data|R], _Flags) -> + decode_4_flags(R, [append]); +decode_4_flags([append_data_atomic|R], _Flags) -> + decode_4_flags(R, [append]); +decode_4_flags([_|R], Flags) -> + decode_4_flags(R, Flags). + +decode_4_access_flag(read_data) -> + [read]; +decode_4_access_flag(list_directory) -> + [read]; +decode_4_access_flag(write_data) -> + [write]; +decode_4_access_flag(add_file) -> + [write]; +decode_4_access_flag(add_subdirectory) -> + [read]; +decode_4_access_flag(append_data) -> + [append]; +decode_4_access_flag(_) -> + [read]. + +decode_4_acess([_ | _] = Flags) -> + lists:map(fun(Flag) -> + [decode_4_access_flag(Flag)] + end, Flags); +decode_4_acess([]) -> + []. + +open(Vsn, ReqId, Data, State) when Vsn =< 3 -> + <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(PFlags), + _Attrs/binary>> = Data, + Path = binary_to_list(BPath), + Flags = ssh_xfer:decode_open_flags(Vsn, PFlags) -- [creat, excl, trunc], + ?dbg(true, "open: Flags=~p\n", [Flags]), + do_open(ReqId, State, Path, Flags); +open(Vsn, ReqId, Data, State) when Vsn >= 4 -> + <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(Access), + ?UINT32(PFlags), _Attrs/binary>> = Data, + Path = binary_to_list(BPath), + FlagBits = ssh_xfer:decode_open_flags(Vsn, PFlags), + AcessBits = ssh_xfer:decode_ace_mask(Access), + ?dbg(true, "open: Fl=~p\n", [FlagBits]), + %% TODO: This is to make sure the Access flags are not ignored + %% but this should be thought through better. This solution should + %% be considered a hack in order to buy some time. At least + %% it works better than when the Access flags where totally ignored. + %% A better solution may need some code refactoring that we do + %% not have time for right now. + AcessFlags = decode_4_acess(AcessBits), + Flags = lists:append(lists:umerge( + [[decode_4_flags(FlagBits)] | AcessFlags])), + + ?dbg(true, "open: Flags=~p\n", [Flags]), + + do_open(ReqId, State, Path, Flags). + +do_open(ReqId, State0, Path, Flags) -> + #state{file_handler = FileMod, file_state = FS0, root = Root} = State0, + XF = State0#state.xf, + F = [raw, binary | Flags], + %% case FileMod:is_dir(Path) of %% This is version 6 we still have 5 + %% true -> + %% ssh_xfer:xf_send_status(State#state.xf, ReqId, + %% ?SSH_FX_FILE_IS_A_DIRECTORY); + %% false -> + + AbsPath = case Root of + "" -> + Path; + _ -> + relate_file_name(Path, State0) + end, + + {Res, FS1} = FileMod:open(AbsPath, F, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + {ok, IoDevice} -> + add_handle(State1, XF, ReqId, file, {Path,IoDevice}); + {error, Error} -> + ssh_xfer:xf_send_status(State1#state.xf, ReqId, + ssh_xfer:encode_erlang_status(Error)), + State1 + end. + +%% resolve all symlinks in a path +resolve_symlinks(Path, State) -> + resolve_symlinks(Path, _LinkCnt=32, State). + +resolve_symlinks(Path, LinkCnt, State0) -> + resolve_symlinks_2(filename:split(Path), State0, LinkCnt, []). + +resolve_symlinks_2(_Path, State, LinkCnt, _AccPath) when LinkCnt =:= 0 -> + %% Too many links (there might be a symlink loop) + {{error, emlink}, State}; +resolve_symlinks_2(["." | RestPath], State0, LinkCnt, AccPath) -> + resolve_symlinks_2(RestPath, State0, LinkCnt, AccPath); +resolve_symlinks_2([".." | RestPath], State0, LinkCnt, AccPath) -> + %% Remove the last path component + AccPathComps0 = filename:split(AccPath), + Path = case lists:reverse(tl(lists:reverse(AccPathComps0))) of + [] -> + ""; + AccPathComps -> + filename:join(AccPathComps) + end, + resolve_symlinks_2(RestPath, State0, LinkCnt, Path); +resolve_symlinks_2([PathComp | RestPath], State0, LinkCnt, AccPath0) -> + #state{file_handler = FileMod, file_state = FS0} = State0, + AccPath1 = filename:join(AccPath0, PathComp), + {Res, FS1} = FileMod:read_link(AccPath1, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + {ok, Target0} -> % path is a symlink + %% The target may be a relative or an absolute path and + %% may contain symlinks + Target1 = filename:absname(Target0, AccPath0), + {FollowRes, State2} = resolve_symlinks(Target1, LinkCnt-1, State1), + case FollowRes of + {ok, Target} -> + resolve_symlinks_2(RestPath, State2, LinkCnt-1, Target); + {error, _} = Error -> + {Error, State2} + end; + {error, einval} -> % path exists, but is not a symlink + resolve_symlinks_2(RestPath, State1, LinkCnt, AccPath1); + {error, _} = Error -> + {Error, State1} + end; +resolve_symlinks_2([], State, _LinkCnt, AccPath) -> + {{ok, AccPath}, State}. + + +relate_file_name(File, State) -> + relate_file_name(File, State, _Canonicalize=true). + +relate_file_name(File, State, Canonicalize) when is_binary(File) -> + relate_file_name(binary_to_list(File), State, Canonicalize); +relate_file_name(File, #state{cwd = CWD, root = ""}, Canonicalize) -> + relate_filename_to_path(File, CWD, Canonicalize); +relate_file_name(File, #state{root = Root}, Canonicalize) -> + case is_within_root(Root, File) of + true -> + File; + false -> + RelFile = make_relative_filename(File), + NewFile = relate_filename_to_path(RelFile, Root, Canonicalize), + case is_within_root(Root, NewFile) of + true -> + NewFile; + false -> + Root + end + end. + +is_within_root(Root, File) -> + lists:prefix(Root, File). + +%% Remove leading slash (/), if any, in order to make the filename +%% relative (to the root) +make_relative_filename("/") -> "./"; % Make it relative and preserve / +make_relative_filename("/"++File) -> File; +make_relative_filename(File) -> File. + +relate_filename_to_path(File0, Path, Canonicalize) -> + File1 = filename:absname(File0, Path), + File2 = if Canonicalize -> canonicalize_filename(File1); + true -> File1 + end, + ensure_trailing_slash_is_preserved(File0, File2). + +%% It seems as if the openssh client (observed with the +%% openssh-4.2p1-18.30 package on SLED 10), and possibly other clients +%% as well (Maverick?), rely on the fact that a trailing slash (/) is +%% preserved. If trailing slashes aren't preserved, symlinks which +%% point at directories won't be properly identified as directories. +%% +%% A failing example: +%% +%% 1) assume the following directory structure: +%% $ mkdir /tmp/symlink-target +%% $ touch /tmp/symlink-target/foo +%% $ ln -s /tmp/symlink-target /tmp/symlink +%% +%% 2) login using the sftp client in openssh +%% sftp> cd /tmp/ +%% sftp> ls symlink-target +%% symlink-target/foo +%% sftp> ls symlink +%% symlink/ <===== foo should have been visible here +%% sftp> cd symlink-target +%% sftp> ls +%% foo +%% sftp> cd .. +%% sftp> cd symlink +%% sftp> ls +%% <===== foo should have been visible here +%% +%% The symlinks are resolved by file:read_link_info/1 only if the path +%% has a trailing slash, which seems to something that some of the +%% sftp clients utilize: +%% +%% 1> file:read_link_info(".../symlink"). +%% {ok,{file_info,4,symlink,read_write, +%% {{2008,10,20},{10,25,26}}, +%% {{2008,10,17},{16,22,33}}, +%% {{2008,10,17},{16,22,33}}, +%% 41471,1,2053,0,570447,20996,9935}} +%% +%% 2> file:read_link_info(".../symlink/"). +%% {ok,{file_info,8192,directory,read_write, +%% {{2008,10,20},{10,36,2}}, +%% {{2008,10,20},{10,44,35}}, +%% {{2008,10,20},{10,44,35}}, +%% 17407,29,2053,0,521224,0,0}} +ensure_trailing_slash_is_preserved(File0, File1) -> + case {lists:suffix("/", File0), lists:suffix("/", File1)} of + {true, false} -> File1 ++ "/"; + _Other -> File1 + end. + + + +%%% fix file just a little: a/b/.. -> a and a/. -> a +canonicalize_filename(File0) -> + File = filename:join(canonicalize_filename_2(filename:split(File0), [])), + ensure_trailing_slash_is_preserved(File0, File). + +canonicalize_filename_2([".." | Rest], ["/"] = Acc) -> + canonicalize_filename_2(Rest, Acc); +canonicalize_filename_2([".." | Rest], [_Dir | Paths]) -> + canonicalize_filename_2(Rest, Paths); +canonicalize_filename_2(["." | Rest], Acc) -> + canonicalize_filename_2(Rest, Acc); +canonicalize_filename_2([A | Rest], Acc) -> + canonicalize_filename_2(Rest, [A | Acc]); +canonicalize_filename_2([], Acc) -> + lists:reverse(Acc). + +%% return a filename which is relative to the root directory +%% (any filename that's outside the root directory is forced to the root) +chroot_filename(Filename, #state{root = Root}) -> + FilenameComps0 = filename:split(Filename), + RootComps = filename:split(Root), + filename:join(chroot_filename_2(FilenameComps0, RootComps)). + +chroot_filename_2([PathComp | FilenameRest], [PathComp | RootRest]) -> + chroot_filename_2(FilenameRest, RootRest); +chroot_filename_2(FilenameComps, []) when length(FilenameComps) > 0 -> + %% Ensure there's a leading / (filename:join above will take care + %% of any duplicates) + ["/" | FilenameComps]; +chroot_filename_2(_FilenameComps, _RootComps) -> + %% The filename is either outside the root or at the root. In + %% both cases we want to force the filename to the root. + ["/"]. + + +read_file(ReqId, IoDevice, Offset, Len, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + {Res1, FS1} = FileMod:position(IoDevice, {bof, Offset}, FS0), + case Res1 of + {ok, _NewPos} -> + {Res2, FS2} = FileMod:read(IoDevice, Len, FS1), + State1 = State0#state{file_state = FS2}, + case Res2 of + {ok, Data} -> + ssh_xfer:xf_send_data(State1#state.xf, ReqId, Data), + State1; + {error, Error} -> + send_status({error, Error}, ReqId, State1); + eof -> + send_status(eof, ReqId, State1) + end; + {error, Error} -> + State1 = State0#state{file_state = FS1}, + send_status({error, Error}, ReqId, State1) + end. + +write_file(ReqId, IoDevice, Offset, Data, + State0 = #state{file_handler = FileMod, file_state = FS0}) -> + {Res, FS1} = FileMod:position(IoDevice, {bof, Offset}, FS0), + case Res of + {ok, _NewPos} -> + {Status, FS2} = FileMod:write(IoDevice, Data, FS1), + State1 = State0#state{file_state = FS2}, + send_status(Status, ReqId, State1); + {error, Error} -> + State1 = State0#state{file_state = FS1}, + send_status({error, Error}, ReqId, State1) + end. + +get_status(ok) -> + ?SSH_FX_OK; +get_status(eof) -> + ?SSH_FX_EOF; +get_status({error,Error}) -> + ssh_xfer:encode_erlang_status(Error). + +send_status(Status, ReqId, State) -> + ssh_xfer:xf_send_status(State#state.xf, ReqId, get_status(Status)), + State. + +set_stat(<<>>, _Path, State) -> + {ok, State}; +set_stat(Attr, Path, + State0 = #state{file_handler=FileMod, file_state=FS0}) -> + {DecodedAttr, _Rest} = + ssh_xfer:decode_ATTR((State0#state.xf)#ssh_xfer.vsn, Attr), + ?dbg(true, "set_stat DecodedAttr=~p\n", [DecodedAttr]), + Info = ssh_sftp:attr_to_info(DecodedAttr), + {Res1, FS1} = FileMod:read_link_info(Path, FS0), + case Res1 of + {ok, OldInfo} -> + NewInfo = set_file_info(Info, OldInfo), + ?dbg(true, "set_stat Path=~p\nInfo=~p\nOldInfo=~p\nNewInfo=~p\n", + [Path, Info, OldInfo, NewInfo]), + {Res2, FS2} = FileMod:write_file_info(Path, NewInfo, FS1), + State1 = State0#state{file_state = FS2}, + {Res2, State1}; + {error, Error} -> + State1 = State0#state{file_state = FS1}, + {{error, Error}, State1} + end. + + +set_file_info_sel(undefined, F) -> + F; +set_file_info_sel(F, _) -> + F. + +set_file_info(#file_info{atime = Dst_atime, mtime = Dst_mtime, + ctime = Dst_ctime, + mode = Dst_mode, uid = Dst_uid, gid = Dst_gid}, + #file_info{atime = Src_atime, mtime = Src_mtime, + ctime = Src_ctime, + mode = Src_mode, uid = Src_uid, gid = Src_gid}) -> + #file_info{atime = set_file_info_sel(Dst_atime, Src_atime), + mtime = set_file_info_sel(Dst_mtime, Src_mtime), + ctime = set_file_info_sel(Dst_ctime, Src_ctime), + mode = set_file_info_sel(Dst_mode, Src_mode), + uid = set_file_info_sel(Dst_uid, Src_uid), + gid = set_file_info_sel(Dst_gid, Src_gid)}. + +rename(Path, Path2, ReqId, State0) -> + #state{file_handler = FileMod, file_state = FS0} = State0, + {Status, FS1} = FileMod:rename(Path, Path2, FS0), + State1 = State0#state{file_state = FS1}, + send_status(Status, ReqId, State1). diff --git a/lib/ssh/src/ssh_sftpd_file.erl b/lib/ssh/src/ssh_sftpd_file.erl new file mode 100644 index 0000000000..f0b6bb4de5 --- /dev/null +++ b/lib/ssh/src/ssh_sftpd_file.erl @@ -0,0 +1,83 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: Default Callback module for ssh_sftpd + +-module(ssh_sftpd_file). + +-behaviour(ssh_sftpd_file_api). + +%% API +-export([close/2, delete/2, del_dir/2, get_cwd/1, is_dir/2, list_dir/2, + make_dir/2, make_symlink/3, open/3, position/3, read/3, + read_file_info/2, read_link/2, read_link_info/2, rename/3, + write/3, write_file_info/3]). + +close(IoDevice, State) -> + {file:close(IoDevice), State}. + +delete(Path, State) -> + {file:delete(Path), State}. + +del_dir(Path, State) -> + {file:del_dir(Path), State}. + +get_cwd(State) -> + {file:get_cwd(), State}. + +is_dir(AbsPath, State) -> + {filelib:is_dir(AbsPath), State}. + +list_dir(AbsPath, State) -> + {file:list_dir(AbsPath), State}. + +make_dir(Dir, State) -> + {file:make_dir(Dir), State}. + +make_symlink(Path2, Path, State) -> + {file:make_symlink(Path2, Path), State}. + +open(Path, Flags, State) -> + {file:open(Path, Flags), State}. + +position(IoDevice, Offs, State) -> + {file:position(IoDevice, Offs), State}. + +read(IoDevice, Len, State) -> + {file:read(IoDevice, Len), State}. + +read_link(Path, State) -> + {file:read_link(Path), State}. + +read_link_info(Path, State) -> + {file:read_link_info(Path), State}. + +read_file_info(Path, State) -> + {file:read_file_info(Path), State}. + +rename(Path, Path2, State) -> + {file:rename(Path, Path2), State}. + +write(IoDevice, Data, State) -> + {file:write(IoDevice, Data), State}. + +write_file_info(Path,Info, State) -> + {file:write_file_info(Path, Info), State}. diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl new file mode 100644 index 0000000000..8decfb38d9 --- /dev/null +++ b/lib/ssh/src/ssh_sftpd_file_api.erl @@ -0,0 +1,47 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_sftpd_file_api). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [ + {close, 2}, + {delete, 2}, + {del_dir, 2}, + {get_cwd, 1}, + {is_dir, 2}, + {list_dir, 2}, + {make_dir, 2}, + {make_symlink, 3}, + {open, 3}, + {position, 3}, + {read, 3}, + {read_file_info, 2}, + {read_link, 2}, + {read_link_info, 2}, + {rename, 3}, + {write, 3}, + {write_file_info, 3} + ]; +behaviour_info(_) -> + undefined. diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl new file mode 100644 index 0000000000..f81b949119 --- /dev/null +++ b/lib/ssh/src/ssh_shell.erl @@ -0,0 +1,178 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_shell). + +-include("ssh_connect.hrl"). + +-behaviour(ssh_channel). + +%% ssh_channel callbacks +-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). + +%% Spawn export +-export([input_loop/2]). + +-record(state, + { + io, %% Io process + channel, %% Id of the ssh channel + cm %% Ssh connection manager + } + ). + +%%==================================================================== +%% ssh_channel callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} +%% +%% Description: Initiates the CLI +%%-------------------------------------------------------------------- +init([ConnectionManager, ChannelId] = Args) -> + + %% Make sure that we are proclib compatible as + %% this client should be runnable from the + %% erlang shell. + case get('$initial_call') of + undefined -> + Me = get_my_name(), + Ancestors = get_ancestors(), + put('$ancestors', [Me | Ancestors]), + put('$initial_call', {?MODULE, init, Args}); + _ -> + ok + end, + + case ssh_connection:shell(ConnectionManager, ChannelId) of + ok -> + {group_leader, GIO} = + process_info(self(), group_leader), + IoPid = spawn_link(?MODULE, input_loop, + [GIO, self()]), + {ok, #state{io = IoPid, + channel = ChannelId, + cm = ConnectionManager}}; + Error -> + {stop, Error} + end. + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles channel messages received on the ssh-connection. +%%-------------------------------------------------------------------- +handle_ssh_msg({ssh_cm, _, {data, _ChannelId, 0, Data}}, State) -> + %% TODO: When unicode support is ready + %% should we call this function or perhaps a new + %% function. + io:put_chars(Data), + {ok, State}; + +handle_ssh_msg({ssh_cm, _, + {data, _ChannelId, ?SSH_EXTENDED_DATA_STDERR, Data}}, + State) -> + %% TODO: When unicode support is ready + %% should we call this function or perhaps a new + %% function. + io:put_chars(Data), + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {eof, _ChannelId}}, State) -> + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) -> + %% Ignore signals according to RFC 4254 section 6.9. + {ok, State}; + +handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, State) -> + io:put_chars("Connection closed by peer"), + %% TODO: When unicode support is ready + %% should we call this function or perhaps a new + %% function. The error is encoded as UTF-8! + io:put_chars(Error), + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, 0}}, State) -> + io:put_chars("logout"), + io:put_chars("Connection closed"), + {stop, ChannelId, State}; + +handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State) -> + io:put_chars("Connection closed by peer"), + io:put_chars("Status: " ++ integer_to_list(Status)), + {stop, ChannelId, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_ssh_msg(Args) -> {ok, State} | {stop, ChannelId, State} +%% +%% Description: Handles other channel messages +%%-------------------------------------------------------------------- +handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, + #state{channel = ChannelId, + cm = ConnectionManager} = State) -> + {ok, State}; + +handle_msg({input, IoPid, eof}, #state{io = IoPid, channel = ChannelId, + cm = ConnectionManager} = State) -> + ssh_connection:send_eof(ConnectionManager, ChannelId), + {ok, State}; + +handle_msg({input, IoPid, Line}, #state{io = IoPid, + channel = ChannelId, + cm = ConnectionManager} = State) -> + ssh_connection:send(ConnectionManager, ChannelId, Line), + {ok, State}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reasons, State) -> _ +%% +%% Description: Cleanup when shell channel is terminated +%%-------------------------------------------------------------------- +terminate(_Reason, #state{io = IoPid}) -> + exit(IoPid, kill). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +input_loop(Fd, Pid) -> + case io:get_line(Fd, '>') of + eof -> + Pid ! {input, self(), eof}, + ok; + Line -> + Pid ! {input, self(), Line}, + input_loop (Fd, Pid) + end. + +get_my_name() -> + case process_info(self(),registered_name) of + {registered_name,Name} -> Name; + _ -> self() + end. + +get_ancestors() -> + case get('$ancestors') of + A when is_list(A) -> A; + _ -> [] + end. diff --git a/lib/ssh/src/ssh_ssh.erl b/lib/ssh/src/ssh_ssh.erl new file mode 100644 index 0000000000..6be8bf7a5a --- /dev/null +++ b/lib/ssh/src/ssh_ssh.erl @@ -0,0 +1,65 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: THIS MODULE IS DEPRECATD AND SHOULD BE REMOVED IN R14 + +-module(ssh_ssh). + +-export([connect/1, connect/2, connect/3]). +-deprecated({connect, 1, next_major_release}). +-deprecated({connect, 2, next_major_release}). +-deprecated({connect, 3, next_major_release}). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). + +-define(default_timeout, 10000). + +%%% Backwards compatibility +connect(A) -> + connect(A, []). + +connect(Host, Opts) when is_list(Host) -> + connect(Host, 22, Opts); +connect(CM, Opts) -> + Timeout = proplists:get_value(connect_timeout, Opts, ?default_timeout), + session(CM, Timeout). + +connect(Host, Port, Opts) -> + case ssh:connect(Host, Port, Opts) of + {ok, CM} -> + session(CM, proplists:get_value(connect_timeout, + Opts, ?default_timeout)); + Error -> + Error + end. + +session(CM, Timeout) -> + case ssh_connection:session_channel(CM, Timeout) of + {ok, ChannelId} -> + Args = [{channel_cb, ssh_shell}, + {init_args,[CM, ChannelId]}, + {cm, CM}, {channel_id, ChannelId}], + {ok, State} = ssh_channel:init([Args]), + ssh_channel:enter_loop(State); + Error -> + Error + end. diff --git a/lib/ssh/src/ssh_sshd.erl b/lib/ssh/src/ssh_sshd.erl new file mode 100644 index 0000000000..4bc0469061 --- /dev/null +++ b/lib/ssh/src/ssh_sshd.erl @@ -0,0 +1,48 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Description: This module uses the erlang shell and +%% ssh_cli to make an erlang sshd + +-module(ssh_sshd). + +%% API +-export([listen/0, listen/1, listen/2, listen/3, stop/1]). + +-deprecated({listen, 0, next_major_release}). +-deprecated({listen, 1, next_major_release}). +-deprecated({listen, 2, next_major_release}). +-deprecated({listen, 3, next_major_release}). +-deprecated({stop, 1, next_major_release}). + +listen() -> + listen(22). + +listen(Port) -> + listen(Port, []). + +listen(Port, Opts) -> + listen(any, Port, Opts). + +listen(Addr, Port, Opts) -> + ssh:daemon(Addr, Port, Opts). + +stop(Pid) -> + ssh:stop_daemon(Pid). diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl new file mode 100644 index 0000000000..17d47a91d5 --- /dev/null +++ b/lib/ssh/src/ssh_subsystem_sup.erl @@ -0,0 +1,109 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The ssh subsystem supervisor +%%---------------------------------------------------------------------- + +-module(ssh_subsystem_sup). + +-behaviour(supervisor). + +-export([start_link/1, connection_supervisor/1, channel_supervisor/1 + ]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(Opts) -> + supervisor:start_link(?MODULE, [Opts]). + +connection_supervisor(SupPid) -> + Children = supervisor:which_children(SupPid), + ssh_connection_sup(Children). + +channel_supervisor(SupPid) -> + Children = supervisor:which_children(SupPid), + ssh_channel_sup(Children). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([Opts]) -> + RestartStrategy = one_for_all, + MaxR = 0, + MaxT = 3600, + Children = child_specs(Opts), + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +child_specs(Opts) -> + case proplists:get_value(role, Opts) of + client -> + [ssh_connectinon_child_spec(Opts)]; + server -> + [ssh_connectinon_child_spec(Opts), ssh_channel_child_spec(Opts)] + end. + +ssh_connectinon_child_spec(Opts) -> + Address = proplists:get_value(address, Opts), + Port = proplists:get_value(port, Opts), + Role = proplists:get_value(role, Opts), + Name = id(Role, ssh_connection_controler, Address, Port), + StartFunc = {ssh_connection_controler, start_link, [Opts]}, + Restart = transient, +% Restart = permanent, + Shutdown = 5000, + Modules = [ssh_connection_controler], + Type = worker, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +ssh_channel_child_spec(Opts) -> + Address = proplists:get_value(address, Opts), + Port = proplists:get_value(port, Opts), + Role = proplists:get_value(role, Opts), + Name = id(Role, ssh_channel_sup, Address, Port), + StartFunc = {ssh_channel_sup, start_link, [Opts]}, + Restart = transient, +% Restart = permanent, + Shutdown = infinity, + Modules = [ssh_channel_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +id(Role, Sup, Address, Port) -> + {Role, Sup, Address, Port}. + +ssh_connection_sup([{_, Child, _, [ssh_connection_controler]} | _]) -> + Child; +ssh_connection_sup([_ | Rest]) -> + ssh_connection_sup(Rest). + +ssh_channel_sup([{_, Child, _, [ssh_channel_sup]} | _]) -> + Child; +ssh_channel_sup([_ | Rest]) -> + ssh_channel_sup(Rest). + + + diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl new file mode 100644 index 0000000000..4c46b1586b --- /dev/null +++ b/lib/ssh/src/ssh_sup.erl @@ -0,0 +1,101 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: The top supervisor for the ssh application. +%%---------------------------------------------------------------------- +-module(ssh_sup). + +-behaviour(supervisor). + +-export([init/1]). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([]) -> + SupFlags = {one_for_one, 10, 3600}, + Children = children(), + {ok, {SupFlags, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +get_services() -> + case (catch application:get_env(ssh, services)) of + {ok, Services} -> + Services; + _ -> + [] + end. + +children() -> + Services = get_services(), + Clients = [Service || Service <- Services, is_client(Service)], + Servers = [Service || Service <- Services, is_server(Service)], + + [server_child_spec(Servers), client_child_spec(Clients), + ssh_userauth_reg_spec()]. + +server_child_spec(Servers) -> + Name = sshd_sup, + StartFunc = {sshd_sup, start_link, [Servers]}, + Restart = permanent, + Shutdown = infinity, + Modules = [sshd_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +client_child_spec(Clients) -> + Name = sshc_sup, + StartFunc = {sshc_sup, start_link, [Clients]}, + Restart = permanent, + Shutdown = infinity, + Modules = [sshc_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +ssh_userauth_reg_spec() -> + Name = ssh_userreg, + StartFunc = {ssh_userreg, start_link, []}, + Restart = transient, + Shutdown = 5000, + Modules = [ssh_userreg], + Type = worker, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + + +is_server({sftpd, _}) -> + true; +is_server({shelld, _}) -> + true; +is_server(_) -> + false. + +is_client({sftpc, _}) -> + true; +is_client({shellc, _}) -> + true; +is_client(_) -> + false. + + + + diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl new file mode 100644 index 0000000000..477f60f993 --- /dev/null +++ b/lib/ssh/src/ssh_system_sup.erl @@ -0,0 +1,160 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: The ssh server instance supervisor, an instans of this supervisor +%% exists for every ip-address and port combination, hangs under +%% sshd_sup. +%%---------------------------------------------------------------------- + +-module(ssh_system_sup). + +-behaviour(supervisor). + +-export([start_link/1, stop_listener/1, + stop_listener/2, stop_system/1, + stop_system/2, system_supervisor/2, + subsystem_supervisor/1, channel_supervisor/1, + connection_supervisor/1, + acceptor_supervisor/1, start_subsystem/2, restart_subsystem/2, restart_acceptor/2]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(ServerOpts) -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + Name = make_name(Address, Port), + supervisor:start_link({local, Name}, ?MODULE, [ServerOpts]). + +stop_listener(SysSup) -> + stop_acceptor(SysSup). + +stop_listener(Address, Port) -> + Name = make_name(Address, Port), + stop_acceptor(whereis(Name)). + +stop_system(SysSup) -> + Name = sshd_sup:system_name(SysSup), + sshd_sup:stop_child(Name). + +stop_system(Address, Port) -> + sshd_sup:stop_child(Address, Port). + +system_supervisor(Address, Port) -> + Name = make_name(Address, Port), + whereis(Name). + +subsystem_supervisor(SystemSup) -> + ssh_subsystem_sup(supervisor:which_children(SystemSup)). + +channel_supervisor(SystemSup) -> + SubSysSup = ssh_subsystem_sup(supervisor:which_children(SystemSup)), + ssh_subsystem_sup:channel_supervisor(SubSysSup). + +connection_supervisor(SystemSup) -> + SubSysSup = ssh_subsystem_sup(supervisor:which_children(SystemSup)), + ssh_subsystem_sup:connection_supervisor(SubSysSup). + +acceptor_supervisor(SystemSup) -> + ssh_acceptor_sup(supervisor:which_children(SystemSup)). + +start_subsystem(SystemSup, Options) -> + Spec = ssh_subsystem_child_spec(Options), + supervisor:start_child(SystemSup, Spec). + +restart_subsystem(Address, Port) -> + SysSupName = make_name(Address, Port), + SubSysName = id(ssh_subsystem_sup, Address, Port), + case supervisor:terminate_child(SysSupName, SubSysName) of + ok -> + supervisor:restart_child(SysSupName, SubSysName); + Error -> + Error + end. + +restart_acceptor(Address, Port) -> + SysSupName = make_name(Address, Port), + AcceptorName = id(ssh_acceptor_sup, Address, Port), + supervisor:restart_child(SysSupName, AcceptorName). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([ServerOpts]) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Children = child_specs(ServerOpts), + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +child_specs(ServerOpts) -> + [ssh_acceptor_child_spec(ServerOpts)]. + +ssh_acceptor_child_spec(ServerOpts) -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + Name = id(ssh_acceptor_sup, Address, Port), + StartFunc = {ssh_acceptor_sup, start_link, [ServerOpts]}, + Restart = permanent, + Shutdown = infinity, + Modules = [ssh_acceptor_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +ssh_subsystem_child_spec(ServerOpts) -> + Name = make_ref(), + StartFunc = {ssh_subsystem_sup, start_link, [ServerOpts]}, + Restart = temporary, + Shutdown = infinity, + Modules = [ssh_subsystem_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + + +id(Sup, Address, Port) -> + {Sup, Address, Port}. + +make_name(Address, Port) -> + list_to_atom(lists:flatten(io_lib:format("ssh_system_~p_~p_sup", + [Address, Port]))). + +ssh_subsystem_sup([{_, Child, _, [ssh_subsystem_sup]} | _]) -> + Child; +ssh_subsystem_sup([_ | Rest]) -> + ssh_subsystem_sup(Rest). + +ssh_acceptor_sup([{_, Child, _, [ssh_acceptor_sup]} | _]) -> + Child; +ssh_acceptor_sup([_ | Rest]) -> + ssh_acceptor_sup(Rest). + +stop_acceptor(Sup) -> + [Name] = + [SupName || {SupName, _, _, [ssh_acceptor_sup]} <- + supervisor:which_children(Sup)], + supervisor:terminate_child(Sup, Name). + diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl new file mode 100644 index 0000000000..5617231c60 --- /dev/null +++ b/lib/ssh/src/ssh_transport.erl @@ -0,0 +1,1161 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SSH transport protocol + +-module(ssh_transport). + +-include("ssh_transport.hrl"). + +-include("ssh.hrl"). +-include_lib("kernel/include/inet.hrl"). + +-export([connect/5, accept/4]). +-export([versions/2, hello_version_msg/1]). +-export([next_seqnum/1, decrypt_first_block/2, decrypt_blocks/3, + is_valid_mac/3, transport_messages/1, kexdh_messages/0, + kex_dh_gex_messages/0, handle_hello_version/1, + key_exchange_init_msg/1, key_init/3, new_keys_message/1, + handle_kexinit_msg/3, handle_kexdh_init/2, + handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2, + handle_new_keys/2, handle_kex_dh_gex_request/2, + handle_kexdh_reply/2, + unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1]). + +%% debug flagso +-define(DBG_ALG, true). +-define(DBG_KEX, true). +-define(DBG_CRYPTO, false). +-define(DBG_PACKET, false). +-define(DBG_MESSAGE, true). +-define(DBG_BIN_MESSAGE, true). +-define(DBG_MAC, false). +-define(DBG_ZLIB, true). + +versions(client, Options)-> + Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION), + Version = format_version(Vsn), + {Vsn, Version}; +versions(server, Options) -> + Vsn = proplists:get_value(vsn, Options, ?DEFAULT_SERVER_VERSION), + Version = format_version(Vsn), + {Vsn, Version}. + +hello_version_msg(Data) -> + [Data,"\r\n"]. + +next_seqnum(SeqNum) -> + (SeqNum + 1) band 16#ffffffff. + +decrypt_first_block(Bin, #ssh{decrypt_block_size = BlockSize} = Ssh0) -> + <<EncBlock:BlockSize/binary, EncData/binary>> = Bin, + {Ssh, <<?UINT32(PacketLen), _/binary>> = DecData} = + decrypt(Ssh0, EncBlock), + {Ssh, PacketLen, DecData, EncData}. + +decrypt_blocks(Bin, Length, Ssh0) -> + <<EncBlocks:Length/binary, EncData/binary>> = Bin, + {Ssh, DecData} = decrypt(Ssh0, EncBlocks), + {Ssh, DecData, EncData}. + +is_valid_mac(_, _ , #ssh{recv_mac_size = 0}) -> + true; +is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm, + recv_mac_key = Key, recv_sequence = SeqNum}) -> + Mac == mac(Algorithm, Key, SeqNum, Data). + +transport_messages(_) -> + [{ssh_msg_disconnect, ?SSH_MSG_DISCONNECT, + [uint32, string, string]}, + + {ssh_msg_ignore, ?SSH_MSG_IGNORE, + [string]}, + + {ssh_msg_unimplemented, ?SSH_MSG_UNIMPLEMENTED, + [uint32]}, + + {ssh_msg_debug, ?SSH_MSG_DEBUG, + [boolean, string, string]}, + + {ssh_msg_service_request, ?SSH_MSG_SERVICE_REQUEST, + [string]}, + + {ssh_msg_service_accept, ?SSH_MSG_SERVICE_ACCEPT, + [string]}, + + {ssh_msg_kexinit, ?SSH_MSG_KEXINIT, + [cookie, + name_list, name_list, + name_list, name_list, + name_list, name_list, + name_list, name_list, + name_list, name_list, + boolean, + uint32]}, + + {ssh_msg_newkeys, ?SSH_MSG_NEWKEYS, + []} + ]. + +kexdh_messages() -> + [{ssh_msg_kexdh_init, ?SSH_MSG_KEXDH_INIT, + [mpint]}, + + {ssh_msg_kexdh_reply, ?SSH_MSG_KEXDH_REPLY, + [binary, mpint, binary]} + ]. + +kex_dh_gex_messages() -> + [{ssh_msg_kex_dh_gex_request, ?SSH_MSG_KEX_DH_GEX_REQUEST, + [uint32, uint32, uint32]}, + + {ssh_msg_kex_dh_gex_request_old, ?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, + [uint32]}, + + {ssh_msg_kex_dh_gex_group, ?SSH_MSG_KEX_DH_GEX_GROUP, + [mpint, mpint]}, + + {ssh_msg_kex_dh_gex_init, ?SSH_MSG_KEX_DH_GEX_INIT, + [mpint]}, + + {ssh_msg_kex_dh_gex_reply, ?SSH_MSG_KEX_DH_GEX_REPLY, + [binary, mpint, binary]} + ]. + +yes_no(Ssh, Prompt) -> + (Ssh#ssh.io_cb):yes_no(Prompt). + +connect(ConnectionSup, Address, Port, SocketOpts, Opts) -> + Timeout = proplists:get_value(connect_timeout, Opts, infinity), + {_, Callback, _} = + proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}), + case do_connect(Callback, Address, Port, SocketOpts, Timeout) of + {ok, Socket} -> + {ok, Pid} = + ssh_connection_controler:start_handler_child(ConnectionSup, + [client, Socket, + [{address, Address}, + {port, Port} | + Opts]]), + Callback:controlling_process(Socket, Pid), + ssh_connection_handler:send_event(Pid, socket_control), + {ok, Pid}; + {error, Reason} -> + {error, Reason} + end. + +do_connect(Callback, Address, Port, SocketOpts, Timeout) -> + Opts = [{active, false} | SocketOpts], + case Callback:connect(Address, Port, Opts, Timeout) of + {error, nxdomain} -> + Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout); + {error, eafnosupport} -> + Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout); + Other -> + Other + end. + +accept(Address, Port, Socket, Options) -> + {_, Callback, _} = + proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}), + ConnectionSup = + ssh_system_sup:connection_supervisor( + ssh_system_sup:system_supervisor(Address, Port)), + {ok, Pid} = + ssh_connection_controler:start_handler_child(ConnectionSup, + [server, Socket, + [{address, Address}, + {port, Port} | Options]]), + Callback:controlling_process(Socket, Pid), + ssh_connection_handler:send_event(Pid, socket_control), + {ok, Pid}. + +format_version({Major,Minor}) -> + "SSH-" ++ integer_to_list(Major) ++ "." ++ + integer_to_list(Minor) ++ "-Erlang". + +handle_hello_version(Version) -> + StrVersion = trim_tail(Version), + case string:tokens(Version, "-") of + [_, "2.0" | _] -> + {{2,0}, StrVersion}; + [_, "1.99" | _] -> + {{2,0}, StrVersion}; + [_, "1.3" | _] -> + {{1,3}, StrVersion}; + [_, "1.5" | _] -> + {{1,5}, StrVersion} + end. + +key_exchange_init_msg(Ssh0) -> + Msg = kex_init(Ssh0), + {SshPacket, Ssh} = ssh_packet(Msg, Ssh0), + {Msg, SshPacket, Ssh}. + +kex_init(#ssh{role = Role, opts = Opts}) -> + Random = ssh_bits:random(16), + Compression = case proplists:get_value(compression, Opts, none) of + zlib -> ["zlib", "none"]; + none -> ["none", "zlib"] + end, + kexinit_messsage(Role, Random, Compression). + +key_init(client, Ssh, Value) -> + Ssh#ssh{c_keyinit = Value}; +key_init(server, Ssh, Value) -> + Ssh#ssh{s_keyinit = Value}. + +kexinit_messsage(client, Random, Compression) -> + #ssh_msg_kexinit{ + cookie = Random, + kex_algorithms = ["diffie-hellman-group1-sha1"], + server_host_key_algorithms = ["ssh-rsa", "ssh-dss"], + encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"], + encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"], + mac_algorithms_client_to_server = ["hmac-sha1"], + mac_algorithms_server_to_client = ["hmac-sha1"], + compression_algorithms_client_to_server = Compression, + compression_algorithms_server_to_client = Compression, + languages_client_to_server = [], + languages_server_to_client = [] + }; + +kexinit_messsage(server, Random, Compression) -> + #ssh_msg_kexinit{ + cookie = Random, + kex_algorithms = ["diffie-hellman-group1-sha1"], + server_host_key_algorithms = ["ssh-dss"], + encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"], + encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"], + mac_algorithms_client_to_server = ["hmac-sha1"], + mac_algorithms_server_to_client = ["hmac-sha1"], + compression_algorithms_client_to_server = Compression, + compression_algorithms_server_to_client = Compression, + languages_client_to_server = [], + languages_server_to_client = [] + }. + +new_keys_message(Ssh0) -> + {SshPacket, Ssh} = + ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh}. + +handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, + #ssh{role = client} = Ssh0) -> + {ok, Algoritms} = select_algorithm(client, Own, CounterPart), + case verify_algorithm(Algoritms) of + true -> + install_messages(Algoritms#alg.kex), + key_exchange_first_msg(Algoritms#alg.kex, + Ssh0#ssh{algorithms = Algoritms}); + _ -> + %% TODO: Correct code? + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Selection of key exchange" + " algorithm failed", + language = "en"}) + end; + +handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, + #ssh{role = server} = Ssh) -> + {ok, Algoritms} = select_algorithm(server, CounterPart, Own), + install_messages(Algoritms#alg.kex), + {ok, Ssh#ssh{algorithms = Algoritms}}. + + +%% TODO: diffie-hellman-group14-sha1 should also be supported. +%% Maybe check more things ... +verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) -> + true; +verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) -> + true; +verify_algorithm(_) -> + false. + +install_messages('diffie-hellman-group1-sha1') -> + ssh_bits:install_messages(kexdh_messages()); +install_messages('diffie-hellman-group-exchange-sha1') -> + ssh_bits:install_messages(kex_dh_gex_messages()). + +key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) -> + {G, P} = dh_group1(), + {Private, Public} = dh_gen_key(G, P, 1024), + %%?dbg(?DBG_KEX, "public: ~p~n", [Public]), + {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0), + {ok, SshPacket, + Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}}; + +key_exchange_first_msg('diffie-hellman-group-exchange-sha1', Ssh0) -> + Min = ?DEFAULT_DH_GROUP_MIN, + NBits = ?DEFAULT_DH_GROUP_NBITS, + Max = ?DEFAULT_DH_GROUP_MAX, + {SshPacket, Ssh1} = + ssh_packet(#ssh_msg_kex_dh_gex_request{min = Min, + n = NBits, max = Max}, + Ssh0), + {ok, SshPacket, + Ssh1#ssh{keyex_info = {Min, Max, NBits}}}. + + +handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> + {G, P} = dh_group1(), + {Private, Public} = dh_gen_key(G, P, 1024), + %%?dbg(?DBG_KEX, "public: ~p~n", [Public]), + K = ssh_math:ipow(E, Private, P), + {Key, K_S} = get_host_key(Ssh0), + H = kex_h(Ssh0, K_S, E, Public, K), + H_SIG = sign_host_key(Ssh0, Key, H), + {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = K_S, + f = Public, + h_sig = H_SIG + }, Ssh0), + %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), + %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}, + shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh1, H)}}. + +handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) -> + {Private, Public} = dh_gen_key(G,P,1024), + %%?dbg(?DBG_KEX, "public: ~p ~n", [Public]), + {SshPacket, Ssh1} = + ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), + {ok, SshPacket, + Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}}. + +handle_new_keys(#ssh_msg_newkeys{}, Ssh0) -> + try install_alg(Ssh0) of + #ssh{} = Ssh -> + {ok, Ssh} + catch + error:_Error -> %% TODO: Throw earlier .... + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR, + description = "Install alg failed", + language = "en"}) + end. + + +%% %% Select algorithms +handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey, f = F, + h_sig = H_SIG}, + #ssh{keyex_key = {{Private, Public}, {_G, P}}} = Ssh0) -> + K = ssh_math:ipow(F, Private, P), + H = kex_h(Ssh0, HostKey, Public, F, K), + %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), + %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + case verify_host_key(Ssh0, HostKey, H, H_SIG) of + ok -> + {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H)}}; + _Error -> + Disconnect = #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed", + language = "en"}, + throw(Disconnect) + end. + +handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = _Min, + n = _NBits, + max = _Max}, Ssh0) -> + {G,P} = dh_group1(), %% TODO real imp this seems to be a hack?! + {Private, Public} = dh_gen_key(G, P, 1024), + {SshPacket, Ssh} = + ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0), + {ok, SshPacket, + Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}}. + +handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey, + f = F, + h_sig = H_SIG}, + #ssh{keyex_key = {{Private, Public}, {G, P}}, + keyex_info = {Min, Max, NBits}} = + Ssh0) -> + K = ssh_math:ipow(F, Private, P), + H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K), + %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), + %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + case verify_host_key(Ssh0, HostKey, H, H_SIG) of + ok -> + {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), + {ok, SshPacket, Ssh#ssh{shared_secret = K, + exchanged_hash = H, + session_id = sid(Ssh, H)}}; + _Error -> + Disconnect = #ssh_msg_disconnect{ + code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, + description = "Key exchange failed", + language = "en"}, + throw(Disconnect) + end. + +%% select session id +sid(#ssh{session_id = undefined}, H) -> + H; +sid(#ssh{session_id = Id}, _) -> + Id. + +%% +%% The host key should be read from storage +%% +get_host_key(SSH) -> + #ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH, + Scope = proplists:get_value(key_scope, Opts, system), + case ALG#alg.hkey of + 'ssh-rsa' -> + case Mod:private_host_rsa_key(Scope, Opts) of + {ok,Key=#ssh_key { public={N,E}} } -> + %%?dbg(true, "x~n", []), + {Key, + ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])}; + Error -> + %%?dbg(true, "y~n", []), + exit(Error) + end; + 'ssh-dss' -> + case Mod:private_host_dsa_key(Scope, Opts) of + {ok,Key=#ssh_key { public={P,Q,G,Y}}} -> + {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y], + [string,mpint,mpint,mpint,mpint])}; + Error -> + exit(Error) + end; + _ -> + exit({error, bad_key_type}) + end. + +sign_host_key(Ssh, Private, H) -> + ALG = Ssh#ssh.algorithms, + Module = case ALG#alg.hkey of + 'ssh-rsa' -> + ssh_rsa; + 'ssh-dss' -> + ssh_dsa + end, + case catch Module:sign(Private, H) of + {'EXIT', Reason} -> + error_logger:format("SIGN FAILED: ~p\n", [Reason]), + {error, Reason}; + SIG -> + ssh_bits:encode([Module:alg_name() ,SIG],[string,binary]) + end. + +verify_host_key(SSH, K_S, H, H_SIG) -> + ALG = SSH#ssh.algorithms, + case ALG#alg.hkey of + 'ssh-rsa' -> + case ssh_bits:decode(K_S,[string,mpint,mpint]) of + ["ssh-rsa", E, N] -> + ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]), + Public = #ssh_key { type=rsa, public={N,E} }, + case catch ssh_rsa:verify(Public, H, SIG) of + {'EXIT', Reason} -> + error_logger:format("VERIFY FAILED: ~p\n", [Reason]), + {error, bad_signature}; + ok -> + known_host_key(SSH, Public, "ssh-rsa") + end; + _ -> + {error, bad_format} + end; + 'ssh-dss' -> + case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of + ["ssh-dss",P,Q,G,Y] -> + ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]), + Public = #ssh_key { type=dsa, public={P,Q,G,Y} }, + case catch ssh_dsa:verify(Public, H, SIG) of + {'EXIT', Reason} -> + error_logger:format("VERIFY FAILED: ~p\n", [Reason]), + {error, bad_signature}; + ok -> + known_host_key(SSH, Public, "ssh-dss") + end; + _ -> + {error, bad_host_key_format} + end; + _ -> + {error, bad_host_key_algorithm} + end. + +accepted_host(Ssh, PeerName, Opts) -> + case proplists:get_value(silently_accept_hosts, Opts, false) of + true -> + yes; + false -> + yes_no(Ssh, "New host " ++ PeerName ++ " accept") + end. + +known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh, + Public, Alg) -> + PeerName = peer_name(Peer), + case Mod:lookup_host_key(PeerName, Alg, Opts) of + {ok, Public} -> + ok; + {ok, BadPublic} -> + error_logger:format("known_host_key: Public ~p BadPublic ~p\n", + [Public, BadPublic]), + {error, bad_public_key}; + {error, not_found} -> + case accepted_host(Ssh, PeerName, Opts) of + yes -> + Mod:add_host_key(PeerName, Public, Opts); + no -> + {error, rejected} + end + end. + + +%% Each of the algorithm strings MUST be a comma-separated list of +%% algorithm names (see ''Algorithm Naming'' in [SSH-ARCH]). Each +%% supported (allowed) algorithm MUST be listed in order of preference. +%% +%% The first algorithm in each list MUST be the preferred (guessed) +%% algorithm. Each string MUST contain at least one algorithm name. +select_algorithm(Role, Client, Server) -> + {Encrypt, Decrypt} = select_encrypt_decrypt(Role, Client, Server), + {SendMac, RecvMac} = select_send_recv_mac(Role, Client, Server), + {Compression, Decompression} = + select_compression_decompression(Role, Client, Server), + + C_Lng = select(Client#ssh_msg_kexinit.languages_client_to_server, + Server#ssh_msg_kexinit.languages_client_to_server), + S_Lng = select(Client#ssh_msg_kexinit.languages_server_to_client, + Server#ssh_msg_kexinit.languages_server_to_client), + HKey = select_all(Client#ssh_msg_kexinit.server_host_key_algorithms, + Server#ssh_msg_kexinit.server_host_key_algorithms), + HK = case HKey of + [] -> undefined; + [HK0|_] -> HK0 + end, + %% Fixme verify Kex against HKey list and algorithms + + Kex = select(Client#ssh_msg_kexinit.kex_algorithms, + Server#ssh_msg_kexinit.kex_algorithms), + + Alg = #alg{kex = Kex, + hkey = HK, + encrypt = Encrypt, + decrypt = Decrypt, + send_mac = SendMac, + recv_mac = RecvMac, + compress = Compression, + decompress = Decompression, + c_lng = C_Lng, + s_lng = S_Lng}, + {ok, Alg}. + +select_encrypt_decrypt(client, Client, Server) -> + Encrypt = + select(Client#ssh_msg_kexinit.encryption_algorithms_client_to_server, + Server#ssh_msg_kexinit.encryption_algorithms_client_to_server), + Decrypt = + select(Client#ssh_msg_kexinit.encryption_algorithms_server_to_client, + Server#ssh_msg_kexinit.encryption_algorithms_server_to_client), + {Encrypt, Decrypt}; +select_encrypt_decrypt(server, Client, Server) -> + Decrypt = + select(Client#ssh_msg_kexinit.encryption_algorithms_client_to_server, + Server#ssh_msg_kexinit.encryption_algorithms_client_to_server), + Encrypt = + select(Client#ssh_msg_kexinit.encryption_algorithms_server_to_client, + Server#ssh_msg_kexinit.encryption_algorithms_server_to_client), + {Encrypt, Decrypt}. + +select_send_recv_mac(client, Client, Server) -> + SendMac = select(Client#ssh_msg_kexinit.mac_algorithms_client_to_server, + Server#ssh_msg_kexinit.mac_algorithms_client_to_server), + RecvMac = select(Client#ssh_msg_kexinit.mac_algorithms_server_to_client, + Server#ssh_msg_kexinit.mac_algorithms_server_to_client), + {SendMac, RecvMac}; +select_send_recv_mac(server, Client, Server) -> + RecvMac = select(Client#ssh_msg_kexinit.mac_algorithms_client_to_server, + Server#ssh_msg_kexinit.mac_algorithms_client_to_server), + SendMac = select(Client#ssh_msg_kexinit.mac_algorithms_server_to_client, + Server#ssh_msg_kexinit.mac_algorithms_server_to_client), + {SendMac, RecvMac}. + +select_compression_decompression(client, Client, Server) -> + Compression = + select(Client#ssh_msg_kexinit.compression_algorithms_client_to_server, + Server#ssh_msg_kexinit.compression_algorithms_client_to_server), + Decomprssion = + select(Client#ssh_msg_kexinit.compression_algorithms_server_to_client, + Server#ssh_msg_kexinit.compression_algorithms_server_to_client), + {Compression, Decomprssion}; +select_compression_decompression(server, Client, Server) -> + Decomprssion = + select(Client#ssh_msg_kexinit.compression_algorithms_client_to_server, + Server#ssh_msg_kexinit.compression_algorithms_client_to_server), + Compression = + select(Client#ssh_msg_kexinit.compression_algorithms_server_to_client, + Server#ssh_msg_kexinit.compression_algorithms_server_to_client), + {Compression, Decomprssion}. + +install_alg(SSH) -> + SSH1 = alg_final(SSH), + SSH2 = alg_setup(SSH1), + alg_init(SSH2). + +alg_setup(SSH) -> + ALG = SSH#ssh.algorithms, + %%?dbg(?DBG_ALG, "ALG: setup ~p ~n", [ALG]), + SSH#ssh{kex = ALG#alg.kex, + hkey = ALG#alg.hkey, + encrypt = ALG#alg.encrypt, + decrypt = ALG#alg.decrypt, + send_mac = ALG#alg.send_mac, + send_mac_size = mac_digest_size(ALG#alg.send_mac), + recv_mac = ALG#alg.recv_mac, + recv_mac_size = mac_digest_size(ALG#alg.recv_mac), + compress = ALG#alg.compress, + decompress = ALG#alg.decompress, + c_lng = ALG#alg.c_lng, + s_lng = ALG#alg.s_lng, + algorithms = undefined + }. + +alg_init(SSH0) -> + %%?dbg(?DBG_ALG, "ALG: init~n", []), + {ok,SSH1} = send_mac_init(SSH0), + {ok,SSH2} = recv_mac_init(SSH1), + {ok,SSH3} = encrypt_init(SSH2), + {ok,SSH4} = decrypt_init(SSH3), + {ok,SSH5} = compress_init(SSH4), + {ok,SSH6} = decompress_init(SSH5), + SSH6. + +alg_final(SSH0) -> + %%?dbg(?DBG_ALG, "ALG: final ~n", []), + {ok,SSH1} = send_mac_final(SSH0), + {ok,SSH2} = recv_mac_final(SSH1), + {ok,SSH3} = encrypt_final(SSH2), + {ok,SSH4} = decrypt_final(SSH3), + {ok,SSH5} = compress_final(SSH4), + {ok,SSH6} = decompress_final(SSH5), + SSH6. + +select_all(CL, SL) -> + A = CL -- SL, %% algortihms only used by client + %% algorithms used by client and server (client pref) + lists:map(fun(ALG) -> list_to_atom(ALG) end, (CL -- A)). + +select([], []) -> + none; +select(CL, SL) -> + C = case select_all(CL,SL) of + [] -> undefined; + [ALG|_] -> ALG + end, + %%?dbg(?DBG_ALG, "ALG: select: ~p ~p = ~p~n", [CL, SL, C]), + C. + +ssh_packet(#ssh_msg_kexinit{} = Msg, Ssh0) -> + BinMsg = ssh_bits:encode(Msg), + Ssh = key_init(Ssh0#ssh.role, Ssh0, BinMsg), + %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]), + pack(BinMsg, Ssh); + +ssh_packet(Msg, Ssh) -> + BinMsg = ssh_bits:encode(Msg), + %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]), + %%?dbg(?DBG_BIN_MESSAGE, "Encoded: ~p~n", [BinMsg]), + pack(BinMsg, Ssh). + +pack(Data0, #ssh{encrypt_block_size = BlockSize, + send_sequence = SeqNum, send_mac = MacAlg, + send_mac_key = MacKey} + = Ssh0) when is_binary(Data0) -> + {Ssh1, Data} = compress(Ssh0, Data0), + PL = (BlockSize - ((4 + 1 + size(Data)) rem BlockSize)) rem BlockSize, + PaddingLen = if PL < 4 -> PL + BlockSize; + true -> PL + end, + Padding = ssh_bits:random(PaddingLen), + PacketLen = 1 + PaddingLen + size(Data), + PacketData = <<?UINT32(PacketLen),?BYTE(PaddingLen), + Data/binary, Padding/binary>>, + {Ssh2, EncPacket} = encrypt(Ssh1, PacketData), + MAC = mac(MacAlg, MacKey, SeqNum, PacketData), + Packet = [EncPacket, MAC], + Ssh = Ssh2#ssh{send_sequence = (SeqNum+1) band 16#ffffffff}, + {Packet, Ssh}. + +unpack(EncodedSoFar, ReminingLenght, #ssh{recv_mac_size = MacSize} = Ssh0) -> + SshLength = ReminingLenght - MacSize, + {NoMac, Mac, Rest} = case MacSize of + 0 -> + <<NoMac0:SshLength/binary, + Rest0/binary>> = EncodedSoFar, + {NoMac0, <<>>, Rest0}; + _ -> + <<NoMac0:SshLength/binary, + Mac0:MacSize/binary, + Rest0/binary>> = EncodedSoFar, + {NoMac0, Mac0, Rest0} + end, + {Ssh1, DecData, <<>>} = + case SshLength of + 0 -> + {Ssh0, <<>>, <<>>}; + _ -> + decrypt_blocks(NoMac, SshLength, Ssh0) + end, + {Ssh1, DecData, Rest, Mac}. + +msg_data(PacketData) -> + <<Len:32, PaddingLen:8, _/binary>> = PacketData, + DataLen = Len - PaddingLen - 1, + <<_:32, _:8, Data:DataLen/binary, + _:PaddingLen/binary>> = PacketData, + Data. + + +%% Send a disconnect message +%% terminate(S, SSH, Code, Message) -> +%% M = #ssh_msg_disconnect{code=Code, +%% description = Message, +%% language = "en"}, +%% send_msg(S, SSH, M), +%% gen_tcp:close(S), +%% {error, M}. + + +%% public key algorithms +%% +%% ssh-dss REQUIRED sign Raw DSS Key +%% ssh-rsa RECOMMENDED sign Raw RSA Key +%% x509v3-sign-rsa OPTIONAL sign X.509 certificates (RSA key) +%% x509v3-sign-dss OPTIONAL sign X.509 certificates (DSS key) +%% spki-sign-rsa OPTIONAL sign SPKI certificates (RSA key) +%% spki-sign-dss OPTIONAL sign SPKI certificates (DSS key) +%% pgp-sign-rsa OPTIONAL sign OpenPGP certificates (RSA key) +%% pgp-sign-dss OPTIONAL sign OpenPGP certificates (DSS key) +%% + +%% key exchange +%% +%% diffie-hellman-group1-sha1 REQUIRED +%% +%% + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Encryption +%% +%% chiphers +%% +%% 3des-cbc REQUIRED +%% three-key 3DES in CBC mode +%% blowfish-cbc OPTIONAL Blowfish in CBC mode +%% twofish256-cbc OPTIONAL Twofish in CBC mode, +%% with 256-bit key +%% twofish-cbc OPTIONAL alias for "twofish256-cbc" (this +%% is being retained for +%% historical reasons) +%% twofish192-cbc OPTIONAL Twofish with 192-bit key +%% twofish128-cbc OPTIONAL Twofish with 128-bit key +%% aes256-cbc OPTIONAL AES in CBC mode, +%% with 256-bit key +%% aes192-cbc OPTIONAL AES with 192-bit key +%% aes128-cbc RECOMMENDED AES with 128-bit key +%% serpent256-cbc OPTIONAL Serpent in CBC mode, with +%% 256-bit key +%% serpent192-cbc OPTIONAL Serpent with 192-bit key +%% serpent128-cbc OPTIONAL Serpent with 128-bit key +%% arcfour OPTIONAL the ARCFOUR stream cipher +%% idea-cbc OPTIONAL IDEA in CBC mode +%% cast128-cbc OPTIONAL CAST-128 in CBC mode +%% none OPTIONAL no encryption; NOT RECOMMENDED +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +encrypt_init(#ssh{encrypt = none} = Ssh) -> + {ok, Ssh}; +encrypt_init(#ssh{encrypt = '3des-cbc', role = client} = Ssh) -> + IV = hash(Ssh, "A", 64), + <<K1:8/binary, K2:8/binary, K3:8/binary>> = hash(Ssh, "C", 192), + {ok, Ssh#ssh{encrypt_keys = {K1,K2,K3}, + encrypt_block_size = 8, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = '3des-cbc', role = server} = Ssh) -> + IV = hash(Ssh, "B", 64), + <<K1:8/binary, K2:8/binary, K3:8/binary>> = hash(Ssh, "D", 192), + {ok, Ssh#ssh{encrypt_keys = {K1,K2,K3}, + encrypt_block_size = 8, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = 'aes128-cbc', role = client} = Ssh) -> + IV = hash(Ssh, "A", 128), + <<K:16/binary>> = hash(Ssh, "C", 128), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}; +encrypt_init(#ssh{encrypt = 'aes128-cbc', role = server} = Ssh) -> + IV = hash(Ssh, "B", 128), + <<K:16/binary>> = hash(Ssh, "D", 128), + {ok, Ssh#ssh{encrypt_keys = K, + encrypt_block_size = 16, + encrypt_ctx = IV}}. + +encrypt_final(Ssh) -> + {ok, Ssh#ssh{encrypt = none, + encrypt_keys = undefined, + encrypt_block_size = 8, + encrypt_ctx = undefined + }}. + +encrypt(#ssh{encrypt = none} = Ssh, Data) -> + {Ssh, Data}; +encrypt(#ssh{encrypt = '3des-cbc', + encrypt_keys = {K1,K2,K3}, + encrypt_ctx = IV0} = Ssh, Data) -> + %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K1=~p, K2=~p, K3=~p ~n", + %% [IV0,K1,K2,K3]), + Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data), + %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]), + IV = crypto:des_cbc_ivec(Enc), + {Ssh#ssh{encrypt_ctx = IV}, Enc}; +encrypt(#ssh{encrypt = 'aes128-cbc', + encrypt_keys = K, + encrypt_ctx = IV0} = Ssh, Data) -> + %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K=~p ~n", + %% [IV0,K]), + Enc = crypto:aes_cbc_128_encrypt(K,IV0,Data), + %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]), + IV = crypto:aes_cbc_ivec(Enc), + {Ssh#ssh{encrypt_ctx = IV}, Enc}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Decryption +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +decrypt_init(#ssh{decrypt = none} = Ssh) -> + {ok, Ssh}; +decrypt_init(#ssh{decrypt = '3des-cbc', role = client} = Ssh) -> + {IV, KD} = {hash(Ssh, "B", 64), + hash(Ssh, "D", 192)}, + <<K1:8/binary, K2:8/binary, K3:8/binary>> = KD, + {ok, Ssh#ssh{decrypt_keys = {K1,K2,K3}, decrypt_ctx = IV, + decrypt_block_size = 8}}; +decrypt_init(#ssh{decrypt = '3des-cbc', role = server} = Ssh) -> + {IV, KD} = {hash(Ssh, "A", 64), + hash(Ssh, "C", 192)}, + <<K1:8/binary, K2:8/binary, K3:8/binary>> = KD, + {ok, Ssh#ssh{decrypt_keys = {K1, K2, K3}, decrypt_ctx = IV, + decrypt_block_size = 8}}; +decrypt_init(#ssh{decrypt = 'aes128-cbc', role = client} = Ssh) -> + {IV, KD} = {hash(Ssh, "B", 128), + hash(Ssh, "D", 128)}, + <<K:16/binary>> = KD, + {ok, Ssh#ssh{decrypt_keys = K, decrypt_ctx = IV, + decrypt_block_size = 16}}; +decrypt_init(#ssh{decrypt = 'aes128-cbc', role = server} = Ssh) -> + {IV, KD} = {hash(Ssh, "A", 128), + hash(Ssh, "C", 128)}, + <<K:16/binary>> = KD, + {ok, Ssh#ssh{decrypt_keys = K, decrypt_ctx = IV, + decrypt_block_size = 16}}. + + +decrypt_final(Ssh) -> + {ok, Ssh#ssh {decrypt = none, + decrypt_keys = undefined, + decrypt_ctx = undefined, + decrypt_block_size = 8}}. + +decrypt(#ssh{decrypt = none} = Ssh, Data) -> + {Ssh, Data}; +decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys, + decrypt_ctx = IV0} = Ssh, Data) -> + {K1, K2, K3} = Keys, + %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p K1=~p, K2=~p, K3=~p ~n", + %%[IV0,K1,K2,K3]), + Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data), + %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]), + IV = crypto:des_cbc_ivec(Data), + {Ssh#ssh{decrypt_ctx = IV}, Dec}; +decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key, + decrypt_ctx = IV0} = Ssh, Data) -> + %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p Key=~p ~n", + %% [IV0,Key]), + Dec = crypto:aes_cbc_128_decrypt(Key,IV0,Data), + %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]), + IV = crypto:aes_cbc_ivec(Data), + {Ssh#ssh{decrypt_ctx = IV}, Dec}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Compression +%% +%% none REQUIRED no compression +%% zlib OPTIONAL ZLIB (LZ77) compression +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +compress_init(SSH) -> + compress_init(SSH, 1). + +compress_init(#ssh{compress = none} = Ssh, _) -> + {ok, Ssh}; +compress_init(#ssh{compress = zlib} = Ssh, Level) -> + Zlib = zlib:open(), + ok = zlib:deflateInit(Zlib, Level), + {ok, Ssh#ssh{compress_ctx = Zlib}}. + + +compress_final(#ssh{compress = none} = Ssh) -> + {ok, Ssh}; +compress_final(#ssh{compress = zlib, compress_ctx = Context} = Ssh) -> + zlib:close(Context), + {ok, Ssh#ssh{compress = none, compress_ctx = undefined}}. + +compress(#ssh{compress = none} = Ssh, Data) -> + {Ssh, Data}; +compress(#ssh{compress = zlib, compress_ctx = Context} = Ssh, Data) -> + Compressed = zlib:deflate(Context, Data, sync), + %%?dbg(?DBG_ZLIB, "deflate: ~p -> ~p ~n", [Data, Compressed]), + {Ssh, list_to_binary(Compressed)}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Decompression +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +decompress_init(#ssh{decompress = none} = Ssh) -> + {ok, Ssh}; +decompress_init(#ssh{decompress = zlib} = Ssh) -> + Zlib = zlib:open(), + ok = zlib:inflateInit(Zlib), + {ok, Ssh#ssh{decompress_ctx = Zlib}}. + +decompress_final(#ssh{decompress = none} = Ssh) -> + {ok, Ssh}; +decompress_final(#ssh{decompress = zlib, decompress_ctx = Context} = Ssh) -> + zlib:close(Context), + {ok, Ssh#ssh{decompress = none, decompress_ctx = undefined}}. + +decompress(#ssh{decompress = none} = Ssh, Data) -> + {Ssh, Data}; +decompress(#ssh{decompress = zlib, decompress_ctx = Context} = Ssh, Data) -> + Decompressed = zlib:inflate(Context, Data), + %%?dbg(?DBG_ZLIB, "inflate: ~p -> ~p ~n", [Data, Decompressed]), + {Ssh, list_to_binary(Decompressed)}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% MAC calculation +%% +%% hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key +%% length = 20) +%% hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest +%% length = 12, key length = 20) +%% hmac-md5 OPTIONAL HMAC-MD5 (digest length = key +%% length = 16) +%% hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest +%% length = 12, key length = 16) +%% none OPTIONAL no MAC; NOT RECOMMENDED +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +send_mac_init(SSH) -> + case SSH#ssh.role of + client -> + KeySize =mac_key_size(SSH#ssh.send_mac), + Key = hash(SSH, "E", KeySize), + {ok, SSH#ssh { send_mac_key = Key }}; + server -> + KeySize = mac_key_size(SSH#ssh.send_mac), + Key = hash(SSH, "F", KeySize), + {ok, SSH#ssh { send_mac_key = Key }} + end. + +send_mac_final(SSH) -> + {ok, SSH#ssh { send_mac = none, send_mac_key = undefined }}. + +recv_mac_init(SSH) -> + case SSH#ssh.role of + client -> + Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)), + {ok, SSH#ssh { recv_mac_key = Key }}; + server -> + Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)), + {ok, SSH#ssh { recv_mac_key = Key }} + end. + +recv_mac_final(SSH) -> + {ok, SSH#ssh { recv_mac = none, recv_mac_key = undefined }}. + +mac(none, _ , _, _) -> + <<>>; +mac('hmac-sha1', Key, SeqNum, Data) -> + crypto:sha_mac(Key, [<<?UINT32(SeqNum)>>, Data]); +mac('hmac-sha1-96', Key, SeqNum, Data) -> + crypto:sha_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]); +mac('hmac-md5', Key, SeqNum, Data) -> + crypto:md5_mac(Key, [<<?UINT32(SeqNum)>>, Data]); +mac('hmac-md5-96', Key, SeqNum, Data) -> + crypto:md5_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]). + +%% return N hash bytes (HASH) +hash(SSH, Char, Bits) -> + HASH = + case SSH#ssh.kex of + 'diffie-hellman-group1-sha1' -> + fun(Data) -> crypto:sha(Data) end; + 'diffie-hellman-group-exchange-sha1' -> + fun(Data) -> crypto:sha(Data) end; + _ -> + exit({bad_algorithm,SSH#ssh.kex}) + end, + hash(SSH, Char, Bits, HASH). + +hash(_SSH, _Char, 0, _HASH) -> + <<>>; +hash(SSH, Char, N, HASH) -> + K = ssh_bits:mpint(SSH#ssh.shared_secret), + H = SSH#ssh.exchanged_hash, + SessionID = SSH#ssh.session_id, + K1 = HASH([K, H, Char, SessionID]), + Sz = N div 8, + <<Key:Sz/binary, _/binary>> = hash(K, H, K1, N-128, HASH), + %%?dbg(?DBG_KEX, "Key ~s: ~s ~n", [Char, fmt_binary(Key, 16, 4)]), + Key. + +hash(_K, _H, Ki, N, _HASH) when N =< 0 -> + Ki; +hash(K, H, Ki, N, HASH) -> + Kj = HASH([K, H, Ki]), + hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH). + +kex_h(SSH, K_S, E, F, K) -> + L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version, + SSH#ssh.c_keyinit, SSH#ssh.s_keyinit, + K_S, E,F,K], + [string,string,binary,binary,binary, + mpint,mpint,mpint]), + crypto:sha(L). + +kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> + L = if Min==-1; Max==-1 -> + Ts = [string,string,binary,binary,binary, + uint32, + mpint,mpint,mpint,mpint,mpint], + ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, + SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, + K_S, NBits, Prime, Gen, E,F,K], + Ts); + true -> + Ts = [string,string,binary,binary,binary, + uint32,uint32,uint32, + mpint,mpint,mpint,mpint,mpint], + ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, + SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, + K_S, Min, NBits, Max, + Prime, Gen, E,F,K], Ts) + end, + crypto:sha(L). + +mac_key_size('hmac-sha1') -> 20*8; +mac_key_size('hmac-sha1-96') -> 20*8; +mac_key_size('hmac-md5') -> 16*8; +mac_key_size('hmac-md5-96') -> 16*8; +mac_key_size(none) -> 0. + +mac_digest_size('hmac-sha1') -> 20; +mac_digest_size('hmac-sha1-96') -> 12; +mac_digest_size('hmac-md5') -> 20; +mac_digest_size('hmac-md5-96') -> 12; +mac_digest_size(none) -> 0. + +peer_name({Host, _}) -> + Host. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Diffie-Hellman utils +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +dh_group1() -> + {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}. + +dh_gen_key(G, P, _Bits) -> + Private = ssh_bits:irandom(ssh_bits:isize(P)-1, 1, 1), + Public = ssh_math:ipow(G, Private, P), + {Private,Public}. + +%% trim(Str) -> +%% lists:reverse(trim_head(lists:reverse(trim_head(Str)))). + +trim_tail(Str) -> + lists:reverse(trim_head(lists:reverse(Str))). + +trim_head([$\s|Cs]) -> trim_head(Cs); +trim_head([$\t|Cs]) -> trim_head(Cs); +trim_head([$\n|Cs]) -> trim_head(Cs); +trim_head([$\r|Cs]) -> trim_head(Cs); +trim_head(Cs) -> Cs. + +%% Retrieve session_id from ssh, needed by public-key auth +%get_session_id(SSH) -> +% {ok, SessionID} = call(SSH, get_session_id), + +%% DEBUG utils +%% Format integers and binaries as hex blocks +%% +%% -ifdef(debug). +%% fmt_binary(B, BlockSize, GroupSize) -> +%% fmt_block(fmt_bin(B), BlockSize, GroupSize). + +%% fmt_block(Bin, BlockSize, GroupSize) -> +%% fmt_block(Bin, BlockSize, 0, GroupSize). + + +%% fmt_block(Bin, 0, _I, _G) -> +%% binary_to_list(Bin); +%% fmt_block(Bin, Sz, G, G) when G =/= 0 -> +%% ["~n#" | fmt_block(Bin, Sz, 0, G)]; +%% fmt_block(Bin, Sz, I, G) -> +%% case Bin of +%% <<Block:Sz/binary, Tail/binary>> -> +%% if Tail == <<>> -> +%% [binary_to_list(Block)]; +%% true -> +%% [binary_to_list(Block), " " | fmt_block(Tail, Sz, I+1, G)] +%% end; +%% <<>> -> +%% []; +%% _ -> +%% [binary_to_list(Bin)] +%% end. + +%% %% Format integer or binary as hex +%% fmt_bin(X) when integer(X) -> +%% list_to_binary(io_lib:format("~p", [X])); +%% fmt_bin(X) when binary(X) -> +%% Sz = size(X)*8, +%% <<Y:Sz/unsigned-big>> = X, +%% %%Fmt = "~"++integer_to_list(size(X)*2)++"~p", +%% list_to_binary(io_lib:format("~p", [Y])). + +%% -endif. + diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl new file mode 100644 index 0000000000..18a23f0533 --- /dev/null +++ b/lib/ssh/src/ssh_transport.hrl @@ -0,0 +1,235 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Record and constant defenitions for the SSH-tansport layer +%% protocol see RFC 4253 +%%---------------------------------------------------------------------- + +-ifndef(ssh_transport). +-define(ssh_transport, true). + +-define(DEFAULT_CLIENT_VERSION, {2, 0}). +-define(DEFAULT_SERVER_VERSION, {2, 0}). +-define(DEFAULT_DH_GROUP_MIN, 512). +-define(DEFAULT_DH_GROUP_NBITS, 1024). +-define(DEFAULT_DH_GROUP_MAX, 4096). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% BASIC transport messages +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(SSH_MSG_DISCONNECT, 1). +-define(SSH_MSG_IGNORE, 2). +-define(SSH_MSG_UNIMPLEMENTED, 3). +-define(SSH_MSG_DEBUG, 4). +-define(SSH_MSG_SERVICE_REQUEST, 5). +-define(SSH_MSG_SERVICE_ACCEPT, 6). + +-define(SSH_MSG_KEXINIT, 20). +-define(SSH_MSG_NEWKEYS, 21). + + +-record(ssh_msg_disconnect, + { + code, %% uint32 + description, %% string + language %% string + }). + +-record(ssh_msg_ignore, + { + data %% string + }). + +-record(ssh_msg_unimplemented, + { + sequence %% uint32 + }). + +-record(ssh_msg_debug, + { + always_display, %% boolean + message, %% string + language %% string + }). + + +-record(ssh_msg_service_request, + { + name %% string (service name) + }). + +-record(ssh_msg_service_accept, + { + name %% string + }). + +-record(ssh_msg_kexinit, + { + cookie, %% random(16) + kex_algorithms, %% string + server_host_key_algorithms, %% string + encryption_algorithms_client_to_server, %% string + encryption_algorithms_server_to_client, %% string + mac_algorithms_client_to_server, %% string + mac_algorithms_server_to_client, %% string + compression_algorithms_client_to_server, %% string + compression_algorithms_server_to_client, %% string + languages_client_to_server, %% string + languages_server_to_client, %% string + first_kex_packet_follows=false, %% boolean + %% (reserved for future extension) + reserved=0 %% uint32=0 + }). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% KEY DH messages +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% diffie-hellman-group1-sha1 +-define(SSH_MSG_KEXDH_INIT, 30). +-define(SSH_MSG_KEXDH_REPLY, 31). + +-record(ssh_msg_kexdh_init, + { + e %% mpint + }). + +-record(ssh_msg_kexdh_reply, + { + public_host_key, %% string (K_S) + f, %% mpint + h_sig %% string, signature of H + }). + +-record(ssh_msg_newkeys, + {}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% KEY DH GEX messages +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% diffie-hellman-group-exchange-sha1 +-define(SSH_MSG_KEX_DH_GEX_REQUEST_OLD, 30). +-define(SSH_MSG_KEX_DH_GEX_REQUEST, 34). +-define(SSH_MSG_KEX_DH_GEX_GROUP, 31). +-define(SSH_MSG_KEX_DH_GEX_INIT, 32). +-define(SSH_MSG_KEX_DH_GEX_REPLY, 33). + +-record(ssh_msg_kex_dh_gex_request, + { + min, + n, + max + }). + +-record(ssh_msg_kex_dh_gex_request_old, + { + n + }). + +-record(ssh_msg_kex_dh_gex_group, + { + p, %% prime + g %% generator + }). + +-record(ssh_msg_kex_dh_gex_init, + { + e + }). + +-record(ssh_msg_kex_dh_gex_reply, + { + public_host_key, %% string (K_S) + f, + h_sig + }). + +%% error codes +-define(SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, 1). +-define(SSH_DISCONNECT_PROTOCOL_ERROR, 2). +-define(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 3). +-define(SSH_DISCONNECT_RESERVED, 4). +-define(SSH_DISCONNECT_MAC_ERROR, 5). +-define(SSH_DISCONNECT_COMPRESSION_ERROR, 6). +-define(SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, 7). +-define(SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, 8). +-define(SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 9). +-define(SSH_DISCONNECT_CONNECTION_LOST, 10). +-define(SSH_DISCONNECT_BY_APPLICATION, 11). +-define(SSH_DISCONNECT_TOO_MANY_CONNECTIONS, 12). +-define(SSH_DISCONNECT_AUTH_CANCELLED_BY_USER, 13). +-define(SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 14). +-define(SSH_DISCONNECT_ILLEGAL_USER_NAME, 15). + + +%%%---------------------------------------------------------------------- +%%% # DH_14_xxx +%%% Description: Oakley group 14 prime numbers and generator. Used in +%%% diffie-hellman-group1-sha1 key exchange method. +%%%---------------------------------------------------------------------- +%%%---------------------------------------------------------------------- +%%% # DH_14_P +%%% Description: Prime for this group +%%%---------------------------------------------------------------------- + +-define(DH_14_P, + <<000,000,000,129,000,255,255,255,255,255,255,255,255,201,015,218, + 162,033,104,194,052,196,198,098,139,128,220,028,209,041,002,078, + 008,138,103,204,116,002,011,190,166,059,019,155,034,081,074,008, + 121,142,052,004,221,239,149,025,179,205,058,067,027,048,043,010, + 109,242,095,020,055,079,225,053,109,109,081,194,069,228,133,181, + 118,098,094,126,198,244,076,066,233,166,055,237,107,011,255,092, + 182,244,006,183,237,238,056,107,251,090,137,159,165,174,159,036, + 017,124,075,031,230,073,040,102,081,236,230,083,129,255,255,255, + 255,255,255,255,255>>). + +%%%---------------------------------------------------------------------- +%%% # DH_14_G +%%% Description: Generator for DH_14_P. +%%%---------------------------------------------------------------------- + +-define(DH_14_G, <<0,0,0,1,2>>). + +%%%---------------------------------------------------------------------- +%%% # DH_14_Q +%%% Description: Group order (DH_14_P - 1) / 2. +%%%---------------------------------------------------------------------- + +-define(DH_14_Q, + <<000,000,000,128,127,255,255,255,255,255,255,255,228,135,237,081, + 016,180,097,026,098,099,049,069,192,110,014,104,148,129,039,004, + 069,051,230,058,001,005,223,083,029,137,205,145,040,165,004,060, + 199,026,002,110,247,202,140,217,230,157,033,141,152,021,133,054, + 249,047,138,027,167,240,154,182,182,168,225,034,242,066,218,187, + 049,047,063,099,122,038,033,116,211,027,246,181,133,255,174,091, + 122,003,091,246,247,028,053,253,173,068,207,210,215,079,146,008, + 190,037,143,243,036,148,051,040,246,115,041,192,255,255,255,255, + 255,255,255,255>>). + +-endif. % -ifdef(ssh_transport). diff --git a/lib/ssh/src/ssh_userauth.hrl b/lib/ssh/src/ssh_userauth.hrl new file mode 100755 index 0000000000..39cc032ca5 --- /dev/null +++ b/lib/ssh/src/ssh_userauth.hrl @@ -0,0 +1,77 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: user authentication protocol + +-define(SSH_MSG_USERAUTH_REQUEST, 50). +-define(SSH_MSG_USERAUTH_FAILURE, 51). +-define(SSH_MSG_USERAUTH_SUCCESS, 52). +-define(SSH_MSG_USERAUTH_BANNER, 53). +-define(SSH_MSG_USERAUTH_PK_OK, 60). +-define(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 60). +-define(SSH_MSG_USERAUTH_INFO_REQUEST, 60). +-define(SSH_MSG_USERAUTH_INFO_RESPONSE, 61). + +-record(ssh_msg_userauth_request, + { + user, %% string + service, %% string + method, %% string "publickey", "password" + data %% opaque + }). + +-record(ssh_msg_userauth_failure, + { + authentications, %% string + partial_success %% boolean + }). + +-record(ssh_msg_userauth_success, + { + }). + +-record(ssh_msg_userauth_banner, + { + message, %% string + language %% string + }). + +-record(ssh_msg_userauth_passwd_changereq, + { + prompt, %% string + languge %% string + }). + +-record(ssh_msg_userauth_pk_ok, + { + algorithm_name, % string + key_blob % string + }). + +-record(ssh_msg_userauth_info_request, + {name, + instruction, + language_tag, + num_prompts, + data}). +-record(ssh_msg_userauth_info_response, + {num_responses, + data}). diff --git a/lib/ssh/src/ssh_userreg.erl b/lib/ssh/src/ssh_userreg.erl new file mode 100644 index 0000000000..06f4076b51 --- /dev/null +++ b/lib/ssh/src/ssh_userreg.erl @@ -0,0 +1,127 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Description: User register for ssh_cli + +-module(ssh_userreg). + +-behaviour(gen_server). + +%% API +-export([start_link/0, register_user/2, lookup_user/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-record(state, {user_db = []}). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +register_user(User, Cm) -> + gen_server:cast(?MODULE, {register, {User, Cm}}). + +lookup_user(Cm) -> + gen_server:call(?MODULE, {get_user, Cm}, infinity). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([]) -> + {ok, #state{}}. + +%%-------------------------------------------------------------------- +%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% Description: Handling call messages +%%-------------------------------------------------------------------- +handle_call({get_user, Cm}, _From, #state{user_db = Db} = State) -> + User = lookup(Cm, Db), + {reply, {ok, User}, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast({register, UserCm}, State0) -> + State = insert(UserCm, State0), + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling all non call/cast messages +%%-------------------------------------------------------------------- +handle_info(_Info, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +insert({User, Cm}, #state{user_db = Db} = State) -> + State#state{user_db = [{User, Cm} | Db]}. + +lookup(_, []) -> + undefined; +lookup(Cm, [{User, Cm} | _Rest]) -> + User; +lookup(Cm, [_ | Rest]) -> + lookup(Cm, Rest). + diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl new file mode 100644 index 0000000000..a347a9c095 --- /dev/null +++ b/lib/ssh/src/ssh_xfer.erl @@ -0,0 +1,925 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SFTP functions + +-module(ssh_xfer). + +-export([attach/2, connect/3]). +-export([open/6, opendir/3, readdir/3, close/3, read/5, write/5, + rename/5, remove/3, mkdir/4, rmdir/3, realpath/3, extended/4, + stat/4, fstat/4, lstat/4, setstat/4, + readlink/3, fsetstat/4, symlink/4, + protocol_version_request/1, + xf_reply/2, + xf_send_reply/3, xf_send_names/3, xf_send_name/4, + xf_send_status/3, xf_send_status/4, xf_send_status/5, + xf_send_handle/3, xf_send_attr/3, xf_send_data/3, + encode_erlang_status/1, + decode_open_flags/2, encode_open_flags/1, + decode_ace_mask/1, decode_ext/1, + decode_ATTR/2, encode_ATTR/2]). + +-include("ssh.hrl"). +-include("ssh_xfer.hrl"). + +-import(lists, [foldl/3, reverse/1]). + +-define(is_set(F, Bits), + ((F) band (Bits)) == (F)). + +-define(XFER_PACKET_SIZE, 32768). +-define(XFER_WINDOW_SIZE, 4*?XFER_PACKET_SIZE). + +attach(CM, Opts) -> + open_xfer(CM, Opts). + +connect(Host, Port, Opts) -> + case ssh:connect(Host, Port, Opts) of + {ok, CM} -> open_xfer(CM, Opts); + Error -> Error + end. + +open_xfer(CM, Opts) -> + TMO = proplists:get_value(timeout, Opts, infinity), + case ssh_connection:session_channel(CM, ?XFER_WINDOW_SIZE, ?XFER_PACKET_SIZE, TMO) of + {ok, ChannelId} -> + {ok, ChannelId, CM}; + Error -> + Error + end. + +protocol_version_request(XF) -> + xf_request(XF, ?SSH_FXP_INIT, <<?UINT32(?SSH_SFTP_PROTOCOL_VERSION)>>). + +open(XF, ReqID, FileName, Access, Flags, Attrs) -> + Vsn = XF#ssh_xfer.vsn, + FileName1 = list_to_binary(FileName), + MBits = if Vsn >= 5 -> + M = encode_ace_mask(Access), + ?uint32(M); + true -> + (<<>>) + end, + F = encode_open_flags(Flags), + xf_request(XF,?SSH_FXP_OPEN, + [?uint32(ReqID), + ?binary(FileName1), + MBits, + ?uint32(F), + encode_ATTR(Vsn,Attrs)]). + +opendir(XF, ReqID, DirName) -> + xf_request(XF, ?SSH_FXP_OPENDIR, + [?uint32(ReqID), + ?string(DirName)]). + + +close(XF, ReqID, Handle) -> + xf_request(XF, ?SSH_FXP_CLOSE, + [?uint32(ReqID), + ?binary(Handle)]). + +read(XF, ReqID, Handle, Offset, Length) -> + xf_request(XF, ?SSH_FXP_READ, + [?uint32(ReqID), + ?binary(Handle), + ?uint64(Offset), + ?uint32(Length)]). + +readdir(XF, ReqID, Handle) -> + xf_request(XF, ?SSH_FXP_READDIR, + [?uint32(ReqID), + ?binary(Handle)]). + +write(XF,ReqID, Handle, Offset, Data) -> + Data1 = if + is_binary(Data) -> + Data; + is_list(Data) -> + list_to_binary(Data) + end, + xf_request(XF,?SSH_FXP_WRITE, + [?uint32(ReqID), + ?binary(Handle), + ?uint64(Offset), + ?binary(Data1)]). + +%% Remove a file +remove(XF, ReqID, File) -> + xf_request(XF, ?SSH_FXP_REMOVE, + [?uint32(ReqID), + ?string(File)]). + +%% Rename a file/directory +rename(XF, ReqID, Old, New, Flags) -> + Vsn = XF#ssh_xfer.vsn, + OldPath = list_to_binary(Old), + NewPath = list_to_binary(New), + FlagBits + = if Vsn >= 5 -> + F0 = encode_rename_flags(Flags), + ?uint32(F0); + true -> + (<<>>) + end, + xf_request(XF, ?SSH_FXP_RENAME, + [?uint32(ReqID), + ?binary(OldPath), + ?binary(NewPath), + FlagBits]). + + + +%% Create directory +mkdir(XF, ReqID, Path, Attrs) -> + Path1 = list_to_binary(Path), + xf_request(XF, ?SSH_FXP_MKDIR, + [?uint32(ReqID), + ?binary(Path1), + encode_ATTR(XF#ssh_xfer.vsn, Attrs)]). + +%% Remove a directory +rmdir(XF, ReqID, Dir) -> + Dir1 = list_to_binary(Dir), + xf_request(XF, ?SSH_FXP_RMDIR, + [?uint32(ReqID), + ?binary(Dir1)]). + +%% Stat file +stat(XF, ReqID, Path, Flags) -> + Path1 = list_to_binary(Path), + Vsn = XF#ssh_xfer.vsn, + AttrFlags = if Vsn >= 5 -> + F = encode_attr_flags(Vsn, Flags), + ?uint32(F); + true -> + [] + end, + xf_request(XF, ?SSH_FXP_STAT, + [?uint32(ReqID), + ?binary(Path1), + AttrFlags]). + + +%% Stat file - follow symbolic links +lstat(XF, ReqID, Path, Flags) -> + Path1 = list_to_binary(Path), + Vsn = XF#ssh_xfer.vsn, + AttrFlags = if Vsn >= 5 -> + F = encode_attr_flags(Vsn, Flags), + ?uint32(F); + true -> + [] + end, + xf_request(XF, ?SSH_FXP_LSTAT, + [?uint32(ReqID), + ?binary(Path1), + AttrFlags]). + +%% Stat open file +fstat(XF, ReqID, Handle, Flags) -> + Vsn = XF#ssh_xfer.vsn, + AttrFlags = if Vsn >= 5 -> + F = encode_attr_flags(Vsn, Flags), + ?uint32(F); + true -> + [] + end, + xf_request(XF, ?SSH_FXP_FSTAT, + [?uint32(ReqID), + ?binary(Handle), + AttrFlags]). + +%% Modify file attributes +setstat(XF, ReqID, Path, Attrs) -> + Path1 = list_to_binary(Path), + xf_request(XF, ?SSH_FXP_SETSTAT, + [?uint32(ReqID), + ?binary(Path1), + encode_ATTR(XF#ssh_xfer.vsn, Attrs)]). + + +%% Modify file attributes +fsetstat(XF, ReqID, Handle, Attrs) -> + xf_request(XF, ?SSH_FXP_FSETSTAT, + [?uint32(ReqID), + ?binary(Handle), + encode_ATTR(XF#ssh_xfer.vsn, Attrs)]). + +%% Read a symbolic link +readlink(XF, ReqID, Path) -> + Path1 = list_to_binary(Path), + xf_request(XF, ?SSH_FXP_READLINK, + [?uint32(ReqID), + ?binary(Path1)]). + + +%% Create a symbolic link +symlink(XF, ReqID, LinkPath, TargetPath) -> + LinkPath1 = list_to_binary(LinkPath), + TargetPath1 = list_to_binary(TargetPath), + xf_request(XF, ?SSH_FXP_SYMLINK, + [?uint32(ReqID), + ?binary(LinkPath1), + ?binary(TargetPath1)]). + +%% Convert a path into a 'canonical' form +realpath(XF, ReqID, Path) -> + Path1 = list_to_binary(Path), + xf_request(XF, ?SSH_FXP_REALPATH, + [?uint32(ReqID), + ?binary(Path1)]). + +extended(XF, ReqID, Request, Data) -> + xf_request(XF, ?SSH_FXP_EXTENDED, + [?uint32(ReqID), + ?string(Request), + ?binary(Data)]). + + +%% Send xfer request to connection manager +xf_request(XF, Op, Arg) -> + CM = XF#ssh_xfer.cm, + Channel = XF#ssh_xfer.channel, + Data = if + is_binary(Arg) -> + Arg; + is_list(Arg) -> + list_to_binary(Arg) + end, + Size = 1+size(Data), + ssh_connection:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>). + +xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) -> + Data = if + is_binary(Arg) -> + Arg; + is_list(Arg) -> + list_to_binary(Arg) + end, + Size = 1 + size(Data), + ssh_connection:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>). + +xf_send_name(XF, ReqId, Name, Attr) -> + xf_send_names(XF, ReqId, [{Name, Attr}]). + + +xf_send_handle(#ssh_xfer{cm = CM, channel = Channel}, + ReqId, Handle) -> + HLen = length(Handle), + Size = 1 + 4 + 4+HLen, + ToSend = [<<?UINT32(Size), ?SSH_FXP_HANDLE, ?UINT32(ReqId), ?UINT32(HLen)>>, + Handle], + ssh_connection:send(CM, Channel, ToSend). + +xf_send_names(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn}, + ReqId, NamesAndAttrs) -> + Count = length(NamesAndAttrs), + {Data, Len} = encode_names(Vsn, NamesAndAttrs), + Size = 1 + 4 + 4 + Len, + ToSend = [<<?UINT32(Size), ?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count)>>, + Data], + %%?dbg(true, "xf_send_names: Size=~p size(ToSend)=~p\n", + %% [Size, size(list_to_binary(ToSend))]), + ssh_connection:send(CM, Channel, ToSend). + +xf_send_status(XF, ReqId, ErrorCode) -> + xf_send_status(XF, ReqId, ErrorCode, ""). + +xf_send_status(XF, ReqId, ErrorCode, ErrorMsg) -> + xf_send_status(XF, ReqId, ErrorCode, ErrorMsg, <<>>). + +xf_send_status(#ssh_xfer{cm = CM, channel = Channel}, + ReqId, ErrorCode, ErrorMsg, Data) -> + LangTag = "en", + ELen = length(ErrorMsg), + TLen = 2, %% length(LangTag), + Size = 1 + 4 + 4 + 4+ELen + 4+TLen + size(Data), + ToSend = [<<?UINT32(Size), ?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(ErrorCode)>>, + <<?UINT32(ELen)>>, ErrorMsg, + <<?UINT32(TLen)>>, LangTag, + Data], + ssh_connection:send(CM, Channel, ToSend). + +xf_send_attr(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn}, ReqId, Attr) -> + EncAttr = encode_ATTR(Vsn, Attr), + ALen = size(EncAttr), + Size = 1 + 4 + ALen, + ToSend = [<<?UINT32(Size), ?SSH_FXP_ATTRS, ?UINT32(ReqId)>>, EncAttr], + ssh_connection:send(CM, Channel, ToSend). + +xf_send_data(#ssh_xfer{cm = CM, channel = Channel}, ReqId, Data) -> + DLen = size(Data), + Size = 1 + 4 + 4+DLen, + ToSend = [<<?UINT32(Size), ?SSH_FXP_DATA, ?UINT32(ReqId), ?UINT32(DLen)>>, + Data], + ssh_connection:send(CM, Channel, ToSend). + +xf_reply(_XF, << ?SSH_FXP_STATUS, ?UINT32(ReqID), ?UINT32(Status), + ?UINT32(ELen), Err:ELen/binary, + ?UINT32(LLen), Lang:LLen/binary, + Reply/binary >> ) -> + Stat = decode_status(Status), + {status, ReqID, {Stat,binary_to_list(Err),binary_to_list(Lang), + Reply}}; +xf_reply(_XF, << ?SSH_FXP_STATUS, ?UINT32(ReqID), ?UINT32(Status)>> ) -> + Stat = decode_status(Status), + {status, ReqID, {Stat,"","",<<>>}}; +xf_reply(_XF, <<?SSH_FXP_HANDLE, ?UINT32(ReqID), + ?UINT32(HLen), Handle:HLen/binary>>) -> + {handle, ReqID, Handle}; +xf_reply(_XF, <<?SSH_FXP_DATA, ?UINT32(ReqID), + ?UINT32(DLen), Data:DLen/binary>>) -> + {data, ReqID, Data}; +xf_reply(XF, <<?SSH_FXP_NAME, ?UINT32(ReqID), + ?UINT32(Count), AData/binary>>) -> + %%?dbg(true, "xf_reply ?SSH_FXP_NAME: AData=~p\n", [AData]), + {name, ReqID, decode_names(XF#ssh_xfer.vsn, Count, AData)}; +xf_reply(XF, <<?SSH_FXP_ATTRS, ?UINT32(ReqID), + AData/binary>>) -> + {A, _} = decode_ATTR(XF#ssh_xfer.vsn, AData), + {attrs, ReqID, A}; +xf_reply(_XF, <<?SSH_FXP_EXTENDED_REPLY, ?UINT32(ReqID), + RData>>) -> + {extended_reply, ReqID, RData}. + + + +decode_status(Status) -> + case Status of + ?SSH_FX_OK -> ok; + ?SSH_FX_EOF -> eof; + ?SSH_FX_NO_SUCH_FILE -> no_such_file; + ?SSH_FX_PERMISSION_DENIED -> permission_denied; + ?SSH_FX_FAILURE -> failure; + ?SSH_FX_BAD_MESSAGE -> bad_message; + ?SSH_FX_NO_CONNECTION -> no_connection; + ?SSH_FX_CONNECTION_LOST -> connection_lost; + ?SSH_FX_OP_UNSUPPORTED -> op_unsupported; + ?SSH_FX_INVALID_HANDLE -> invalid_handle; + ?SSH_FX_NO_SUCH_PATH -> no_such_path; + ?SSH_FX_FILE_ALREADY_EXISTS -> file_already_exists; + ?SSH_FX_WRITE_PROTECT -> write_protect; + ?SSH_FX_NO_MEDIA -> no_media; + ?SSH_FX_NO_SPACE_ON_FILESYSTEM -> no_space_on_filesystem; + ?SSH_FX_QUOTA_EXCEEDED -> quota_exceeded; + ?SSH_FX_UNKNOWN_PRINCIPLE -> unknown_principle; + ?SSH_FX_LOCK_CONFlICT -> lock_conflict; + ?SSH_FX_NOT_A_DIRECTORY -> not_a_directory; + _ -> {error,Status} + end. + +encode_erlang_status(Status) -> + case Status of + ok -> ?SSH_FX_OK; + eof -> ?SSH_FX_EOF; + enoent -> ?SSH_FX_NO_SUCH_FILE; + eacces -> ?SSH_FX_PERMISSION_DENIED; + _ -> ?SSH_FX_FAILURE + end. + +decode_ext(<<?UINT32(NameLen), Name:NameLen/binary, + ?UINT32(DataLen), Data:DataLen/binary, + Tail/binary>>) -> + [{binary_to_list(Name), binary_to_list(Data)} + | decode_ext(Tail)]; +decode_ext(<<>>) -> + []. + +%% +%% Encode rename flags +%% +encode_rename_flags(Flags) -> + encode_bits( + fun(overwrite) -> ?SSH_FXP_RENAME_OVERWRITE; + (atomic) -> ?SSH_FXP_RENAME_ATOMIC; + (native) -> ?SSH_FXP_RENAME_NATIVE + end, Flags). + +%% decode_rename_flags(F) -> +%% decode_bits(F, +%% [{?SSH_FXP_RENAME_OVERWRITE, overwrite}, +%% {?SSH_FXP_RENAME_ATOMIC, atomic}, +%% {?SSH_FXP_RENAME_NATIVE, native}]). + + +encode_open_flags(Flags) -> + encode_bits( + fun (read) -> ?SSH_FXF_READ; + (write) -> ?SSH_FXF_WRITE; + (append) -> ?SSH_FXF_APPEND; + (creat) -> ?SSH_FXF_CREAT; + (trunc) -> ?SSH_FXF_TRUNC; + (excl) -> ?SSH_FXF_EXCL; + (create_new) -> ?SSH_FXF_CREATE_NEW; + (create_truncate) -> ?SSH_FXF_CREATE_TRUNCATE; + (open_existing) -> ?SSH_FXF_OPEN_EXISTING; + (open_or_create) -> ?SSH_FXF_OPEN_OR_CREATE; + (truncate_existing) -> ?SSH_FXF_TRUNCATE_EXISTING; + (append_data) -> ?SSH_FXF_ACCESS_APPEND_DATA; + (append_data_atomic) -> ?SSH_FXF_ACCESS_APPEND_DATA_ATOMIC; + (text_mode) -> ?SSH_FXF_ACCESS_TEXT_MODE; + (read_lock) -> ?SSH_FXF_ACCESS_READ_LOCK; + (write_lock) -> ?SSH_FXF_ACCESS_WRITE_LOCK; + (delete_lock) -> ?SSH_FXF_ACCESS_DELETE_LOCK + end, Flags). + +encode_ace_mask(Access) -> + encode_bits( + fun(read_data) -> ?ACE4_READ_DATA; + (list_directory) -> ?ACE4_LIST_DIRECTORY; + (write_data) -> ?ACE4_WRITE_DATA; + (add_file) -> ?ACE4_ADD_FILE; + (append_data) -> ?ACE4_APPEND_DATA; + (add_subdirectory) -> ?ACE4_ADD_SUBDIRECTORY; + (read_named_attrs) -> ?ACE4_READ_NAMED_ATTRS; + (write_named_attrs) -> ?ACE4_WRITE_NAMED_ATTRS; + (execute) -> ?ACE4_EXECUTE; + (delete_child) -> ?ACE4_DELETE_CHILD; + (read_attributes) -> ?ACE4_READ_ATTRIBUTES; + (write_attributes) -> ?ACE4_WRITE_ATTRIBUTES; + (delete) -> ?ACE4_DELETE; + (read_acl) -> ?ACE4_READ_ACL; + (write_acl) -> ?ACE4_WRITE_ACL; + (write_owner) -> ?ACE4_WRITE_OWNER; + (synchronize) -> ?ACE4_SYNCHRONIZE + end, Access). + +decode_ace_mask(F) -> + decode_bits(F, + [ + {?ACE4_READ_DATA, read_data}, + {?ACE4_LIST_DIRECTORY, list_directory}, + {?ACE4_WRITE_DATA, write_data}, + {?ACE4_ADD_FILE, add_file}, + {?ACE4_APPEND_DATA, append_data}, + {?ACE4_ADD_SUBDIRECTORY, add_subdirectory}, + {?ACE4_READ_NAMED_ATTRS, read_named_attrs}, + {?ACE4_WRITE_NAMED_ATTRS, write_named_attrs}, + {?ACE4_EXECUTE, execute}, + {?ACE4_DELETE_CHILD, delete_child}, + {?ACE4_READ_ATTRIBUTES, read_attributes}, + {?ACE4_WRITE_ATTRIBUTES, write_attributes}, + {?ACE4_DELETE, delete}, + {?ACE4_READ_ACL, read_acl}, + {?ACE4_WRITE_ACL, write_acl}, + {?ACE4_WRITE_OWNER, write_owner}, + {?ACE4_SYNCHRONIZE, synchronize} + ]). + +decode_open_flags(Vsn, F) when Vsn =< 3 -> + decode_bits(F, + [ + {?SSH_FXF_READ, read}, + {?SSH_FXF_WRITE, write}, + {?SSH_FXF_APPEND, append}, + {?SSH_FXF_CREAT, creat}, + {?SSH_FXF_TRUNC, trunc}, + {?SSH_FXF_EXCL, excl} + ]); +decode_open_flags(Vsn, F) when Vsn >= 4 -> + R = decode_bits(F, + [ + {?SSH_FXF_ACCESS_APPEND_DATA, append_data}, + {?SSH_FXF_ACCESS_APPEND_DATA_ATOMIC, append_data_atomic}, + {?SSH_FXF_ACCESS_TEXT_MODE, text_mode}, + {?SSH_FXF_ACCESS_READ_LOCK, read_lock}, + {?SSH_FXF_ACCESS_WRITE_LOCK, write_lock}, + {?SSH_FXF_ACCESS_DELETE_LOCK, delete_lock} + ]), + AD = case F band ?SSH_FXF_ACCESS_DISPOSITION of + ?SSH_FXF_CREATE_NEW -> create_new; + ?SSH_FXF_CREATE_TRUNCATE -> create_truncate; + ?SSH_FXF_OPEN_EXISTING -> open_existing; + ?SSH_FXF_OPEN_OR_CREATE -> open_or_create; + ?SSH_FXF_TRUNCATE_EXISTING -> truncate_existing + end, + [AD | R]. + +encode_ace_type(Type) -> + case Type of + access_allowed -> ?ACE4_ACCESS_ALLOWED_ACE_TYPE; + access_denied -> ?ACE4_ACCESS_DENIED_ACE_TYPE; + system_audit -> ?ACE4_SYSTEM_AUDIT_ACE_TYPE; + system_alarm -> ?ACE4_SYSTEM_ALARM_ACE_TYPE + end. + +decode_ace_type(F) -> + case F of + ?ACE4_ACCESS_ALLOWED_ACE_TYPE -> access_allowed; + ?ACE4_ACCESS_DENIED_ACE_TYPE -> access_denied; + ?ACE4_SYSTEM_AUDIT_ACE_TYPE -> system_audit; + ?ACE4_SYSTEM_ALARM_ACE_TYPE -> system_alarm + end. + +encode_ace_flag(Flag) -> + encode_bits( + fun(file_inherit) -> ?ACE4_FILE_INHERIT_ACE; + (directory_inherit) -> ?ACE4_DIRECTORY_INHERIT_ACE; + (no_propagte_inherit) -> ?ACE4_NO_PROPAGATE_INHERIT_ACE; + (inherit_only) -> ?ACE4_INHERIT_ONLY_ACE; + (successful_access) -> ?ACE4_SUCCESSFUL_ACCESS_ACE_FLAG; + (failed_access) -> ?ACE4_FAILED_ACCESS_ACE_FLAG; + (identifier_group) -> ?ACE4_IDENTIFIER_GROUP + end, Flag). + +decode_ace_flag(F) -> + decode_bits(F, + [ + {?ACE4_FILE_INHERIT_ACE, file_inherit}, + {?ACE4_DIRECTORY_INHERIT_ACE, directory_inherit}, + {?ACE4_NO_PROPAGATE_INHERIT_ACE, no_propagte_inherit}, + {?ACE4_INHERIT_ONLY_ACE, inherit_only}, + {?ACE4_SUCCESSFUL_ACCESS_ACE_FLAG, successful_access}, + {?ACE4_FAILED_ACCESS_ACE_FLAG, failed_access}, + {?ACE4_IDENTIFIER_GROUP, identifier_group} + ]). + +encode_attr_flags(Vsn, all) -> + encode_attr_flags(Vsn, + [size, uidgid, permissions, + acmodtime, accesstime, createtime, + modifytime, acl, ownergroup, subsecond_times, + bits, extended]); +encode_attr_flags(Vsn, Flags) -> + encode_bits( + fun(size) -> ?SSH_FILEXFER_ATTR_SIZE; + (uidgid) when Vsn =<3 -> ?SSH_FILEXFER_ATTR_UIDGID; + (permissions) -> ?SSH_FILEXFER_ATTR_PERMISSIONS; + (acmodtime) when Vsn =< 3 -> ?SSH_FILEXFER_ATTR_ACMODTIME; + (accesstime) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_ACCESSTIME; + (createtime) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_CREATETIME; + (modifytime) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_MODIFYTIME; + (acl) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_ACL; + (ownergroup) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_OWNERGROUP; + (subsecond_times) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_SUBSECOND_TIMES; + (bits) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_BITS; + (extended) when Vsn >= 5 -> ?SSH_FILEXFER_ATTR_EXTENDED; + (_) -> 0 + end, Flags). + +encode_file_type(Type) -> + %%?dbg(true, "encode_file_type(~p)\n", [Type]), + case Type of + regular -> ?SSH_FILEXFER_TYPE_REGULAR; + directory -> ?SSH_FILEXFER_TYPE_DIRECTORY; + symlink -> ?SSH_FILEXFER_TYPE_SYMLINK; + special -> ?SSH_FILEXFER_TYPE_SPECIAL; + unknown -> ?SSH_FILEXFER_TYPE_UNKNOWN; + other -> ?SSH_FILEXFER_TYPE_UNKNOWN; + socket -> ?SSH_FILEXFER_TYPE_SOCKET; + char_device -> ?SSH_FILEXFER_TYPE_CHAR_DEVICE; + block_device -> ?SSH_FILEXFER_TYPE_BLOCK_DEVICE; + fifo -> ?SSH_FILEXFER_TYPE_FIFO; + undefined -> ?SSH_FILEXFER_TYPE_UNKNOWN + end. + +decode_file_type(Type) -> + case Type of + ?SSH_FILEXFER_TYPE_REGULAR -> regular; + ?SSH_FILEXFER_TYPE_DIRECTORY -> directory; + ?SSH_FILEXFER_TYPE_SYMLINK -> symlink; + ?SSH_FILEXFER_TYPE_SPECIAL -> special; + ?SSH_FILEXFER_TYPE_UNKNOWN -> other; % unknown + ?SSH_FILEXFER_TYPE_SOCKET -> socket; + ?SSH_FILEXFER_TYPE_CHAR_DEVICE -> char_device; + ?SSH_FILEXFER_TYPE_BLOCK_DEVICE -> block_device; + ?SSH_FILEXFER_TYPE_FIFO -> fifo + end. + +encode_attrib_bits(Bits) -> + encode_bits( + fun(readonly) -> ?SSH_FILEXFER_ATTR_FLAGS_READONLY; + (system) -> ?SSH_FILEXFER_ATTR_FLAGS_SYSTEM; + (hidden) -> ?SSH_FILEXFER_ATTR_FLAGS_HIDDEN; + (case_insensitive) -> ?SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE; + (arcive) -> ?SSH_FILEXFER_ATTR_FLAGS_ARCHIVE; + (encrypted) -> ?SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED; + (compressed) -> ?SSH_FILEXFER_ATTR_FLAGS_COMPRESSED; + (sparse) -> ?SSH_FILEXFER_ATTR_FLAGS_SPARSE; + (append_only) -> ?SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY; + (immutable) -> ?SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE; + (sync) -> ?SSH_FILEXFER_ATTR_FLAGS_SYNC + end, Bits). + +decode_attrib_bits(F) -> + decode_bits(F, + [{?SSH_FILEXFER_ATTR_FLAGS_READONLY, readonly}, + {?SSH_FILEXFER_ATTR_FLAGS_SYSTEM, system}, + {?SSH_FILEXFER_ATTR_FLAGS_HIDDEN, hidden}, + {?SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE, case_insensitive}, + {?SSH_FILEXFER_ATTR_FLAGS_ARCHIVE, arcive}, + {?SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED, encrypted}, + {?SSH_FILEXFER_ATTR_FLAGS_COMPRESSED, compressed}, + {?SSH_FILEXFER_ATTR_FLAGS_SPARSE, sparse}, + {?SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY, append_only}, + {?SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE, immutable}, + {?SSH_FILEXFER_ATTR_FLAGS_SYNC, sync}]). + + +%% +%% Encode file attributes +%% +encode_ATTR(Vsn, A) -> + {Flags,As} = + encode_As(Vsn, + [{size, A#ssh_xfer_attr.size}, + {ownergroup, A#ssh_xfer_attr.owner}, + {ownergroup, A#ssh_xfer_attr.group}, + {permissions, A#ssh_xfer_attr.permissions}, + {acmodtime, A#ssh_xfer_attr.atime}, + {acmodtime, A#ssh_xfer_attr.mtime}, + {accesstime, A#ssh_xfer_attr.atime}, + {subsecond_times, A#ssh_xfer_attr.atime_nseconds}, + {createtime, A#ssh_xfer_attr.createtime}, + {subsecond_times, A#ssh_xfer_attr.createtime_nseconds}, + {modifytime, A#ssh_xfer_attr.mtime}, + {subsecond_times, A#ssh_xfer_attr.mtime_nseconds}, + {acl, A#ssh_xfer_attr.acl}, + {bits, A#ssh_xfer_attr.attrib_bits}, + {extended, A#ssh_xfer_attr.extensions}], + 0, []), + Type = encode_file_type(A#ssh_xfer_attr.type), + %%?dbg(true, "encode_ATTR: Vsn=~p A=~p As=~p Flags=~p Type=~p", + %% [Vsn, A, As, Flags, Type]), + Result = list_to_binary([?uint32(Flags), + if Vsn >= 5 -> + ?byte(Type); + true -> + (<<>>) + end, As]), + %% ?dbg(true, " Result=~p\n", [Result]), + Result. + + +encode_As(Vsn, [{_AName, undefined}|As], Flags, Acc) -> + encode_As(Vsn, As, Flags, Acc); +encode_As(Vsn, [{AName, X}|As], Flags, Acc) -> + case AName of + size -> + encode_As(Vsn, As,Flags bor ?SSH_FILEXFER_ATTR_SIZE, + [?uint64(X) | Acc]); + ownergroup when Vsn=<4 -> + encode_As(Vsn, As,Flags bor ?SSH_FILEXFER_ATTR_UIDGID, + [?uint32(X) | Acc]); + ownergroup when Vsn>=5 -> + X1 = list_to_binary(integer_to_list(X)), % TODO: check owner and group + encode_As(Vsn, As,Flags bor ?SSH_FILEXFER_ATTR_OWNERGROUP, + [?binary(X1) | Acc]); + permissions -> + encode_As(Vsn, As,Flags bor ?SSH_FILEXFER_ATTR_PERMISSIONS, + [?uint32(X) | Acc]); + acmodtime when Vsn=<3 -> + encode_As(Vsn, As,Flags bor ?SSH_FILEXFER_ATTR_ACMODTIME, + [?uint32(X) | Acc]); + accesstime when Vsn>=5 -> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_ACCESSTIME, + [?uint64(X) | Acc]); + createtime when Vsn>=5-> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_CREATETIME, + [?uint64(X) | Acc]); + modifytime when Vsn>=5 -> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_MODIFYTIME, + [?uint64(X) | Acc]); + subsecond_times when Vsn>=5 -> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_SUBSECOND_TIMES, + [?uint64(X) | Acc]); + acl when Vsn >=5 -> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_ACL, + [encode_acl(X) | Acc]); + bits when Vsn>=5 -> + F = encode_attrib_bits(X), + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_BITS, + [?uint32(F) | Acc]); + extended -> + encode_As(Vsn, As, Flags bor ?SSH_FILEXFER_ATTR_EXTENDED, + [encode_extensions(X) | Acc]); + _ -> + encode_As(Vsn, As, Flags, Acc) + end; +encode_As(_Vsn, [], Flags, Acc) -> + {Flags, reverse(Acc)}. + + +decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) -> + %%?dbg(true, "decode_ATTR: Vsn=~p Flags=~p Tail=~p\n", [Vsn, Flags, Tail]), + {Type,Tail2} = + if Vsn =< 3 -> + {?SSH_FILEXFER_TYPE_UNKNOWN, Tail}; + Vsn >= 5 -> + <<?BYTE(T), TL/binary>> = Tail, + {T, TL} + end, + decode_As(Vsn, + [{size, #ssh_xfer_attr.size}, + {ownergroup, #ssh_xfer_attr.owner}, + {ownergroup, #ssh_xfer_attr.group}, + {permissions, #ssh_xfer_attr.permissions}, + {acmodtime, #ssh_xfer_attr.atime}, + {acmodtime, #ssh_xfer_attr.mtime}, + {accesstime, #ssh_xfer_attr.atime}, + {subsecond_times, #ssh_xfer_attr.atime_nseconds}, + {createtime, #ssh_xfer_attr.createtime}, + {subsecond_times, #ssh_xfer_attr.createtime_nseconds}, + {modifytime, #ssh_xfer_attr.mtime}, + {subsecond_times, #ssh_xfer_attr.mtime_nseconds}, + {acl, #ssh_xfer_attr.acl}, + {bits, #ssh_xfer_attr.attrib_bits}, + {extended, #ssh_xfer_attr.extensions}], + #ssh_xfer_attr { type = decode_file_type(Type) }, + Flags, + Tail2). + +decode_As(Vsn, [{AName, AField}|As], R, Flags, Tail) -> + %%?dbg(false, "decode_As: Vsn=~p AName=~p AField=~p Flags=~p Tail=~p\n", [Vsn, AName, AField, Flags, Tail]), + case AName of + size when ?is_set(?SSH_FILEXFER_ATTR_SIZE, Flags) -> + <<?UINT64(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + ownergroup when ?is_set(?SSH_FILEXFER_ATTR_UIDGID, Flags),Vsn=<3 -> + <<?UINT32(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + ownergroup when ?is_set(?SSH_FILEXFER_ATTR_OWNERGROUP, Flags),Vsn>=5 -> + <<?UINT32(Len), Bin:Len/binary, Tail2/binary>> = Tail, + X = binary_to_list(Bin), + %%?dbg(true, "ownergroup X=~p\n", [X]), + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + + permissions when ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS,Flags),Vsn>=5-> + <<?UINT32(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + + permissions when ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS,Flags),Vsn=<3-> + <<?UINT32(X), Tail2/binary>> = Tail, + R1 = setelement(AField, R, X), + Type = case X band ?S_IFMT of + ?S_IFDIR -> directory; + ?S_IFCHR -> char_device; + ?S_IFBLK -> block_device; + ?S_IFIFO -> fifi; + ?S_IFREG -> regular; + ?S_IFSOCK -> socket; + ?S_IFLNK -> symlink; + _ -> unknown + end, + decode_As(Vsn, As, R1#ssh_xfer_attr { type=Type}, Flags, Tail2); + + acmodtime when ?is_set(?SSH_FILEXFER_ATTR_ACMODTIME,Flags),Vsn=<3 -> + <<?UINT32(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + accesstime when ?is_set(?SSH_FILEXFER_ATTR_ACCESSTIME,Flags),Vsn>=5 -> + <<?UINT64(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + modifytime when ?is_set(?SSH_FILEXFER_ATTR_MODIFYTIME,Flags),Vsn>=5 -> + <<?UINT64(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + createtime when ?is_set(?SSH_FILEXFER_ATTR_CREATETIME,Flags),Vsn>=5 -> + <<?UINT64(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + subsecond_times when ?is_set(?SSH_FILEXFER_ATTR_SUBSECOND_TIMES,Flags),Vsn>=5 -> + <<?UINT32(X), Tail2/binary>> = Tail, + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + acl when ?is_set(?SSH_FILEXFER_ATTR_ACL, Flags), Vsn>=5 -> + {X,Tail2} = decode_acl(Tail), + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + bits when ?is_set(?SSH_FILEXFER_ATTR_BITS, Flags), Vsn >=5 -> + <<?UINT32(Y), Tail2/binary>> = Tail, + X = decode_attrib_bits(Y), + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + extended when ?is_set(?SSH_FILEXFER_ATTR_EXTENDED, Flags) -> + {X,Tail2} = decode_extended(Tail), + decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); + _ -> + decode_As(Vsn, As, R, Flags, Tail) + end; +decode_As(_Vsn, [], R, _, Tail) -> + {R, Tail}. + + + + +decode_names(_Vsn, 0, _Data) -> + []; +decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, + ?UINT32(LLen), _LongName:LLen/binary, + Tail/binary>>) when Vsn =< 3 -> + Name = binary_to_list(FileName), + %%?dbg(true, "decode_names: ~p\n", [Name]), + {A, Tail2} = decode_ATTR(Vsn, Tail), + [{Name, A} | decode_names(Vsn, I-1, Tail2)]; +decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, + Tail/binary>>) when Vsn >= 4 -> + Name = binary_to_list(FileName), + %%?dbg(true, "decode_names: ~p\n", [Name]), + {A, Tail2} = decode_ATTR(Vsn, Tail), + [{Name, A} | decode_names(Vsn, I-1, Tail2)]. + +encode_names(Vsn, NamesAndAttrs) -> + lists:mapfoldl(fun(N, L) -> encode_name(Vsn, N, L) end, 0, NamesAndAttrs). + +encode_name(Vsn, {Name,Attr}, Len) when Vsn =< 3 -> + NLen = length(Name), + %%?dbg(true, "encode_name: Vsn=~p Name=~p Attr=~p\n", + %% [Vsn, Name, Attr]), + EncAttr = encode_ATTR(Vsn, Attr), + ALen = size(EncAttr), + NewLen = Len + NLen*2 + 4 + 4 + ALen, + {[<<?UINT32(NLen)>>, Name, <<?UINT32(NLen)>>, Name, EncAttr], NewLen}; +encode_name(Vsn, {Name,Attr}, Len) when Vsn >= 4 -> + NLen = length(Name), + EncAttr = encode_ATTR(Vsn, Attr), + ALen = size(EncAttr), + {[<<?UINT32(NLen)>>, Name, EncAttr], + Len + 4 + NLen + ALen}. + +encode_acl(ACLList) -> + Count = length(ACLList), + [?uint32(Count) | encode_acl_items(ACLList)]. + +encode_acl_items([ACE|As]) -> + Type = encode_ace_type(ACE#ssh_xfer_ace.type), + Flag = encode_ace_flag(ACE#ssh_xfer_ace.flag), + Mask = encode_ace_mask(ACE#ssh_xfer_ace.mask), + Who = list_to_binary(ACE#ssh_xfer_ace.who), + [?uint32(Type), ?uint32(Flag), ?uint32(Mask), + ?binary(Who) | encode_acl_items(As)]; +encode_acl_items([]) -> + []. + + +decode_acl(<<?UINT32(Count), Tail/binary>>) -> + decode_acl_items(Count, Tail, []). + +decode_acl_items(0, Tail, Acc) -> + {reverse(Acc), Tail}; +decode_acl_items(I, <<?UINT32(Type), + ?UINT32(Flag), + ?UINT32(Mask), + ?UINT32(WLen), BWho:WLen/binary, + Tail/binary>>, Acc) -> + decode_acl_items(I-1, Tail, + [#ssh_xfer_ace { type = decode_ace_type(Type), + flag = decode_ace_flag(Flag), + mask = decode_ace_mask(Mask), + who = binary_to_list(BWho)} | Acc]). + +encode_extensions(Exts) -> + Count = length(Exts), + [?uint32(Count) | encode_ext(Exts)]. + +encode_ext([{Type, Data} | Exts]) -> + [?string(Type), ?string(Data) | encode_ext(Exts)]; +encode_ext([]) -> + []. + + +decode_extended(<<?UINT32(Count), Tail/binary>>) -> + decode_ext(Count, Tail, []). + +decode_ext(0, Tail, Acc) -> + {reverse(Acc), Tail}; +decode_ext(I, <<?UINT32(TLen), Type:TLen/binary, + ?UINT32(DLen), Data:DLen/binary, + Tail/binary>>, Acc) -> + decode_ext(I-1, Tail, [{binary_to_list(Type), Data}|Acc]). + + + +%% Encode bit encoded flags +encode_bits(Fun, BitNames) -> + encode_bits(Fun, 0, BitNames). + +encode_bits(Fun, F, [Bit|BitNames]) -> + encode_bits(Fun, Fun(Bit) bor F, BitNames); +encode_bits(_Fun, F, []) -> + F. + +%% Decode bit encoded flags +decode_bits(F, [{Bit,BitName}|Bits]) -> + if F band Bit == Bit -> + [BitName | decode_bits(F, Bits)]; + true -> + decode_bits(F, Bits) + end; +decode_bits(_F, []) -> + []. diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl new file mode 100755 index 0000000000..f32ec5f774 --- /dev/null +++ b/lib/ssh/src/ssh_xfer.hrl @@ -0,0 +1,251 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: SFTP defines +-define(SSH_SFTP_PROTOCOL_VERSION, 6). +%%%---------------------------------------------------------------------- +%%% # SSH_FXP_xxx +%%% Description: Request and initialization packet types for file transfer +%%% protocol. +%%%---------------------------------------------------------------------- +-define(SSH_FXP_INIT, 1). +-define(SSH_FXP_VERSION, 2). +-define(SSH_FXP_OPEN, 3). +-define(SSH_FXP_CLOSE, 4). +-define(SSH_FXP_READ, 5). +-define(SSH_FXP_WRITE, 6). +-define(SSH_FXP_LSTAT, 7). +-define(SSH_FXP_FSTAT, 8). +-define(SSH_FXP_SETSTAT, 9). +-define(SSH_FXP_FSETSTAT, 10). +-define(SSH_FXP_OPENDIR, 11). +-define(SSH_FXP_READDIR, 12). +-define(SSH_FXP_REMOVE, 13). +-define(SSH_FXP_MKDIR, 14). +-define(SSH_FXP_RMDIR, 15). +-define(SSH_FXP_REALPATH, 16). +-define(SSH_FXP_STAT, 17). +-define(SSH_FXP_RENAME, 18). +-define(SSH_FXP_READLINK, 19). +-define(SSH_FXP_SYMLINK, 20). +-define(SSH_FXP_STATUS, 101). +-define(SSH_FXP_HANDLE, 102). +-define(SSH_FXP_DATA, 103). +-define(SSH_FXP_NAME, 104). +-define(SSH_FXP_ATTRS, 105). +-define(SSH_FXP_EXTENDED, 200). +-define(SSH_FXP_EXTENDED_REPLY, 201). + +%%%---------------------------------------------------------------------- +%%% # SSH_FX_xxx +%%% Description: Response packet types for file transfer protocol. +%%%---------------------------------------------------------------------- + +-define(SSH_FX_OK, 0). +-define(SSH_FX_EOF, 1). +-define(SSH_FX_NO_SUCH_FILE, 2). +-define(SSH_FX_PERMISSION_DENIED, 3). +-define(SSH_FX_FAILURE, 4). +-define(SSH_FX_BAD_MESSAGE, 5). +-define(SSH_FX_NO_CONNECTION, 6). +-define(SSH_FX_CONNECTION_LOST, 7). +-define(SSH_FX_OP_UNSUPPORTED, 8). +-define(SSH_FX_INVALID_HANDLE, 9). +-define(SSH_FX_NO_SUCH_PATH, 10). +-define(SSH_FX_FILE_ALREADY_EXISTS, 11). +-define(SSH_FX_WRITE_PROTECT, 12). +-define(SSH_FX_NO_MEDIA, 13). +-define(SSH_FX_NO_SPACE_ON_FILESYSTEM, 14). +-define(SSH_FX_QUOTA_EXCEEDED, 15). +-define(SSH_FX_UNKNOWN_PRINCIPLE, 16). +-define(SSH_FX_LOCK_CONFlICT, 17). +-define(SSH_FX_DIR_NOT_EMPTY, 18). +-define(SSH_FX_NOT_A_DIRECTORY, 19). +-define(SSH_FX_FILE_IS_A_DIRECTORY, 24). + +%%%---------------------------------------------------------------------- +%%% # SSH_FILEXFER_xxx +%%% Description: Bits for file attributes bit mask +%%%---------------------------------------------------------------------- +-define(SSH_FILEXFER_ATTR_SIZE, 16#00000001). %% vsn 3,5 +-define(SSH_FILEXFER_ATTR_UIDGID, 16#00000002). %% vsn 3 +-define(SSH_FILEXFER_ATTR_PERMISSIONS, 16#00000004). %% vsn 3,5 +-define(SSH_FILEXFER_ATTR_ACCESSTIME, 16#00000008). %% vsn 5 +-define(SSH_FILEXFER_ATTR_ACMODTIME, 16#00000008). %% vsn 3 +-define(SSH_FILEXFER_ATTR_CREATETIME, 16#00000010). %% vsn 5 +-define(SSH_FILEXFER_ATTR_MODIFYTIME, 16#00000020) .%% vsn 5 +-define(SSH_FILEXFER_ATTR_ACL, 16#00000040). %% vsn 5 +-define(SSH_FILEXFER_ATTR_OWNERGROUP, 16#00000080). %% vsn 5 +-define(SSH_FILEXFER_ATTR_SUBSECOND_TIMES, 16#00000100). %% vsn 5 +-define(SSH_FILEXFER_ATTR_BITS, 16#00000200). %% vsn 5 +-define(SSH_FILEXFER_ATTR_EXTENDED, 16#80000000). %% vsn 3,5 + +%% File types +-define(SSH_FILEXFER_TYPE_REGULAR, 1). +-define(SSH_FILEXFER_TYPE_DIRECTORY, 2). +-define(SSH_FILEXFER_TYPE_SYMLINK, 3). +-define(SSH_FILEXFER_TYPE_SPECIAL, 4). +-define(SSH_FILEXFER_TYPE_UNKNOWN, 5). +-define(SSH_FILEXFER_TYPE_SOCKET, 6). +-define(SSH_FILEXFER_TYPE_CHAR_DEVICE, 7). +-define(SSH_FILEXFER_TYPE_BLOCK_DEVICE, 8). +-define(SSH_FILEXFER_TYPE_FIFO, 9). + +%% Permissions +-define(S_IRUSR, 8#0000400). +-define(S_IWUSR, 8#0000200). +-define(S_IXUSR, 8#0000100). +-define(S_IRGRP, 8#0000040). +-define(S_IWGRP, 8#0000020). +-define(S_IXGRP, 8#0000010). +-define(S_IROTH, 8#0000004). +-define(S_IWOTH, 8#0000002). +-define(S_IXOTH, 8#0000001). +-define(S_ISUID, 8#0004000). +-define(S_ISGID, 8#0002000). +-define(S_ISVTX, 8#0001000). +%% type bits (version 3 only?) +-define(S_IFMT, 8#0170000). %% file type mask +-define(S_IFDIR, 8#0040000). +-define(S_IFCHR, 8#0020000). +-define(S_IFBLK, 8#0060000). +-define(S_IFIFO, 8#0010000). +-define(S_IFREG, 8#0100000). +-define(S_IFLNK, 8#0120000). +-define(S_IFSOCK, 8#0140000). + +%% ACE-Type +-define(ACE4_ACCESS_ALLOWED_ACE_TYPE, 16#00000000). +-define(ACE4_ACCESS_DENIED_ACE_TYPE, 16#00000001). +-define(ACE4_SYSTEM_AUDIT_ACE_TYPE, 16#00000002). +-define(ACE4_SYSTEM_ALARM_ACE_TYPE, 16#00000003). + +%% ACE-Flag +-define(ACE4_FILE_INHERIT_ACE, 16#00000001). +-define(ACE4_DIRECTORY_INHERIT_ACE, 16#00000002). +-define(ACE4_NO_PROPAGATE_INHERIT_ACE, 16#00000004). +-define(ACE4_INHERIT_ONLY_ACE, 16#00000008). +-define(ACE4_SUCCESSFUL_ACCESS_ACE_FLAG, 16#00000010). +-define(ACE4_FAILED_ACCESS_ACE_FLAG, 16#00000020). +-define(ACE4_IDENTIFIER_GROUP, 16#00000040). + +%% ACE-Mask +-define(ACE4_READ_DATA, 16#00000001). +-define(ACE4_LIST_DIRECTORY, 16#00000001). +-define(ACE4_WRITE_DATA, 16#00000002). +-define(ACE4_ADD_FILE, 16#00000002). +-define(ACE4_APPEND_DATA, 16#00000004). +-define(ACE4_ADD_SUBDIRECTORY, 16#00000004). +-define(ACE4_READ_NAMED_ATTRS, 16#00000008). +-define(ACE4_WRITE_NAMED_ATTRS, 16#00000010). +-define(ACE4_EXECUTE, 16#00000020). +-define(ACE4_DELETE_CHILD, 16#00000040). +-define(ACE4_READ_ATTRIBUTES, 16#00000080). +-define(ACE4_WRITE_ATTRIBUTES, 16#00000100). +-define(ACE4_DELETE, 16#00010000). +-define(ACE4_READ_ACL, 16#00020000). +-define(ACE4_WRITE_ACL, 16#00040000). +-define(ACE4_WRITE_OWNER, 16#00080000). +-define(ACE4_SYNCHRONIZE, 16#00100000). + +%% Attrib-bits +-define(SSH_FILEXFER_ATTR_FLAGS_READONLY, 16#00000001). +-define(SSH_FILEXFER_ATTR_FLAGS_SYSTEM, 16#00000002). +-define(SSH_FILEXFER_ATTR_FLAGS_HIDDEN, 16#00000004). +-define(SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE, 16#00000008). +-define(SSH_FILEXFER_ATTR_FLAGS_ARCHIVE, 16#00000010). +-define(SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED, 16#00000020). +-define(SSH_FILEXFER_ATTR_FLAGS_COMPRESSED, 16#00000040). +-define(SSH_FILEXFER_ATTR_FLAGS_SPARSE, 16#00000080). +-define(SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY, 16#00000100). +-define(SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE, 16#00000200). +-define(SSH_FILEXFER_ATTR_FLAGS_SYNC, 16#00000400). + +%% Open flags (version 3) +-define(SSH_FXF_READ, 16#00000001). +-define(SSH_FXF_WRITE, 16#00000002). +-define(SSH_FXF_APPEND, 16#00000004). +-define(SSH_FXF_CREAT, 16#00000008). +-define(SSH_FXF_TRUNC, 16#00000010). +-define(SSH_FXF_EXCL, 16#00000020). + +%% Open flags (version 5) +-define(SSH_FXF_ACCESS_DISPOSITION, 16#00000007). +-define(SSH_FXF_CREATE_NEW, 16#00000000). +-define(SSH_FXF_CREATE_TRUNCATE, 16#00000001). +-define(SSH_FXF_OPEN_EXISTING, 16#00000002). +-define(SSH_FXF_OPEN_OR_CREATE, 16#00000003). +-define(SSH_FXF_TRUNCATE_EXISTING, 16#00000004). +-define(SSH_FXF_ACCESS_APPEND_DATA, 16#00000008). +-define(SSH_FXF_ACCESS_APPEND_DATA_ATOMIC, 16#00000010). +-define(SSH_FXF_ACCESS_TEXT_MODE, 16#00000020). +-define(SSH_FXF_ACCESS_READ_LOCK, 16#00000040). +-define(SSH_FXF_ACCESS_WRITE_LOCK, 16#00000080). +-define(SSH_FXF_ACCESS_DELETE_LOCK, 16#00000100). + +%% Rename flags +-define(SSH_FXP_RENAME_OVERWRITE, 16#00000001). +-define(SSH_FXP_RENAME_ATOMIC, 16#00000002). +-define(SSH_FXP_RENAME_NATIVE, 16#00000004). + + +-define(SSH_FILEXFER_LARGEFILESIZE, (1 bsl 63)). + +-record(ssh_xfer_attr, + { + type, %% regular, dirctory, symlink, ... + size, + owner, + group, + permissions, + atime, + atime_nseconds, + createtime, + createtime_nseconds, + mtime, + mtime_nseconds, + acl, + attrib_bits, + extensions %% list of [{type,data}] + }). + +-record(ssh_xfer_ace, + { + type, + flag, + mask, + who + }). + +%% connection endpoint and server/client info +-record(ssh_xfer, + { + vsn, %% server version + ext, %% server extensions + cm, %% connection mgr + channel %% SFTP channel + }). + + + + + + diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl new file mode 100644 index 0000000000..265d1a1cd6 --- /dev/null +++ b/lib/ssh/src/sshc_sup.erl @@ -0,0 +1,65 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: The ssh client subsystem supervisor +%%---------------------------------------------------------------------- + +-module(sshc_sup). + +-behaviour(supervisor). + +-export([start_link/1, start_child/1]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(Args) -> + supervisor:start_link({local, ?MODULE}, ?MODULE, [Args]). + +start_child(Args) -> + supervisor:start_child(?MODULE, Args). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init(Args) -> + RestartStrategy = simple_one_for_one, + MaxR = 10, + MaxT = 3600, + {ok, {{RestartStrategy, MaxR, MaxT}, [child_spec(Args)]}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +child_spec(_) -> + Name = undefined, % As simple_one_for_one is used. + StartFunc = {ssh_connection_controler, start_link, []}, + Restart = temporary, +% Shutdown = infinity, + Shutdown = 5000, + Modules = [ssh_connection_controler], +% Type = supervisor, + Type = worker, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl new file mode 100644 index 0000000000..9c9ba5958c --- /dev/null +++ b/lib/ssh/src/sshd_sup.erl @@ -0,0 +1,111 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The top supervisor for ssh servers hangs under +%% ssh_sup. +%%---------------------------------------------------------------------- + +-module(sshd_sup). + +-behaviour(supervisor). + +-export([start_link/1, start_child/1, stop_child/1, + stop_child/2, system_name/1]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% API +%%%========================================================================= +start_link(Servers) -> + supervisor:start_link({local, ?MODULE}, ?MODULE, [Servers]). + +start_child(ServerOpts) -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + case ssh_system_sup:system_supervisor(Address, Port) of + undefined -> + Spec = child_spec(Address, Port, ServerOpts), + case supervisor:start_child(?MODULE, Spec) of + {error, already_present} -> + Name = id(Address, Port), + supervisor:delete_child(?MODULE, Name), + supervisor:start_child(?MODULE, Spec); + Reply -> + Reply + end; + Pid -> + AccPid = ssh_system_sup:acceptor_supervisor(Pid), + ssh_acceptor_sup:start_child(AccPid, ServerOpts) + end. + +stop_child(Name) -> + case supervisor:terminate_child(?MODULE, Name) of + ok -> + supervisor:delete_child(?MODULE, Name); + Error -> + Error + end. + +stop_child(Address, Port) -> + Name = id(Address, Port), + stop_child(Name). + +system_name(SysSup) -> + Children = supervisor:which_children(sshd_sup), + system_name(SysSup, Children). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([Servers]) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Fun = fun(ServerOpts) -> + Address = proplists:get_value(address, ServerOpts), + Port = proplists:get_value(port, ServerOpts), + child_spec(Address, Port, ServerOpts) + end, + Children = lists:map(Fun, Servers), + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +child_spec(Address, Port, ServerOpts) -> + Name = id(Address, Port), + StartFunc = {ssh_system_sup, start_link, [ServerOpts]}, + Restart = transient, + Shutdown = infinity, + Modules = [ssh_system_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +id(Address, Port) -> + {server, ssh_system_sup, Address, Port}. + +system_name([], _ ) -> + undefined; +system_name(SysSup, [{Name, SysSup, _, _} | _]) -> + Name; +system_name(SysSup, [_ | Rest]) -> + system_name(SysSup, Rest). diff --git a/lib/ssh/subdirs.mk b/lib/ssh/subdirs.mk new file mode 100644 index 0000000000..71ab06952f --- /dev/null +++ b/lib/ssh/subdirs.mk @@ -0,0 +1,4 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +SUB_DIRS = src c_src + diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk new file mode 100644 index 0000000000..016fb30c69 --- /dev/null +++ b/lib/ssh/vsn.mk @@ -0,0 +1,73 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +SSH_VSN = 1.1.7 +APP_VSN = "ssh-$(SSH_VSN)" + +TICKETS = OTP-8121 \ + OTP-8277 \ + OTP-8278 \ + OTP-8201 + +TICKETS_1.1.6 = OTP-8110 \ + OTP-8162 \ + OTP-8173 \ + OTP-8174 \ + OTP-8175 \ + OTP-8176 + +TICKETS_1.1.5 = OTP-8159 \ + OTP-8160 \ + OTP-8161 + +TICKETS_1.1.4 = OTP-8071 + +TICKETS_1.1.3 = OTP-7996 \ + OTP-8034 \ + OTP-8035 + +TICKETS_1.1.2 = OTP-7914 \ + OTP-7917 \ + OTP-7918 \ + OTP-7921 \ + OTP-7919 \ + OTP-7930 \ + OTP-7957 + +TICKETS_1.1.1 = OTP-7828 \ + OTP-7795 \ + OTP-7807 \ + OTP-7808 \ + OTP-7809 + +TICKETS_1.1 = OTP-7676 \ + OTP-7683 \ + OTP-7685 \ + OTP-7766 \ + OTP-7767 \ + OTP-7768 \ + OTP-7770 \ + OTP-7456 \ + OTP-7769 \ + OTP-7516 \ + OTP-7645 \ + +TICKETS_1.0.2 = \ + OTP-7141\ + +TICKETS_1.0.1 = \ + OTP-7318 \ + OTP-7305 \ + OTP-7564 \ + OTP-7565 \ + OTP-7566 \ + +TICKETS_1.0 = \ + OTP-7485 \ + OTP-7504 \ + OTP-7356 \ + OTP-7502 \ + OTP-7503 + +TICKETS_0.9.9.6 = \ + OTP-7246 \ + OTP-7247 \
\ No newline at end of file |